Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions NativeScript/runtime/ArgConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class ArgConverter {
public:
static void Init(v8::Local<v8::Context> context, v8::GenericNamedPropertyGetterCallback structPropertyGetter, v8::GenericNamedPropertySetterCallback structPropertySetter);
static v8::Local<v8::Value> Invoke(v8::Local<v8::Context> context, Class klass, v8::Local<v8::Object> receiver, V8Args& args, const MethodMeta* meta, bool isMethodCallback);
static v8::Local<v8::Value> ConvertArgument(v8::Local<v8::Context> context, BaseDataWrapper* wrapper, bool skipGCRegistration = false);
static v8::Local<v8::Value> CreateJsWrapper(v8::Local<v8::Context> context, BaseDataWrapper* wrapper, v8::Local<v8::Object> receiver, bool skipGCRegistration = false);
static v8::Local<v8::Value> ConvertArgument(v8::Local<v8::Context> context, BaseDataWrapper* wrapper, bool skipGCRegistration = false, const std::vector<std::string>& additionalProtocols = std::vector<std::string>());
static v8::Local<v8::Value> CreateJsWrapper(v8::Local<v8::Context> context, BaseDataWrapper* wrapper, v8::Local<v8::Object> receiver, bool skipGCRegistration = false, const std::vector<std::string>& additionalProtocols = std::vector<std::string>());
static std::shared_ptr<v8::Persistent<v8::Value>> CreateEmptyObject(v8::Local<v8::Context> context, bool skipGCRegistration = false);
static std::shared_ptr<v8::Persistent<v8::Value>> CreateEmptyStruct(v8::Local<v8::Context> context);
static const Meta* FindMeta(Class klass, const TypeEncoding* typeEncoding = nullptr);
Expand Down
29 changes: 17 additions & 12 deletions NativeScript/runtime/ArgConverter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@
return Interop::CallFunction(methodCall);
}

Local<Value> ArgConverter::ConvertArgument(Local<Context> context, BaseDataWrapper* wrapper, bool skipGCRegistration) {
Local<Value> ArgConverter::ConvertArgument(Local<Context> context, BaseDataWrapper* wrapper, bool skipGCRegistration, const std::vector<std::string>& additionalProtocols) {
Isolate* isolate = context->GetIsolate();
if (wrapper == nullptr) {
return Null(isolate);
}

Local<Value> result = CreateJsWrapper(context, wrapper, Local<Object>(), skipGCRegistration);
Local<Value> result = CreateJsWrapper(context, wrapper, Local<Object>(), skipGCRegistration, additionalProtocols);
return result;
}

Expand Down Expand Up @@ -526,7 +526,7 @@
return args;
}

