7
7
//
8
8
9
9
#include " FFICall.h"
10
+ #include " FFICache.h"
10
11
#include < JavaScriptCore/Interpreter.h>
11
12
#include < JavaScriptCore/JSPromiseDeferred.h>
12
13
#include < JavaScriptCore/StrongInlines.h>
@@ -18,9 +19,12 @@ using namespace JSC;
18
19
19
20
const ClassInfo FFICall::s_info = { " FFICall" , &Base::s_info, 0 , CREATE_METHOD_TABLE (FFICall) };
20
21
21
- void FFICall::initializeFFI (VM& vm, const InvocationHooks& hooks, JSCell* returnType, const Vector<JSCell*>& parameterTypes, size_t initialArgumentIndex) {
22
- ASSERT (this ->methodTable ()->destroy != FFICall::destroy);
22
+ void deleteCif (ffi_cif* cif) {
23
+ delete[] cif->arg_types ;
24
+ delete cif;
25
+ }
23
26
27
+ void FFICall::initializeFFI (VM& vm, const InvocationHooks& hooks, JSCell* returnType, const Vector<JSCell*>& parameterTypes, size_t initialArgumentIndex) {
24
28
this ->_invocationHooks = hooks;
25
29
26
30
this ->_initialArgumentIndex = initialArgumentIndex;
@@ -33,8 +37,11 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return
33
37
34
38
const ffi_type** parameterTypesFFITypes = new const ffi_type*[parametersCount + initialArgumentIndex];
35
39
40
+ this ->signatureVector .push_back (getFFITypeMethodTable (returnType).ffiType );
41
+
36
42
for (size_t i = 0 ; i < initialArgumentIndex; ++i) {
37
43
parameterTypesFFITypes[i] = &ffi_type_pointer;
44
+ this ->signatureVector .push_back (&ffi_type_pointer);
38
45
}
39
46
40
47
for (size_t i = 0 ; i < parametersCount; i++) {
@@ -45,10 +52,10 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return
45
52
this ->_parameterTypes .append (ffiTypeMethodTable);
46
53
47
54
parameterTypesFFITypes[i + initialArgumentIndex] = ffiTypeMethodTable.ffiType ;
55
+ this ->signatureVector .push_back (parameterTypesFFITypes[i + initialArgumentIndex]);
48
56
}
49
57
50
- this ->_cif = new ffi_cif;
51
- ffi_prep_cif (this ->_cif , FFI_DEFAULT_ABI, parametersCount + initialArgumentIndex, const_cast <ffi_type*>(this ->_returnType .ffiType ), const_cast <ffi_type**>(parameterTypesFFITypes));
58
+ this ->_cif = getCif (parametersCount + initialArgumentIndex, const_cast <ffi_type*>(this ->_returnType .ffiType ), const_cast <ffi_type**>(parameterTypesFFITypes));
52
59
53
60
this ->_argsCount = _cif->nargs ;
54
61
this ->_stackSize = 0 ;
@@ -57,17 +64,34 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return
57
64
this ->_stackSize += malloc_good_size (sizeof (void * [this ->_cif ->nargs ]));
58
65
59
66
this ->_returnOffset = this ->_stackSize ;
60
- this ->_stackSize += malloc_good_size (std::max (this ->_cif ->rtype ->size , sizeof (ffi_arg)));
67
+ this ->_stackSize += malloc_good_size (std::max (this ->_cif . get () ->rtype ->size , sizeof (ffi_arg)));
61
68
62
69
for (size_t i = 0 ; i < this ->_argsCount ; i++) {
63
70
this ->_argValueOffsets .push_back (this ->_stackSize );
64
71
this ->_stackSize += malloc_good_size (std::max (this ->_cif ->arg_types [i]->size , sizeof (ffi_arg)));
65
72
}
66
73
}
67
74
75
+ std::shared_ptr<ffi_cif> FFICall::getCif (unsigned int nargs, ffi_type* rtype, ffi_type** atypes) {
76
+
77
+ FFICache::FFIMap::const_iterator it = FFICache::global ()->cifCache .find (this ->signatureVector );
78
+
79
+ if (it == FFICache::global ()->cifCache .end ()) {
80
+ std::shared_ptr<ffi_cif> shared (new ffi_cif, deleteCif);
81
+ ffi_prep_cif (shared.get (), FFI_DEFAULT_ABI, nargs, rtype, atypes);
82
+ FFICache::global ()->cifCache [this ->signatureVector ] = shared;
83
+ }
84
+
85
+ return FFICache::global ()->cifCache [this ->signatureVector ];
86
+ }
87
+
68
88
FFICall::~FFICall () {
69
- delete[] this ->_cif ->arg_types ;
70
- delete this ->_cif ;
89
+
90
+ if (this ->_cif .use_count () == 2 ) {
91
+ FFICache::FFIMap::const_iterator it;
92
+ it = FFICache::global ()->cifCache .find (this ->signatureVector );
93
+ FFICache::global ()->cifCache .erase (it);
94
+ }
71
95
}
72
96
73
97
void FFICall::visitChildren (JSCell* cell, SlotVisitor& visitor) {
@@ -99,7 +123,7 @@ EncodedJSValue JSC_HOST_CALL FFICall::call(ExecState* execState) {
99
123
100
124
{
101
125
JSLock::DropAllLocks locksDropper (execState);
102
- ffi_call (callee->_cif , FFI_FN (invocation.function ), invocation._buffer + callee->_returnOffset , reinterpret_cast <void **>(invocation._buffer + callee->_argsArrayOffset ));
126
+ ffi_call (callee->_cif . get () , FFI_FN (invocation.function ), invocation._buffer + callee->_returnOffset , reinterpret_cast <void **>(invocation._buffer + callee->_argsArrayOffset ));
103
127
}
104
128
105
129
JSValue result = callee->_returnType .read (execState, invocation._buffer + callee->_returnOffset , callee->_returnTypeCell .get ());
@@ -150,7 +174,7 @@ JSObject* FFICall::async(ExecState* execState, JSValue thisValue, const ArgList&
150
174
JSC::VM& vm = fakeExecState->vm ();
151
175
auto scope = DECLARE_CATCH_SCOPE (vm);
152
176
153
- ffi_call (callee->_cif , FFI_FN (invocation->function ), invocation->resultBuffer (), reinterpret_cast <void **>(invocation->_buffer + callee->_argsArrayOffset ));
177
+ ffi_call (callee->_cif . get () , FFI_FN (invocation->function ), invocation->resultBuffer (), reinterpret_cast <void **>(invocation->_buffer + callee->_argsArrayOffset ));
154
178
155
179
JSLockHolder lockHolder (fakeExecState);
156
180
// we no longer have a valid caller on the stack, what with being async and all
@@ -189,4 +213,4 @@ JSObject* FFICall::async(ExecState* execState, JSValue thisValue, const ArgList&
189
213
190
214
return deferred->promise ();
191
215
}
192
- }
216
+ } // namespace NativeScript
0 commit comments