From 7f8ee7735df1f212e26eae417bdd8e92d5fa933c Mon Sep 17 00:00:00 2001 From: Teodor Dermendzhiev Date: Mon, 2 Oct 2017 17:47:46 +0300 Subject: [PATCH 1/3] Add FFI caching in FFICall initialization --- examples/Gameraww/app/MasterViewController.js | 2 +- src/NativeScript/CMakeLists.txt | 2 + src/NativeScript/Calling/FFICache.cpp | 23 ++++++++++ src/NativeScript/Calling/FFICache.h | 39 ++++++++++++++++ src/NativeScript/Calling/FFICall.cpp | 44 ++++++++++++++----- src/NativeScript/Calling/FFICall.h | 7 ++- src/NativeScript/Calling/FFIFunctionCall.mm | 2 +- .../ObjC/Constructor/ObjCConstructorCall.mm | 2 +- 8 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 src/NativeScript/Calling/FFICache.cpp create mode 100644 src/NativeScript/Calling/FFICache.h diff --git a/examples/Gameraww/app/MasterViewController.js b/examples/Gameraww/app/MasterViewController.js index aa328967d..9a4306df0 100644 --- a/examples/Gameraww/app/MasterViewController.js +++ b/examples/Gameraww/app/MasterViewController.js @@ -87,4 +87,4 @@ var JSMasterViewController = UITableViewController.extend( "aboutPressed:" : {returns : interop.types.void, params : [ UIControl ]} } - }); \ No newline at end of file + }); diff --git a/src/NativeScript/CMakeLists.txt b/src/NativeScript/CMakeLists.txt index 1d0774b56..b293e80ac 100644 --- a/src/NativeScript/CMakeLists.txt +++ b/src/NativeScript/CMakeLists.txt @@ -1,4 +1,5 @@ set(HEADER_FILES + Calling/FFICache.h Calling/FFICall.h Calling/FFICallback.h Calling/FFICallbackInlines.h @@ -102,6 +103,7 @@ set(HEADER_FILES ) set(SOURCE_FILES + Calling/FFICache.cpp Calling/FFICall.cpp Calling/FFICallPrototype.cpp Calling/FFIFunctionCall.mm diff --git a/src/NativeScript/Calling/FFICache.cpp b/src/NativeScript/Calling/FFICache.cpp new file mode 100644 index 000000000..0a2123640 --- /dev/null +++ b/src/NativeScript/Calling/FFICache.cpp @@ -0,0 +1,23 @@ +// +// FFICache.cpp +// NativeScript +// +// Created by Teodor Dermendzhiev on 02/10/2017. +// Copyright (c) 2014 г. Telerik. All rights reserved. +// + +#include "FFICache.h" +#include + +namespace NativeScript { + +FFICache* FFICache::global() { + + static FFICache* instance; + + if (!instance) + instance = new FFICache; + return instance; +} + +} // namespace NativeScript diff --git a/src/NativeScript/Calling/FFICache.h b/src/NativeScript/Calling/FFICache.h new file mode 100644 index 000000000..e503fb448 --- /dev/null +++ b/src/NativeScript/Calling/FFICache.h @@ -0,0 +1,39 @@ +// +// FFICache.h +// NativeScript +// +// Created by Teodor Dermendzhiev on 02/10/2017. +// +// + +#ifndef __NativeScript__FFICache__ +#define __NativeScript__FFICache__ + +#include "FFIType.h" +#include + +namespace NativeScript { + +struct SignatureHash { + + std::size_t operator()(std::vector signature) const { + std::size_t seed = 2166136261; + + for (size_t i = 0; i < signature.size(); i++) { + seed = (seed ^ reinterpret_cast(signature[i])) * 16777619U; + } + return seed; + } +}; + +class FFICache { + +public: + std::unordered_map, std::shared_ptr, SignatureHash> cifCache; + + static FFICache* global(); +}; + +} // namespace NativeScript + +#endif /* FFICache_h */ diff --git a/src/NativeScript/Calling/FFICall.cpp b/src/NativeScript/Calling/FFICall.cpp index abac62944..1e00bafbe 100644 --- a/src/NativeScript/Calling/FFICall.cpp +++ b/src/NativeScript/Calling/FFICall.cpp @@ -7,6 +7,7 @@ // #include "FFICall.h" +#include "FFICache.h" #include #include #include @@ -18,9 +19,12 @@ using namespace JSC; const ClassInfo FFICall::s_info = { "FFICall", &Base::s_info, 0, CREATE_METHOD_TABLE(FFICall) }; -void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* returnType, const Vector& parameterTypes, size_t initialArgumentIndex) { - ASSERT(this->methodTable()->destroy != FFICall::destroy); +void deleteCif(ffi_cif* cif) { + delete[] cif->arg_types; + delete cif; +} +void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* returnType, const Vector& parameterTypes, size_t initialArgumentIndex) { this->_invocationHooks = hooks; this->_initialArgumentIndex = initialArgumentIndex; @@ -33,8 +37,11 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return const ffi_type** parameterTypesFFITypes = new const ffi_type*[parametersCount + initialArgumentIndex]; + this->signatureVector.push_back(getFFITypeMethodTable(returnType).ffiType); + for (size_t i = 0; i < initialArgumentIndex; ++i) { parameterTypesFFITypes[i] = &ffi_type_pointer; + this->signatureVector.push_back(&ffi_type_pointer); } for (size_t i = 0; i < parametersCount; i++) { @@ -45,10 +52,10 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return this->_parameterTypes.append(ffiTypeMethodTable); parameterTypesFFITypes[i + initialArgumentIndex] = ffiTypeMethodTable.ffiType; + this->signatureVector.push_back(parameterTypesFFITypes[i + initialArgumentIndex]); } - this->_cif = new ffi_cif; - ffi_prep_cif(this->_cif, FFI_DEFAULT_ABI, parametersCount + initialArgumentIndex, const_cast(this->_returnType.ffiType), const_cast(parameterTypesFFITypes)); + this->_cif = checkForExistingCif(parametersCount + initialArgumentIndex, const_cast(this->_returnType.ffiType), const_cast(parameterTypesFFITypes)); this->_argsCount = _cif->nargs; this->_stackSize = 0; @@ -57,7 +64,7 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return this->_stackSize += malloc_good_size(sizeof(void * [this->_cif->nargs])); this->_returnOffset = this->_stackSize; - this->_stackSize += malloc_good_size(std::max(this->_cif->rtype->size, sizeof(ffi_arg))); + this->_stackSize += malloc_good_size(std::max(this->_cif.get()->rtype->size, sizeof(ffi_arg))); for (size_t i = 0; i < this->_argsCount; i++) { this->_argValueOffsets.push_back(this->_stackSize); @@ -65,9 +72,26 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return } } +std::shared_ptr FFICall::checkForExistingCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes) { + + std::unordered_map, std::shared_ptr, SignatureHash>::const_iterator it = FFICache::global()->cifCache.find(this->signatureVector); + + if (it == FFICache::global()->cifCache.end()) { + std::shared_ptr shared(new ffi_cif, deleteCif); + ffi_prep_cif(shared.get(), FFI_DEFAULT_ABI, nargs, rtype, atypes); + FFICache::global()->cifCache[this->signatureVector] = shared; + } + + return FFICache::global()->cifCache[this->signatureVector]; +} + FFICall::~FFICall() { - delete[] this->_cif->arg_types; - delete this->_cif; + + if (this->_cif.use_count() == 2) { + std::unordered_map, std::shared_ptr, SignatureHash>::const_iterator it; + it = FFICache::global()->cifCache.find(this->signatureVector); + FFICache::global()->cifCache.erase(it); + } } void FFICall::visitChildren(JSCell* cell, SlotVisitor& visitor) { @@ -99,7 +123,7 @@ EncodedJSValue JSC_HOST_CALL FFICall::call(ExecState* execState) { { JSLock::DropAllLocks locksDropper(execState); - ffi_call(callee->_cif, FFI_FN(invocation.function), invocation._buffer + callee->_returnOffset, reinterpret_cast(invocation._buffer + callee->_argsArrayOffset)); + ffi_call(callee->_cif.get(), FFI_FN(invocation.function), invocation._buffer + callee->_returnOffset, reinterpret_cast(invocation._buffer + callee->_argsArrayOffset)); } 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& JSC::VM& vm = fakeExecState->vm(); auto scope = DECLARE_CATCH_SCOPE(vm); - ffi_call(callee->_cif, FFI_FN(invocation->function), invocation->resultBuffer(), reinterpret_cast(invocation->_buffer + callee->_argsArrayOffset)); + ffi_call(callee->_cif.get(), FFI_FN(invocation->function), invocation->resultBuffer(), reinterpret_cast(invocation->_buffer + callee->_argsArrayOffset)); JSLockHolder lockHolder(fakeExecState); // 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& return deferred->promise(); } -} \ No newline at end of file +} // namespace NativeScript diff --git a/src/NativeScript/Calling/FFICall.h b/src/NativeScript/Calling/FFICall.h index c7e66ec0e..f345ff0a5 100644 --- a/src/NativeScript/Calling/FFICall.h +++ b/src/NativeScript/Calling/FFICall.h @@ -26,6 +26,9 @@ class FFICall : public JSC::InternalFunction { } JSC::JSObject* async(JSC::ExecState*, JSC::JSValue thisValue, const JSC::ArgList&); + std::shared_ptr checkForExistingCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes); + + std::vector signatureVector; protected: FFICall(JSC::VM& vm, JSC::Structure* structure) @@ -34,7 +37,7 @@ class FFICall : public JSC::InternalFunction { ~FFICall(); - ffi_cif* _cif; + std::shared_ptr _cif; class Invocation { WTF_MAKE_NONCOPYABLE(Invocation) @@ -145,6 +148,6 @@ class FFICall : public JSC::InternalFunction { size_t _argsArrayOffset; std::vector _argValueOffsets; }; -} +} // namespace NativeScript #endif /* defined(__NativeScript__FFICall__) */ diff --git a/src/NativeScript/Calling/FFIFunctionCall.mm b/src/NativeScript/Calling/FFIFunctionCall.mm index da838a460..8c60e421f 100644 --- a/src/NativeScript/Calling/FFIFunctionCall.mm +++ b/src/NativeScript/Calling/FFIFunctionCall.mm @@ -31,4 +31,4 @@ [invocation.getResult() release]; } } -} \ No newline at end of file +} diff --git a/src/NativeScript/ObjC/Constructor/ObjCConstructorCall.mm b/src/NativeScript/ObjC/Constructor/ObjCConstructorCall.mm index 13ecba617..5224486e7 100644 --- a/src/NativeScript/ObjC/Constructor/ObjCConstructorCall.mm +++ b/src/NativeScript/ObjC/Constructor/ObjCConstructorCall.mm @@ -55,4 +55,4 @@ return true; } -} \ No newline at end of file +} From 11d7701a9d96df9736998f2117436a23da3b2863 Mon Sep 17 00:00:00 2001 From: Teodor Dermendzhiev Date: Wed, 4 Oct 2017 11:23:02 +0300 Subject: [PATCH 2/3] Rename checkForExistingCif() to getCif(() --- src/NativeScript/Calling/FFICall.cpp | 4 ++-- src/NativeScript/Calling/FFICall.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NativeScript/Calling/FFICall.cpp b/src/NativeScript/Calling/FFICall.cpp index 1e00bafbe..9aab62580 100644 --- a/src/NativeScript/Calling/FFICall.cpp +++ b/src/NativeScript/Calling/FFICall.cpp @@ -55,7 +55,7 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return this->signatureVector.push_back(parameterTypesFFITypes[i + initialArgumentIndex]); } - this->_cif = checkForExistingCif(parametersCount + initialArgumentIndex, const_cast(this->_returnType.ffiType), const_cast(parameterTypesFFITypes)); + this->_cif = getCif(parametersCount + initialArgumentIndex, const_cast(this->_returnType.ffiType), const_cast(parameterTypesFFITypes)); this->_argsCount = _cif->nargs; this->_stackSize = 0; @@ -72,7 +72,7 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return } } -std::shared_ptr FFICall::checkForExistingCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes) { +std::shared_ptr FFICall::getCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes) { std::unordered_map, std::shared_ptr, SignatureHash>::const_iterator it = FFICache::global()->cifCache.find(this->signatureVector); diff --git a/src/NativeScript/Calling/FFICall.h b/src/NativeScript/Calling/FFICall.h index f345ff0a5..c122a2680 100644 --- a/src/NativeScript/Calling/FFICall.h +++ b/src/NativeScript/Calling/FFICall.h @@ -26,7 +26,7 @@ class FFICall : public JSC::InternalFunction { } JSC::JSObject* async(JSC::ExecState*, JSC::JSValue thisValue, const JSC::ArgList&); - std::shared_ptr checkForExistingCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes); + std::shared_ptr getCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes); std::vector signatureVector; From b71b6c007d63006ab9dfc8927502ef79699ea66b Mon Sep 17 00:00:00 2001 From: Teodor Dermendzhiev Date: Wed, 4 Oct 2017 16:16:39 +0300 Subject: [PATCH 3/3] Introduce FFIMap typedef --- src/NativeScript/Calling/FFICache.h | 3 ++- src/NativeScript/Calling/FFICall.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/NativeScript/Calling/FFICache.h b/src/NativeScript/Calling/FFICache.h index e503fb448..13a1d9b0c 100644 --- a/src/NativeScript/Calling/FFICache.h +++ b/src/NativeScript/Calling/FFICache.h @@ -29,7 +29,8 @@ struct SignatureHash { class FFICache { public: - std::unordered_map, std::shared_ptr, SignatureHash> cifCache; + typedef std::unordered_map, std::shared_ptr, SignatureHash> FFIMap; + FFIMap cifCache; static FFICache* global(); }; diff --git a/src/NativeScript/Calling/FFICall.cpp b/src/NativeScript/Calling/FFICall.cpp index 9aab62580..0fdf0bd2c 100644 --- a/src/NativeScript/Calling/FFICall.cpp +++ b/src/NativeScript/Calling/FFICall.cpp @@ -74,7 +74,7 @@ void FFICall::initializeFFI(VM& vm, const InvocationHooks& hooks, JSCell* return std::shared_ptr FFICall::getCif(unsigned int nargs, ffi_type* rtype, ffi_type** atypes) { - std::unordered_map, std::shared_ptr, SignatureHash>::const_iterator it = FFICache::global()->cifCache.find(this->signatureVector); + FFICache::FFIMap::const_iterator it = FFICache::global()->cifCache.find(this->signatureVector); if (it == FFICache::global()->cifCache.end()) { std::shared_ptr shared(new ffi_cif, deleteCif); @@ -88,7 +88,7 @@ std::shared_ptr FFICall::getCif(unsigned int nargs, ffi_type* rtype, ff FFICall::~FFICall() { if (this->_cif.use_count() == 2) { - std::unordered_map, std::shared_ptr, SignatureHash>::const_iterator it; + FFICache::FFIMap::const_iterator it; it = FFICache::global()->cifCache.find(this->signatureVector); FFICache::global()->cifCache.erase(it); }