diff --git a/NativeScript/NativeScript.h b/NativeScript/NativeScript.h index 90355eb2..af8888ae 100644 --- a/NativeScript/NativeScript.h +++ b/NativeScript/NativeScript.h @@ -2,7 +2,7 @@ @interface Config : NSObject -@property (nonatomic) NSString* BaseDir; +@property (nonatomic, retain) NSString* BaseDir; @property (nonatomic) void* MetadataPtr; @property BOOL IsDebug; @property BOOL LogToSystemConsole; diff --git a/NativeScript/NativeScript.mm b/NativeScript/NativeScript.mm index e5afc031..3eb9602a 100644 --- a/NativeScript/NativeScript.mm +++ b/NativeScript/NativeScript.mm @@ -49,6 +49,8 @@ + (void)start:(Config*)config { runtime_->RunMainScript(); + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + tns::Tasks::Drain(); runtime_.reset(); diff --git a/NativeScript/runtime/ArgConverter.h b/NativeScript/runtime/ArgConverter.h index a71528eb..e1658b1f 100644 --- a/NativeScript/runtime/ArgConverter.h +++ b/NativeScript/runtime/ArgConverter.h @@ -18,15 +18,13 @@ struct MethodCallbackWrapper { callback_(callback), initialParamIndex_(initialParamIndex), paramsCount_(paramsCount), - typeEncoding_(typeEncoding), - runLoop_(CFRunLoopGetCurrent()) { + typeEncoding_(typeEncoding) { } v8::Isolate* isolate_; std::shared_ptr> callback_; const uint8_t initialParamIndex_; const uint8_t paramsCount_; const TypeEncoding* typeEncoding_; - const CFRunLoopRef runLoop_; }; class ArgConverter { diff --git a/NativeScript/runtime/ArgConverter.mm b/NativeScript/runtime/ArgConverter.mm index e2c1ab9c..64c7b5c1 100644 --- a/NativeScript/runtime/ArgConverter.mm +++ b/NativeScript/runtime/ArgConverter.mm @@ -25,18 +25,25 @@ bool instanceMethod = !receiver.IsEmpty(); bool callSuper = false; if (instanceMethod) { - tns::Assert(receiver->InternalFieldCount() > 0, isolate); - - Local ext = receiver->GetInternalField(0).As(); - // TODO: Check the actual type of the DataWrapper - ObjCDataWrapper* wrapper = static_cast(ext->Value()); - target = wrapper->Data(); - - std::string className = object_getClassName(target); - auto cache = Caches::Get(isolate); - auto it = cache->ClassPrototypes.find(className); - // For extended classes we will call the base method - callSuper = isMethodCallback && it != cache->ClassPrototypes.end(); + BaseDataWrapper* wrapper = tns::GetValue(isolate, receiver); + tns::Assert(wrapper != nullptr, isolate); + + if (wrapper->Type() == WrapperType::ObjCAllocObject) { + ObjCAllocDataWrapper* allocWrapper = static_cast(wrapper); + Class klass = allocWrapper->Klass(); + target = [klass alloc]; + } else if (wrapper->Type() == WrapperType::ObjCObject) { + ObjCDataWrapper* objcWrapper = static_cast(wrapper); + target = objcWrapper->Data(); + + std::string className = object_getClassName(target); + auto cache = Caches::Get(isolate); + auto it = cache->ClassPrototypes.find(className); + // For extended classes we will call the base method + callSuper = isMethodCallback && it != cache->ClassPrototypes.end(); + } else { + tns::Assert(false, isolate); + } } if (args.Length() != meta->encodings()->count - 1) { @@ -66,7 +73,8 @@ throw NativeScriptException(errorMessage); } - return Interop::CallFunction(context, meta, target, klass, args, callSuper); + ObjCMethodCall methodCall(context, meta, target, klass, args, callSuper); + return Interop::CallFunction(methodCall); } Local ArgConverter::ConvertArgument(Local context, BaseDataWrapper* wrapper, bool skipGCRegistration) { @@ -324,6 +332,7 @@ ArgConverter::CreateJsWrapper(context, wrapper, thiz); std::shared_ptr> poThiz = ObjectManager::Register(context, thiz); cache->Instances.emplace(result, poThiz); + [result retain]; } } @@ -540,6 +549,32 @@ return receiver; } + if (wrapper->Type() == WrapperType::ObjCAllocObject) { + ObjCAllocDataWrapper* allocDataWrapper = static_cast(wrapper); + Class klass = allocDataWrapper->Klass(); + + std::shared_ptr> poValue = CreateEmptyObject(context, false); + receiver = poValue->Get(isolate).As(); + + const Meta* meta = FindMeta(klass); + if (meta != nullptr) { + auto cache = Caches::Get(isolate); + cache->ObjectCtorInitializer(context, static_cast(meta)); + auto it = cache->Prototypes.find(meta); + if (it != cache->Prototypes.end()) { + Local prototype = it->second->Get(isolate); + bool success; + if (!receiver->SetPrototype(context, prototype).To(&success) || !success) { + tns::Assert(false, isolate); + } + } + } + + tns::SetValue(isolate, receiver, wrapper); + + return receiver; + } + id target = nil; if (wrapper->Type() == WrapperType::ObjCObject) { ObjCDataWrapper* dataWrapper = static_cast(wrapper); @@ -558,8 +593,12 @@ } else { std::shared_ptr> poValue = CreateEmptyObject(context, skipGCRegistration); receiver = poValue->Get(isolate).As(); + tns::SetValue(isolate, receiver, wrapper); cache->Instances.emplace(target, poValue); + [target retain]; } + } else { + tns::SetValue(isolate, receiver, wrapper); } Class klass = [target class]; @@ -594,8 +633,6 @@ } } - tns::SetValue(isolate, receiver, wrapper); - return receiver; } diff --git a/NativeScript/runtime/ArrayAdapter.mm b/NativeScript/runtime/ArrayAdapter.mm index 119ddc01..01fb754f 100644 --- a/NativeScript/runtime/ArrayAdapter.mm +++ b/NativeScript/runtime/ArrayAdapter.mm @@ -1,5 +1,4 @@ #include "ArrayAdapter.h" -#include "ObjectManager.h" #include "DataWrapper.h" #include "Helpers.h" #include "Interop.h" @@ -17,8 +16,8 @@ - (instancetype)initWithJSObject:(Local)jsObject isolate:(Isolate*)isola if (self) { self->isolate_ = isolate; std::shared_ptr cache = Caches::Get(isolate); - Local context = cache->GetContext(); - self->object_ = ObjectManager::Register(context, jsObject); + // TODO: Handle the lifetime of this persistent js object + self->object_ = std::make_shared>(isolate, jsObject); cache->Instances.emplace(self, self->object_); tns::SetValue(isolate, jsObject, new ObjCDataWrapper(self)); } @@ -101,6 +100,7 @@ - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state object - (void)dealloc { self->object_->Reset(); + [super dealloc]; } @end diff --git a/NativeScript/runtime/ClassBuilder.h b/NativeScript/runtime/ClassBuilder.h index de2ba2cb..41d0dfc6 100644 --- a/NativeScript/runtime/ClassBuilder.h +++ b/NativeScript/runtime/ClassBuilder.h @@ -28,6 +28,8 @@ class ClassBuilder { static std::string GetTypeEncoding(const TypeEncoding* typeEncoding, int argsCount); static std::string GetTypeEncoding(const TypeEncoding* typeEncoding); static BinaryTypeEncodingType GetTypeEncodingType(v8::Isolate* isolate, v8::Local value); + static IMP FindNotOverridenMethod(Class klass, SEL method); + struct CacheItem { public: diff --git a/NativeScript/runtime/ClassBuilder.mm b/NativeScript/runtime/ClassBuilder.mm index 7b186d25..f680f711 100644 --- a/NativeScript/runtime/ClassBuilder.mm +++ b/NativeScript/runtime/ClassBuilder.mm @@ -2,6 +2,7 @@ #include #include #include "ClassBuilder.h" +#include "TNSDerivedClass.h" #include "NativeScriptException.h" #include "FastEnumerationAdapter.h" #include "ArgConverter.h" @@ -61,6 +62,9 @@ } Class extendedClass = ClassBuilder::GetExtendedClass(baseClassName, staticClassName); + class_addProtocol(extendedClass, @protocol(TNSDerivedClass)); + class_addProtocol(object_getClass(extendedClass), @protocol(TNSDerivedClass)); + if (!nativeSignature.IsEmpty()) { ClassBuilder::ExposeDynamicMembers(context, extendedClass, implementationObject, nativeSignature); } else { @@ -182,14 +186,17 @@ return; } - ObjCDataWrapper* dataWrapper = static_cast(wrapper); - Class baseClass = dataWrapper->Data(); + ObjCClassWrapper* classWrapper = static_cast(wrapper); + Class baseClass = classWrapper->Klass(); std::string baseClassName = class_getName(baseClass); Local extendedClassCtorFunc = info[0].As(); std::string extendedClassName = tns::ToString(isolate, extendedClassCtorFunc->GetName()); __block Class extendedClass = ClassBuilder::GetExtendedClass(baseClassName, extendedClassName); + class_addProtocol(extendedClass, @protocol(TNSDerivedClass)); + class_addProtocol(object_getClass(extendedClass), @protocol(TNSDerivedClass)); + extendedClassName = class_getName(extendedClass); tns::SetValue(isolate, extendedClassCtorFunc, new ObjCClassWrapper(extendedClass, true)); @@ -247,6 +254,54 @@ }); class_addMethod(object_getClass(extendedClass), @selector(initialize), newInitialize, "v@:"); + /// We swizzle the retain and release methods for the following reason: + /// When we instantiate a native class via a JavaScript call we add it to the object instances map thus + /// incrementing the retainCount by 1. Then, when the native object is referenced somewhere else its count will become more than 1. + /// Since we want to keep the corresponding JavaScript object alive even if it is not used anywhere, we call GcProtect on it. + /// Whenever the native object is released so that its retainCount is 1 (the object instances map), we unprotect the corresponding JavaScript object + /// in order to make both of them destroyable/GC-able. When the JavaScript object is GC-ed we release the native counterpart as well. + void (*retain)(id, SEL) = (void (*)(id, SEL))FindNotOverridenMethod(extendedClass, @selector(retain)); + IMP newRetain = imp_implementationWithBlock(^(id self) { + if ([self retainCount] == 1) { + auto it = cache->Instances.find(self); + if (it != cache->Instances.end()) { + v8::Locker locker(isolate); + Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); + Local value = it->second->Get(isolate); + BaseDataWrapper* wrapper = tns::GetValue(isolate, value); + if (wrapper != nullptr && wrapper->Type() == WrapperType::ObjCObject) { + ObjCDataWrapper* objcWrapper = static_cast(wrapper); + objcWrapper->GcProtect(); + } + } + } + + return retain(self, @selector(retain)); + }); + class_addMethod(extendedClass, @selector(retain), newRetain, "@@:"); + + void (*release)(id, SEL) = (void (*)(id, SEL))FindNotOverridenMethod(extendedClass, @selector(release)); + IMP newRelease = imp_implementationWithBlock(^(id self) { + if ([self retainCount] == 2) { + auto it = cache->Instances.find(self); + if (it != cache->Instances.end()) { + v8::Locker locker(isolate); + Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); + Local value = it->second->Get(isolate); + BaseDataWrapper* wrapper = tns::GetValue(isolate, value); + if (wrapper != nullptr && wrapper->Type() == WrapperType::ObjCObject) { + ObjCDataWrapper* objcWrapper = static_cast(wrapper); + objcWrapper->GcUnprotect(); + } + } + } + + release(self, @selector(release)); + }); + class_addMethod(extendedClass, @selector(release), newRelease, "v@:"); + info.GetReturnValue().Set(v8::Undefined(isolate)); }).ToLocalChecked(); @@ -761,6 +816,14 @@ info.GetReturnValue().Set(superValue); } +IMP ClassBuilder::FindNotOverridenMethod(Class klass, SEL method) { + while (class_conformsToProtocol(klass, @protocol(TNSDerivedClass))) { + klass = class_getSuperclass(klass); + } + + return class_getMethodImplementation(klass, method); +} + unsigned long long ClassBuilder::classNameCounter_ = 0; } diff --git a/NativeScript/runtime/DataWrapper.h b/NativeScript/runtime/DataWrapper.h index a394547a..a7a0d421 100644 --- a/NativeScript/runtime/DataWrapper.h +++ b/NativeScript/runtime/DataWrapper.h @@ -13,25 +13,26 @@ namespace tns { class PrimitiveDataWrapper; enum class WrapperType { - Base, - Primitive, - Enum, - Struct, - StructType, - ObjCObject, - ObjCClass, - ObjCProtocol, - Function, - AnonymousFunction, - Block, - Reference, - ReferenceType, - Pointer, - PointerType, - FunctionReference, - FunctionReferenceType, - ExtVector, - Worker, + 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, }; struct V8Args { @@ -160,11 +161,29 @@ struct StructInfo { class BaseDataWrapper { public: + BaseDataWrapper() + : gcProtected_(false) { + } + virtual ~BaseDataWrapper() = default; const virtual WrapperType Type() { return WrapperType::Base; } + + bool IsGcProtected() { + return this->gcProtected_; + } + + void GcProtect() { + this->gcProtected_ = true; + } + + void GcUnprotect() { + this->gcProtected_ = false; + } +private: + bool gcProtected_; }; class EnumDataWrapper: public BaseDataWrapper { @@ -367,6 +386,23 @@ class StructWrapper: public StructTypeWrapper { std::shared_ptr> parent_; }; +class ObjCAllocDataWrapper: public BaseDataWrapper { +public: + ObjCAllocDataWrapper(Class klass) + : klass_(klass) { + } + + const WrapperType Type() { + return WrapperType::ObjCAllocObject; + } + + Class Klass() { + return this->klass_; + } +private: + Class klass_; +}; + class ObjCDataWrapper: public BaseDataWrapper { public: ObjCDataWrapper(id data) @@ -378,7 +414,7 @@ class ObjCDataWrapper: public BaseDataWrapper { } id Data() { - return data_; + return this->data_; } private: id data_; diff --git a/NativeScript/runtime/DictionaryAdapter.mm b/NativeScript/runtime/DictionaryAdapter.mm index 58282ed1..3b813c6a 100644 --- a/NativeScript/runtime/DictionaryAdapter.mm +++ b/NativeScript/runtime/DictionaryAdapter.mm @@ -1,6 +1,5 @@ #import #include "DictionaryAdapter.h" -#include "ObjectManager.h" #include "DataWrapper.h" #include "Helpers.h" #include "Interop.h" @@ -50,6 +49,7 @@ - (id)nextObject { } - (void)dealloc { + [super dealloc]; } @end @@ -118,6 +118,7 @@ - (NSArray*)allObjects { } - (void)dealloc { + [super dealloc]; } @end @@ -131,8 +132,9 @@ - (instancetype)initWithJSObject:(Local)jsObject isolate:(Isolate*)isola if (self) { self->isolate_ = isolate; std::shared_ptr cache = Caches::Get(isolate); - Local context = cache->GetContext(); - self->object_ = ObjectManager::Register(context, jsObject); + // TODO: Handle the lifetime of this persistent js object + + self->object_ = std::make_shared>(isolate, jsObject); cache->Instances.emplace(self, self->object_); tns::SetValue(isolate, jsObject, new ObjCDataWrapper(self)); } @@ -201,6 +203,7 @@ - (NSEnumerator*)keyEnumerator { - (void)dealloc { self->object_->Reset(); + [super dealloc]; } @end diff --git a/NativeScript/runtime/Helpers.h b/NativeScript/runtime/Helpers.h index ad739821..ba55d2ce 100644 --- a/NativeScript/runtime/Helpers.h +++ b/NativeScript/runtime/Helpers.h @@ -33,6 +33,7 @@ v8::Local GetPrivateValue(const v8::Local& obj, const v8: void SetValue(v8::Isolate* isolate, const v8::Local& obj, BaseDataWrapper* value); BaseDataWrapper* GetValue(v8::Isolate* isolate, const v8::Local& val); +void DeleteValue(v8::Isolate* isolate, const v8::Local& val); std::vector> ArgsToVector(const v8::FunctionCallbackInfo& info); bool IsString(v8::Local value); diff --git a/NativeScript/runtime/Helpers.mm b/NativeScript/runtime/Helpers.mm index 114a659e..68f61a48 100644 --- a/NativeScript/runtime/Helpers.mm +++ b/NativeScript/runtime/Helpers.mm @@ -265,6 +265,30 @@ return static_cast(metadataProp.As()->Value()); } +void tns::DeleteValue(Isolate* isolate, const Local& val) { + if (val.IsEmpty() || val->IsNullOrUndefined() || !val->IsObject()) { + return; + } + + Local obj = val.As(); + if (obj->InternalFieldCount() > 0) { + obj->SetInternalField(0, v8::Undefined(isolate)); + return; + } + + Local metadataKey = tns::ToV8String(isolate, "metadata"); + Local metadataProp = tns::GetPrivateValue(obj, metadataKey); + if (metadataProp.IsEmpty() || metadataProp->IsNullOrUndefined() || !metadataProp->IsExternal()) { + return; + } + + Local context = obj->CreationContext(); + Local privateKey = Private::ForApi(isolate, metadataKey); + + bool success = obj->DeletePrivate(context, privateKey).FromMaybe(false); + tns::Assert(success, isolate); +} + std::vector> tns::ArgsToVector(const FunctionCallbackInfo& info) { std::vector> args; args.reserve(info.Length()); diff --git a/NativeScript/runtime/Interop.h b/NativeScript/runtime/Interop.h index 2ce3d0a8..edde29e9 100644 --- a/NativeScript/runtime/Interop.h +++ b/NativeScript/runtime/Interop.h @@ -2,6 +2,7 @@ #define Interop_h #include +#include #include "libffi.h" #include "Common.h" #include "Metadata.h" @@ -12,21 +13,114 @@ namespace tns { typedef void (*FFIMethodCallback)(ffi_cif* cif, void* retValue, void** argValues, void* userData); +struct MethodCall { + MethodCall(v8::Local context, + bool isPrimitiveFunction, + void* functionPointer, + const TypeEncoding* typeEncoding, + V8Args& args, + id target, + Class clazz, + SEL selector, + bool callSuper, + MetaType metaType, + bool provideErrorOutParameter, + bool ownsReturnedObject, + bool isInitializer) + : context_(context), + isPrimitiveFunction_(isPrimitiveFunction), + functionPointer_(functionPointer), + typeEncoding_(typeEncoding), + args_(args), + target_(target), + clazz_(clazz), + selector_(selector), + callSuper_(callSuper), + metaType_(metaType), + provideErrorOutParameter_(provideErrorOutParameter), + ownsReturnedObject_(ownsReturnedObject), + isInitializer_(isInitializer) { + } + + v8::Local context_; + bool isPrimitiveFunction_; + void* functionPointer_; + const TypeEncoding* typeEncoding_; + V8Args& args_; + id target_; + Class clazz_; + SEL selector_; + bool callSuper_; + MetaType metaType_; + bool provideErrorOutParameter_; + bool ownsReturnedObject_; + bool isInitializer_; +}; + +struct CMethodCall: MethodCall { + CMethodCall( + v8::Local context, + void* functionPointer, + const TypeEncoding* typeEncoding, + V8Args& args, + bool ownsReturnedObject) + : MethodCall( + context, + true, + functionPointer, + typeEncoding, + args, + nil, + nil, + nil, + false, + MetaType::Undefined, + false, + ownsReturnedObject, + false) { + } +}; + +struct ObjCMethodCall: public MethodCall { + ObjCMethodCall( + v8::Local context, + const MethodMeta* meta, + id target, + Class clazz, + V8Args& args, + bool callSuper) + : MethodCall( + context, + false, + callSuper ? (void*)objc_msgSendSuper : (void*)objc_msgSend, + meta->encodings()->first(), + args, + target, + clazz, + meta->selector(), + callSuper, + meta->type(), + meta->hasErrorOutParameter() && args.Length() < meta->encodings()->count - 1, + meta->ownsReturnedCocoaObject(), + meta->isInitializer()) { + } +}; + class Interop { public: static void RegisterInteropTypes(v8::Local context); - static CFTypeRef CreateBlock(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData); static IMP CreateMethod(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData); static id CallInitializer(v8::Local context, const MethodMeta* methodMeta, id target, Class clazz, V8Args& args); - static v8::Local CallFunction(v8::Local context, const MethodMeta* meta, id target, Class clazz, V8Args& args, bool callSuper); - static v8::Local CallFunction(v8::Local context, void* functionPointer, const TypeEncoding* typeEncoding, V8Args& args); - static v8::Local GetResult(v8::Local context, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive, std::shared_ptr> parentStruct = nullptr, bool isStructMember = false); + static v8::Local CallFunction(ObjCMethodCall& methodCall); + static v8::Local CallFunction(CMethodCall& methodCall); + static v8::Local GetResult(v8::Local context, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive, std::shared_ptr> parentStruct = nullptr, bool isStructMember = false, bool ownsReturnedObject = false, bool isInitializer = false); static void SetStructPropertyValue(v8::Local context, StructWrapper* wrapper, StructField field, v8::Local value); static void InitializeStruct(v8::Local context, void* destBuffer, std::vector fields, v8::Local inititalizer); static void WriteValue(v8::Local context, const TypeEncoding* typeEncoding, void* dest, v8::Local arg); static id ToObject(v8::Local context, v8::Local arg); static v8::Local GetPrimitiveReturnType(v8::Local context, BinaryTypeEncodingType type, BaseCall* call); private: + static CFTypeRef CreateBlock(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData); template static void SetStructValue(v8::Local value, void* destBuffer, ptrdiff_t position); static void InitializeStruct(v8::Local context, void* destBuffer, std::vector fields, v8::Local inititalizer, ptrdiff_t& position); @@ -42,7 +136,7 @@ class Interop { static v8::Local StructToValue(v8::Local context, void* result, StructInfo structInfo, std::shared_ptr> parentStruct); static const TypeEncoding* CreateEncoding(BinaryTypeEncodingType type); static v8::Local HandleOf(v8::Local context, v8::Local value); - static v8::Local CallFunctionInternal(v8::Local context, bool isPrimitiveFunction, void* functionPointer, const TypeEncoding* typeEncoding, V8Args& args, id target, Class clazz, SEL selector, bool callSuper, MetaType metaType, bool provideErrorOurParameter = false); + static v8::Local CallFunctionInternal(MethodCall& methodCall); static bool IsNumbericType(BinaryTypeEncodingType type); static v8::Local GetInteropType(v8::Local context, BinaryTypeEncodingType type); diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index 9837a6ed..d97b106b 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -1,5 +1,4 @@ #include -#include #include #include "Runtime.h" #include "Interop.h" @@ -35,9 +34,16 @@ MethodCallbackWrapper* wrapper = static_cast(block->userData); Runtime* runtime = Runtime::GetCurrentRuntime(); if (runtime != nullptr) { + Isolate* isolate = runtime->GetIsolate(); + v8::Locker locker(isolate); + Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); + Local callback = wrapper->callback_->Get(isolate); + tns::DeleteValue(isolate, callback); wrapper->callback_->Reset(); } delete wrapper; + block->~JSBlock(); } } }; @@ -71,29 +77,12 @@ return blockPointer; } -Local Interop::CallFunction(Local context, void* functionPointer, const TypeEncoding* typeEncoding, V8Args& args) { - return Interop::CallFunctionInternal(context, true, functionPointer, typeEncoding, args, nil, nil, nil, false, MetaType::Undefined); +Local Interop::CallFunction(CMethodCall& methodCall) { + return Interop::CallFunctionInternal(methodCall); } -Local Interop::CallFunction(Local context, const MethodMeta* meta, id target, Class clazz, V8Args& args, bool callSuper) { - SEL selector = nil; - void* functionPointer = nullptr; - const TypeEncoding* typeEncoding = nullptr; - bool isPrimitiveFunction = false; - MetaType metaType = MetaType::Undefined; - - metaType = meta->type(); - selector = meta->selector(); - typeEncoding = meta->encodings()->first(); - if (callSuper) { - functionPointer = (void*)objc_msgSendSuper; - } else { - functionPointer = (void*)objc_msgSend; - } - - bool provideErrorOutParameter = meta->hasErrorOutParameter() && args.Length() < meta->encodings()->count - 1; - - return Interop::CallFunctionInternal(context, isPrimitiveFunction, functionPointer, typeEncoding, args, target, clazz, selector, callSuper, metaType, provideErrorOutParameter); +Local Interop::CallFunction(ObjCMethodCall& methodCall) { + return Interop::CallFunctionInternal(methodCall); } id Interop::CallInitializer(Local context, const MethodMeta* methodMeta, id target, Class clazz, V8Args& args) { @@ -333,14 +322,21 @@ const TypeEncoding* blockTypeEncoding = typeEncoding->details.block.signature.first(); int argsCount = typeEncoding->details.block.signature.count - 1; - std::shared_ptr> poCallback = std::make_shared>(isolate, arg); - MethodCallbackWrapper* userData = new MethodCallbackWrapper(isolate, poCallback, 1, argsCount, blockTypeEncoding); - CFTypeRef blockPtr = Interop::CreateBlock(1, argsCount, blockTypeEncoding, ArgConverter::MethodCallback, userData); + CFTypeRef blockPtr = nullptr; + BaseDataWrapper* baseWrapper = tns::GetValue(isolate, arg); + if (baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Block) { + BlockWrapper* wrapper = static_cast(baseWrapper); + blockPtr = wrapper->Block(); + } else { + std::shared_ptr> poCallback = std::make_shared>(isolate, arg); + MethodCallbackWrapper* userData = new MethodCallbackWrapper(isolate, poCallback, 1, argsCount, blockTypeEncoding); + blockPtr = Interop::CreateBlock(1, argsCount, blockTypeEncoding, ArgConverter::MethodCallback, userData); - [(id)blockPtr autorelease]; + [(id)blockPtr autorelease]; - BlockWrapper* wrapper = new BlockWrapper((void*)blockPtr, blockTypeEncoding); - tns::SetValue(isolate, arg.As(), wrapper); + BlockWrapper* wrapper = new BlockWrapper((void*)blockPtr, blockTypeEncoding); + tns::SetValue(isolate, arg.As(), wrapper); + } Interop::SetValue(dest, blockPtr); } else if (arg->IsObject() && typeEncoding->type == BinaryTypeEncodingType::StructDeclarationReference) { @@ -698,7 +694,7 @@ *static_cast((void*)((uint8_t*)destBuffer + position)) = result; } -Local Interop::GetResult(Local context, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive, std::shared_ptr> parentStruct, bool isStructMember) { +Local Interop::GetResult(Local context, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive, std::shared_ptr> parentStruct, bool isStructMember, bool ownsReturnedObject, bool isInitializer) { Isolate* isolate = context->GetIsolate(); if (typeEncoding->type == BinaryTypeEncodingType::ExtVectorEncoding) { @@ -887,7 +883,8 @@ const TypeEncoding* typeEncoding = wrapper->ParametersEncoding(); Local context = isolate->GetCurrentContext(); - Local result = Interop::CallFunction(context, functionPointer, typeEncoding, args); + CMethodCall methodCall(context, functionPointer, typeEncoding, args, false); + Local result = Interop::CallFunction(methodCall); info.GetReturnValue().Set(result); }, ext).ToLocal(&func); @@ -1001,6 +998,10 @@ ObjCDataWrapper* wrapper = new ObjCDataWrapper(result); Local jsResult = ArgConverter::ConvertArgument(context, wrapper); + if (ownsReturnedObject || isInitializer) { + [result release]; + } + if ([result isKindOfClass:[NSArray class]]) { // attach Symbol.iterator to the instance SymbolIterator::Set(context, jsResult); @@ -1270,68 +1271,68 @@ return result.As(); } -Local Interop::CallFunctionInternal(Local context, bool isPrimitiveFunction, void* functionPointer, const TypeEncoding* typeEncoding, V8Args& args, id target, Class clazz, SEL selector, bool callSuper, MetaType metaType, bool provideErrorOurParameter) { - int initialParameterIndex = isPrimitiveFunction ? 0 : 2; +Local Interop::CallFunctionInternal(MethodCall& methodCall) { + int initialParameterIndex = methodCall.isPrimitiveFunction_ ? 0 : 2; - int argsCount = initialParameterIndex + (int)args.Length(); - int cifArgsCount = provideErrorOurParameter ? argsCount + 1 : argsCount; + int argsCount = initialParameterIndex + (int)methodCall.args_.Length(); + int cifArgsCount = methodCall.provideErrorOutParameter_ ? argsCount + 1 : argsCount; - ParametrizedCall* parametrizedCall = ParametrizedCall::Get(typeEncoding, initialParameterIndex, cifArgsCount); + ParametrizedCall* parametrizedCall = ParametrizedCall::Get(methodCall.typeEncoding_, initialParameterIndex, cifArgsCount); FFICall call(parametrizedCall); objc_super sup; - bool isInstanceMethod = (target && target != nil); + bool isInstanceMethod = (methodCall.target_ && methodCall.target_ != nil); if (initialParameterIndex > 1) { #if defined(__x86_64__) - if (metaType == MetaType::Undefined || metaType == MetaType::Union || metaType == MetaType::Struct) { + if (methodCall.metaType_ == MetaType::Undefined || methodCall.metaType_ == MetaType::Union || methodCall.metaType_ == MetaType::Struct) { const unsigned UNIX64_FLAG_RET_IN_MEM = (1 << 10); - ffi_type* returnType = FFICall::GetArgumentType(typeEncoding); + ffi_type* returnType = FFICall::GetArgumentType(methodCall.typeEncoding_); if (returnType->type == FFI_TYPE_LONGDOUBLE) { - functionPointer = (void*)objc_msgSend_fpret; + methodCall.functionPointer_ = (void*)objc_msgSend_fpret; } else if (returnType->type == FFI_TYPE_STRUCT && (parametrizedCall->Cif->flags & UNIX64_FLAG_RET_IN_MEM)) { - if (callSuper) { - functionPointer = (void*)objc_msgSendSuper_stret; + if (methodCall.callSuper_) { + methodCall.functionPointer_ = (void*)objc_msgSendSuper_stret; } else { - functionPointer = (void*)objc_msgSend_stret; + methodCall.functionPointer_ = (void*)objc_msgSend_stret; } } } #endif if (isInstanceMethod) { - if (callSuper) { - sup.receiver = target; - sup.super_class = class_getSuperclass(object_getClass(target)); + if (methodCall.callSuper_) { + sup.receiver = methodCall.target_; + sup.super_class = class_getSuperclass(object_getClass(methodCall.target_)); Interop::SetValue(call.ArgumentBuffer(0), &sup); } else { - Interop::SetValue(call.ArgumentBuffer(0), target); + Interop::SetValue(call.ArgumentBuffer(0), methodCall.target_); } } else { - Interop::SetValue(call.ArgumentBuffer(0), clazz); + Interop::SetValue(call.ArgumentBuffer(0), methodCall.clazz_); } - Interop::SetValue(call.ArgumentBuffer(1), selector); + Interop::SetValue(call.ArgumentBuffer(1), methodCall.selector_); } - bool isInstanceReturnType = typeEncoding->type == BinaryTypeEncodingType::InstanceTypeEncoding; - bool marshalToPrimitive = isPrimitiveFunction || !isInstanceReturnType; + bool isInstanceReturnType = methodCall.typeEncoding_->type == BinaryTypeEncodingType::InstanceTypeEncoding; + bool marshalToPrimitive = methodCall.isPrimitiveFunction_ || !isInstanceReturnType; - Interop::SetFFIParams(context, typeEncoding, &call, argsCount, initialParameterIndex, args); + Interop::SetFFIParams(methodCall.context_, methodCall.typeEncoding_, &call, argsCount, initialParameterIndex, methodCall.args_); void* errorRef = nullptr; - if (provideErrorOurParameter) { + if (methodCall.provideErrorOutParameter_) { void* dest = call.ArgumentBuffer(argsCount); errorRef = malloc(ffi_type_pointer.size); Interop::SetValue(dest, errorRef); } @try { - ffi_call(parametrizedCall->Cif, FFI_FN(functionPointer), call.ResultBuffer(), call.ArgsArray()); + ffi_call(parametrizedCall->Cif, FFI_FN(methodCall.functionPointer_), call.ResultBuffer(), call.ArgsArray()); } @catch (NSException* e) { std::string message = [[e description] UTF8String]; throw NativeScriptException(message); @@ -1346,7 +1347,7 @@ } } - Local result = Interop::GetResult(context, typeEncoding, &call, marshalToPrimitive, nullptr); + Local result = Interop::GetResult(methodCall.context_, methodCall.typeEncoding_, &call, marshalToPrimitive, nullptr, false, methodCall.ownsReturnedObject_, methodCall.isInitializer_); return result; } diff --git a/NativeScript/runtime/MetadataBuilder.mm b/NativeScript/runtime/MetadataBuilder.mm index a7929adb..ceb53de9 100644 --- a/NativeScript/runtime/MetadataBuilder.mm +++ b/NativeScript/runtime/MetadataBuilder.mm @@ -352,6 +352,12 @@ } } + MetadataBuilder::RegisterStaticMethods(context, ctorFunc, meta, staticMembers); + MetadataBuilder::RegisterStaticProperties(context, ctorFunc, meta, meta->name(), staticMembers); + MetadataBuilder::RegisterStaticProtocols(context, ctorFunc, meta, meta->name(), staticMembers); + + cache->CtorFuncTemplates.emplace(meta, std::make_unique>(isolate, ctorFuncTemplate)); + if (meta->type() == MetaType::Interface) { const InterfaceMeta* interfaceMeta = static_cast(meta); MetadataBuilder::RegisterAllocMethod(context, ctorFunc, interfaceMeta); @@ -361,12 +367,6 @@ tns::Assert(success, isolate); } - MetadataBuilder::RegisterStaticMethods(context, ctorFunc, meta, staticMembers); - MetadataBuilder::RegisterStaticProperties(context, ctorFunc, meta, meta->name(), staticMembers); - MetadataBuilder::RegisterStaticProtocols(context, ctorFunc, meta, meta->name(), staticMembers); - - cache->CtorFuncTemplates.emplace(meta, std::make_unique>(isolate, ctorFuncTemplate)); - Local prototypeValue; success = ctorFunc->Get(context, tns::ToV8String(isolate, "prototype")).ToLocal(&prototypeValue); tns::Assert(success, isolate); @@ -611,11 +611,9 @@ klass = objc_getClass(meta->name()); } - id obj = [klass alloc]; - - std::string className = class_getName(klass); Local context = isolate->GetCurrentContext(); - Local result = ArgConverter::CreateJsWrapper(context, new ObjCDataWrapper(obj), Local()); + ObjCAllocDataWrapper* allocWrapper = new ObjCAllocDataWrapper(klass); + Local result = ArgConverter::CreateJsWrapper(context, allocWrapper, Local()); info.GetReturnValue().Set(result); } catch (NativeScriptException& ex) { ex.ReThrowToV8(isolate); @@ -836,7 +834,8 @@ V8VectorArgs vectorArgs(localArgs); Local context = Caches::Get(isolate)->GetContext(); v8::Unlocker unlocker(isolate); - Interop::CallFunction(context, item->userData_, typeEncoding, vectorArgs); + CMethodCall methodCall(context, item->userData_, typeEncoding, vectorArgs, item->meta_->ownsReturnedCocoaObject()); + Interop::CallFunction(methodCall); }); return; @@ -845,7 +844,8 @@ V8FunctionCallbackArgs args(info); const TypeEncoding* typeEncoding = item->meta_->encodings()->first(); Local context = isolate->GetCurrentContext(); - Local result = Interop::CallFunction(context, item->userData_, typeEncoding, args); + CMethodCall methodCall(context, item->userData_, typeEncoding, args, item->meta_->ownsReturnedCocoaObject()); + Local result = Interop::CallFunction(methodCall); if (typeEncoding->type != BinaryTypeEncodingType::VoidEncoding) { info.GetReturnValue().Set(result); diff --git a/NativeScript/runtime/NSDataAdapter.mm b/NativeScript/runtime/NSDataAdapter.mm index 1df659de..13e4bc4b 100644 --- a/NativeScript/runtime/NSDataAdapter.mm +++ b/NativeScript/runtime/NSDataAdapter.mm @@ -1,5 +1,4 @@ #include "NSDataAdapter.h" -#include "ObjectManager.h" #include "Helpers.h" #include "Caches.h" @@ -16,8 +15,8 @@ - (instancetype)initWithJSObject:(Local)jsObject isolate:(Isolate*)isola tns::Assert(jsObject->IsArrayBuffer() || jsObject->IsArrayBufferView(), isolate); self->isolate_ = isolate; std::shared_ptr cache = Caches::Get(isolate); - Local context = cache->GetContext(); - self->object_ = ObjectManager::Register(context, jsObject); + // TODO: Handle the lifetime of this persistent js object + self->object_ = std::make_shared>(isolate, jsObject); cache->Instances.emplace(self, self->object_); tns::SetValue(isolate, jsObject, new ObjCDataWrapper(self)); } @@ -60,6 +59,7 @@ - (NSUInteger)length { - (void)dealloc { self->object_->Reset(); + [super dealloc]; } @end diff --git a/NativeScript/runtime/ObjectManager.mm b/NativeScript/runtime/ObjectManager.mm index 964a2920..b79977e7 100644 --- a/NativeScript/runtime/ObjectManager.mm +++ b/NativeScript/runtime/ObjectManager.mm @@ -1,8 +1,5 @@ #include #include -#include "DictionaryAdapter.h" -#include "NSDataAdapter.h" -#include "ArrayAdapter.h" #include "ObjectManager.h" #include "DataWrapper.h" #include "Helpers.h" @@ -62,6 +59,10 @@ return true; } + if (wrapper->IsGcProtected()) { + return false; + } + std::shared_ptr cache = Caches::Get(isolate); switch (wrapper->Type()) { case WrapperType::Struct: { @@ -91,20 +92,8 @@ ObjCDataWrapper* objCObjectWrapper = static_cast(wrapper); id target = objCObjectWrapper->Data(); if (target != nil) { - long retainCount = ObjectManager::GetRetainCount(target); - if (retainCount > 2) { - return false; - } - - bool isAdapter = - [target isKindOfClass:[DictionaryAdapter class]] || - [target isKindOfClass:[ArrayAdapter class]] || - [target isKindOfClass:[NSDataAdapter class]]; - if (isAdapter /**&& retainCount > 2**/) { - return false; - } - cache->Instances.erase(target); + [target release]; } break; } @@ -170,7 +159,7 @@ delete wrapper; wrapper = nullptr; - tns::SetValue(isolate, obj, nullptr); + tns::DeleteValue(isolate, obj); return true; } @@ -216,10 +205,7 @@ cache->Instances.erase(it); } - long retainCount = ObjectManager::GetRetainCount(data); - for (int i = 0; i < retainCount - 1; i++) { - [data release]; - } + [data dealloc]; delete wrapper; tns::SetValue(isolate, value.As(), nullptr); diff --git a/NativeScript/runtime/PromiseProxy.cpp b/NativeScript/runtime/PromiseProxy.cpp index 0f0a1efe..85952f11 100644 --- a/NativeScript/runtime/PromiseProxy.cpp +++ b/NativeScript/runtime/PromiseProxy.cpp @@ -28,7 +28,7 @@ void PromiseProxy::Init(v8::Local context) { return new Proxy(promise, { get: function(target, name) { let orig = target[name]; - if (name === "then") { + if (name === "then" || name === "catch") { return orig.bind(target); } return function(x) { diff --git a/NativeScript/runtime/Runtime.mm b/NativeScript/runtime/Runtime.mm index fd6f5e0e..593187fa 100644 --- a/NativeScript/runtime/Runtime.mm +++ b/NativeScript/runtime/Runtime.mm @@ -15,6 +15,7 @@ #include "TSHelpers.h" #include "WeakRef.h" #include "Worker.h" +// #include "SetTimeout.h" #define STRINGIZE(x) #x #define STRINGIZE_VALUE_OF(x) STRINGIZE(x) @@ -84,6 +85,7 @@ DefineTimeMethod(isolate, globalTemplate); WeakRef::Init(isolate, globalTemplate); ObjectManager::Init(isolate, globalTemplate); +// SetTimeout::Init(isolate, globalTemplate); isolate->SetCaptureStackTraceForUncaughtExceptions(true, 100, StackTrace::kOverview); isolate->AddMessageListener(NativeScriptException::OnUncaughtError); diff --git a/NativeScript/runtime/SetTimeout.cpp b/NativeScript/runtime/SetTimeout.cpp index 815dc2c1..a8472618 100644 --- a/NativeScript/runtime/SetTimeout.cpp +++ b/NativeScript/runtime/SetTimeout.cpp @@ -1,6 +1,7 @@ #include #include "SetTimeout.h" #include "Helpers.h" +#include "Caches.h" using namespace v8; @@ -71,11 +72,13 @@ void SetTimeout::Elapsed(const uint32_t key) { Isolate* isolate = it->second.isolate_; Persistent* poCallback = it->second.callback_; + v8::Locker locker(isolate); Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); Local cb = poCallback->Get(isolate); - Local context = isolate->GetCurrentContext(); + std::shared_ptr cache = Caches::Get(isolate); + Local context = cache->GetContext(); Local global = context->Global(); Local result; if (!cb->Call(context, global, 0, nullptr).ToLocal(&result)) { diff --git a/NativeScript/runtime/SymbolLoader.mm b/NativeScript/runtime/SymbolLoader.mm index b8ca24ba..d5006b18 100644 --- a/NativeScript/runtime/SymbolLoader.mm +++ b/NativeScript/runtime/SymbolLoader.mm @@ -97,7 +97,7 @@ virtual bool load() override { if (CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, (CFURLRef)bundleUrl)) { resolver = std::make_unique(bundle); } else { - //WTF::dataLogF("NativeScript could not load bundle %s\n", bundleUrl.absoluteString.UTF8String); + NSLog(@"NativeScript could not load bundle %s\n", bundleUrl.absoluteString.UTF8String); } } else if (module->libraries->count == 1) { if (module->isSystem()) { @@ -106,10 +106,10 @@ virtual bool load() override { NSString* libraryPath = [NSString stringWithFormat:@"%@/lib%s.dylib", libsPath, module->libraries->first()->value().getName()]; if (void* library = dlopen(libraryPath.UTF8String, RTLD_LAZY | RTLD_LOCAL)) { - //WTF::dataLogF("NativeScript loaded library %s\n", libraryPath.UTF8String); + NSLog(@"NativeScript loaded library %s\n", libraryPath.UTF8String); resolver = std::make_unique(library); } else if (const char* libraryError = dlerror()) { - //WTF::dataLogF("NativeScript could not load library %s, error: %s\n", libraryPath.UTF8String, libraryError); + NSLog(@"NativeScript could not load library %s, error: %s\n", libraryPath.UTF8String, libraryError); } } } diff --git a/NativeScript/runtime/TNSDerivedClass.h b/NativeScript/runtime/TNSDerivedClass.h new file mode 100644 index 00000000..9b8f5b33 --- /dev/null +++ b/NativeScript/runtime/TNSDerivedClass.h @@ -0,0 +1,8 @@ +#ifndef TNSDerivedClass_h +#define TNSDerivedClass_h + +@protocol TNSDerivedClass + +@end + +#endif /* TNSDerivedClass_h */ diff --git a/v8ios.xcodeproj/project.pbxproj b/v8ios.xcodeproj/project.pbxproj index 5f923b47..d48595f2 100644 --- a/v8ios.xcodeproj/project.pbxproj +++ b/v8ios.xcodeproj/project.pbxproj @@ -395,7 +395,7 @@ C2DDEB9D229EAC8300345BFE /* SetTimeout.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB74229EAC8200345BFE /* SetTimeout.h */; }; C2DDEB9E229EAC8300345BFE /* SymbolLoader.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2DDEB75229EAC8200345BFE /* SymbolLoader.mm */; }; C2DDEB9F229EAC8300345BFE /* Tasks.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB76229EAC8200345BFE /* Tasks.h */; }; - C2DDEBA0229EAC8300345BFE /* Interop.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2DDEB77229EAC8200345BFE /* Interop.mm */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C2DDEBA0229EAC8300345BFE /* Interop.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2DDEB77229EAC8200345BFE /* Interop.mm */; }; C2DDEBA1229EAC8300345BFE /* FFICall.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB78229EAC8200345BFE /* FFICall.h */; }; C2DDEBA2229EAC8300345BFE /* Console.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB79229EAC8200345BFE /* Console.h */; }; C2DDEBA3229EAC8300345BFE /* ArrayAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2DDEB7A229EAC8200345BFE /* ArrayAdapter.mm */; }; @@ -409,7 +409,7 @@ C2DDEBAC229EAC8300345BFE /* ObjectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB83229EAC8300345BFE /* ObjectManager.h */; }; C2DDEBAD229EAC8300345BFE /* Caches.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB84229EAC8300345BFE /* Caches.h */; }; C2DDEBAE229EAC8300345BFE /* DictionaryAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB85229EAC8300345BFE /* DictionaryAdapter.h */; }; - C2DDEBAF229EAC8300345BFE /* ObjectManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2DDEB86229EAC8300345BFE /* ObjectManager.mm */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C2DDEBAF229EAC8300345BFE /* ObjectManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2DDEB86229EAC8300345BFE /* ObjectManager.mm */; }; C2DDEBB0229EAC8300345BFE /* StringHasher.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB87229EAC8300345BFE /* StringHasher.h */; }; C2DDEBB1229EAC8300345BFE /* Caches.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2DDEB88229EAC8300345BFE /* Caches.cpp */; }; C2DDEBB2229EAC8300345BFE /* ModuleInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DDEB89229EAC8300345BFE /* ModuleInternal.h */; }; @@ -529,6 +529,7 @@ /* Begin PBXFileReference section */ 2B7EA6AD2353476F00E5184E /* NativeScriptException.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NativeScriptException.mm; sourceTree = ""; }; 2B7EA6AE2353477000E5184E /* NativeScriptException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeScriptException.h; sourceTree = ""; }; + C2003F9E23FA78CD0043B815 /* TNSDerivedClass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TNSDerivedClass.h; sourceTree = ""; }; C2229971235449B300C1DFD6 /* InspectorServer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorServer.mm; sourceTree = ""; }; C2229972235449B400C1DFD6 /* InspectorServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorServer.h; sourceTree = ""; }; C2229975235492EC00C1DFD6 /* v8-ns-debugger-agent-impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "v8-ns-debugger-agent-impl.h"; sourceTree = ""; }; @@ -1864,6 +1865,7 @@ C2DDEB75229EAC8200345BFE /* SymbolLoader.mm */, C2DDEB76229EAC8200345BFE /* Tasks.h */, C2DDEB8C229EAC8300345BFE /* Tasks.cpp */, + C2003F9E23FA78CD0043B815 /* TNSDerivedClass.h */, C298C026233C9AEA000DDF54 /* TSHelpers.h */, C298C025233C9AEA000DDF54 /* TSHelpers.cpp */, C2DDEB82229EAC8200345BFE /* WeakRef.h */, @@ -3064,7 +3066,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++17"; - CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_ARC = NO; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = NO; DYLIB_COMPATIBILITY_VERSION = 1; @@ -3131,7 +3133,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++17"; - CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_ARC = NO; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = NO; DYLIB_COMPATIBILITY_VERSION = 1;