Skip to content

Commit 673ec7d

Browse files
committed
Marshalling function pointers as return types
1 parent 2a0a042 commit 673ec7d

12 files changed

Lines changed: 222 additions & 165 deletions

File tree

NativeScript/runtime/ArgConverter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class ArgConverter {
3232
static const Meta* GetMeta(std::string name);
3333
static const ProtocolMeta* FindProtocolMeta(Protocol* protocol);
3434
static void MethodCallback(ffi_cif* cif, void* retValue, void** argValues, void* userData);
35-
static void SetValue(v8::Isolate* isolate, void* retValue, v8::Local<v8::Value> value, BinaryTypeEncodingType type);
35+
static void SetValue(v8::Isolate* isolate, void* retValue, v8::Local<v8::Value> value, const TypeEncoding* typeEncoding);
3636
static void ConstructObject(v8::Isolate* isolate, const v8::FunctionCallbackInfo<v8::Value>& info, Class klass, const InterfaceMeta* interfaceMeta = nullptr);
3737
private:
3838
static v8::Local<v8::Function> CreateEmptyInstanceFunction(v8::Isolate* isolate, v8::GenericNamedPropertyGetterCallback propertyGetter = nullptr, v8::GenericNamedPropertySetterCallback propertySetter = nullptr);

NativeScript/runtime/ArgConverter.mm

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@
128128
assert(false);
129129
}
130130

131-
ArgConverter::SetValue(isolate, retValue, result, data->typeEncoding_->type);
131+
ArgConverter::SetValue(isolate, retValue, result, data->typeEncoding_);
132132
};
133133

134134
if ([NSThread isMainThread]) {
@@ -147,14 +147,15 @@
147147
}
148148
}
149149