Local<Value> ArgConverter::CreateJsWrapper(Local<Context> context, BaseDataWrapper* wrapper, Local<Object> receiver, bool skipGCRegistration) {
Local<Value> ArgConverter::CreateJsWrapper(Local<Context> context, BaseDataWrapper* wrapper, Local<Object> receiver, bool skipGCRegistration, const std::vector<std::string>& additionalProtocols) {
Isolate* isolate = context->GetIsolate();

if (wrapper == nullptr) {
Expand Down Expand Up @@ -567,7 +567,8 @@
if (meta != nullptr) {
auto cache = Caches::Get(isolate);
KnownUnknownClassPair pair(objc_getClass(meta->name()));
cache->ObjectCtorInitializer(context, static_cast<const BaseClassMeta*>(meta), pair);
std::vector<std::string> emptyProtocols;
cache->ObjectCtorInitializer(context, static_cast<const BaseClassMeta*>(meta), pair, emptyProtocols);
auto it = cache->Prototypes.find(meta);
if (it != cache->Prototypes.end()) {
Local<Value> prototype = it->second->Get(isolate);
Expand Down Expand Up @@ -625,14 +626,18 @@
} else {
Class knownClass = objc_getClass(meta->name());
KnownUnknownClassPair pair(knownClass, klass);
cache->ObjectCtorInitializer(context, static_cast<const BaseClassMeta*>(meta), pair);
auto it = cache->Prototypes.find(meta);
if (it != cache->Prototypes.end()) {
Local<Value> prototype = it->second->Get(isolate);
bool success;
if (!receiver->SetPrototype(context, prototype).To(&success) || !success) {
tns::Assert(false, isolate);
}
Local<FunctionTemplate> ctorFuncTemplate = cache->ObjectCtorInitializer(context, static_cast<const BaseClassMeta*>(meta), pair, additionalProtocols);
Local<v8::Function> ctorFunc;
bool success = ctorFuncTemplate->GetFunction(context).ToLocal(&ctorFunc);
tns::Assert(success, isolate);

Local<Value> prototypeValue;
success = ctorFunc->Get(context, tns::ToV8String(isolate, "prototype")).ToLocal(&prototypeValue);
tns::Assert(success, isolate);
Local<Object> prototype = prototypeValue.As<Object>();

if (!receiver->SetPrototype(context, prototype).To(&success) || !success) {
tns::Assert(false, isolate);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion NativeScript/runtime/Caches.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define Caches_h

#include <string>
#include <vector>
#include "ConcurrentMap.h"
#include "robin_hood.h"
#include "Common.h"
Expand Down Expand Up @@ -70,7 +71,7 @@ class Caches {
robin_hood::unordered_map<std::pair<void*, std::string>, std::shared_ptr<v8::Persistent<v8::Value>>, pair_hash> StructInstances;
robin_hood::unordered_map<const void*, std::shared_ptr<v8::Persistent<v8::Object>>> PointerInstances;

std::function<v8::Local<v8::FunctionTemplate>(v8::Local<v8::Context>, const BaseClassMeta*, KnownUnknownClassPair)> ObjectCtorInitializer;
std::function<v8::Local<v8::FunctionTemplate>(v8::Local<v8::Context>, const BaseClassMeta*, KnownUnknownClassPair, const std::vector<std::string>&)> ObjectCtorInitializer;
std::function<v8::Local<v8::Function>(v8::Local<v8::Context>, StructInfo)> StructCtorInitializer;
robin_hood::unordered_map<std::string, double> Timers;
robin_hood::unordered_map<const InterfaceMeta*, std::vector<const MethodMeta*>> Initializers;
Expand Down
2 changes: 1 addition & 1 deletion NativeScript/runtime/Interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class Interop {
static v8::Local<v8::Value> CallFunctionInternal(MethodCall& methodCall);
static bool IsNumbericType(BinaryTypeEncodingType type);
static v8::Local<v8::Object> GetInteropType(v8::Local<v8::Context> context, BinaryTypeEncodingType type);
static void AttachProtocols(v8::Local<v8::Context> context, v8::Local<v8::Object> instance, PtrTo<Array<PtrTo<char>>> protocols, KnownUnknownClassPair pair);
static std::vector<std::string> GetAdditionalProtocols(const TypeEncoding* typeEncoding);

template <typename T>
static inline void SetValue(void* dest, T value) {
Expand Down
59 changes: 20 additions & 39 deletions NativeScript/runtime/Interop.mm
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,8 @@

auto cache = Caches::Get(isolate);
KnownUnknownClassPair pair;
cache->ObjectCtorInitializer(context, protocolMeta, pair);
std::vector<std::string> emptyProtocols;
cache->ObjectCtorInitializer(context, protocolMeta, pair, emptyProtocols);

auto it = cache->ProtocolCtorFuncs.find(protocolMeta->name());
if (it != cache->ProtocolCtorFuncs.end()) {
Expand All @@ -817,7 +818,8 @@
const BaseClassMeta* baseMeta = static_cast<const BaseClassMeta*>(meta);
Class knownClass = meta->type() == MetaType::Interface ? objc_getClass(meta->name()) : nil;
KnownUnknownClassPair pair(knownClass);
cache->ObjectCtorInitializer(context, baseMeta, pair);
std::vector<std::string> emptyProtocols;
cache->ObjectCtorInitializer(context, baseMeta, pair, emptyProtocols);
}

auto it = cache->CtorFuncs.find(name);
Expand Down Expand Up @@ -1024,23 +1026,8 @@
const TypeEncoding* te = [result isProxy] ? typeEncoding : nullptr;

ObjCDataWrapper* wrapper = new ObjCDataWrapper(result, te);
Local<Value> jsResult = ArgConverter::ConvertArgument(context, wrapper);

PtrTo<Array<PtrTo<char>>> additionalProtocols;
int32_t count = 0;
if (typeEncoding->type == BinaryTypeEncodingType::IdEncoding && typeEncoding->details.idDetails._protocols.offset > 0) {
additionalProtocols = typeEncoding->details.idDetails._protocols;
count = additionalProtocols->count;
} else if (typeEncoding->type == BinaryTypeEncodingType::InterfaceDeclarationReference && typeEncoding->details.interfaceDeclarationReference._protocols.offset > 0) {
additionalProtocols = typeEncoding->details.interfaceDeclarationReference._protocols;
count = additionalProtocols->count;
}

if (count > 0) {
// Attach the protocols to the prototype of the resulting object
KnownUnknownClassPair pair(nullptr, [result class]);
Interop::AttachProtocols(context, jsResult.As<Object>(), additionalProtocols, pair);
}
std::vector<std::string> additionalProtocols = Interop::GetAdditionalProtocols(typeEncoding);
Local<Value> jsResult = ArgConverter::ConvertArgument(context, wrapper, false, additionalProtocols);

if (ownsReturnedObject || isInitializer) {
[result release];
Expand Down Expand Up @@ -1167,30 +1154,24 @@
return Local<Value>();
}

void Interop::AttachProtocols(Local<Context> context, Local<Object> instance, PtrTo<Array<PtrTo<char>>> protocols, KnownUnknownClassPair pair) {
Isolate* isolate = context->GetIsolate();
std::shared_ptr<Caches> cache = Caches::Get(isolate);
std::vector<std::string> Interop::GetAdditionalProtocols(const TypeEncoding* typeEncoding) {
std::vector<std::string> additionalProtocols;

Local<Object> prototype = instance->GetPrototype().As<Object>();
for (auto it = protocols->begin(); it != protocols->end(); it++) {
const char* protocolName = (*it).valuePtr();
const Meta* protocolMeta = ArgConverter::GetMeta(protocolName);
if (protocolMeta == nullptr) {
continue;
if (typeEncoding->type == BinaryTypeEncodingType::IdEncoding && typeEncoding->details.idDetails._protocols.offset > 0) {
PtrTo<Array<String>> protocols = typeEncoding->details.idDetails._protocols;
for (auto it = protocols->begin(); it != protocols->end(); it++) {
const char* protocolName = (*it).valuePtr();
additionalProtocols.push_back(protocolName);
}

cache->ObjectCtorInitializer(context, static_cast<const BaseClassMeta*>(protocolMeta), pair);
auto protoIt = cache->Prototypes.find(protocolMeta);
if (protoIt == cache->Prototypes.end()) {
continue;
} else if (typeEncoding->type == BinaryTypeEncodingType::InterfaceDeclarationReference && typeEncoding->details.interfaceDeclarationReference._protocols.offset > 0) {
PtrTo<Array<String>> protocols = typeEncoding->details.interfaceDeclarationReference._protocols;
for (auto it = protocols->begin(); it != protocols->end(); it++) {
const char* protocolName = (*it).valuePtr();
additionalProtocols.push_back(protocolName);
}

Local<Object> protocolPrototype = protoIt->second->Get(isolate).As<Object>();

prototype->SetPrototype(context, protocolPrototype).FromMaybe(false);

prototype = protocolPrototype;
}

return additionalProtocols;
}

bool Interop::IsNumbericType(BinaryTypeEncodingType type) {
Expand Down
5 changes: 3 additions & 2 deletions NativeScript/runtime/MetadataBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ namespace tns {
class MetadataBuilder {
public:
static void RegisterConstantsOnGlobalObject(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> globalTemplate, bool isWorkerThread);
static v8::Local<v8::FunctionTemplate> GetOrCreateConstructorFunctionTemplate(v8::Local<v8::Context> context, const BaseClassMeta* meta, KnownUnknownClassPair pair);
static v8::Local<v8::FunctionTemplate> GetOrCreateConstructorFunctionTemplate(v8::Local<v8::Context> context, const BaseClassMeta* meta, KnownUnknownClassPair pair, const std::vector<std::string>& additionalProtocols = std::vector<std::string>());
static v8::Local<v8::Function> GetOrCreateStructCtorFunction(v8::Local<v8::Context> context, StructInfo structInfo);
static void StructPropertyGetterCallback(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& info);
static void StructPropertySetterCallback(v8::Local<v8::Name> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info);
private:
static v8::Local<v8::FunctionTemplate> GetOrCreateConstructorFunctionTemplateInternal(v8::Local<v8::Context> context, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& instanceMembers, robin_hood::unordered_map<std::string, uint8_t>& staticMembers);
static v8::Local<v8::FunctionTemplate> GetOrCreateConstructorFunctionTemplateInternal(v8::Local<v8::Context> context, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& instanceMembers, robin_hood::unordered_map<std::string, uint8_t>& staticMembers, const std::vector<std::string>& additionalProtocols = std::vector<std::string>());
static void GlobalPropertyGetter(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& info);
static void ClassConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
static void AllocCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
Expand All @@ -38,6 +38,7 @@ class MetadataBuilder {
static void RegisterInstanceMethods(v8::Local<v8::Context> context, v8::Local<v8::FunctionTemplate> ctorFuncTemplate, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& names);
static void RegisterInstanceProperties(v8::Local<v8::Context> context, v8::Local<v8::FunctionTemplate> ctorFuncTemplate, const BaseClassMeta* meta, std::string className, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& names);
static void RegisterInstanceProtocols(v8::Local<v8::Context> context, v8::Local<v8::FunctionTemplate> ctorFuncTemplate, const BaseClassMeta* meta, std::string className, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& names);
static void RegisterAdditionalProtocols(v8::Local<v8::Context> context, v8::Local<v8::FunctionTemplate> ctorFuncTemplate, KnownUnknownClassPair pair, const std::vector<std::string>& additionalProtocols, robin_hood::unordered_map<std::string, uint8_t>& names);
static void RegisterStaticMethods(v8::Local<v8::Context> context, v8::Local<v8::Function> ctorFunc, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& names);
static void RegisterStaticProperties(v8::Local<v8::Context> context, v8::Local<v8::Function> ctorFunc, const BaseClassMeta* meta, const std::string className, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& names);
static void RegisterStaticProtocols(v8::Local<v8::Context> context, v8::Local<v8::Function> ctorFunc, const BaseClassMeta* meta, const std::string className, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& names);
Expand Down
37 changes: 30 additions & 7 deletions NativeScript/runtime/MetadataBuilder.mm
Original file line number Diff line number Diff line change
Expand Up @@ -265,20 +265,23 @@
return std::make_pair(ffiType, data);
}

Local<FunctionTemplate> MetadataBuilder::GetOrCreateConstructorFunctionTemplate(Local<Context> context, const BaseClassMeta* meta, KnownUnknownClassPair pair) {
Local<FunctionTemplate> MetadataBuilder::GetOrCreateConstructorFunctionTemplate(Local<Context> context, const BaseClassMeta* meta, KnownUnknownClassPair pair, const std::vector<std::string>& additionalProtocols) {
robin_hood::unordered_map<std::string, uint8_t> instanceMembers;
robin_hood::unordered_map<std::string, uint8_t> staticMembers;
return MetadataBuilder::GetOrCreateConstructorFunctionTemplateInternal(context, meta, pair, instanceMembers, staticMembers);
return MetadataBuilder::GetOrCreateConstructorFunctionTemplateInternal(context, meta, pair, instanceMembers, staticMembers, additionalProtocols);
}

Local<FunctionTemplate> MetadataBuilder::GetOrCreateConstructorFunctionTemplateInternal(Local<Context> context, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& instanceMembers, robin_hood::unordered_map<std::string, uint8_t>& staticMembers) {
Local<FunctionTemplate> MetadataBuilder::GetOrCreateConstructorFunctionTemplateInternal(Local<Context> context, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& instanceMembers, robin_hood::unordered_map<std::string, uint8_t>& staticMembers, const std::vector<std::string>& additionalProtocols) {
Isolate* isolate = context->GetIsolate();
Local<FunctionTemplate> ctorFuncTemplate;
auto cache = Caches::Get(isolate);
auto it = cache->CtorFuncTemplates.find(meta);
if (it != cache->CtorFuncTemplates.end()) {
ctorFuncTemplate = it->second->Get(isolate);
return ctorFuncTemplate;

if (additionalProtocols.empty()) {
auto it = cache->CtorFuncTemplates.find(meta);
if (it != cache->CtorFuncTemplates.end()) {
ctorFuncTemplate = it->second->Get(isolate);
return ctorFuncTemplate;
}
}

std::string className;
Expand Down Expand Up @@ -325,6 +328,7 @@
MetadataBuilder::RegisterInstanceProperties(context, ctorFuncTemplate, meta, meta->name(), pair, instanceMembers);
MetadataBuilder::RegisterInstanceMethods(context, ctorFuncTemplate, meta, pair, instanceMembers);
MetadataBuilder::RegisterInstanceProtocols(context, ctorFuncTemplate, meta, meta->name(), pair, instanceMembers);
MetadataBuilder::RegisterAdditionalProtocols(context, ctorFuncTemplate, pair, additionalProtocols, instanceMembers);

ctorFuncTemplate->PrototypeTemplate()->Set(tns::ToV8String(isolate, "toString"), FunctionTemplate::New(isolate, MetadataBuilder::ToStringFunctionCallback));

Expand Down Expand Up @@ -482,6 +486,25 @@
}
}

void MetadataBuilder::RegisterAdditionalProtocols(Local<Context> context, Local<FunctionTemplate> ctorFuncTemplate, KnownUnknownClassPair pair, const std::vector<std::string>& additionalProtocols, robin_hood::unordered_map<std::string, uint8_t>& names) {
for (std::string protocolName : additionalProtocols) {
const Meta* meta = ArgConverter::GetMeta(protocolName.c_str());
if (meta != nullptr) {
const BaseClassMeta* baseMeta = static_cast<const BaseClassMeta*>(meta);
MetadataBuilder::RegisterInstanceMethods(context, ctorFuncTemplate, baseMeta, pair, names);
MetadataBuilder::RegisterInstanceProperties(context, ctorFuncTemplate, baseMeta, baseMeta->name(), pair, names);

std::vector<std::string> metaProtocols;
for (auto it = baseMeta->protocols->begin(); it != baseMeta->protocols->end(); it++) {
std::string name = (*it).valuePtr();
metaProtocols.push_back(name);
}

MetadataBuilder::RegisterAdditionalProtocols(context, ctorFuncTemplate, pair, metaProtocols, names);
}
}
}

void MetadataBuilder::RegisterStaticMethods(Local<Context> context, Local<v8::Function> ctorFunc, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map<std::string, uint8_t>& names) {
Isolate* isolate = context->GetIsolate();
for (auto it = meta->staticMethods->begin(); it != meta->staticMethods->end(); it++) {
Expand Down
2 changes: 2 additions & 0 deletions TestFixtures/Api/TNSPseudoDataTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

@protocol Proto1

@property (nonatomic) NSString* propertyFromProto1;
-(void)methodFromProto1;

@end

@protocol Proto2

@property (nonatomic) NSString* propertyFromProto2;
-(void)methodFromProto2:(NSString*)param;

@end
Expand Down
7 changes: 7 additions & 0 deletions TestFixtures/Api/TNSPseudoDataTypes.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ -(void)method {

@implementation TNSPseudoDataTypeInternal

@synthesize propertyFromProto1;
@synthesize propertyFromProto2;

-(void)methodFromProto1 {
TNSLog(@"methodFromProto1 called");
}
Expand All @@ -33,11 +36,15 @@ @implementation TNSPseudoDataType

+(id<Proto1, Proto2>)getId {
TNSPseudoDataTypeInternal* internal = [[TNSPseudoDataTypeInternal alloc] init];
internal.propertyFromProto1 = @"property from proto1";
internal.propertyFromProto2 = @"property from proto2";
return internal;
}

+(TNSType<Proto1, Proto2>*)getType {
TNSPseudoDataTypeInternal* internal = [[TNSPseudoDataTypeInternal alloc] init];
internal.propertyFromProto1 = @"property from proto1";
internal.propertyFromProto2 = @"property from proto2";
return internal;
}

Expand Down
Loading