|
1 | 1 | #include <Foundation/Foundation.h> |
| 2 | +#include <objc/message.h> |
2 | 3 | #include "Interop.h" |
3 | 4 | #include "ObjectManager.h" |
4 | 5 | #include "Helpers.h" |
5 | 6 | #include "ArgConverter.h" |
6 | 7 | #include "DictionaryAdapter.h" |
| 8 | +#include "SymbolLoader.h" |
7 | 9 | #include "ArrayAdapter.h" |
8 | 10 | #include "NSDataAdapter.h" |
9 | 11 | #include "Caches.h" |
|
50 | 52 | return blockPointer; |
51 | 53 | } |
52 | 54 |
|
| 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 | + |
53 | 111 | void Interop::SetFFIParams(Isolate* isolate, const TypeEncoding* typeEncoding, FFICall* call, const int argsCount, const int initialParameterIndex, const std::vector<Local<Value>> args) { |
54 | 112 | const TypeEncoding* enc = typeEncoding; |
55 | 113 | for (int i = initialParameterIndex; i < argsCount; i++) { |
|
172 | 230 | assert(wrapper != nullptr && wrapper->Type() == WrapperType::FunctionReference); |
173 | 231 | FunctionReferenceWrapper* funcWrapper = static_cast<FunctionReferenceWrapper*>(wrapper); |
174 | 232 | 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; |
176 | 234 |
|
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>(); |
178 | 238 | Persistent<Value>* poCallback = new Persistent<Value>(isolate, callback); |
179 | 239 | MethodCallbackWrapper* userData = new MethodCallbackWrapper(isolate, poCallback, 0, argsCount, functionTypeEncoding); |
180 | 240 |
|
|
620 | 680 | return Null(isolate); |
621 | 681 | } |
622 | 682 |
|
623 | | - auto cache = Caches::Get(isolate); |
| 683 | + Caches* cache = Caches::Get(isolate); |
624 | 684 | while (true) { |
625 | 685 | const char* name = class_getName(result); |
626 | 686 | auto it = cache->CtorFuncs.find(name); |
|
688 | 748 | return callback; |
689 | 749 | } |
690 | 750 |
|
| 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 | + |
691 | 785 | if (typeEncoding->type == BinaryTypeEncodingType::PointerEncoding) { |
692 | 786 | uint8_t* result = call->GetResult<uint8_t*>(); |
693 | 787 | if (result == nullptr) { |
|
1010 | 1104 | return result.As<v8::Array>(); |
1011 | 1105 | } |
1012 | 1106 |
|
| 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 | + |
1013 | 1170 | } |
0 commit comments