From f4b0b43bf97cb7894744db0f23db48860f527772 Mon Sep 17 00:00:00 2001 From: Darin Dimitrov Date: Fri, 16 Oct 2020 10:34:19 +0300 Subject: [PATCH 1/2] fix: Do not update in-place object prototypes (#67) --- NativeScript/runtime/ArgConverter.h | 4 +- NativeScript/runtime/ArgConverter.mm | 11 ++--- NativeScript/runtime/Caches.h | 3 +- NativeScript/runtime/Interop.h | 2 +- NativeScript/runtime/Interop.mm | 59 +++++++++---------------- NativeScript/runtime/MetadataBuilder.h | 5 ++- NativeScript/runtime/MetadataBuilder.mm | 29 +++++++++--- TestFixtures/Api/TNSPseudoDataTypes.h | 2 + TestFixtures/Api/TNSPseudoDataTypes.m | 7 +++ TestRunner/app/tests/ApiTests.js | 14 +++++- 10 files changed, 78 insertions(+), 58 deletions(-) diff --git a/NativeScript/runtime/ArgConverter.h b/NativeScript/runtime/ArgConverter.h index 9fb20046..427794a1 100644 --- a/NativeScript/runtime/ArgConverter.h +++ b/NativeScript/runtime/ArgConverter.h @@ -31,8 +31,8 @@ class ArgConverter { public: static void Init(v8::Local context, v8::GenericNamedPropertyGetterCallback structPropertyGetter, v8::GenericNamedPropertySetterCallback structPropertySetter); static v8::Local Invoke(v8::Local context, Class klass, v8::Local receiver, V8Args& args, const MethodMeta* meta, bool isMethodCallback); - static v8::Local ConvertArgument(v8::Local context, BaseDataWrapper* wrapper, bool skipGCRegistration = false); - static v8::Local CreateJsWrapper(v8::Local context, BaseDataWrapper* wrapper, v8::Local receiver, bool skipGCRegistration = false); + static v8::Local ConvertArgument(v8::Local context, BaseDataWrapper* wrapper, bool skipGCRegistration = false, const std::vector& additionalProtocols = std::vector()); + static v8::Local CreateJsWrapper(v8::Local context, BaseDataWrapper* wrapper, v8::Local receiver, bool skipGCRegistration = false, const std::vector& additionalProtocols = std::vector()); static std::shared_ptr> CreateEmptyObject(v8::Local context, bool skipGCRegistration = false); static std::shared_ptr> CreateEmptyStruct(v8::Local context); static const Meta* FindMeta(Class klass, const TypeEncoding* typeEncoding = nullptr); diff --git a/NativeScript/runtime/ArgConverter.mm b/NativeScript/runtime/ArgConverter.mm index cf3f971f..875a2682 100644 --- a/NativeScript/runtime/ArgConverter.mm +++ b/NativeScript/runtime/ArgConverter.mm @@ -78,13 +78,13 @@ return Interop::CallFunction(methodCall); } -Local ArgConverter::ConvertArgument(Local context, BaseDataWrapper* wrapper, bool skipGCRegistration) { +Local ArgConverter::ConvertArgument(Local context, BaseDataWrapper* wrapper, bool skipGCRegistration, const std::vector& additionalProtocols) { Isolate* isolate = context->GetIsolate(); if (wrapper == nullptr) { return Null(isolate); } - Local result = CreateJsWrapper(context, wrapper, Local(), skipGCRegistration); + Local result = CreateJsWrapper(context, wrapper, Local(), skipGCRegistration, additionalProtocols); return result; } @@ -526,7 +526,7 @@ return args; } -Local ArgConverter::CreateJsWrapper(Local context, BaseDataWrapper* wrapper, Local receiver, bool skipGCRegistration) { +Local ArgConverter::CreateJsWrapper(Local context, BaseDataWrapper* wrapper, Local receiver, bool skipGCRegistration, const std::vector& additionalProtocols) { Isolate* isolate = context->GetIsolate(); if (wrapper == nullptr) { @@ -567,7 +567,8 @@ if (meta != nullptr) { auto cache = Caches::Get(isolate); KnownUnknownClassPair pair(objc_getClass(meta->name())); - cache->ObjectCtorInitializer(context, static_cast(meta), pair); + std::vector emptyProtocols; + cache->ObjectCtorInitializer(context, static_cast(meta), pair, emptyProtocols); auto it = cache->Prototypes.find(meta); if (it != cache->Prototypes.end()) { Local prototype = it->second->Get(isolate); @@ -625,7 +626,7 @@ } else { Class knownClass = objc_getClass(meta->name()); KnownUnknownClassPair pair(knownClass, klass); - cache->ObjectCtorInitializer(context, static_cast(meta), pair); + cache->ObjectCtorInitializer(context, static_cast(meta), pair, additionalProtocols); auto it = cache->Prototypes.find(meta); if (it != cache->Prototypes.end()) { Local prototype = it->second->Get(isolate); diff --git a/NativeScript/runtime/Caches.h b/NativeScript/runtime/Caches.h index 234aff4e..77de8715 100644 --- a/NativeScript/runtime/Caches.h +++ b/NativeScript/runtime/Caches.h @@ -2,6 +2,7 @@ #define Caches_h #include +#include #include "ConcurrentMap.h" #include "robin_hood.h" #include "Common.h" @@ -70,7 +71,7 @@ class Caches { robin_hood::unordered_map, std::shared_ptr>, pair_hash> StructInstances; robin_hood::unordered_map>> PointerInstances; - std::function(v8::Local, const BaseClassMeta*, KnownUnknownClassPair)> ObjectCtorInitializer; + std::function(v8::Local, const BaseClassMeta*, KnownUnknownClassPair, const std::vector&)> ObjectCtorInitializer; std::function(v8::Local, StructInfo)> StructCtorInitializer; robin_hood::unordered_map Timers; robin_hood::unordered_map> Initializers; diff --git a/NativeScript/runtime/Interop.h b/NativeScript/runtime/Interop.h index 5ad791cc..8f764070 100644 --- a/NativeScript/runtime/Interop.h +++ b/NativeScript/runtime/Interop.h @@ -139,7 +139,7 @@ class Interop { static v8::Local CallFunctionInternal(MethodCall& methodCall); static bool IsNumbericType(BinaryTypeEncodingType type); static v8::Local GetInteropType(v8::Local context, BinaryTypeEncodingType type); - static void AttachProtocols(v8::Local context, v8::Local instance, PtrTo>> protocols, KnownUnknownClassPair pair); + static std::vector GetAdditionalProtocols(const TypeEncoding* typeEncoding); template static inline void SetValue(void* dest, T value) { diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index e704a42f..b18c40d8 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -792,7 +792,8 @@ auto cache = Caches::Get(isolate); KnownUnknownClassPair pair; - cache->ObjectCtorInitializer(context, protocolMeta, pair); + std::vector emptyProtocols; + cache->ObjectCtorInitializer(context, protocolMeta, pair, emptyProtocols); auto it = cache->ProtocolCtorFuncs.find(protocolMeta->name()); if (it != cache->ProtocolCtorFuncs.end()) { @@ -817,7 +818,8 @@ const BaseClassMeta* baseMeta = static_cast(meta); Class knownClass = meta->type() == MetaType::Interface ? objc_getClass(meta->name()) : nil; KnownUnknownClassPair pair(knownClass); - cache->ObjectCtorInitializer(context, baseMeta, pair); + std::vector emptyProtocols; + cache->ObjectCtorInitializer(context, baseMeta, pair, emptyProtocols); } auto it = cache->CtorFuncs.find(name); @@ -1024,23 +1026,8 @@ const TypeEncoding* te = [result isProxy] ? typeEncoding : nullptr; ObjCDataWrapper* wrapper = new ObjCDataWrapper(result, te); - Local jsResult = ArgConverter::ConvertArgument(context, wrapper); - - PtrTo>> 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(), additionalProtocols, pair); - } + std::vector additionalProtocols = Interop::GetAdditionalProtocols(typeEncoding); + Local jsResult = ArgConverter::ConvertArgument(context, wrapper, false, additionalProtocols); if (ownsReturnedObject || isInitializer) { [result release]; @@ -1167,30 +1154,24 @@ return Local(); } -void Interop::AttachProtocols(Local context, Local instance, PtrTo>> protocols, KnownUnknownClassPair pair) { - Isolate* isolate = context->GetIsolate(); - std::shared_ptr cache = Caches::Get(isolate); +std::vector Interop::GetAdditionalProtocols(const TypeEncoding* typeEncoding) { + std::vector additionalProtocols; - Local prototype = instance->GetPrototype().As(); - 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> 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(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> protocols = typeEncoding->details.interfaceDeclarationReference._protocols; + for (auto it = protocols->begin(); it != protocols->end(); it++) { + const char* protocolName = (*it).valuePtr(); + additionalProtocols.push_back(protocolName); } - - Local protocolPrototype = protoIt->second->Get(isolate).As(); - - prototype->SetPrototype(context, protocolPrototype).FromMaybe(false); - - prototype = protocolPrototype; } + + return additionalProtocols; } bool Interop::IsNumbericType(BinaryTypeEncodingType type) { diff --git a/NativeScript/runtime/MetadataBuilder.h b/NativeScript/runtime/MetadataBuilder.h index 4aad2d0e..8c0470f9 100644 --- a/NativeScript/runtime/MetadataBuilder.h +++ b/NativeScript/runtime/MetadataBuilder.h @@ -13,12 +13,12 @@ namespace tns { class MetadataBuilder { public: static void RegisterConstantsOnGlobalObject(v8::Isolate* isolate, v8::Local globalTemplate, bool isWorkerThread); - static v8::Local GetOrCreateConstructorFunctionTemplate(v8::Local context, const BaseClassMeta* meta, KnownUnknownClassPair pair); + static v8::Local GetOrCreateConstructorFunctionTemplate(v8::Local context, const BaseClassMeta* meta, KnownUnknownClassPair pair, const std::vector& additionalProtocols = std::vector()); static v8::Local GetOrCreateStructCtorFunction(v8::Local context, StructInfo structInfo); static void StructPropertyGetterCallback(v8::Local property, const v8::PropertyCallbackInfo& info); static void StructPropertySetterCallback(v8::Local property, v8::Local value, const v8::PropertyCallbackInfo& info); private: - static v8::Local GetOrCreateConstructorFunctionTemplateInternal(v8::Local context, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map& instanceMembers, robin_hood::unordered_map& staticMembers); + static v8::Local GetOrCreateConstructorFunctionTemplateInternal(v8::Local context, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map& instanceMembers, robin_hood::unordered_map& staticMembers, const std::vector& additionalProtocols = std::vector()); static void GlobalPropertyGetter(v8::Local property, const v8::PropertyCallbackInfo& info); static void ClassConstructorCallback(const v8::FunctionCallbackInfo& info); static void AllocCallback(const v8::FunctionCallbackInfo& info); @@ -38,6 +38,7 @@ class MetadataBuilder { static void RegisterInstanceMethods(v8::Local context, v8::Local ctorFuncTemplate, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map& names); static void RegisterInstanceProperties(v8::Local context, v8::Local ctorFuncTemplate, const BaseClassMeta* meta, std::string className, KnownUnknownClassPair pair, robin_hood::unordered_map& names); static void RegisterInstanceProtocols(v8::Local context, v8::Local ctorFuncTemplate, const BaseClassMeta* meta, std::string className, KnownUnknownClassPair pair, robin_hood::unordered_map& names); + static void RegisterAdditionalProtocols(v8::Local context, v8::Local ctorFuncTemplate, KnownUnknownClassPair pair, const std::vector& additionalProtocols, robin_hood::unordered_map& names); static void RegisterStaticMethods(v8::Local context, v8::Local ctorFunc, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map& names); static void RegisterStaticProperties(v8::Local context, v8::Local ctorFunc, const BaseClassMeta* meta, const std::string className, KnownUnknownClassPair pair, robin_hood::unordered_map& names); static void RegisterStaticProtocols(v8::Local context, v8::Local ctorFunc, const BaseClassMeta* meta, const std::string className, KnownUnknownClassPair pair, robin_hood::unordered_map& names); diff --git a/NativeScript/runtime/MetadataBuilder.mm b/NativeScript/runtime/MetadataBuilder.mm index e72b2f84..b902920d 100644 --- a/NativeScript/runtime/MetadataBuilder.mm +++ b/NativeScript/runtime/MetadataBuilder.mm @@ -265,20 +265,23 @@ return std::make_pair(ffiType, data); } -Local MetadataBuilder::GetOrCreateConstructorFunctionTemplate(Local context, const BaseClassMeta* meta, KnownUnknownClassPair pair) { +Local MetadataBuilder::GetOrCreateConstructorFunctionTemplate(Local context, const BaseClassMeta* meta, KnownUnknownClassPair pair, const std::vector& additionalProtocols) { robin_hood::unordered_map instanceMembers; robin_hood::unordered_map staticMembers; - return MetadataBuilder::GetOrCreateConstructorFunctionTemplateInternal(context, meta, pair, instanceMembers, staticMembers); + return MetadataBuilder::GetOrCreateConstructorFunctionTemplateInternal(context, meta, pair, instanceMembers, staticMembers, additionalProtocols); } -Local MetadataBuilder::GetOrCreateConstructorFunctionTemplateInternal(Local context, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map& instanceMembers, robin_hood::unordered_map& staticMembers) { +Local MetadataBuilder::GetOrCreateConstructorFunctionTemplateInternal(Local context, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map& instanceMembers, robin_hood::unordered_map& staticMembers, const std::vector& additionalProtocols) { Isolate* isolate = context->GetIsolate(); Local 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; @@ -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)); @@ -482,6 +486,17 @@ } } +void MetadataBuilder::RegisterAdditionalProtocols(Local context, Local ctorFuncTemplate, KnownUnknownClassPair pair, const std::vector& additionalProtocols, robin_hood::unordered_map& names) { + for (std::string protocolName : additionalProtocols) { + const Meta* meta = ArgConverter::GetMeta(protocolName.c_str()); + if (meta != nullptr) { + const BaseClassMeta* baseMeta = static_cast(meta); + MetadataBuilder::RegisterInstanceMethods(context, ctorFuncTemplate, baseMeta, pair, names); + MetadataBuilder::RegisterInstanceProperties(context, ctorFuncTemplate, baseMeta, baseMeta->name(), pair, names); + } + } +} + void MetadataBuilder::RegisterStaticMethods(Local context, Local ctorFunc, const BaseClassMeta* meta, KnownUnknownClassPair pair, robin_hood::unordered_map& names) { Isolate* isolate = context->GetIsolate(); for (auto it = meta->staticMethods->begin(); it != meta->staticMethods->end(); it++) { diff --git a/TestFixtures/Api/TNSPseudoDataTypes.h b/TestFixtures/Api/TNSPseudoDataTypes.h index 83ad81a1..b275ec44 100644 --- a/TestFixtures/Api/TNSPseudoDataTypes.h +++ b/TestFixtures/Api/TNSPseudoDataTypes.h @@ -2,12 +2,14 @@ @protocol Proto1 +@property (nonatomic) NSString* propertyFromProto1; -(void)methodFromProto1; @end @protocol Proto2 +@property (nonatomic) NSString* propertyFromProto2; -(void)methodFromProto2:(NSString*)param; @end diff --git a/TestFixtures/Api/TNSPseudoDataTypes.m b/TestFixtures/Api/TNSPseudoDataTypes.m index e2cce838..e8c9dfd1 100644 --- a/TestFixtures/Api/TNSPseudoDataTypes.m +++ b/TestFixtures/Api/TNSPseudoDataTypes.m @@ -19,6 +19,9 @@ -(void)method { @implementation TNSPseudoDataTypeInternal +@synthesize propertyFromProto1; +@synthesize propertyFromProto2; + -(void)methodFromProto1 { TNSLog(@"methodFromProto1 called"); } @@ -33,11 +36,15 @@ @implementation TNSPseudoDataType +(id)getId { TNSPseudoDataTypeInternal* internal = [[TNSPseudoDataTypeInternal alloc] init]; + internal.propertyFromProto1 = @"property from proto1"; + internal.propertyFromProto2 = @"property from proto2"; return internal; } +(TNSType*)getType { TNSPseudoDataTypeInternal* internal = [[TNSPseudoDataTypeInternal alloc] init]; + internal.propertyFromProto1 = @"property from proto1"; + internal.propertyFromProto2 = @"property from proto2"; return internal; } diff --git a/TestRunner/app/tests/ApiTests.js b/TestRunner/app/tests/ApiTests.js index 8f5b9b64..b881ae7f 100644 --- a/TestRunner/app/tests/ApiTests.js +++ b/TestRunner/app/tests/ApiTests.js @@ -738,34 +738,46 @@ describe(module.id, function () { it("Additional protocols should be attached to the prototype of id pseudo-types", () => { let actual = TNSPseudoDataType.getId(); + expect(actual.propertyFromProto1).toBeDefined(); expect(actual.methodFromProto1).toBeDefined(); + expect(actual.propertyFromProto2).toBeDefined(); expect(actual.methodFromProto2).toBeDefined(); + expect(actual.propertyFromProto1).toBe("property from proto1"); actual.methodFromProto1(); + expect(actual.propertyFromProto2).toBe("property from proto2"); actual.methodFromProto2("test"); expect(TNSGetOutput()).toBe("methodFromProto1 calledmethodFromProto2 called with test"); let obj = NSObject.alloc().init(); + expect(obj.propertyFromProto1).toBeUndefined(); expect(obj.methodFromProto1).toBeUndefined(); + expect(obj.propertyFromProto2).toBeUndefined(); expect(obj.methodFromProto2).toBeUndefined(); }); it("Additional protocols should be attached to the prototype of interface pseudo-types", () => { let actual = TNSPseudoDataType.getType(); expect(actual.method).toBeDefined(); - expect(actual.methodFromProto2).toBeDefined(); + expect(actual.propertyFromProto1).toBeDefined(); + expect(actual.methodFromProto1).toBeDefined(); + expect(actual.propertyFromProto2).toBeDefined(); expect(actual.methodFromProto2).toBeDefined(); actual.method(); + expect(actual.propertyFromProto1).toBe("property from proto1"); actual.methodFromProto1(); + expect(actual.propertyFromProto2).toBe("property from proto2"); actual.methodFromProto2("test"); expect(TNSGetOutput()).toBe("method calledmethodFromProto1 calledmethodFromProto2 called with test"); let obj = NSObject.alloc().init(); expect(obj.method).toBeUndefined(); + expect(obj.propertyFromProto1).toBeUndefined(); expect(obj.methodFromProto1).toBeUndefined(); + expect(obj.propertyFromProto2).toBeUndefined(); expect(obj.methodFromProto2).toBeUndefined(); }); From 71ffa0d927302d4c19e459a0db1ccd35a0323364 Mon Sep 17 00:00:00 2001 From: Darin Dimitrov Date: Sat, 17 Oct 2020 14:34:56 +0300 Subject: [PATCH 2/2] fix: Load proper prototype when registering additional protocols --- NativeScript/runtime/ArgConverter.mm | 20 ++++++++++++-------- NativeScript/runtime/MetadataBuilder.mm | 8 ++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/NativeScript/runtime/ArgConverter.mm b/NativeScript/runtime/ArgConverter.mm index 875a2682..45dcd2ec 100644 --- a/NativeScript/runtime/ArgConverter.mm +++ b/NativeScript/runtime/ArgConverter.mm @@ -626,14 +626,18 @@ } else { Class knownClass = objc_getClass(meta->name()); KnownUnknownClassPair pair(knownClass, klass); - cache->ObjectCtorInitializer(context, static_cast(meta), pair, additionalProtocols); - 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); - } + Local ctorFuncTemplate = cache->ObjectCtorInitializer(context, static_cast(meta), pair, additionalProtocols); + Local ctorFunc; + bool success = ctorFuncTemplate->GetFunction(context).ToLocal(&ctorFunc); + tns::Assert(success, isolate); + + Local prototypeValue; + success = ctorFunc->Get(context, tns::ToV8String(isolate, "prototype")).ToLocal(&prototypeValue); + tns::Assert(success, isolate); + Local prototype = prototypeValue.As(); + + if (!receiver->SetPrototype(context, prototype).To(&success) || !success) { + tns::Assert(false, isolate); } } } diff --git a/NativeScript/runtime/MetadataBuilder.mm b/NativeScript/runtime/MetadataBuilder.mm index b902920d..157f099d 100644 --- a/NativeScript/runtime/MetadataBuilder.mm +++ b/NativeScript/runtime/MetadataBuilder.mm @@ -493,6 +493,14 @@ const BaseClassMeta* baseMeta = static_cast(meta); MetadataBuilder::RegisterInstanceMethods(context, ctorFuncTemplate, baseMeta, pair, names); MetadataBuilder::RegisterInstanceProperties(context, ctorFuncTemplate, baseMeta, baseMeta->name(), pair, names); + + std::vector 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); } } }