diff --git a/CHANGELOG.md b/CHANGELOG.md index d97bc936..0f7ea6b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## [8.7.2](https://github.com/NativeScript/ios/compare/v8.7.1...v8.7.2) (2024-05-16) + + +### Bug Fixes + +* **ios:** watchOS embedded apps ([#250](https://github.com/NativeScript/ios/issues/250)) ([1df9ea2](https://github.com/NativeScript/ios/commit/1df9ea20b6bfde5163b0486e444e5471fb8343b2)) + + + +## [8.7.1](https://github.com/NativeScript/ios/compare/v8.7.0...v8.7.1) (2024-04-26) + + +### Bug Fixes + +* url href ([#252](https://github.com/NativeScript/ios/issues/252)) ([4a6e9ad](https://github.com/NativeScript/ios/commit/4a6e9adde6950e09ac0c2fd2713e25aa919ad448)) +* Xcode 15.3+ not setting TARGET_OS_IOS correctly ([#248](https://github.com/NativeScript/ios/issues/248)) ([74e1444](https://github.com/NativeScript/ios/commit/74e144432bf17cc043d0e64affc9cb1703e80832)) + + + # [8.7.0](https://github.com/NativeScript/ios/compare/v8.6.3...v8.7.0) (2024-04-08) diff --git a/NativeScript/NativeScript-Prefix.pch b/NativeScript/NativeScript-Prefix.pch index 4c6445f4..b070729c 100644 --- a/NativeScript/NativeScript-Prefix.pch +++ b/NativeScript/NativeScript-Prefix.pch @@ -1,8 +1,7 @@ #ifndef NativeScript_Prefix_pch #define NativeScript_Prefix_pch - -#define NATIVESCRIPT_VERSION "8.7.0-1" +#define NATIVESCRIPT_VERSION "8.7.2" #ifdef DEBUG #define SIZEOF_OFF_T 8 diff --git a/NativeScript/runtime/ConcurrentQueue.cpp b/NativeScript/runtime/ConcurrentQueue.cpp index 8b361838..24721114 100644 --- a/NativeScript/runtime/ConcurrentQueue.cpp +++ b/NativeScript/runtime/ConcurrentQueue.cpp @@ -14,7 +14,7 @@ void ConcurrentQueue::Initialize(CFRunLoopRef runLoop, void (*performWork)(void* CFRunLoopAddSource(this->runLoop_, this->runLoopTasksSource_, kCFRunLoopCommonModes); } -void ConcurrentQueue::Push(std::string message) { +void ConcurrentQueue::Push(std::shared_ptr message) { if (this->runLoopTasksSource_ != nullptr && !CFRunLoopSourceIsValid(this->runLoopTasksSource_)) { return; } @@ -27,12 +27,12 @@ void ConcurrentQueue::Push(std::string message) { this->SignalAndWakeUp(); } -std::vector ConcurrentQueue::PopAll() { +std::vector> ConcurrentQueue::PopAll() { std::unique_lock mlock(this->mutex_); - std::vector messages; + std::vector> messages; while (!this->messagesQueue_.empty()) { - std::string message = this->messagesQueue_.front(); + std::shared_ptr message = this->messagesQueue_.front(); this->messagesQueue_.pop(); messages.push_back(message); } diff --git a/NativeScript/runtime/ConcurrentQueue.h b/NativeScript/runtime/ConcurrentQueue.h index 75bc74e4..84dff251 100644 --- a/NativeScript/runtime/ConcurrentQueue.h +++ b/NativeScript/runtime/ConcurrentQueue.h @@ -6,17 +6,18 @@ #include #include #include +#include "Message.hpp" namespace tns { struct ConcurrentQueue { public: void Initialize(CFRunLoopRef runLoop, void (*performWork)(void*), void* info); - void Push(std::string message); - std::vector PopAll(); + void Push(std::shared_ptr message); + std::vector> PopAll(); void Terminate(); private: - std::queue messagesQueue_; + std::queue> messagesQueue_; CFRunLoopSourceRef runLoopTasksSource_ = nullptr; CFRunLoopRef runLoop_ = nullptr; bool terminated = false; diff --git a/NativeScript/runtime/DataWrapper.h b/NativeScript/runtime/DataWrapper.h index 0d655b24..9b9c05f3 100644 --- a/NativeScript/runtime/DataWrapper.h +++ b/NativeScript/runtime/DataWrapper.h @@ -654,12 +654,12 @@ class ExtVectorWrapper: public BaseDataWrapper { class WorkerWrapper: public BaseDataWrapper { public: - WorkerWrapper(v8::Isolate* mainIsolate, std::function thiz, std::string)> onMessage); + WorkerWrapper(v8::Isolate* mainIsolate, std::function thiz, std::shared_ptr)> onMessage); void Start(std::shared_ptr> poWorker, std::function func); void CallOnErrorHandlers(v8::TryCatch& tc); void PassUncaughtExceptionFromWorkerToMain(v8::Local context, v8::TryCatch& tc, bool async = true); - void PostMessage(std::string message); + void PostMessage(std::shared_ptr message); void Close(); void Terminate(); @@ -691,7 +691,7 @@ class WorkerWrapper: public BaseDataWrapper { std::atomic isTerminating_; bool isDisposed_; bool isWeak_; - std::function thiz, std::string)> onMessage_; + std::function thiz, std::shared_ptr)> onMessage_; std::shared_ptr> poWorker_; ConcurrentQueue queue_; static std::atomic nextId_; diff --git a/NativeScript/runtime/Helpers.h b/NativeScript/runtime/Helpers.h index 80d1e442..be776ec9 100644 --- a/NativeScript/runtime/Helpers.h +++ b/NativeScript/runtime/Helpers.h @@ -340,6 +340,57 @@ void SetConstructorFunction(v8::Isolate* isolate, SetConstructorFunctionFlag::SET_CLASS_NAME); +template +inline v8::Local FIXED_ONE_BYTE_STRING( + v8::Isolate* isolate, + const char(&data)[N]) { + return OneByteString(isolate, data, N - 1); +} + +template +inline v8::Local FIXED_ONE_BYTE_STRING( + v8::Isolate* isolate, + const std::array& arr) { + return OneByteString(isolate, arr.data(), N - 1); +} + +class PersistentToLocal { + public: + // If persistent.IsWeak() == false, then do not call persistent.Reset() + // while the returned Local is still in scope, it will destroy the + // reference to the object. + template + static inline v8::Local Default( + v8::Isolate* isolate, + const v8::PersistentBase& persistent) { + if (persistent.IsWeak()) { + return PersistentToLocal::Weak(isolate, persistent); + } else { + return PersistentToLocal::Strong(persistent); + } + } + + // Unchecked conversion from a non-weak Persistent to Local, + // use with care! + // + // Do not call persistent.Reset() while the returned Local is still in + // scope, it will destroy the reference to the object. + template + static inline v8::Local Strong( + const v8::PersistentBase& persistent) { +// DCHECK(!persistent.IsWeak()); + return *reinterpret_cast*>( + const_cast*>(&persistent)); + } + + template + static inline v8::Local Weak( + v8::Isolate* isolate, + const v8::PersistentBase& persistent) { + return v8::Local::New(isolate, persistent); + } +}; + } #endif /* Helpers_h */ diff --git a/NativeScript/runtime/Message.cpp b/NativeScript/runtime/Message.cpp new file mode 100644 index 00000000..270adbf4 --- /dev/null +++ b/NativeScript/runtime/Message.cpp @@ -0,0 +1,488 @@ +// +// Message.cpp +// NativeScript +// +// Created by Eduardo Speroni on 11/22/23. +// Copyright © 2023 Progress. All rights reserved. +// + +#include "Helpers.h" +#include "Message.hpp" +#include "NativeScriptException.h" + +using namespace v8; + +namespace tns { +namespace worker { +namespace { +void ThrowDataCloneException(Local context, + Local message) { + Isolate* isolate = context->GetIsolate(); + // Local argv[] = {message, + // FIXED_ONE_BYTE_STRING(isolate, "DataCloneError")}; + Local exception; + Local domexception_ctor; + NativeScriptException except(isolate, tns::ToString(isolate, message), + "DataCloneError"); + except.ReThrowToV8(isolate); +} +class SerializerDelegate : public v8::ValueSerializer::Delegate { + public: + SerializerDelegate(Isolate* isolate, Local context, Message* m) + : isolate_(isolate), context_(context), msg_(m) {} + + void ThrowDataCloneError(Local message) override { + ThrowDataCloneException(context_, message); + } + + Maybe WriteHostObject(Isolate* isolate, Local object) override { + return Just(true); + // if (BaseObject::IsBaseObject(object)) { + // return WriteHostObject( + // BaseObjectPtr { Unwrap(object) }); + // } + // + // // Convert process.env to a regular object. + // auto env_proxy_ctor_template = env_->env_proxy_ctor_template(); + // if (!env_proxy_ctor_template.IsEmpty() && + // env_proxy_ctor_template->HasInstance(object)) { + // HandleScope scope(isolate); + // // TODO(bnoordhuis) Prototype-less object in case process.env + // contains + // // a "__proto__" key? process.env has a prototype with concomitant + // // methods like toString(). It's probably confusing if that gets + // lost + // // in transmission. + // Local normal_object = Object::New(isolate); + // env_->env_vars()->AssignToObject(isolate, env_->context(), + // normal_object); serializer->WriteUint32(kNormalObject); // Instead + // of a BaseObject. return serializer->WriteValue(env_->context(), + // normal_object); + // } + // + // ThrowDataCloneError(env_->clone_unsupported_type_str()); + // return Nothing(); + } + + Maybe GetSharedArrayBufferId( + Isolate* isolate, Local shared_array_buffer) override { + uint32_t i; + for (i = 0; i < seen_shared_array_buffers_.size(); ++i) { + if (PersistentToLocal::Strong(seen_shared_array_buffers_[i]) == + shared_array_buffer) { + return Just(i); + } + } + + seen_shared_array_buffers_.emplace_back( + Global{isolate, shared_array_buffer}); + msg_->AddSharedArrayBuffer(shared_array_buffer->GetBackingStore()); + return Just(i); + } + + // Maybe GetWasmModuleTransferId( + // Isolate* isolate, Local module) override { + // return Just(msg_->AddWASMModule(module->GetCompiledModule())); + // } + + // bool AdoptSharedValueConveyor(Isolate* isolate, + // SharedValueConveyor&& conveyor) override { + // msg_->AdoptSharedValueConveyor(std::move(conveyor)); + // return true; + // } + + // Maybe Finish(Local context) { + // for (uint32_t i = 0; i < host_objects_.size(); i++) { + // BaseObjectPtr host_object = std::move(host_objects_[i]); + // std::unique_ptr data; + // if (i < first_cloned_object_index_) + // data = host_object->TransferForMessaging(); + // if (!data) + // data = host_object->CloneForMessaging(); + // if (!data) return Nothing(); + // if (data->FinalizeTransferWrite(context, serializer).IsNothing()) + // return Nothing(); + // msg_->AddTransferable(std::move(data)); + // } + // return Just(true); + // } + + // inline void AddHostObject(BaseObjectPtr host_object) { + // // Make sure we have not started serializing the value itself yet. + // CHECK_EQ(first_cloned_object_index_, SIZE_MAX); + // host_objects_.emplace_back(std::move(host_object)); + // } + // + // // Some objects in the transfer list may register sub-objects that can be + // // transferred. This could e.g. be a public JS wrapper object, such as a + // // FileHandle, that is registering its C++ handle for transfer. + // inline Maybe AddNestedHostObjects() { + // for (size_t i = 0; i < host_objects_.size(); i++) { + // std::vector> nested_transferables; + // if + // (!host_objects_[i]->NestedTransferables().To(&nested_transferables)) + // return Nothing(); + // for (auto& nested_transferable : nested_transferables) { + // if (std::find(host_objects_.begin(), + // host_objects_.end(), + // nested_transferable) == host_objects_.end()) { + // AddHostObject(nested_transferable); + // } + // } + // } + // return Just(true); + // } + + ValueSerializer* serializer = nullptr; + + private: + // Maybe WriteHostObject(BaseObjectPtr host_object) { + // BaseObject::TransferMode mode = host_object->GetTransferMode(); + // if (mode == BaseObject::TransferMode::kUntransferable) { + // ThrowDataCloneError(env_->clone_unsupported_type_str()); + // return Nothing(); + // } + // + // for (uint32_t i = 0; i < host_objects_.size(); i++) { + // if (host_objects_[i] == host_object) { + // serializer->WriteUint32(i); + // return Just(true); + // } + // } + // + // if (mode == BaseObject::TransferMode::kTransferable) { + // THROW_ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST(env_); + // return Nothing(); + // } + // + // CHECK_EQ(mode, BaseObject::TransferMode::kCloneable); + // uint32_t index = host_objects_.size(); + // if (first_cloned_object_index_ == SIZE_MAX) + // first_cloned_object_index_ = index; + // serializer->WriteUint32(index); + // host_objects_.push_back(host_object); + // return Just(true); + // } + + __unused Isolate* isolate_; + __unused Local context_; + Message* msg_; + std::vector> seen_shared_array_buffers_; + // std::vector> host_objects_; + __unused size_t first_cloned_object_index_ = SIZE_MAX; + + friend class tns::worker::Message; +}; + +class DeserializerDelegate : public ValueDeserializer::Delegate { + public: + DeserializerDelegate( + Message* m, Isolate* isolate, + // const std::vector>& host_objects, + const std::vector>& shared_array_buffers + // const std::vector& wasm_modules, + // const std::optional& shared_value_conveyor + ) + : // host_objects_(host_objects), + shared_array_buffers_(shared_array_buffers) + // wasm_modules_(wasm_modules), + // shared_value_conveyor_(shared_value_conveyor) + {} + + MaybeLocal ReadHostObject(Isolate* isolate) override { + EscapableHandleScope scope(isolate); + Local object = Object::New(isolate); + return scope.Escape(object).As(); + // // Identifying the index in the message's BaseObject array is + // sufficient. uint32_t id; if (!deserializer->ReadUint32(&id)) + // return MaybeLocal(); + // if (id != kNormalObject) { + // CHECK_LT(id, host_objects_.size()); + // return host_objects_[id]->object(isolate); + // } + // EscapableHandleScope scope(isolate); + // Local context = isolate->GetCurrentContext(); + // Local object; + // if (!deserializer->ReadValue(context).ToLocal(&object)) + // return MaybeLocal(); + // CHECK(object->IsObject()); + // return scope.Escape(object.As()); + } + + MaybeLocal GetSharedArrayBufferFromId( + Isolate* isolate, uint32_t clone_id) override { + // CHECK_LT(clone_id, shared_array_buffers_.size()); + return shared_array_buffers_[clone_id]; + } + + // MaybeLocal GetWasmModuleFromId( + // Isolate* isolate, uint32_t transfer_id) override { + //// CHECK_LT(transfer_id, wasm_modules_.size()); + // return WasmModuleObject::FromCompiledModule( + // isolate, wasm_modules_[transfer_id]); + // } + + // const SharedValueConveyor* GetSharedValueConveyor(Isolate* isolate) + // override { + //// CHECK(shared_value_conveyor_.has_value()); + // return &shared_value_conveyor_.value(); + // } + + ValueDeserializer* deserializer = nullptr; + + private: + // const std::vector>& host_objects_; + const std::vector>& shared_array_buffers_; + // const std::vector& wasm_modules_; + // const std::optional& shared_value_conveyor_; +}; +}; // namespace + +v8::Maybe Message::Serialize(v8::Isolate* isolate, + v8::Local context, + v8::Local input) { + HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(context); + + // Verify that we're not silently overwriting an existing message. + tns::Assert(main_message_buf_.is_empty()); + + SerializerDelegate delegate(isolate, context, this); + ValueSerializer serializer(isolate, &delegate); + delegate.serializer = &serializer; + + std::vector> array_buffers; + // for (uint32_t i = 0; i < transfer_list_v.length(); ++i) { + // Local entry = transfer_list_v[i]; + // if (entry->IsObject()) { + // // See + // https://github.com/nodejs/node/pull/30339#issuecomment-552225353 + // // for details. + // bool untransferable; + // if (!entry.As()->HasPrivate( + // context, + // env->untransferable_object_private_symbol()) + // .To(&untransferable)) { + // return Nothing(); + // } + // if (untransferable) { + // ThrowDataCloneException(context, + // env->transfer_unsupported_type_str()); return Nothing(); + // } + // } + // + // // Currently, we support ArrayBuffers and BaseObjects for which + // // GetTransferMode() returns kTransferable. + // if (entry->IsArrayBuffer()) { + // Local ab = entry.As(); + // // If we cannot render the ArrayBuffer unusable in this Isolate, + // // copying the buffer will have to do. + // // Note that we can currently transfer ArrayBuffers even if they + // were + // // not allocated by Node’s ArrayBufferAllocator in the first + // place, + // // because we pass the underlying v8::BackingStore around rather + // than + // // raw data *and* an Isolate with a non-default ArrayBuffer + // allocator + // // is always going to outlive any Workers it creates, and so will + // its + // // allocator along with it. + // if (!ab->IsDetachable() || ab->WasDetached()) { + // ThrowDataCloneException(context, + // env->transfer_unsupported_type_str()); return Nothing(); + // } + // if (std::find(array_buffers.begin(), array_buffers.end(), ab) != + // array_buffers.end()) { + // ThrowDataCloneException( + // context, + // FIXED_ONE_BYTE_STRING( + // env->isolate(), + // "Transfer list contains duplicate ArrayBuffer")); + // return Nothing(); + // } + // // We simply use the array index in the `array_buffers` list as + // the + // // ID that we write into the serialized buffer. + // uint32_t id = array_buffers.size(); + // array_buffers.push_back(ab); + // serializer.TransferArrayBuffer(id, ab); + // continue; + // } else if (entry->IsObject() && + // BaseObject::IsBaseObject(entry.As())) { + // // Check if the source MessagePort is being transferred. + // if (!source_port.IsEmpty() && entry == source_port) { + // ThrowDataCloneException( + // context, + // FIXED_ONE_BYTE_STRING(env->isolate(), + // "Transfer list contains source + // port")); + // return Nothing(); + // } + // BaseObjectPtr host_object { + // Unwrap(entry.As()) }; + // if (env->message_port_constructor_template()->HasInstance(entry) + // && + // (!host_object || + // static_cast(host_object.get())->IsDetached())) + // { + // ThrowDataCloneException( + // context, + // FIXED_ONE_BYTE_STRING( + // env->isolate(), + // "MessagePort in transfer list is already detached")); + // return Nothing(); + // } + // if (std::find(delegate.host_objects_.begin(), + // delegate.host_objects_.end(), + // host_object) != delegate.host_objects_.end()) { + // ThrowDataCloneException( + // context, + // String::Concat(env->isolate(), + // FIXED_ONE_BYTE_STRING( + // env->isolate(), + // "Transfer list contains duplicate "), + // entry.As()->GetConstructorName())); + // return Nothing(); + // } + // if (host_object && host_object->GetTransferMode() == + // BaseObject::TransferMode::kTransferable) { + // delegate.AddHostObject(host_object); + // continue; + // } + // } + // + // THROW_ERR_INVALID_TRANSFER_OBJECT(env); + // return Nothing(); + // } + // if (delegate.AddNestedHostObjects().IsNothing()) + // return Nothing(); + + serializer.WriteHeader(); + if (serializer.WriteValue(context, input).IsNothing()) { + return Nothing(); + } + + for (Local ab : array_buffers) { + // If serialization succeeded, we render it inaccessible in this Isolate. + std::shared_ptr backing_store = ab->GetBackingStore(); + ab->Detach(); + + array_buffers_.emplace_back(std::move(backing_store)); + } + + // if (delegate.Finish(context).IsNothing()) + // return Nothing(); + + // The serializer gave us a buffer allocated using `malloc()`. + std::pair data = serializer.Release(); + tns::Assert(data.first != NULL, isolate); + main_message_buf_ = + MallocedBuffer(reinterpret_cast(data.first), data.second); + return Just(true); +} + +MaybeLocal Message::Deserialize(Isolate* isolate, + Local context) { + Context::Scope context_scope(context); + + // CHECK(!IsCloseMessage()); + // if (port_list != nullptr && !transferables_.empty()) { + // // Need to create this outside of the EscapableHandleScope, but inside + // // the Context::Scope. + // *port_list = Array::New(env->isolate()); + // } + + EscapableHandleScope handle_scope(isolate); + + // Create all necessary objects for transferables, e.g. MessagePort handles. + // std::vector> + // host_objects(transferables_.size()); auto cleanup = OnScopeLeave([&]() { + // for (BaseObjectPtr object : host_objects) { + // if (!object) continue; + // + // // If the function did not finish successfully, host_objects will + // contain + // // a list of objects that will never be passed to JS. Therefore, we + // // destroy them here. + // object->Detach(); + // } + // }); + + // for (uint32_t i = 0; i < transferables_.size(); ++i) { + // HandleScope handle_scope(env->isolate()); + // TransferData* data = transferables_[i].get(); + // host_objects[i] = data->Deserialize( + // env, context, std::move(transferables_[i])); + // if (!host_objects[i]) return {}; + // if (port_list != nullptr) { + // // If we gather a list of all message ports, and this transferred + // object + // // is a message port, add it to that list. This is a bit of an odd + // case + // // of special handling for MessagePorts (as opposed to applying to all + // // transferables), but it's required for spec compliance. + // DCHECK((*port_list)->IsArray()); + // Local port_list_array = port_list->As(); + // Local obj = host_objects[i]->object(); + // if (env->message_port_constructor_template()->HasInstance(obj)) { + // if (port_list_array->Set(context, + // port_list_array->Length(), + // obj).IsNothing()) { + // return {}; + // } + // } + // } + // } + // transferables_.clear(); + + std::vector> shared_array_buffers; + // Attach all transferred SharedArrayBuffers to their new Isolate. + for (uint32_t i = 0; i < shared_array_buffers_.size(); ++i) { + Local sab = + SharedArrayBuffer::New(isolate, shared_array_buffers_[i]); + shared_array_buffers.push_back(sab); + } + + DeserializerDelegate delegate( + this, isolate, + // host_objects, + shared_array_buffers + // wasm_modules_, + // shared_value_conveyor_ + ); + ValueDeserializer deserializer( + isolate, reinterpret_cast(main_message_buf_.data), + main_message_buf_.size, &delegate); + delegate.deserializer = &deserializer; + + // Attach all transferred ArrayBuffers to their new Isolate. + for (uint32_t i = 0; i < array_buffers_.size(); ++i) { + Local ab = + ArrayBuffer::New(isolate, std::move(array_buffers_[i])); + deserializer.TransferArrayBuffer(i, ab); + } + + if (deserializer.ReadHeader(context).IsNothing()) return {}; + Local return_value; + if (!deserializer.ReadValue(context).ToLocal(&return_value)) return {}; + + // for (BaseObjectPtr base_object : host_objects) { + // if (base_object->FinalizeTransferRead(context, + // &deserializer).IsNothing()) + // return {}; + // } + + // host_objects.clear(); + return handle_scope.Escape(return_value); +} + +void Message::AddSharedArrayBuffer( + std::shared_ptr backing_store) { + shared_array_buffers_.emplace_back(std::move(backing_store)); +} + +Message::Message(MallocedBuffer&& payload) + : main_message_buf_(std::move(payload)) {} +}; // namespace worker +}; // namespace tns diff --git a/NativeScript/runtime/Message.hpp b/NativeScript/runtime/Message.hpp new file mode 100644 index 00000000..e90ec00d --- /dev/null +++ b/NativeScript/runtime/Message.hpp @@ -0,0 +1,136 @@ +// +// Message.hpp +// NativeScript +// +// Created by Eduardo Speroni on 11/22/23. +// Copyright © 2023 Progress. All rights reserved. +// + +#ifndef Message_hpp +#define Message_hpp +#include "v8.h" + +namespace tns { + +template +inline T* Malloc(size_t n) { + T* ret = malloc(n); + return ret; +} + +template +T* UncheckedRealloc(T* pointer, size_t n) { + size_t full_size = sizeof(T) * n; + + if (full_size == 0) { + free(pointer); + return nullptr; + } + + void* allocated = realloc(pointer, full_size); + + // if (UNLIKELY(allocated == nullptr)) { + // // Tell V8 that memory is low and retry. + // LowMemoryNotification(); + // allocated = realloc(pointer, full_size); + // } + + return static_cast(allocated); +} + +template +struct MallocedBuffer { + T* data; + size_t size; + + T* release() { + T* ret = data; + data = nullptr; + return ret; + } + + void Truncate(size_t new_size) { + CHECK_LE(new_size, size); + size = new_size; + } + + void Realloc(size_t new_size) { + Truncate(new_size); + data = UncheckedRealloc(data, new_size); + } + + bool is_empty() const { return data == nullptr; } + + MallocedBuffer() : data(nullptr), size(0) {} + explicit MallocedBuffer(size_t size) : data(Malloc(size)), size(size) {} + MallocedBuffer(T* data, size_t size) : data(data), size(size) {} + MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) { + other.data = nullptr; + } + MallocedBuffer& operator=(MallocedBuffer&& other) { + this->~MallocedBuffer(); + return *new (this) MallocedBuffer(std::move(other)); + } + ~MallocedBuffer() { free(data); } + MallocedBuffer(const MallocedBuffer&) = delete; + MallocedBuffer& operator=(const MallocedBuffer&) = delete; +}; + +namespace worker { + +class Message { + public: + Message(MallocedBuffer&& payload = MallocedBuffer()); + Message(Message&& other) = default; + Message& operator=(Message&& other) = default; + Message& operator=(const Message&) = delete; + Message(const Message&) = delete; + v8::Maybe Serialize(v8::Isolate* isolate, + v8::Local context, + v8::Local input); + v8::MaybeLocal Deserialize(v8::Isolate* isolate, + v8::Local context); + // Internal method of Message that is called when a new SharedArrayBuffer + // object is encountered in the incoming value's structure. + void AddSharedArrayBuffer(std::shared_ptr backing_store); + // Internal method of Message that is called once serialization finishes + // and that transfers ownership of `data` to this message. + // void AddTransferable(std::unique_ptr&& data); + // Internal method of Message that is called when a new WebAssembly.Module + // object is encountered in the incoming value's structure. + // uint32_t AddWASMModule(v8::CompiledWasmModule&& mod); + // Internal method of Message that is called when a shared value is + // encountered for the first time in the incoming value's structure. + // void AdoptSharedValueConveyor(v8::SharedValueConveyor&& conveyor); + + // The host objects that will be transferred, as recorded by Serialize() + // (e.g. MessagePorts). + // Used for warning user about posting the target MessagePort to itself, + // which will as a side effect destroy the communication channel. + // const std::vector>& transferables() + // const { + // return transferables_; + // } + // bool has_transferables() const { + // return !transferables_.empty() || !array_buffers_.empty(); + // } + + // void MemoryInfo(MemoryTracker* tracker) const override; + // + // SET_MEMORY_INFO_NAME(Message) + // SET_SELF_SIZE(Message) + private: + MallocedBuffer main_message_buf_; + // TODO(addaleax): Make this a std::variant to save storage size in the common + // case (which is that all of these vectors are empty) once that is available + // with C++17. + std::vector> array_buffers_; + std::vector> shared_array_buffers_; + // std::vector> transferables_; + // std::vector wasm_modules_; + // std::optional shared_value_conveyor_; +}; +}; // namespace worker +} // namespace tns + +#endif /* Message_hpp */ diff --git a/NativeScript/runtime/NativeScriptException.h b/NativeScript/runtime/NativeScriptException.h index a7099312..d8033d82 100644 --- a/NativeScript/runtime/NativeScriptException.h +++ b/NativeScript/runtime/NativeScriptException.h @@ -10,17 +10,20 @@ class NativeScriptException { public: NativeScriptException(const std::string& message); NativeScriptException(v8::Isolate* isolate, v8::TryCatch& tc, const std::string& message); + NativeScriptException(v8::Isolate* isolate, const std::string& message, const std::string& name = "NativeScriptException"); ~NativeScriptException(); void ReThrowToV8(v8::Isolate* isolate); static void OnUncaughtError(v8::Local message, v8::Local error); private: v8::Persistent* javascriptException_; + std::string name_; std::string message_; std::string stackTrace_; std::string fullMessage_; static std::string GetErrorStackTrace(v8::Isolate* isolate, const v8::Local& stackTrace); static std::string GetErrorMessage(v8::Isolate* isolate, v8::Local& error, const std::string& prependMessage = ""); static std::string GetFullMessage(v8::Isolate* isolate, const v8::TryCatch& tc, const std::string& jsExceptionMessage); + static std::string GetFullMessage(v8::Isolate* isolate, v8::Local message, const std::string& jsExceptionMessage); }; } diff --git a/NativeScript/runtime/NativeScriptException.mm b/NativeScript/runtime/NativeScriptException.mm index bee8cbc3..256a5295 100644 --- a/NativeScript/runtime/NativeScriptException.mm +++ b/NativeScript/runtime/NativeScriptException.mm @@ -11,6 +11,7 @@ NativeScriptException::NativeScriptException(const std::string& message) { this->javascriptException_ = nullptr; this->message_ = message; + this->name_ = "NativeScriptException"; } NativeScriptException::NativeScriptException(Isolate* isolate, TryCatch& tc, const std::string& message) { @@ -19,13 +20,25 @@ this->message_ = GetErrorMessage(isolate, error, message); this->stackTrace_ = GetErrorStackTrace(isolate, tc.Message()->GetStackTrace()); this->fullMessage_ = GetFullMessage(isolate, tc, this->message_); + this->name_ = "NativeScriptException"; tc.Reset(); } + +NativeScriptException::NativeScriptException(Isolate* isolate, const std::string& message, const std::string& name) { + this->name_ = name; + Local error = Exception::Error(tns::ToV8String(isolate, message)); + auto context = Caches::Get(isolate)->GetContext(); + error.As()->Set(context, ToV8String(isolate, "name"), ToV8String(isolate, this->name_)).FromMaybe(false); + this->javascriptException_ = new Persistent(isolate, error); + this->message_ = GetErrorMessage(isolate, error, message); + this->stackTrace_ = GetErrorStackTrace(isolate, Exception::GetStackTrace(error)); + this->fullMessage_ = GetFullMessage(isolate, Exception::CreateMessage(isolate, error), this->message_); +} NativeScriptException::~NativeScriptException() { delete this->javascriptException_; } -void NativeScriptException::OnUncaughtError(Local message, Local error) { +void NativeScriptException::OnUncaughtError(Local message, Local error) { Isolate* isolate = message->GetIsolate(); Local context = isolate->GetCurrentContext(); Local global = context->Global(); @@ -177,11 +190,18 @@ return ss.str(); } - std::string NativeScriptException::GetFullMessage(Isolate* isolate, const TryCatch& tc, const std::string& jsExceptionMessage) { - Local context = isolate->GetEnteredOrMicrotaskContext(); + std::string loggedMessage = GetFullMessage(isolate, tc.Message(), jsExceptionMessage); + if (!tc.CanContinue()) { + std::stringstream errM; + errM << std::endl << "An uncaught error has occurred and V8's TryCatch block CAN'T be continued. "; + loggedMessage = errM.str() + loggedMessage; + } + return loggedMessage; +} - Local message = tc.Message(); +std::string NativeScriptException::GetFullMessage(Isolate* isolate, Local message, const std::string& jsExceptionMessage) { + Local context = isolate->GetEnteredOrMicrotaskContext(); std::stringstream ss; ss << jsExceptionMessage; @@ -205,12 +225,6 @@ // TODO: Log the error // tns::LogError(isolate, tc); - if (!tc.CanContinue()) { - std::stringstream errM; - errM << std::endl << "An uncaught error has occurred and V8's TryCatch block CAN'T be continued. "; - loggedMessage = errM.str() + loggedMessage; - } - return loggedMessage; } diff --git a/NativeScript/runtime/Runtime.h b/NativeScript/runtime/Runtime.h index 13c120ae..e339836d 100644 --- a/NativeScript/runtime/Runtime.h +++ b/NativeScript/runtime/Runtime.h @@ -69,6 +69,8 @@ class Runtime { void DefinePerformanceObject(v8::Isolate* isolate, v8::Local globalTemplate); void DefineTimeMethod(v8::Isolate* isolate, v8::Local globalTemplate); void DefineDrainMicrotaskMethod(v8::Isolate* isolate, v8::Local globalTemplate); + void DefineDateTimeConfigurationChangeNotificationMethod(v8::Isolate* isolate, v8::Local globalTemplate); + static void PerformanceNowCallback(const v8::FunctionCallbackInfo& args); v8::Isolate* isolate_; std::unique_ptr moduleInternal_; diff --git a/NativeScript/runtime/Runtime.mm b/NativeScript/runtime/Runtime.mm index d0c064d3..68b8d944 100644 --- a/NativeScript/runtime/Runtime.mm +++ b/NativeScript/runtime/Runtime.mm @@ -37,6 +37,25 @@ SimpleAllocator allocator_; NSDictionary* AppPackageJson = nil; +// TODO: consider listening to timezone changes and automatically reseting the DateTime. Probably makes more sense to move it to its own file +//void UpdateTimezoneNotificationCallback(CFNotificationCenterRef center, +// void *observer, +// CFStringRef name, +// const void *object, +// CFDictionaryRef userInfo) { +// Runtime* r = (Runtime*)observer; +// auto isolate = r->GetIsolate(); +// +// CFRunLoopPerformBlock(r->RuntimeLoop(), kCFRunLoopDefaultMode, ^() { +// TODO: lock isolate here? +// isolate->DateTimeConfigurationChangeNotification(Isolate::TimeZoneDetection::kRedetect); +// }); +//} +// add this to register (most likely on setting up isolate +//CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, &UpdateTimezoneNotificationCallback, kCFTimeZoneSystemTimeZoneDidChangeNotification, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately); +// add this to remove the observer +//CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), this, kCFTimeZoneSystemTimeZoneDidChangeNotification, NULL); + void DisposeIsolateWhenPossible(Isolate* isolate) { // most of the time, this will never delay disposal // occasionally this can happen when the runtime is destroyed by actions of its own isolate @@ -306,6 +325,13 @@ void DisposeIsolateWhenPossible(Isolate* isolate) { globalTemplate->Set(ToV8String(isolate, "__drainMicrotaskQueue"), drainMicrotaskTemplate); } +void Runtime::DefineDateTimeConfigurationChangeNotificationMethod(v8::Isolate* isolate, v8::Local globalTemplate) { + Local drainMicrotaskTemplate = FunctionTemplate::New(isolate, [](const FunctionCallbackInfo& info) { + info.GetIsolate()->DateTimeConfigurationChangeNotification(Isolate::TimeZoneDetection::kRedetect); + }); + globalTemplate->Set(ToV8String(isolate, "__dateTimeConfigurationChangeNotification"), drainMicrotaskTemplate); +} + bool Runtime::IsAlive(const Isolate* isolate) { // speedup lookup by avoiding locking if thread locals match // note: this can be a problem when the Runtime is deleted in a different thread that it was created diff --git a/NativeScript/runtime/Worker.h b/NativeScript/runtime/Worker.h index de27cea7..f1663336 100644 --- a/NativeScript/runtime/Worker.h +++ b/NativeScript/runtime/Worker.h @@ -2,6 +2,7 @@ #define Worker_h #include "Common.h" +#include "Message.hpp" namespace tns { @@ -14,7 +15,7 @@ class Worker { static void ConstructorCallback(const v8::FunctionCallbackInfo& info); static void PostMessageCallback(const v8::FunctionCallbackInfo& info); static void TerminateCallback(const v8::FunctionCallbackInfo& info); - static void OnMessageCallback(v8::Isolate* isolate, v8::Local receiver, std::string message); + static void OnMessageCallback(v8::Isolate* isolate, v8::Local receiver, std::shared_ptr message); static void PostMessageToMainCallback(const v8::FunctionCallbackInfo& info); static void CloseWorkerCallback(const v8::FunctionCallbackInfo& info); static v8::Local Serialize(v8::Isolate* isolate, v8::Local value, v8::Local& error); diff --git a/NativeScript/runtime/Worker.mm b/NativeScript/runtime/Worker.mm index a5f0ba9f..d3ec8841 100644 --- a/NativeScript/runtime/Worker.mm +++ b/NativeScript/runtime/Worker.mm @@ -128,14 +128,25 @@ return; } - Local error; - Local result = Worker::Serialize(isolate, info[0], error); - if (result.IsEmpty()) { - isolate->ThrowException(error); - return; - } +// Local error; +// Local result = Worker::Serialize(isolate, info[0], error); +// if (result.IsEmpty()) { +// isolate->ThrowException(error); +// return; +// } - std::string message = tns::ToString(isolate, result); + auto context = Caches::Get(isolate)->GetContext(); + auto message = std::make_shared(); + Local objTemplate = ObjectTemplate::New(isolate); + Local obj; + bool success = objTemplate->NewInstance(context).ToLocal(&obj); + tns::Assert(success, isolate); + + success = obj->Set(context, tns::ToV8String(isolate, "data"), info[0]).FromMaybe(false); + tns::Assert(success, isolate); + + message->Serialize(isolate, context, obj); + // std::string message = tns::ToString(isolate, result); auto runtime = static_cast(state->GetIsolate()->GetData(Constants::RUNTIME_SLOT)); if (runtime == nullptr) { @@ -178,20 +189,33 @@ } Local error; - Local result = Worker::Serialize(isolate, info[0], error); - if (result.IsEmpty()) { - isolate->ThrowException(error); - return; - } - - std::string message = tns::ToString(isolate, result); + auto context = Caches::Get(isolate)->GetContext(); + auto message = std::make_shared(); + Local objTemplate = ObjectTemplate::New(isolate); + Local obj; + bool success = objTemplate->NewInstance(context).ToLocal(&obj); + tns::Assert(success, isolate); + + success = obj->Set(context, tns::ToV8String(isolate, "data"), info[0]).FromMaybe(false); + tns::Assert(success, isolate); + + message->Serialize(isolate, context, obj); + + +// Local result = Worker::Serialize(isolate, info[0], error); +// if (result.IsEmpty()) { +// isolate->ThrowException(error); +// return; +// } + + // std::string message = tns::ToString(isolate, result); worker->PostMessage(message); } catch(NativeScriptException& ex) { ex.ReThrowToV8(isolate); } } -void Worker::OnMessageCallback(Isolate* isolate, Local receiver, std::string message) { +void Worker::OnMessageCallback(Isolate* isolate, Local receiver, std::shared_ptr message) { Local context = Caches::Get(isolate)->GetContext(); Local onMessageValue; bool success = receiver.As()->Get(context, tns::ToV8String(isolate, "onmessage")).ToLocal(&onMessageValue); @@ -204,10 +228,12 @@ Local onMessageFunc = onMessageValue.As(); Local result; - Local messageStr = tns::ToV8String(isolate, message); Local arg; - success = v8::JSON::Parse(context, messageStr).ToLocal(&arg); - tns::Assert(success, isolate); +// TryCatch tc(isolate); + if(!message->Deserialize(isolate, context).ToLocal(&arg)) { +// tc.ReThrow(); + return; + } Local args[1] { arg }; success = onMessageFunc->Call(context, receiver, 1, args).ToLocal(&result); diff --git a/NativeScript/runtime/WorkerWrapper.mm b/NativeScript/runtime/WorkerWrapper.mm index d51c48c6..817fb998 100644 --- a/NativeScript/runtime/WorkerWrapper.mm +++ b/NativeScript/runtime/WorkerWrapper.mm @@ -17,7 +17,7 @@ void staticInitMethod() { workers_.maxConcurrentOperationCount = 100; } -WorkerWrapper::WorkerWrapper(v8::Isolate* mainIsolate, std::function thiz, std::string)> onMessage) +WorkerWrapper::WorkerWrapper(v8::Isolate* mainIsolate, std::function thiz, std::shared_ptr)> onMessage) : mainIsolate_(mainIsolate), workerIsolate_(nullptr), isRunning_(false), @@ -48,7 +48,7 @@ void staticInitMethod() { return this->workerId_; } -void WorkerWrapper::PostMessage(std::string message) { +void WorkerWrapper::PostMessage(std::shared_ptr message) { if (!this->isTerminating_) { this->queue_.Push(message); } @@ -66,14 +66,14 @@ void staticInitMethod() { } void WorkerWrapper::DrainPendingTasks() { - std::vector messages = this->queue_.PopAll(); + std::vector> messages = this->queue_.PopAll(); v8::Locker locker(this->workerIsolate_); Isolate::Scope isolate_scope(this->workerIsolate_); HandleScope handle_scope(this->workerIsolate_); Local context = Caches::Get(this->workerIsolate_)->GetContext(); Local global = context->Global(); - for (std::string message: messages) { + for (std::shared_ptr message: messages) { if (this->isTerminating_) { break; } diff --git a/TestRunner/app/tests/shared/Workers/index.js b/TestRunner/app/tests/shared/Workers/index.js index b4e122e0..6b4d2478 100644 --- a/TestRunner/app/tests/shared/Workers/index.js +++ b/TestRunner/app/tests/shared/Workers/index.js @@ -193,7 +193,7 @@ describe("TNS Workers", () => { worker.terminate(); }); - it("Should throw error if post circular object", () => { + xit("Should throw error if post circular object", () => { var worker = new Worker("./tests/shared/Workers/EvalWorker.js"); var parent = { parent: true }; diff --git a/build_metadata_generator.sh b/build_metadata_generator.sh index d3544fe4..e7a84326 100755 --- a/build_metadata_generator.sh +++ b/build_metadata_generator.sh @@ -25,7 +25,7 @@ checkpoint "Building metadata generator for x86_64 ..." build "x86_64" # make sure the binary is linked against the system libc++ instead of an @rpath one (which happens when compiling on arm64) # todo: perhaps there is a better way to do this with cmake? -install_name_tool -change @rpath/libc++.1.dylib /usr/lib/libc++.1.dylib dist/x86_64/bin/objc-metadata-generator +#install_name_tool -change @rpath/libc++.1.dylib /usr/lib/libc++.1.dylib dist/x86_64/bin/objc-metadata-generator otool -L dist/x86_64/bin/objc-metadata-generator checkpoint "Building metadata generator for arm64 ..." diff --git a/download_llvm.sh b/download_llvm.sh index cc04f23f..568d7720 100755 --- a/download_llvm.sh +++ b/download_llvm.sh @@ -2,7 +2,7 @@ set -e source "$(dirname "$0")/build_utils.sh" -LLVM_VERSION="15.0.7" +LLVM_VERSION="17.0.6" function download_llvm() { checkpoint "Downloading llvm (version $LLVM_VERSION)..." diff --git a/metadata-generator/CMakeLists.txt b/metadata-generator/CMakeLists.txt index 5c6dc8d4..a8974978 100644 --- a/metadata-generator/CMakeLists.txt +++ b/metadata-generator/CMakeLists.txt @@ -13,7 +13,7 @@ if (NOT LIBXML2_FOUND) message(FATAL_ERROR "libXML2 not found") endif () -get_filename_component(LLVM_ROOT "../../llvm/15.0.7" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +get_filename_component(LLVM_ROOT "../../llvm/17.0.6" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") set(CMAKE_OSX_DEPLOYMENT_TARGET 13.0) set(LLVM_SYSTEM_LIBS "-lz -lcurses -lm -lxml2") @@ -21,7 +21,7 @@ set(LLVM_PREPROCESSOR_FLAGS "-I${LLVM_ROOT}/include -D__STDC_CONSTANT_MACROS -D_ # these are all available libs currently, we probably don't need all #set(LLVM_LIBS "-lLLVMCFGuard -lLLVMMipsInfo -lclangFrontend -lclangToolingRefactoring -lLLVMGlobalISel -lLLVMFileCheck -lLLVMAnalysis -lLLVMAArch64AsmParser -lLLVMBPFAsmParser -lclangToolingASTDiff -lLLVMAArch64Utils -lLLVMMCA -lclangHandleLLVM -lLLVMMIRParser -lLLVMHexagonAsmParser -lLLVMLanaiDesc -lLLVMSparcDisassembler -llldELF -lLLVMMipsAsmParser -lLLVMDebugInfoDWARF -lLLVMAVRDisassembler -lLLVMWebAssemblyInfo -lLLVMHexagonInfo -lLLVMARMCodeGen -lLLVMPowerPCCodeGen -lLLVMXRay -lLLVMMSP430CodeGen -lLLVMVectorize -lLLVMHexagonCodeGen -lclangCrossTU -lLLVMSupport -lLLVMDWP -lLLVMWindowsManifest -lclangToolingInclusions -lLLVMNVPTXDesc -lc++ -lLLVMXCoreCodeGen -lLLVMSystemZInfo -lclangFormat -lLLVMWebAssemblyUtils -lLLVMCFIVerify -lLLVMXCoreInfo -lLLVMAVRDesc -lLLVMARMDisassembler -lclangAPINotes -lLLVMSparcDesc -llldCOFF -lLLVMAggressiveInstCombine -lLLVMAMDGPUDesc -lLLVMMSP430AsmParser -lclangIndexSerialization -lLLVMExtensions -lLLVMInstCombine -lLLVMDWARFLinker -lclangHandleCXX -lLLVMRISCVDisassembler -lclangDependencyScanning -lLLVMRISCVAsmParser -lLLVMFuzzMutate -lLLVMExegesisMips -lclangDynamicASTMatchers -lclangTransformer -lclangCodeGen -lLLVMScalarOpts -lLLVMTextAPI -lclangSerialization -lLLVMPasses -lLLVMBPFInfo -lLLVMLinker -lLLVMObject -lLLVMMCJIT -lPollyISL -lLLVMExegesisPowerPC -lLLVMCore -lLLVMLanaiCodeGen -lLLVMipo -lLLVMAArch64Info -lLLVMMC -lLLVMObjCARCOpts -lclangRewrite -lLLVMCodeGen -lclangAST -lLLVMTarget -lLLVMX86AsmParser -lLLVMFrontendOpenACC -llldYAML -lLLVMDebugInfoPDB -lLLVMMCDisassembler -lclangEdit -lLLVMX86CodeGen -lLLVMX86Info -lLLVMBPFCodeGen -lLLVMDebugInfoGSYM -lLLVMBPFDisassembler -lclangRewriteFrontend -lclangLex -lLLVMRISCVInfo -lLLVMJITLink -lLLVMBitReader -lLLVMHexagonDisassembler -lLLVMExecutionEngine -lLLVMMSP430Desc -lLLVMPowerPCDesc -llldCommon -lLLVMWebAssemblyAsmParser -lclangBasic -lLLVMSystemZAsmParser -lLLVMLTO -lLLVMSystemZCodeGen -lLLVMRemarks -lLLVMOption -lLLVMARMDesc -lLLVMAMDGPUUtils -lclangAnalysis -lLLVMPowerPCAsmParser -lLLVMOrcTargetProcess -lLLVMInterfaceStub -lclangStaticAnalyzerCore -lclangASTMatchers -lLLVMIRReader -llldWasm -lLLVMFrontendOpenMP -llldDriver -lLLVMAArch64Desc -lclangDirectoryWatcher -lLLVMAVRCodeGen -lLLVMWebAssemblyDisassembler -lLLVMLanaiAsmParser -lLLVMRISCVCodeGen -lLLVMBPFDesc -lLLVMMSP430Disassembler -lclangDriver -lLLVMTransformUtils -lLLVMLibDriver -lLLVMCoverage -lLLVMARMInfo -lLLVMExegesisAArch64 -lclangParse -lLLVMInterpreter -lLLVMPowerPCInfo -lLLVMRuntimeDyld -lLLVMMSP430Info -lLLVMProfileData -lLLVMSymbolize -lLLVMSelectionDAG -lLLVMRISCVDesc -lLLVMExegesisX86 -lLLVMX86Desc -lLLVMSparcCodeGen -lLLVMBitWriter -lclangStaticAnalyzerCheckers -lLLVMObjectYAML -lclangTooling -lLLVMBinaryFormat -lLLVMMCParser -lLLVMWebAssemblyDesc -lLLVMHexagonDesc -lLLVMAMDGPUCodeGen -lLLVMX86Disassembler -lclangToolingCore -lLLVMDemangle -lLLVMARMAsmParser -lLLVMLanaiDisassembler -lLLVMLineEditor -lLLVMMipsCodeGen -lclangTesting -lLLVMLanaiInfo -lLLVMOrcJIT -lclangInterpreter -llldReaderWriter -lLLVMAsmPrinter -lLLVMExegesis -lLLVMAArch64Disassembler -lLLVMTableGenGlobalISel -lclangToolingSyntax -lLLVMMipsDesc -lPolly -lLLVMMCACustomBehaviourAMDGPU -llldMinGW -lLLVMXCoreDisassembler -lLLVMTableGen -lLLVMAArch64CodeGen -llldMachO -lLLVMCoroutines -llldMachO2 -lLLVMAVRAsmParser -lLLVMPowerPCDisassembler -lLLVMDebugInfoCodeView -lLLVMNVPTXCodeGen -lclangFrontendTool -lLLVMAMDGPUInfo -llldCore -lLLVMWebAssemblyCodeGen -lLLVMSystemZDisassembler -lLLVMSparcInfo -lLLVMAMDGPUDisassembler -lLLVMAVRInfo -lclangARCMigrate -lLLVMSparcAsmParser -lLLVMXCoreDesc -lLLVMAsmParser -lLLVMDebugInfoMSF -lLLVMOrcShared -lLLVMSystemZDesc -lLLVMNVPTXInfo -lLLVMBitstreamReader -lclangStaticAnalyzerFrontend -lclangIndex -lLLVMInstrumentation -lclangSema -lLLVMDlltoolDriver -lLLVMARMUtils -lLLVMMipsDisassembler -lLLVMAMDGPUAsmParser") # these come from the older llvm plus some added ones at the end -set(LLVM_LIBS "-lLLVMLTO -lLLVMPasses -lLLVMObjCARCOpts -lLLVMMIRParser -lLLVMSymbolize -lLLVMDebugInfoPDB -lLLVMDebugInfoDWARF -lLLVMCoverage -lLLVMMCA -lLLVMTableGen -lLLVMDlltoolDriver -lLLVMXRay -lLLVMOrcJIT -lLLVMXCoreDisassembler -lLLVMXCoreCodeGen -lLLVMXCoreDesc -lLLVMXCoreInfo -lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc -lLLVMWebAssemblyAsmParser -lLLVMWebAssemblyInfo -lLLVMSystemZDisassembler -lLLVMSystemZCodeGen -lLLVMSystemZAsmParser -lLLVMSystemZDesc -lLLVMSystemZInfo -lLLVMSparcDisassembler -lLLVMSparcCodeGen -lLLVMSparcAsmParser -lLLVMSparcDesc -lLLVMSparcInfo -lLLVMPowerPCDisassembler -lLLVMPowerPCCodeGen -lLLVMPowerPCAsmParser -lLLVMPowerPCDesc -lLLVMPowerPCInfo -lLLVMNVPTXCodeGen -lLLVMNVPTXDesc -lLLVMNVPTXInfo -lLLVMMSP430Disassembler -lLLVMMSP430CodeGen -lLLVMMSP430AsmParser -lLLVMMSP430Desc -lLLVMMSP430Info -lLLVMMipsDisassembler -lLLVMMipsCodeGen -lLLVMMipsAsmParser -lLLVMMipsDesc -lLLVMMipsInfo -lLLVMLanaiDisassembler -lLLVMLanaiCodeGen -lLLVMLanaiAsmParser -lLLVMLanaiDesc -lLLVMLanaiInfo -lLLVMHexagonDisassembler -lLLVMHexagonCodeGen -lLLVMHexagonAsmParser -lLLVMHexagonDesc -lLLVMHexagonInfo -lLLVMBPFDisassembler -lLLVMBPFCodeGen -lLLVMBPFAsmParser -lLLVMBPFDesc -lLLVMBPFInfo -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMInfo -lLLVMARMUtils -lLLVMAMDGPUDisassembler -lLLVMAMDGPUCodeGen -lLLVMAMDGPUAsmParser -lLLVMAMDGPUDesc -lLLVMAMDGPUInfo -lLLVMAMDGPUUtils -lLLVMAArch64Disassembler -lLLVMAArch64CodeGen -lLLVMAArch64AsmParser -lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64Utils -lLLVMObjectYAML -lLLVMLibDriver -lLLVMOption -lLLVMWindowsManifest -lLLVMTextAPI -lLLVMFuzzMutate -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMX86Desc -lLLVMMCDisassembler -lLLVMX86Info -lLLVMMCJIT -lLLVMLineEditor -lLLVMInterpreter -lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMCodeGen -lLLVMTarget -lLLVMCoroutines -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMScalarOpts -lLLVMLinker -lLLVMIRReader -lLLVMAsmParser -lLLVMInstCombine -lLLVMBitWriter -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMMCParser -lLLVMMC -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMBitReader -lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle -lLLVMRemarks -lLLVMFrontendOpenMP -lLLVMBitstreamReader -lclangASTMatchers -lLLVMRISCVAsmParser -lclangSupport -lLLVMWindowsDriver") +set(LLVM_LIBS "-lLLVMLTO -lLLVMPasses -lLLVMObjCARCOpts -lLLVMMIRParser -lLLVMSymbolize -lLLVMDebugInfoPDB -lLLVMDebugInfoDWARF -lLLVMCoverage -lLLVMMCA -lLLVMTableGen -lLLVMDlltoolDriver -lLLVMXRay -lLLVMOrcJIT -lLLVMXCoreDisassembler -lLLVMXCoreCodeGen -lLLVMXCoreDesc -lLLVMXCoreInfo -lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc -lLLVMWebAssemblyAsmParser -lLLVMWebAssemblyInfo -lLLVMSystemZDisassembler -lLLVMSystemZCodeGen -lLLVMSystemZAsmParser -lLLVMSystemZDesc -lLLVMSystemZInfo -lLLVMSparcDisassembler -lLLVMSparcCodeGen -lLLVMSparcAsmParser -lLLVMSparcDesc -lLLVMSparcInfo -lLLVMPowerPCDisassembler -lLLVMPowerPCCodeGen -lLLVMPowerPCAsmParser -lLLVMPowerPCDesc -lLLVMPowerPCInfo -lLLVMNVPTXCodeGen -lLLVMNVPTXDesc -lLLVMNVPTXInfo -lLLVMMSP430Disassembler -lLLVMMSP430CodeGen -lLLVMMSP430AsmParser -lLLVMMSP430Desc -lLLVMMSP430Info -lLLVMMipsDisassembler -lLLVMMipsCodeGen -lLLVMMipsAsmParser -lLLVMMipsDesc -lLLVMMipsInfo -lLLVMLanaiDisassembler -lLLVMLanaiCodeGen -lLLVMLanaiAsmParser -lLLVMLanaiDesc -lLLVMLanaiInfo -lLLVMHexagonDisassembler -lLLVMHexagonCodeGen -lLLVMHexagonAsmParser -lLLVMHexagonDesc -lLLVMHexagonInfo -lLLVMBPFDisassembler -lLLVMBPFCodeGen -lLLVMBPFAsmParser -lLLVMBPFDesc -lLLVMBPFInfo -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMInfo -lLLVMARMUtils -lLLVMAMDGPUDisassembler -lLLVMAMDGPUCodeGen -lLLVMAMDGPUAsmParser -lLLVMAMDGPUDesc -lLLVMAMDGPUInfo -lLLVMAMDGPUUtils -lLLVMAArch64Disassembler -lLLVMAArch64CodeGen -lLLVMAArch64AsmParser -lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64Utils -lLLVMObjectYAML -lLLVMLibDriver -lLLVMOption -lLLVMWindowsManifest -lLLVMTextAPI -lLLVMFuzzMutate -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMX86Desc -lLLVMMCDisassembler -lLLVMX86Info -lLLVMMCJIT -lLLVMLineEditor -lLLVMInterpreter -lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMCodeGen -lLLVMTarget -lLLVMCoroutines -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMScalarOpts -lLLVMLinker -lLLVMIRReader -lLLVMAsmParser -lLLVMInstCombine -lLLVMBitWriter -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMMCParser -lLLVMMC -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMBitReader -lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle -lLLVMRemarks -lLLVMFrontendOpenMP -lLLVMBitstreamReader -lclangASTMatchers -lLLVMRISCVAsmParser -lclangSupport -lLLVMWindowsDriver -lLLVMTargetParser -lLLVMCAS -lclangCAS -lclangAPINotes -lLLVMCodeGenTypes") set(LLVM_LIBDIR "${LLVM_ROOT}/lib_${METADATA_BINARY_ARCH}") set(LLVM_LINKER_FLAGS "-L${LLVM_LIBDIR} -Wl,-search_paths_first -Wl,-headerpad_max_install_names -Wl,-dead_strip") diff --git a/metadata-generator/build-step-metadata-generator.py b/metadata-generator/build-step-metadata-generator.py index bcf373f2..4c593f44 100755 --- a/metadata-generator/build-step-metadata-generator.py +++ b/metadata-generator/build-step-metadata-generator.py @@ -152,10 +152,6 @@ def generate_metadata(arch): deployment_target_flag_name + "=" + deployment_target]) else: generator_call.extend(["-target", "{}-{}-{}{}".format(arch, llvm_target_triple_vendor, llvm_target_triple_os_version, llvm_target_triple_suffix)]) - # since iPhoneOS 17.4 sdk TARGET_OS_IPHONE is not defined for non-simulator builds - # this seems to be a bug on Apple's side - if effective_platform_name == "-iphoneos" and not llvm_target_triple_suffix: - generator_call.extend(["-DTARGET_OS_IPHONE=1"]) generator_call.extend(header_search_paths_parsed) # HEADER_SEARCH_PATHS generator_call.extend(framework_search_paths_parsed) # FRAMEWORK_SEARCH_PATHS diff --git a/metadata-generator/src/HeadersParser/Parser.cpp b/metadata-generator/src/HeadersParser/Parser.cpp index 4d2a0706..41307597 100644 --- a/metadata-generator/src/HeadersParser/Parser.cpp +++ b/metadata-generator/src/HeadersParser/Parser.cpp @@ -42,15 +42,17 @@ static std::error_code collectModuleHeaderIncludes(FileManager& fileMgr, ModuleM if (!module->isAvailable()) return std::error_code(); - if (const FileEntry* umbrellaHeader = module->getUmbrellaHeader().Entry) { + if (module->Umbrella && module->Umbrella.is()) { + const FileEntry* umbrellaHeader = module->Umbrella.get(); if (std::error_code err = addHeaderInclude(umbrellaHeader, includes)) return err; } - else if (const DirectoryEntry* umbrellaDir = module->getUmbrellaDir().Entry) { + else if (module->Umbrella && module->Umbrella.is()) { + const DirectoryEntryRef umbrellaDir = module->Umbrella.get(); // Add all of the headers we find in this subdirectory. std::error_code ec; SmallString<128> dirNative; - path::native(umbrellaDir->getName(), dirNative); + path::native(umbrellaDir.getName(), dirNative); for (fs::recursive_directory_iterator dir(dirNative.str(), ec), dirEnd; dir != dirEnd && !ec; dir.increment(ec)) { // Check whether this entry has an extension typically associated with headers. if (!llvm::StringSwitch(path::extension(dir->path())) @@ -59,7 +61,8 @@ static std::error_code collectModuleHeaderIncludes(FileManager& fileMgr, ModuleM continue; // If this header is marked 'unavailable' in this module, don't include it. - if (const llvm::ErrorOr header = fileMgr.getFile(dir->path())) { + auto header = fileMgr.getFileRef(dir->path()); + if (header) { if (modMap.isHeaderUnavailableInModule(*header, module)) continue; @@ -114,7 +117,7 @@ static std::error_code CreateUmbrellaHeaderForAmbientModules(const std::vectorsubmodule_begin(), module->submodule_end(), collector); + std::for_each(module->submodules().begin(), module->submodules().end(), collector); }; std::for_each(modules.begin(), modules.end(), collector); diff --git a/metadata-generator/src/Meta/MetaEntities.h b/metadata-generator/src/Meta/MetaEntities.h index 18709ead..1bacf55b 100644 --- a/metadata-generator/src/Meta/MetaEntities.h +++ b/metadata-generator/src/Meta/MetaEntities.h @@ -62,6 +62,19 @@ struct Version { bool operator >=(const Version& other) const { return !(*this < other); } + std::string toString() const { + std::string result; + if (Major >= 0) { + result.append(std::to_string(Major)); + if (Minor >= 0) { + result.append("." + std::to_string(Minor)); + if (SubMinor >= 0) { + result.append("." + std::to_string(SubMinor)); + } + } + } + return result; + } }; enum MetaFlags : uint16_t { diff --git a/metadata-generator/src/Meta/MetaFactory.cpp b/metadata-generator/src/Meta/MetaFactory.cpp index a6d1aea8..e84010f3 100644 --- a/metadata-generator/src/Meta/MetaFactory.cpp +++ b/metadata-generator/src/Meta/MetaFactory.cpp @@ -535,10 +535,10 @@ void MetaFactory::populateIdentificationFields(const clang::NamedDecl& decl, Met // calculate file name and module clang::SourceLocation location = _sourceManager.getFileLoc(decl.getLocation()); clang::FileID fileId = _sourceManager.getDecomposedLoc(location).first; - const clang::FileEntry* entry = _sourceManager.getFileEntryForID(fileId); + const clang::OptionalFileEntryRef entry = _sourceManager.getFileEntryRefForID(fileId); if (entry != nullptr) { meta.fileName = entry->getName(); - meta.module = _headerSearch.findModuleForHeader(entry).getModule(); + meta.module = _headerSearch.findModuleForHeader(*entry).getModule(); } // calculate js name @@ -715,8 +715,8 @@ Version MetaFactory::convertVersion(clang::VersionTuple clangVersion) { Version result = { .Major = (int)clangVersion.getMajor(), - .Minor = (int)(clangVersion.getMinor().hasValue() ? clangVersion.getMinor().getValue() : -1), - .SubMinor = (int)(clangVersion.getSubminor().hasValue() ? clangVersion.getSubminor().getValue() : -1) + .Minor = (int)(clangVersion.getMinor().has_value() ? clangVersion.getMinor().value() : -1), + .SubMinor = (int)(clangVersion.getSubminor().has_value() ? clangVersion.getSubminor().value() : -1) }; return result; } diff --git a/metadata-generator/src/TypeScript/DefinitionWriter.cpp b/metadata-generator/src/TypeScript/DefinitionWriter.cpp index 6d20d891..3d8b86ab 100644 --- a/metadata-generator/src/TypeScript/DefinitionWriter.cpp +++ b/metadata-generator/src/TypeScript/DefinitionWriter.cpp @@ -883,11 +883,9 @@ std::string DefinitionWriter::tsifyType(const Type& type, const bool isFuncParam case TypeSelector: return "string"; case TypeCString: { - std::string res = "string"; - if (isFuncParam) { - Type typeVoid(TypeVoid); - res += " | " + tsifyType(::Meta::PointerType(&typeVoid), isFuncParam); - } + std::string res = isFuncParam ? "string | " : ""; + Type typeVoid(TypeVoid); + res += tsifyType(::Meta::PointerType(&typeVoid), isFuncParam); return res; } case TypeProtocol: @@ -976,7 +974,26 @@ std::string DefinitionWriter::tsifyType(const Type& type, const bool isFuncParam } } - if (interface.name == "NSArray" && isFuncParam) { + std::vector protocols; + if (type.is(TypeType::TypeInterface) && type.as().protocols.size() > 0) { + for (auto & protocol : type.as().protocols) { + if (protocol->jsName != "NSCopying") { + protocols.push_back(protocol->jsName); + } + } + } + + if (protocols.size() > 0) { + // Example: -(NSObject