150-
void ArgConverter::SetValue(Isolate* isolate, void* retValue, Local<Value> value, BinaryTypeEncodingType type) {
150+
void ArgConverter::SetValue(Isolate* isolate, void* retValue, Local<Value> value, const TypeEncoding* typeEncoding) {
151151
if (value.IsEmpty() || value->IsNullOrUndefined()) {
152152
void* nullPtr = nullptr;
153153
*(ffi_arg *)retValue = (unsigned long)nullPtr;
154154
return;
155155
}
156156

157157
// TODO: Refactor this to reuse some existing logic in Interop::SetFFIParams
158+
BinaryTypeEncodingType type = typeEncoding->type;
158159

159160
if (tns::IsBool(value)) {
160161
bool boolValue = value.As<v8::Boolean>()->Value();
@@ -227,7 +228,15 @@
227228
}
228229
} else if (type == BinaryTypeEncodingType::StructDeclarationReference) {
229230
BaseDataWrapper* baseWrapper = tns::GetValue(isolate, value);
230-
if (baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Struct) {
231+
if (baseWrapper == nullptr) {
232+
const char* structName = typeEncoding->details.declarationReference.name.valuePtr();
233+
const Meta* meta = ArgConverter::GetMeta(structName);
234+
assert(meta != nullptr && meta->type() == MetaType::Struct);
235+
const StructMeta* structMeta = static_cast<const StructMeta*>(meta);
236+
StructInfo structInfo = FFICall::GetStructInfo(structMeta);
237+
Interop::InitializeStruct(isolate, retValue, structInfo.Fields(), value);
238+
return;
239+
} else if (baseWrapper->Type() == WrapperType::Struct) {
231240
StructWrapper* structWrapper = static_cast<StructWrapper*>(baseWrapper);
232241
*(ffi_arg*)retValue = (unsigned long)structWrapper->Data();
233242
return;

NativeScript/runtime/ClassBuilder.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@
653653
assert(getterFunc->Call(context->isolate_->GetCurrentContext(), self_, 0, nullptr).ToLocal(&res));
654654

655655
const TypeEncoding* typeEncoding = context->meta_->getter()->encodings()->first();
656-
ArgConverter::SetValue(context->isolate_, retValue, res, typeEncoding->type);
656+
ArgConverter::SetValue(context->isolate_, retValue, res, typeEncoding);
657657
};
658658
const TypeEncoding* typeEncoding = propertyMeta->getter()->encodings()->first();
659659
IMP impGetter = Interop::CreateMethod(2, 0, typeEncoding, getterCallback , userData);

NativeScript/runtime/DataWrapper.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum class WrapperType {
2222
ObjCClass,
2323
ObjCProtocol,
2424
Function,
25+
AnonymousFunction,
2526
Block,
2627
Reference,
2728
ReferenceType,
@@ -350,6 +351,29 @@ class FunctionWrapper: public BaseDataWrapper {
350351
const FunctionMeta* meta_;
351352
};
352353

354+
class AnonymousFunctionWrapper: public BaseDataWrapper {
355+
public:
356+
AnonymousFunctionWrapper(void* functionPointer, const TypeEncoding* parametersEncoding, size_t parametersCount)
357+
: data_(functionPointer),
358+
parametersEncoding_(parametersEncoding) {
359+
}
360+
361+
const WrapperType Type() {
362+
return WrapperType::AnonymousFunction;
363+
}
364+
365+
void* Data() {
366+
return this->data_;
367+
}
368+
369+
const TypeEncoding* ParametersEncoding() {
370+
return this->parametersEncoding_;
371+
}
372+
private:
373+
void* data_;
374+
const TypeEncoding* parametersEncoding_;
375+
};
376+
353377
class BlockWrapper: public BaseDataWrapper {
354378
public:
355379
BlockWrapper(void* block, const TypeEncoding* typeEncoding)
@@ -382,7 +406,7 @@ class FunctionReferenceTypeWrapper: public BaseDataWrapper {
382406

383407
class FunctionReferenceWrapper: public BaseDataWrapper {
384408
public:
385-
FunctionReferenceWrapper(v8::Persistent<v8::Function>* function)
409+
FunctionReferenceWrapper(v8::Persistent<v8::Value>* function)
386410
: function_(function),
387411
data_(nullptr) {
388412
}
@@ -391,7 +415,7 @@ class FunctionReferenceWrapper: public BaseDataWrapper {
391415
return WrapperType::FunctionReference;
392416
}
393417

394-
v8::Persistent<v8::Function>* Function() {
418+
v8::Persistent<v8::Value>* Function() {
395419
return this->function_;
396420
}
397421

@@ -403,7 +427,7 @@ class FunctionReferenceWrapper: public BaseDataWrapper {
403427
this->data_ = data;
404428
}
405429
private:
406-
v8::Persistent<v8::Function>* function_;
430+
v8::Persistent<v8::Value>* function_;
407431
void* data_;
408432
};
409433

NativeScript/runtime/FunctionReference.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,17 @@ Local<v8::Function> FunctionReference::GetFunctionReferenceCtorFunc(Isolate* iso
3939
return ctorFunc;
4040
}
4141

42-
void FunctionReference::FunctionReferenceConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
42+
void FunctionReference::FunctionReferenceConstructorCallback(const FunctionCallbackInfo<Value>& info) {
4343
assert(info.Length() == 1);
4444
assert(info[0]->IsFunction());
4545

4646
Isolate* isolate = info.GetIsolate();
4747

4848
Local<v8::Function> arg = info[0].As<v8::Function>();
49-
Persistent<v8::Function>* poArg = new Persistent<v8::Function>(isolate, arg);
50-
49+
Persistent<v8::Value>* poArg = ObjectManager::Register(isolate, arg);
5150
FunctionReferenceWrapper* wrapper = new FunctionReferenceWrapper(poArg);
52-
tns::SetValue(isolate, info.This(), wrapper);
53-
ObjectManager::Register(isolate, info.This());
51+
tns::SetValue(isolate, arg, wrapper);
52+
info.GetReturnValue().Set(arg);
5453
}
5554

5655
}

NativeScript/runtime/Interop.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ class Interop {
1717
static void RegisterInteropTypes(v8::Isolate* isolate);
1818
static CFTypeRef CreateBlock(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData);
1919
static IMP CreateMethod(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData);
20-
template <typename TMeta>
21-
static inline v8::Local<v8::Value> CallFunction(v8::Isolate* isolate, const TMeta* meta, id target, Class clazz, const std::vector<v8::Local<v8::Value>> args, bool callSuper = false);
2220
static id CallInitializer(v8::Isolate* isolate, const MethodMeta* methodMeta, id target, Class clazz, const std::vector<v8::Local<v8::Value>> args);
21+
static v8::Local<v8::Value> CallFunction(v8::Isolate* isolate, const MethodMeta* meta, id target, Class clazz, const std::vector<v8::Local<v8::Value>> args, bool callSuper);
22+
static v8::Local<v8::Value> CallFunction(v8::Isolate* isolate, const FunctionMeta* meta, const std::vector<v8::Local<v8::Value>> args);
23+
static v8::Local<v8::Value> CallFunction(v8::Isolate* isolate, void* functionPointer, const TypeEncoding* typeEncoding, const std::vector<v8::Local<v8::Value>> args);
2324
static v8::Local<v8::Value> GetResult(v8::Isolate* isolate, const TypeEncoding* typeEncoding, BaseCall* call, bool marshalToPrimitive);
2425
static void SetStructPropertyValue(v8::Isolate* isolate, StructWrapper* wrapper, StructField field, v8::Local<v8::Value> value);
2526
static void InitializeStruct(v8::Isolate* isolate, void* destBuffer, std::vector<StructField> fields, v8::Local<v8::Value> inititalizer);
@@ -41,6 +42,7 @@ class Interop {
4142
static v8::Local<v8::Value> GetPrimitiveReturnType(v8::Isolate* isolate, BinaryTypeEncodingType type, BaseCall* call);
4243
static const TypeEncoding* CreateEncoding(BinaryTypeEncodingType type);
4344
static v8::Local<v8::Value> HandleOf(v8::Isolate* isolate, v8::Local<v8::Value> value);
45+
static v8::Local<v8::Value> CallFunctionInternal(v8::Isolate* isolate, bool isPrimitiveFunction, void* functionPointer, const TypeEncoding* typeEncoding, const std::vector<v8::Local<v8::Value>> args, id target, Class clazz, SEL selector, bool callSuper, MetaType metaType);
4446

4547
template <typename T>
4648
static void SetValue(void* dest, T value) {
@@ -90,8 +92,8 @@ class Interop {
9092

9193
}
9294

93-
#ifdef __OBJC__
94-
#include "Interop_impl.h"
95-
#endif
95+
//#ifdef __OBJC__
96+
//#include "Interop_impl.h"
97+
//#endif
9698

9799
#endif /* Interop_h */

NativeScript/runtime/Interop.mm

Lines changed: 160 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#include <Foundation/Foundation.h>
2+
#include <objc/message.h>
23
#include "Interop.h"
34
#include "ObjectManager.h"
45
#include "Helpers.h"
56
#include "ArgConverter.h"
67
#include "DictionaryAdapter.h"
8+
#include "SymbolLoader.h"
79
#include "ArrayAdapter.h"
810
#include "NSDataAdapter.h"
911
#include "Caches.h"
@@ -50,6 +52,62 @@
5052
return blockPointer;
5153
}
5254

55+
Local<Value> Interop::CallFunction(Isolate* isolate, const FunctionMeta* meta, const std::vector<Local<Value>> args) {
56+
void* functionPointer = SymbolLoader::instance().loadFunctionSymbol(meta->topLevelModule(), meta->name());
57+
if (!functionPointer) {
58+
NSLog(@"Unable to load \"%s\" function", meta->name());
59+
assert(false);
60+
}
61+
62+
const TypeEncoding* typeEncoding = meta->encodings()->first();;
63+
return Interop::CallFunction(isolate, functionPointer, typeEncoding, args);
64+
}
65+
66+
Local<Value> Interop::CallFunction(Isolate* isolate, void* functionPointer, const TypeEncoding* typeEncoding, const std::vector<Local<Value>> args) {
67+
return Interop::CallFunctionInternal(isolate, true, functionPointer, typeEncoding, args, nil, nil, nil, false, MetaType::Undefined);
68+
}
69+
70+
Local<Value> Interop::CallFunction(Isolate* isolate, const MethodMeta* meta, id target, Class clazz, const std::vector<Local<Value>> args, bool callSuper) {
71+
SEL selector = nil;
72+
void* functionPointer = nullptr;
73+
const TypeEncoding* typeEncoding = nullptr;
74+
bool isPrimitiveFunction = false;
75+
MetaType metaType = MetaType::Undefined;
76+
77+
metaType = meta->type();
78+
selector = meta->selector();
79+
typeEncoding = meta->encodings()->first();
80+
if (callSuper) {
81+
functionPointer = (void*)objc_msgSendSuper;
82+
} else {
83+
functionPointer = (void*)objc_msgSend;
84+
}
85+
86+
return Interop::CallFunctionInternal(isolate, isPrimitiveFunction, functionPointer, typeEncoding, args, target, clazz, selector, callSuper, metaType);
87+
}
88+
89+
id Interop::CallInitializer(Isolate* isolate, const MethodMeta* methodMeta, id target, Class clazz, const std::vector<Local<Value>> args) {
90+
const TypeEncoding* typeEncoding = methodMeta->encodings()->first();
91+
SEL selector = methodMeta->selector();
92+
void* functionPointer = (void*)objc_msgSend;
93+
94+
int initialParameterIndex = 2;
95+
int argsCount = initialParameterIndex + (int)args.size();
96+
97+
ffi_cif* cif = FFICall::GetCif(typeEncoding, initialParameterIndex, argsCount);
98+
FFICall call(cif);
99+
100+
Interop::SetValue(call.ArgumentBuffer(0), target);
101+
Interop::SetValue(call.ArgumentBuffer(1), selector);
102+
Interop::SetFFIParams(isolate, typeEncoding, &call, argsCount, initialParameterIndex, args);
103+
104+
ffi_call(cif, FFI_FN(functionPointer), call.ResultBuffer(), call.ArgsArray());
105+
106+
id result = call.GetResult<id>();
107+
108+
return result;
109+
}
110+
53111
void Interop::SetFFIParams(Isolate* isolate, const TypeEncoding* typeEncoding, FFICall* call, const int argsCount, const int initialParameterIndex, const std::vector<Local<Value>> args) {
54112
const TypeEncoding* enc = typeEncoding;
55113
for (int i = initialParameterIndex; i < argsCount; i++) {
@@ -172,9 +230,11 @@
172230
assert(wrapper != nullptr && wrapper->Type() == WrapperType::FunctionReference);
173231
FunctionReferenceWrapper* funcWrapper = static_cast<FunctionReferenceWrapper*>(wrapper);
174232
const TypeEncoding* functionTypeEncoding = typeEncoding->details.functionPointer.signature.first();
175-
int argsCount = typeEncoding->details.block.signature.count - 1;
233+
int argsCount = typeEncoding->details.functionPointer.signature.count - 1;
176234

177-
Local<v8::Function> callback = funcWrapper->Function()->Get(isolate);
235+
Local<Value> callbackValue = funcWrapper->Function()->Get(isolate);
236+
assert(callbackValue->IsFunction());
237+
Local<v8::Function> callback = callbackValue.As<v8::Function>();
178238
Persistent<Value>* poCallback = new Persistent<Value>(isolate, callback);
179239
MethodCallbackWrapper* userData = new MethodCallbackWrapper(isolate, poCallback, 0, argsCount, functionTypeEncoding);
180240

@@ -620,7 +680,7 @@
620680
return Null(isolate);
621681
}
622682

623-
auto cache = Caches::Get(isolate);
683+
Caches* cache = Caches::Get(isolate);
624684
while (true) {
625685
const char* name = class_getName(result);
626686
auto it = cache->CtorFuncs.find(name);
@@ -688,6 +748,40 @@
688748
return callback;
689749
}
690750

751+
if (typeEncoding->type == BinaryTypeEncodingType::FunctionPointerEncoding) {
752+
uint8_t* functionPointer = call->GetResult<uint8_t*>();
753+
if (functionPointer == nullptr) {
754+
return Null(isolate);
755+
}
756+
757+
const TypeEncoding* parametersEncoding = typeEncoding->details.functionPointer.signature.first();
758+
size_t parametersCount = typeEncoding->details.functionPointer.signature.count;
759+
AnonymousFunctionWrapper* wrapper = new AnonymousFunctionWrapper(functionPointer, parametersEncoding, parametersCount);
760+
Local<External> ext = External::New(isolate, wrapper);
761+
762+
Local<Context> context = isolate->GetCurrentContext();
763+
Local<v8::Function> func;
764+
bool success = v8::Function::New(context, [](const FunctionCallbackInfo<Value>& info) {
765+
Isolate* isolate = info.GetIsolate();
766+
AnonymousFunctionWrapper* wrapper = static_cast<AnonymousFunctionWrapper*>(info.Data().As<External>()->Value());
767+
assert(wrapper != nullptr);
768+
769+
const std::vector<Local<Value>> args = tns::ArgsToVector(info);
770+
void* functionPointer = wrapper->Data();
771+
const TypeEncoding* typeEncoding = wrapper->ParametersEncoding();
772+
773+
Local<Value> result = Interop::CallFunction(isolate, functionPointer, typeEncoding, args);
774+
775+
info.GetReturnValue().Set(result);
776+
}, ext).ToLocal(&func);
777+
assert(success);
778+
779+
tns::SetValue(isolate, func, wrapper);
780+
ObjectManager::Register(isolate, func);
781+
782+
return func;
783+
}
784+
691785
if (typeEncoding->type == BinaryTypeEncodingType::PointerEncoding) {
692786
uint8_t* result = call->GetResult<uint8_t*>();
693787
if (result == nullptr) {
@@ -1010,4 +1104,67 @@
10101104
return result.As<v8::Array>();
10111105
}
10121106

1107+
Local<Value> Interop::CallFunctionInternal(Isolate* isolate, bool isPrimitiveFunction, void* functionPointer, const TypeEncoding* typeEncoding, const std::vector<Local<Value>> args, id target, Class clazz, SEL selector, bool callSuper, MetaType metaType) {
1108+
int initialParameterIndex = isPrimitiveFunction ? 0 : 2;
1109+
1110+
int argsCount = initialParameterIndex + (int)args.size();
1111+
1112+
ffi_cif* cif = FFICall::GetCif(typeEncoding, initialParameterIndex, argsCount);
1113+
1114+
FFICall call(cif);
1115+
1116+
std::unique_ptr<objc_super> sup = std::unique_ptr<objc_super>(new objc_super());
1117+
1118+
bool isInstanceMethod = (target && target != nil);
1119+
1120+
if (initialParameterIndex > 1) {
1121+
#if defined(__x86_64__)
1122+
if (metaType == MetaType::Undefined || metaType == MetaType::Union) {
1123+
const unsigned UNIX64_FLAG_RET_IN_MEM = (1 << 10);
1124+
1125+
ffi_type* returnType = FFICall::GetArgumentType(typeEncoding);
1126+
1127+
if (returnType->type == FFI_TYPE_LONGDOUBLE) {
1128+
functionPointer = (void*)objc_msgSend_fpret;
1129+
} else if (returnType->type == FFI_TYPE_STRUCT && (cif->flags & UNIX64_FLAG_RET_IN_MEM)) {
1130+
if (callSuper) {
1131+
functionPointer = (void*)objc_msgSendSuper_stret;
1132+
} else {
1133+
functionPointer = (void*)objc_msgSend_stret;
1134+
}
1135+
}
1136+
}
1137+
#endif
1138+
1139+
if (isInstanceMethod) {
1140+
if (callSuper) {
1141+
sup->receiver = target;
1142+
sup->super_class = class_getSuperclass(object_getClass(target));
1143+
Interop::SetValue(call.ArgumentBuffer(0), sup.get());
1144+
} else {
1145+
Interop::SetValue(call.ArgumentBuffer(0), target);
1146+
}
1147+
} else {
1148+
Interop::SetValue(call.ArgumentBuffer(0), clazz);
1149+
}
1150+
1151+
Interop::SetValue(call.ArgumentBuffer(1), selector);
1152+
}
1153+
1154+
bool isInstanceReturnType = typeEncoding->type == BinaryTypeEncodingType::InstanceTypeEncoding;
1155+
bool marshalToPrimitive = isPrimitiveFunction || !isInstanceReturnType;
1156+
1157+
@autoreleasepool {
1158+
Interop::SetFFIParams(isolate, typeEncoding, &call, argsCount, initialParameterIndex, args);
1159+
}
1160+
1161+
ffi_call(cif, FFI_FN(functionPointer), call.ResultBuffer(), call.ArgsArray());
1162+
1163+
@autoreleasepool {
1164+
Local<Value> result = Interop::GetResult(isolate, typeEncoding, &call, marshalToPrimitive);
1165+
1166+
return result;
1167+
}
1168+
}
1169+
10131170
}

0 commit comments

Comments
 (0)