Skip to content

Commit 7f8ee77

Browse files
committed
Add FFI caching in FFICall initialization
1 parent 7a5e27c commit 7f8ee77

File tree

8 files changed

+106
-15
lines changed

8 files changed

+106
-15
lines changed

examples/Gameraww/app/MasterViewController.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,4 @@ var JSMasterViewController = UITableViewController.extend(
8787
"aboutPressed:" :
8888
{returns : interop.types.void, params : [ UIControl ]}
8989
}
90-
});
90+
});

src/NativeScript/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
set(HEADER_FILES
2+
Calling/FFICache.h
23
Calling/FFICall.h
34
Calling/FFICallback.h
45
Calling/FFICallbackInlines.h
@@ -102,6 +103,7 @@ set(HEADER_FILES
102103
)
103104

104105
set(SOURCE_FILES
106+
Calling/FFICache.cpp
105107
Calling/FFICall.cpp
106108
Calling/FFICallPrototype.cpp
107109
Calling/FFIFunctionCall.mm

src/NativeScript/Calling/FFICache.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// FFICache.cpp
3+
// NativeScript
4+
//
5+
// Created by Teodor Dermendzhiev on 02/10/2017.
6+
// Copyright (c) 2014 г. Telerik. All rights reserved.
7+
//
8+
9+
#include "FFICache.h"
10+
#include <stdio.h>
11+
12+
namespace NativeScript {
13+
14+
FFICache* FFICache::global() {
15+
16+
static FFICache* instance;
17+
18+
if (!instance)
19+
instance = new FFICache;
20+
return instance;
21+
}
22+
23+
} // namespace NativeScript

src/NativeScript/Calling/FFICache.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// FFICache.h
3+
// NativeScript
4+
//
5+
// Created by Teodor Dermendzhiev on 02/10/2017.
6+
//
7+
//
8+
9+
#ifndef __NativeScript__FFICache__
10+
#define __NativeScript__FFICache__
11+
12+
#include "FFIType.h"
13+
#include <vector>
14+
15+
namespace NativeScript {
16+
17+
struct SignatureHash {
18+
19+
std::size_t operator()(std::vector<const ffi_type*> signature) const {
20+
std::size_t seed = 2166136261;
21+
22+
for (size_t i = 0; i < signature.size(); i++) {
23+
seed = (seed ^ reinterpret_cast<size_t>(signature[i])) * 16777619U;
24+
}
25+
return seed;
26+
}
27+
};
28+
29+
class FFICache {
30+
31+
public:
32+
std::unordered_map<std::vector<const ffi_type*>, std::shared_ptr<ffi_cif>, SignatureHash> cifCache;
33+
34+
static FFICache* global();
35+
};
36+
37+
} // namespace NativeScript
38+
39+
#endif /* FFICache_h */

src/NativeScript/Calling/FFICall.cpp

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//
88

99
#include "FFICall.h"
10+
#include "FFICache.h"
1011
#include <JavaScriptCore/Interpreter.h>
1112
#include <JavaScriptCore/JSPromiseDeferred.h>
1213
#include <JavaScriptCore/StrongInlines.h>
@@ -18,9 +19,12 @@ using namespace JSC;
1819

1920
const ClassInfo FFICall::s_info = { "FFICall", &Base::s_info, 0, CREATE_METHOD_TABLE(FFICall) };
2021

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+
}
2326

27+
void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* returnType, const Vector<JSCell*>& parameterTypes, size_t initialArgumentIndex) {
2428
this->_invocationHooks = hooks;
2529

2630
this->_initialArgumentIndex = initialArgumentIndex;
@@ -33,8 +37,11 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return
3337

3438
const ffi_type** parameterTypesFFITypes = new const ffi_type*[parametersCount + initialArgumentIndex];
3539

40+
this->signatureVector.push_back(getFFITypeMethodTable(returnType).ffiType);
41+
3642
for (size_t i = 0; i < initialArgumentIndex; ++i) {
3743
parameterTypesFFITypes[i] = &ffi_type_pointer;
44+
this->signatureVector.push_back(&ffi_type_pointer);
3845
}
3946

4047
for (size_t i = 0; i < parametersCount; i++) {
@@ -45,10 +52,10 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return
4552
this->_parameterTypes.append(ffiTypeMethodTable);
4653

4754
parameterTypesFFITypes[i + initialArgumentIndex] = ffiTypeMethodTable.ffiType;
55+
this->signatureVector.push_back(parameterTypesFFITypes[i + initialArgumentIndex]);
4856
}
4957

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 = checkForExistingCif(parametersCount + initialArgumentIndex, const_cast<ffi_type*>(this->_returnType.ffiType), const_cast<ffi_type**>(parameterTypesFFITypes));
5259

5360
this->_argsCount = _cif->nargs;
5461
this->_stackSize = 0;
@@ -57,17 +64,34 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return
5764
this->_stackSize += malloc_good_size(sizeof(void * [this->_cif->nargs]));
5865

5966
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)));
6168

