From 7fc278f6c80044007faa3d4c21db03829b5acfd8 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Wed, 27 May 2026 00:19:55 -0300 Subject: [PATCH 1/2] feat: allow custom priority for workers --- NativeScript/runtime/DataWrapper.h | 963 +++++++++++--------------- NativeScript/runtime/Worker.mm | 47 +- NativeScript/runtime/WorkerWrapper.mm | 20 +- 3 files changed, 453 insertions(+), 577 deletions(-) diff --git a/NativeScript/runtime/DataWrapper.h b/NativeScript/runtime/DataWrapper.h index c0e7c585..e06e868e 100644 --- a/NativeScript/runtime/DataWrapper.h +++ b/NativeScript/runtime/DataWrapper.h @@ -1,711 +1,558 @@ #ifndef DataWrapper_h #define DataWrapper_h -#include #include +#include + +#include "Common.h" +#include "ConcurrentQueue.h" #include "Metadata.h" #include "libffi.h" -#include "ConcurrentQueue.h" -#include "Common.h" namespace tns { class PrimitiveDataWrapper; enum class WrapperType { - Base = 1 << 0, - Primitive = 1 << 1, - Enum = 1 << 2, - Struct = 1 << 3, - StructType = 1 << 4, - ObjCAllocObject = 1 << 5, - ObjCObject = 1 << 6, - ObjCClass = 1 << 7, - ObjCProtocol = 1 << 8, - Function = 1 << 9, - AnonymousFunction = 1 << 10, - Block = 1 << 11, - Reference = 1 << 12, - ReferenceType = 1 << 13, - Pointer = 1 << 14, - PointerType = 1 << 15, - FunctionReference = 1 << 16, - FunctionReferenceType = 1 << 17, - ExtVector = 1 << 18, - Worker = 1 << 19, - UnmanagedType = 1 << 20, + Base = 1 << 0, + Primitive = 1 << 1, + Enum = 1 << 2, + Struct = 1 << 3, + StructType = 1 << 4, + ObjCAllocObject = 1 << 5, + ObjCObject = 1 << 6, + ObjCClass = 1 << 7, + ObjCProtocol = 1 << 8, + Function = 1 << 9, + AnonymousFunction = 1 << 10, + Block = 1 << 11, + Reference = 1 << 12, + ReferenceType = 1 << 13, + Pointer = 1 << 14, + PointerType = 1 << 15, + FunctionReference = 1 << 16, + FunctionReferenceType = 1 << 17, + ExtVector = 1 << 18, + Worker = 1 << 19, + UnmanagedType = 1 << 20, }; struct V8Args { -public: - virtual v8::Local operator[](int i) const = 0; - virtual size_t Length() const = 0; + public: + virtual v8::Local operator[](int i) const = 0; + virtual size_t Length() const = 0; }; -struct V8FunctionCallbackArgs: public V8Args { -public: - V8FunctionCallbackArgs(const v8::FunctionCallbackInfo& info) - : info_(info) { - } +struct V8FunctionCallbackArgs : public V8Args { + public: + V8FunctionCallbackArgs(const v8::FunctionCallbackInfo& info) + : info_(info) {} - v8::Local operator[](int i) const override { - return this->info_[i]; - } + v8::Local operator[](int i) const override { + return this->info_[i]; + } - size_t Length() const override { - return this->info_.Length(); - } -private: - const v8::FunctionCallbackInfo& info_; + size_t Length() const override { return this->info_.Length(); } + + private: + const v8::FunctionCallbackInfo& info_; }; -struct V8VectorArgs: public V8Args { -public: - V8VectorArgs(const std::vector>& args) - : args_(args) { - } +struct V8VectorArgs : public V8Args { + public: + V8VectorArgs(const std::vector>& args) : args_(args) {} - v8::Local operator[](int i) const override { - return this->args_[i]; - } + v8::Local operator[](int i) const override { + return this->args_[i]; + } - size_t Length() const override { - return this->args_.size(); - } -private: - const std::vector>& args_; + size_t Length() const override { return this->args_.size(); } + + private: + const std::vector>& args_; }; -struct V8SimpleValueArgs: public V8Args { -public: - V8SimpleValueArgs(v8::Local& value) - : value_(value) { - } +struct V8SimpleValueArgs : public V8Args { + public: + V8SimpleValueArgs(v8::Local& value) : value_(value) {} - v8::Local operator[](int i) const override { - return this->value_; - } + v8::Local operator[](int i) const override { return this->value_; } - size_t Length() const override { - return 1; - } -private: - v8::Local& value_; + size_t Length() const override { return 1; } + + private: + v8::Local& value_; }; -struct V8EmptyValueArgs: public V8Args { -public: - v8::Local operator[](int i) const override { - return v8::Local(); - } +struct V8EmptyValueArgs : public V8Args { + public: + v8::Local operator[](int i) const override { + return v8::Local(); + } - size_t Length() const override { - return 0; - } + size_t Length() const override { return 0; } }; struct StructField { -public: - StructField(ptrdiff_t offset, ffi_type* ffiType, std::string name, const TypeEncoding* encoding) - : offset_(offset), - ffiType_(ffiType), - name_(name), - encoding_(encoding) { - } + public: + StructField(ptrdiff_t offset, ffi_type* ffiType, std::string name, + const TypeEncoding* encoding) + : offset_(offset), ffiType_(ffiType), name_(name), encoding_(encoding) {} - ptrdiff_t Offset() { - return this->offset_; - } + ptrdiff_t Offset() { return this->offset_; } - ffi_type* FFIType() { - return this->ffiType_; - } + ffi_type* FFIType() { return this->ffiType_; } - std::string Name() { - return this->name_; - } + std::string Name() { return this->name_; } - const TypeEncoding* Encoding() { - return this->encoding_; - } -private: - ptrdiff_t offset_; - ffi_type* ffiType_; - std::string name_; - const TypeEncoding* encoding_; + const TypeEncoding* Encoding() { return this->encoding_; } + + private: + ptrdiff_t offset_; + ffi_type* ffiType_; + std::string name_; + const TypeEncoding* encoding_; }; struct StructInfo { -public: - StructInfo(std::string name, ffi_type* ffiType, std::vector fields) - : name_(name), - ffiType_(ffiType), - fields_(fields) { - } + public: + StructInfo(std::string name, ffi_type* ffiType, + std::vector fields) + : name_(name), ffiType_(ffiType), fields_(fields) {} - std::string Name() const { - return this->name_; - } + std::string Name() const { return this->name_; } - ffi_type* FFIType() const { - return this->ffiType_; - } + ffi_type* FFIType() const { return this->ffiType_; } - std::vector Fields() { - return this->fields_; - } -private: - std::string name_; - ffi_type* ffiType_; - std::vector fields_; + std::vector Fields() { return this->fields_; } + + private: + std::string name_; + ffi_type* ffiType_; + std::vector fields_; }; class BaseDataWrapper { -public: - BaseDataWrapper() - : gcProtected_(false) { - } + public: + BaseDataWrapper() : gcProtected_(false) {} - virtual ~BaseDataWrapper() = default; + virtual ~BaseDataWrapper() = default; - const virtual WrapperType Type() { - return WrapperType::Base; - } + const virtual WrapperType Type() { return WrapperType::Base; } - bool IsGcProtected() { - return this->gcProtected_; - } + bool IsGcProtected() { return this->gcProtected_; } - void GcProtect() { - this->gcProtected_ = true; - } + void GcProtect() { this->gcProtected_ = true; } - void GcUnprotect() { - this->gcProtected_ = false; - } -private: - bool gcProtected_; + void GcUnprotect() { this->gcProtected_ = false; } + + private: + bool gcProtected_; }; -class EnumDataWrapper: public BaseDataWrapper { -public: - EnumDataWrapper(std::string jsCode) - : jsCode_(jsCode) { - } +class EnumDataWrapper : public BaseDataWrapper { + public: + EnumDataWrapper(std::string jsCode) : jsCode_(jsCode) {} - const WrapperType Type() { - return WrapperType::Enum; - } + const WrapperType Type() { return WrapperType::Enum; } - std::string JSCode() { - return jsCode_; - } -private: - std::string jsCode_; + std::string JSCode() { return jsCode_; } + + private: + std::string jsCode_; }; -class PointerTypeWrapper: public BaseDataWrapper { -public: - const WrapperType Type() { - return WrapperType::PointerType; - } +class PointerTypeWrapper : public BaseDataWrapper { + public: + const WrapperType Type() { return WrapperType::PointerType; } }; -class PointerWrapper: public BaseDataWrapper { -public: - PointerWrapper(void* data) - : data_(data), - isAdopted_(false) { - } +class PointerWrapper : public BaseDataWrapper { + public: + PointerWrapper(void* data) : data_(data), isAdopted_(false) {} - const WrapperType Type() { - return WrapperType::Pointer; - } + const WrapperType Type() { return WrapperType::Pointer; } - void* Data() const { - return this->data_; - } + void* Data() const { return this->data_; } - void SetData(void* data) { - this->data_ = data; - } + void SetData(void* data) { this->data_ = data; } - bool IsAdopted() const { - return this->isAdopted_; - } + bool IsAdopted() const { return this->isAdopted_; } - void SetAdopted(bool value) { - this->isAdopted_ = value; - } -private: - void* data_; - bool isAdopted_; + void SetAdopted(bool value) { this->isAdopted_ = value; } + + private: + void* data_; + bool isAdopted_; }; -class ReferenceTypeWrapper: public BaseDataWrapper { -public: - const WrapperType Type() { - return WrapperType::ReferenceType; - } +class ReferenceTypeWrapper : public BaseDataWrapper { + public: + const WrapperType Type() { return WrapperType::ReferenceType; } }; -class ReferenceWrapper: public BaseDataWrapper { -public: - ReferenceWrapper(BaseDataWrapper* typeWrapper, v8::Persistent* value) - : typeWrapper_(typeWrapper), - value_(value), - encoding_(nullptr), - data_(nullptr), - disposeData_(false) { - } +class ReferenceWrapper : public BaseDataWrapper { + public: + ReferenceWrapper(BaseDataWrapper* typeWrapper, + v8::Persistent* value) + : typeWrapper_(typeWrapper), + value_(value), + encoding_(nullptr), + data_(nullptr), + disposeData_(false) {} - ~ReferenceWrapper() { - if(this->value_ != nullptr) { - value_->Reset(); - delete value_; - } - - if (this->data_ != nullptr) { - std::free(this->data_); - } + ~ReferenceWrapper() { + if (this->value_ != nullptr) { + value_->Reset(); + delete value_; } - const WrapperType Type() { - return WrapperType::Reference; + if (this->data_ != nullptr) { + std::free(this->data_); } + } - BaseDataWrapper* TypeWrapper() { - return this->typeWrapper_; - } + const WrapperType Type() { return WrapperType::Reference; } - v8::Persistent* Value() { - return this->value_; - } + BaseDataWrapper* TypeWrapper() { return this->typeWrapper_; } - void SetValue(v8::Persistent* value) { - if (this->value_ != nullptr) { - this->value_->Reset(); - } - this->value_ = value; - } + v8::Persistent* Value() { return this->value_; } - const TypeEncoding* Encoding() { - return this->encoding_; + void SetValue(v8::Persistent* value) { + if (this->value_ != nullptr) { + this->value_->Reset(); } + this->value_ = value; + } - void SetEncoding(const TypeEncoding* encoding) { - this->encoding_ = encoding; - } + const TypeEncoding* Encoding() { return this->encoding_; } - void* Data() const { - return this->data_; - } + void SetEncoding(const TypeEncoding* encoding) { this->encoding_ = encoding; } - void SetData(void* data, bool disposeData = false) { - if (this->data_ != nullptr && this->disposeData_) { - std::free(this->data_); - } - this->data_ = data; - this->disposeData_ = disposeData; + void* Data() const { return this->data_; } + + void SetData(void* data, bool disposeData = false) { + if (this->data_ != nullptr && this->disposeData_) { + std::free(this->data_); } -private: - BaseDataWrapper* typeWrapper_; - v8::Persistent* value_; - const TypeEncoding* encoding_; - void* data_; - bool disposeData_; + this->data_ = data; + this->disposeData_ = disposeData; + } + + private: + BaseDataWrapper* typeWrapper_; + v8::Persistent* value_; + const TypeEncoding* encoding_; + void* data_; + bool disposeData_; }; -class PrimitiveDataWrapper: public BaseDataWrapper { -public: - PrimitiveDataWrapper(size_t size,const TypeEncoding* typeEncoding, bool autoDeleteEncoding) - : size_(size), - typeEncoding_(typeEncoding), - autoDeleteEncoding_(autoDeleteEncoding) { - } - ~PrimitiveDataWrapper() { - if (autoDeleteEncoding_) { - std::free((struct TypeEncoding*)typeEncoding_); - } +class PrimitiveDataWrapper : public BaseDataWrapper { + public: + PrimitiveDataWrapper(size_t size, const TypeEncoding* typeEncoding, + bool autoDeleteEncoding) + : size_(size), + typeEncoding_(typeEncoding), + autoDeleteEncoding_(autoDeleteEncoding) {} + ~PrimitiveDataWrapper() { + if (autoDeleteEncoding_) { + std::free((struct TypeEncoding*)typeEncoding_); } + } - const WrapperType Type() { - return WrapperType::Primitive; - } + const WrapperType Type() { return WrapperType::Primitive; } - size_t Size() { - return this->size_; - } + size_t Size() { return this->size_; } - const TypeEncoding* TypeEncoding() { - return this->typeEncoding_; - } -private: - size_t size_; - const struct TypeEncoding* typeEncoding_; - bool autoDeleteEncoding_; + const TypeEncoding* TypeEncoding() { return this->typeEncoding_; } + + private: + size_t size_; + const struct TypeEncoding* typeEncoding_; + bool autoDeleteEncoding_; }; -class StructTypeWrapper: public BaseDataWrapper { -public: - StructTypeWrapper(StructInfo structInfo) - : structInfo_(structInfo) { - } +class StructTypeWrapper : public BaseDataWrapper { + public: + StructTypeWrapper(StructInfo structInfo) : structInfo_(structInfo) {} - const WrapperType Type() { - return WrapperType::StructType; - } + const WrapperType Type() { return WrapperType::StructType; } - const StructInfo StructInfo() { - return this->structInfo_; - } -private: - struct StructInfo structInfo_; + const StructInfo StructInfo() { return this->structInfo_; } + + private: + struct StructInfo structInfo_; }; -class StructWrapper: public StructTypeWrapper { -public: - StructWrapper(struct StructInfo structInfo, void* data, std::shared_ptr> parent) - : StructTypeWrapper(structInfo), - data_(data), - childCount_(0), - parent_(parent) { - } +class StructWrapper : public StructTypeWrapper { + public: + StructWrapper(struct StructInfo structInfo, void* data, + std::shared_ptr> parent) + : StructTypeWrapper(structInfo), + data_(data), + childCount_(0), + parent_(parent) {} - const WrapperType Type() { - return WrapperType::Struct; - } + const WrapperType Type() { return WrapperType::Struct; } - void* Data() const { - return this->data_; - } + void* Data() const { return this->data_; } - std::shared_ptr> Parent() { - return this->parent_; - } + std::shared_ptr> Parent() { return this->parent_; } - void IncrementChildren() { - this->childCount_++; - } + void IncrementChildren() { this->childCount_++; } - void DecrementChildren() { - this->childCount_--; - } + void DecrementChildren() { this->childCount_--; } - int ChildCount() { - return this->childCount_; - } -private: - void* data_; - int childCount_; - std::shared_ptr> parent_; + int ChildCount() { return this->childCount_; } + + private: + void* data_; + int childCount_; + std::shared_ptr> parent_; }; -class ObjCAllocDataWrapper: public BaseDataWrapper { -public: - ObjCAllocDataWrapper(Class klass) - : klass_(klass) { - } +class ObjCAllocDataWrapper : public BaseDataWrapper { + public: + ObjCAllocDataWrapper(Class klass) : klass_(klass) {} - const WrapperType Type() { - return WrapperType::ObjCAllocObject; - } + const WrapperType Type() { return WrapperType::ObjCAllocObject; } - Class Klass() { - return this->klass_; - } -private: - Class klass_; + Class Klass() { return this->klass_; } + + private: + Class klass_; }; -class UnmanagedTypeWrapper: public BaseDataWrapper { -public: - UnmanagedTypeWrapper(uint8_t* data, const TypeEncoding* typeEncoding) - : data_(data), typeEncoding_(typeEncoding), valueTaken_(false) { - } - - const WrapperType Type() { - return WrapperType::UnmanagedType; - } - - uint8_t* Data() { - this->valueTaken_ = true; - return this->data_; - } - - const TypeEncoding* TypeEncoding() { - return this->typeEncoding_; - } - - bool ValueTaken() { - return this->valueTaken_; - } -private: - uint8_t* data_; - const tns::TypeEncoding* typeEncoding_; - bool valueTaken_; +class UnmanagedTypeWrapper : public BaseDataWrapper { + public: + UnmanagedTypeWrapper(uint8_t* data, const TypeEncoding* typeEncoding) + : data_(data), typeEncoding_(typeEncoding), valueTaken_(false) {} + + const WrapperType Type() { return WrapperType::UnmanagedType; } + + uint8_t* Data() { + this->valueTaken_ = true; + return this->data_; + } + + const TypeEncoding* TypeEncoding() { return this->typeEncoding_; } + + bool ValueTaken() { return this->valueTaken_; } + + private: + uint8_t* data_; + const tns::TypeEncoding* typeEncoding_; + bool valueTaken_; }; -class ObjCDataWrapper: public BaseDataWrapper { -public: - ObjCDataWrapper(id data, const TypeEncoding* typeEncoding = nullptr) - : data_(data), typeEncoding_(typeEncoding) { - } +class ObjCDataWrapper : public BaseDataWrapper { + public: + ObjCDataWrapper(id data, const TypeEncoding* typeEncoding = nullptr) + : data_(data), typeEncoding_(typeEncoding) {} - const WrapperType Type() { - return WrapperType::ObjCObject; - } + const WrapperType Type() { return WrapperType::ObjCObject; } - id Data() { - return this->data_; - } + id Data() { return this->data_; } - const TypeEncoding* TypeEncoding() { - return this->typeEncoding_; - } -private: - id data_; - const tns::TypeEncoding* typeEncoding_; + const TypeEncoding* TypeEncoding() { return this->typeEncoding_; } + + private: + id data_; + const tns::TypeEncoding* typeEncoding_; }; -class ObjCClassWrapper: public BaseDataWrapper { -public: - ObjCClassWrapper(Class klazz, bool extendedClass = false) - : klass_(klazz), - extendedClass_(extendedClass) { - } +class ObjCClassWrapper : public BaseDataWrapper { + public: + ObjCClassWrapper(Class klazz, bool extendedClass = false) + : klass_(klazz), extendedClass_(extendedClass) {} - const WrapperType Type() { - return WrapperType::ObjCClass; - } + const WrapperType Type() { return WrapperType::ObjCClass; } - Class Klass() { - return this->klass_; - } + Class Klass() { return this->klass_; } - bool ExtendedClass() { - return this->extendedClass_; - } -private: - Class klass_; - bool extendedClass_; + bool ExtendedClass() { return this->extendedClass_; } + + private: + Class klass_; + bool extendedClass_; }; -class ObjCProtocolWrapper: public BaseDataWrapper { -public: - ObjCProtocolWrapper(Protocol* proto, const ProtocolMeta* protoMeta) - : proto_(proto), - protoMeta_(protoMeta) { - } +class ObjCProtocolWrapper : public BaseDataWrapper { + public: + ObjCProtocolWrapper(Protocol* proto, const ProtocolMeta* protoMeta) + : proto_(proto), protoMeta_(protoMeta) {} - const WrapperType Type() { - return WrapperType::ObjCProtocol; - } + const WrapperType Type() { return WrapperType::ObjCProtocol; } - Protocol* Proto() { - return this->proto_; - } + Protocol* Proto() { return this->proto_; } - const ProtocolMeta* ProtoMeta() { - return this->protoMeta_; - } -private: - Protocol* proto_; - const ProtocolMeta* protoMeta_; + const ProtocolMeta* ProtoMeta() { return this->protoMeta_; } + + private: + Protocol* proto_; + const ProtocolMeta* protoMeta_; }; -class FunctionWrapper: public BaseDataWrapper { -public: - FunctionWrapper(const FunctionMeta* meta) - : meta_(meta) { - } +class FunctionWrapper : public BaseDataWrapper { + public: + FunctionWrapper(const FunctionMeta* meta) : meta_(meta) {} - const WrapperType Type() { - return WrapperType::Function; - } + const WrapperType Type() { return WrapperType::Function; } - const FunctionMeta* Meta() { - return this->meta_; - } -private: - const FunctionMeta* meta_; + const FunctionMeta* Meta() { return this->meta_; } + + private: + const FunctionMeta* meta_; }; -class AnonymousFunctionWrapper: public BaseDataWrapper { -public: - AnonymousFunctionWrapper(void* functionPointer, const TypeEncoding* parametersEncoding, size_t parametersCount) - : data_(functionPointer), - parametersEncoding_(parametersEncoding) { - } +class AnonymousFunctionWrapper : public BaseDataWrapper { + public: + AnonymousFunctionWrapper(void* functionPointer, + const TypeEncoding* parametersEncoding, + size_t parametersCount) + : data_(functionPointer), parametersEncoding_(parametersEncoding) {} - const WrapperType Type() { - return WrapperType::AnonymousFunction; - } + const WrapperType Type() { return WrapperType::AnonymousFunction; } - void* Data() { - return this->data_; - } + void* Data() { return this->data_; } - const TypeEncoding* ParametersEncoding() { - return this->parametersEncoding_; - } -private: - void* data_; - const TypeEncoding* parametersEncoding_; + const TypeEncoding* ParametersEncoding() { return this->parametersEncoding_; } + + private: + void* data_; + const TypeEncoding* parametersEncoding_; }; -class BlockWrapper: public BaseDataWrapper { -public: - BlockWrapper(void* block, const TypeEncoding* typeEncoding, bool ownsBlock) - : block_(block), - typeEncoding_(typeEncoding), - ownsBlock_(ownsBlock) { - } - - const WrapperType Type() { - return WrapperType::Block; - } +class BlockWrapper : public BaseDataWrapper { + public: + BlockWrapper(void* block, const TypeEncoding* typeEncoding, bool ownsBlock) + : block_(block), typeEncoding_(typeEncoding), ownsBlock_(ownsBlock) {} - void* Block() { - return this->block_; - } - - const TypeEncoding* Encodings() { - return this->typeEncoding_; - } - - bool OwnsBlock() { - return this->ownsBlock_; - } + const WrapperType Type() { return WrapperType::Block; } + + void* Block() { return this->block_; } -private: - void* block_; - const TypeEncoding* typeEncoding_; - bool ownsBlock_; + const TypeEncoding* Encodings() { return this->typeEncoding_; } + + bool OwnsBlock() { return this->ownsBlock_; } + + private: + void* block_; + const TypeEncoding* typeEncoding_; + bool ownsBlock_; }; -class FunctionReferenceTypeWrapper: public BaseDataWrapper { -public: - const WrapperType Type() { - return WrapperType::FunctionReferenceType; - } +class FunctionReferenceTypeWrapper : public BaseDataWrapper { + public: + const WrapperType Type() { return WrapperType::FunctionReferenceType; } }; -class FunctionReferenceWrapper: public BaseDataWrapper { -public: - FunctionReferenceWrapper(std::shared_ptr> function) - : function_(function), - data_(nullptr) { - } +class FunctionReferenceWrapper : public BaseDataWrapper { + public: + FunctionReferenceWrapper(std::shared_ptr> function) + : function_(function), data_(nullptr) {} - const WrapperType Type() { - return WrapperType::FunctionReference; - } + const WrapperType Type() { return WrapperType::FunctionReference; } - std::shared_ptr> Function() { - return this->function_; - } + std::shared_ptr> Function() { + return this->function_; + } - void* Data() const { - return this->data_; - } + void* Data() const { return this->data_; } - void SetData(void* data) { - this->data_ = data; - } -private: - std::shared_ptr> function_; - void* data_; + void SetData(void* data) { this->data_ = data; } + + private: + std::shared_ptr> function_; + void* data_; }; -class ExtVectorWrapper: public BaseDataWrapper { -public: - ExtVectorWrapper(void* data, ffi_type* ffiType, const TypeEncoding* innerTypeEncoding, const TypeEncoding* typeEncoding) - : data_(data), - ffiType_(ffiType), - innerTypeEncoding_(innerTypeEncoding), - typeEncoding_(typeEncoding) { - } +class ExtVectorWrapper : public BaseDataWrapper { + public: + ExtVectorWrapper(void* data, ffi_type* ffiType, + const TypeEncoding* innerTypeEncoding, + const TypeEncoding* typeEncoding) + : data_(data), + ffiType_(ffiType), + innerTypeEncoding_(innerTypeEncoding), + typeEncoding_(typeEncoding) {} - const WrapperType Type() { - return WrapperType::ExtVector; - } + const WrapperType Type() { return WrapperType::ExtVector; } - void* Data() { - return this->data_; - } + void* Data() { return this->data_; } - ffi_type* FFIType() { - return this->ffiType_; - } + ffi_type* FFIType() { return this->ffiType_; } - const TypeEncoding* InnerTypeEncoding() { - return this->innerTypeEncoding_; - } - const TypeEncoding* TypeEncoding() { - return this->typeEncoding_; - } -private: - void* data_; - ffi_type* ffiType_; - const struct TypeEncoding* innerTypeEncoding_; - const struct TypeEncoding* typeEncoding_; + const TypeEncoding* InnerTypeEncoding() { return this->innerTypeEncoding_; } + const TypeEncoding* TypeEncoding() { return this->typeEncoding_; } + + private: + void* data_; + ffi_type* ffiType_; + const struct TypeEncoding* innerTypeEncoding_; + const struct TypeEncoding* typeEncoding_; }; -class WorkerWrapper: public BaseDataWrapper { -public: - 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); - // Overload to pass a pre-built error payload when a TryCatch isn't available - // Note: this overload accepts only primitive types to avoid passing V8 handles - // across isolates/threads. - void PassUncaughtExceptionFromWorkerToMain(const std::string& message, const std::string& source, const std::string& stackTrace, int lineNumber, bool async = true); - void PostMessage(std::shared_ptr message); - void Close(); - void Terminate(); - - const WrapperType Type(); - const int Id(); - const inline bool isDisposed() { - return isDisposed_; - } - const bool IsRunning(); - const bool IsClosing(); - const int WorkerId(); - const inline v8::Isolate* GetMainIsolate() { - return mainIsolate_; - } - const inline v8::Isolate* GetWorkerIsolate() { - return workerIsolate_; - } - const inline void MakeWeak() { - isWeak_ = true; - } - const inline bool IsWeak() { - return isWeak_; - } -private: - v8::Isolate* mainIsolate_; - v8::Isolate* workerIsolate_; - std::atomic isRunning_; - std::atomic isClosing_; - std::atomic isTerminating_; - std::atomic isDisposed_; - std::atomic isWeak_; - std::function thiz, std::shared_ptr)> onMessage_; - std::shared_ptr> poWorker_; - ConcurrentQueue queue_; - static std::atomic nextId_; - int workerId_; - - void BackgroundLooper(std::function func); - void DrainPendingTasks(); - v8::Local ConstructErrorObject(v8::Local context, std::string message, std::string source, std::string stackTrace, int lineNumber); +class WorkerWrapper : public BaseDataWrapper { + public: + WorkerWrapper(v8::Isolate* mainIsolate, + std::function thiz, + std::shared_ptr)> + onMessage); + + void Start(std::shared_ptr> poWorker, + std::function func, int qualityOfService = -1); + void CallOnErrorHandlers(v8::TryCatch& tc); + void PassUncaughtExceptionFromWorkerToMain(v8::Local context, + v8::TryCatch& tc, + bool async = true); + // Overload to pass a pre-built error payload when a TryCatch isn't available + // Note: this overload accepts only primitive types to avoid passing V8 + // handles across isolates/threads. + void PassUncaughtExceptionFromWorkerToMain(const std::string& message, + const std::string& source, + const std::string& stackTrace, + int lineNumber, bool async = true); + void PostMessage(std::shared_ptr message); + void Close(); + void Terminate(); + + const WrapperType Type(); + const int Id(); + const inline bool isDisposed() { return isDisposed_; } + const bool IsRunning(); + const bool IsClosing(); + const int WorkerId(); + const inline v8::Isolate* GetMainIsolate() { return mainIsolate_; } + const inline v8::Isolate* GetWorkerIsolate() { return workerIsolate_; } + const inline void MakeWeak() { isWeak_ = true; } + const inline bool IsWeak() { return isWeak_; } + + private: + v8::Isolate* mainIsolate_; + v8::Isolate* workerIsolate_; + std::atomic isRunning_; + std::atomic isClosing_; + std::atomic isTerminating_; + std::atomic isDisposed_; + std::atomic isWeak_; + std::function thiz, + std::shared_ptr)> + onMessage_; + std::shared_ptr> poWorker_; + ConcurrentQueue queue_; + static std::atomic nextId_; + int workerId_; + + void BackgroundLooper(std::function func); + void DrainPendingTasks(); + v8::Local ConstructErrorObject(v8::Local context, + std::string message, + std::string source, + std::string stackTrace, + int lineNumber); }; -} +} // namespace tns #endif /* DataWrapper_h */ diff --git a/NativeScript/runtime/Worker.mm b/NativeScript/runtime/Worker.mm index b68c8236..de771cdd 100644 --- a/NativeScript/runtime/Worker.mm +++ b/NativeScript/runtime/Worker.mm @@ -102,10 +102,29 @@ throw NativeScriptException( throw NativeScriptException("Worker constructor expects a string URL or URL object."); } - // TODO: Handle options parameter (info[1]) if provided - // For now, we ignore the options parameter to maintain compatibility // TODO: Validate worker path and call worker.onerror if the script does not exist + int qos = -1; + if (info.Length() >= 2 && info[1]->IsObject()) { + Local options = info[1].As(); + Local iosPriorityVal; + if (options->Get(context, tns::ToV8String(isolate, "iosPriority")).ToLocal(&iosPriorityVal) && + IsString(iosPriorityVal)) { + std::string priority = ToString(isolate, iosPriorityVal); + if (priority == "userInteractive") { + qos = 0x21; // NSQualityOfServiceUserInteractive + } else if (priority == "userInitiated") { + qos = 0x19; // NSQualityOfServiceUserInitiated + } else if (priority == "default") { + qos = 0x15; // NSQualityOfServiceDefault + } else if (priority == "utility") { + qos = 0x11; // NSQualityOfServiceUtility + } else if (priority == "background") { + qos = 0x09; // NSQualityOfServiceBackground + } + } + } + WorkerWrapper* worker = new WorkerWrapper(isolate, Worker::OnMessageCallback); tns::SetValue(isolate, thiz, worker); std::shared_ptr> poWorker = ObjectManager::Register(context, thiz); @@ -158,11 +177,11 @@ throw NativeScriptException( std::string src = resolvedPath; std::string stackTrace = ""; int lineNumber = 1; - // Dispatch asynchronously so the main thread can attach handlers - worker->PassUncaughtExceptionFromWorkerToMain(message, src, stackTrace, lineNumber, true); - // Clear the global flag to avoid duplicate reporting - jsErrorOccurred = false; - } + // Dispatch asynchronously so the main thread can attach handlers + worker->PassUncaughtExceptionFromWorkerToMain(message, src, stackTrace, lineNumber, true); + // Clear the global flag to avoid duplicate reporting + jsErrorOccurred = false; + } if (tc.HasCaught()) { Isolate::Scope isolate_scope(isolate); @@ -177,18 +196,18 @@ throw NativeScriptException( // printf("Worker: Exception: %s\n", *error_str); } - // Ensure we dispatch the error asynchronously to the main thread so - // the caller has a chance to attach `worker.onerror` immediately - // after construction. Delivering synchronously can race with the - // test which sets the handler right after `new Worker(...)`. - worker->PassUncaughtExceptionFromWorkerToMain(context, tc, true); + // Ensure we dispatch the error asynchronously to the main thread so + // the caller has a chance to attach `worker.onerror` immediately + // after construction. Delivering synchronously can race with the + // test which sets the handler right after `new Worker(...)`. + worker->PassUncaughtExceptionFromWorkerToMain(context, tc, true); worker->Terminate(); } return isolate; }); - worker->Start(poWorker, func); + worker->Start(poWorker, func, qos); std::shared_ptr state = std::make_shared(isolate, poWorker, worker); @@ -417,6 +436,6 @@ throw NativeScriptException( return number->Value(); } -} +} // namespace tns NODE_BINDING_PER_ISOLATE_INIT_OBJ(worker, tns::Worker::Init) diff --git a/NativeScript/runtime/WorkerWrapper.mm b/NativeScript/runtime/WorkerWrapper.mm index 70ea6e40..a08820e9 100644 --- a/NativeScript/runtime/WorkerWrapper.mm +++ b/NativeScript/runtime/WorkerWrapper.mm @@ -46,14 +46,20 @@ } void WorkerWrapper::Start(std::shared_ptr> poWorker, - std::function func) { + std::function func, int qualityOfService) { this->poWorker_ = poWorker; this->workerId_ = nextId_.fetch_add(1, std::memory_order_relaxed) + 1; - [workers_ addOperationWithBlock:^{ + NSBlockOperation* op = [NSBlockOperation blockOperationWithBlock:^{ this->BackgroundLooper(func); }]; + if (qualityOfService >= 0) { + op.qualityOfService = static_cast(qualityOfService); + } + + [workers_ addOperation:op]; + this->isRunning_ = true; } @@ -248,7 +254,10 @@ async); } -void WorkerWrapper::PassUncaughtExceptionFromWorkerToMain(const std::string& message, const std::string& source, const std::string& stackTrace, int lineNumber, bool async) { +void WorkerWrapper::PassUncaughtExceptionFromWorkerToMain(const std::string& message, + const std::string& source, + const std::string& stackTrace, + int lineNumber, bool async) { auto runtime = static_cast(mainIsolate_->GetData(Constants::RUNTIME_SLOT)); if (runtime == nullptr) { return; @@ -269,7 +278,8 @@ if (!onErrorVal.IsEmpty() && onErrorVal->IsFunction()) { Local onErrorFunc = onErrorVal.As(); - Local arg = this->ConstructErrorObject(context, message, source, stackTrace, lineNumber); + Local arg = + this->ConstructErrorObject(context, message, source, stackTrace, lineNumber); Local args[1] = {arg}; Local result; TryCatch tc(this->mainIsolate_); @@ -316,4 +326,4 @@ std::atomic WorkerWrapper::nextId_(0); -} +} // namespace tns From 5009176545522bb7fad4700296f422e58e749d95 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Wed, 27 May 2026 16:05:56 -0300 Subject: [PATCH 2/2] fix: replace hardcoded QoS values with named constants for clarity --- NativeScript/runtime/Worker.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/NativeScript/runtime/Worker.mm b/NativeScript/runtime/Worker.mm index de771cdd..fb85540e 100644 --- a/NativeScript/runtime/Worker.mm +++ b/NativeScript/runtime/Worker.mm @@ -112,15 +112,15 @@ throw NativeScriptException( IsString(iosPriorityVal)) { std::string priority = ToString(isolate, iosPriorityVal); if (priority == "userInteractive") { - qos = 0x21; // NSQualityOfServiceUserInteractive + qos = NSQualityOfServiceUserInteractive; } else if (priority == "userInitiated") { - qos = 0x19; // NSQualityOfServiceUserInitiated + qos = NSQualityOfServiceUserInitiated; } else if (priority == "default") { - qos = 0x15; // NSQualityOfServiceDefault + qos = NSQualityOfServiceDefault; } else if (priority == "utility") { - qos = 0x11; // NSQualityOfServiceUtility + qos = NSQualityOfServiceUtility; } else if (priority == "background") { - qos = 0x09; // NSQualityOfServiceBackground + qos = NSQualityOfServiceBackground; } } }