6269
for (size_t i = 0; i < this->_argsCount; i++) {
6370
this->_argValueOffsets.push_back(this->_stackSize);
6471
this->_stackSize += malloc_good_size(std::max(this->_cif->arg_types[i]->size, sizeof(ffi_arg)));
6572
}
6673
}
6774

75+
std::shared_ptr<ffi_cif> FFICall::checkForExistingCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes) {
76+
77+
std::unordered_map<std::vector<const ffi_type*>, std::shared_ptr<ffi_cif>, SignatureHash>::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+
6888
FFICall::~FFICall() {
69-
delete[] this->_cif->arg_types;
70-
delete this->_cif;
89+
90+
if (this->_cif.use_count() == 2) {
91+
std::unordered_map<std::vector<const ffi_type*>, std::shared_ptr<ffi_cif>, SignatureHash>::const_iterator it;
92+
it = FFICache::global()->cifCache.find(this->signatureVector);
93+
FFICache::global()->cifCache.erase(it);
94+
}
7195
}
7296

7397
void FFICall::visitChildren(JSCell* cell, SlotVisitor& visitor) {
@@ -99,7 +123,7 @@ EncodedJSValue JSC_HOST_CALL FFICall::call(ExecState* execState) {
99123

100124
{
101125
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));
103127
}
104128

105129
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&
150174
JSC::VM& vm = fakeExecState->vm();
151175
auto scope = DECLARE_CATCH_SCOPE(vm);
152176

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));
154178

155179
JSLockHolder lockHolder(fakeExecState);
156180
// 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&
189213

190214
return deferred->promise();
191215
}
192-
}
216+
} // namespace NativeScript

src/NativeScript/Calling/FFICall.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ class FFICall : public JSC::InternalFunction {
2626
}
2727

2828
JSC::JSObject* async(JSC::ExecState*, JSC::JSValue thisValue, const JSC::ArgList&);
29+
std::shared_ptr<ffi_cif> checkForExistingCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes);
30+
31+
std::vector<const ffi_type*> signatureVector;
2932

3033
protected:
3134
FFICall(JSC::VM& vm, JSC::Structure* structure)
@@ -34,7 +37,7 @@ class FFICall : public JSC::InternalFunction {
3437

3538
~FFICall();
3639

37-
ffi_cif* _cif;
40+
std::shared_ptr<ffi_cif> _cif;
3841

3942
class Invocation {
4043
WTF_MAKE_NONCOPYABLE(Invocation)
@@ -145,6 +148,6 @@ class FFICall : public JSC::InternalFunction {
145148
size_t _argsArrayOffset;
146149
std::vector<size_t> _argValueOffsets;
147150
};
148-
}
151+
} // namespace NativeScript
149152

150153
#endif /* defined(__NativeScript__FFICall__) */

src/NativeScript/Calling/FFIFunctionCall.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@
3131
[invocation.getResult<id>() release];
3232
}
3333
}
34-
}
34+
}

src/NativeScript/ObjC/Constructor/ObjCConstructorCall.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@
5555

5656
return true;
5757
}
58-
}
58+
}

0 commit comments

Comments
 (0)