-
-
Save ochafik/fe02564f0ce243fead9ec7d1e90ea0e0 to your computer and use it in GitHub Desktop.
BridJ JNI trampolines using modern C++ (Variadic macros + lambdas) instead of hacky ASM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct JNIEnv {}; | |
| typedef void *jobject; | |
| #if 32BITS | |
| #define SIGIL_PTR_VALUE1 0xFEDCBA91 | |
| #define SIGIL_PTR_VALUE2 0xFEDCBA92 | |
| #define SIGIL_PTR_VALUE3 0xFEDCBA93 | |
| #else | |
| #define SIGIL_PTR_VALUE1 0xFEDCBA9876543211 | |
| #define SIGIL_PTR_VALUE2 0xFEDCBA9876543212 | |
| #define SIGIL_PTR_VALUE3 0xFEDCBA9876543213 | |
| #endif | |
| // https://en.cppreference.com/w/cpp/language/parameter_pack | |
| template <class RetType, class... ArgTypes> | |
| RetType callTrampolineTemplate(JNIEnv* env, jobject obj, ArgTypes... args) { | |
| typedef RetType (*FnType)(...ArgTypes); | |
| return ((FnType)SIGIL_PTR_VALUE1)(&args...); | |
| } | |
| template <class RetType, class... ArgTypes> | |
| RetType callbackTrampolineTemplate(ArgTypes... args) { | |
| typedef RetType (*FnType)(jobject, ...ArgTypes); | |
| return ((FnType)SIGIL_PTR_VALUE1)((jobject)SIGIL_PTR_VALUE2, &args...); | |
| } | |
| void* getCallTrampolineTemplate(const char* signature) { | |
| static std::map<std::string, void*> templates; | |
| if (templates.empty()) { | |
| templates[")b"] = callTrampolineTemplate<bool>; | |
| templates["i)b"] = callTrampolineTemplate<bool, int>; | |
| templates["l)b"] = callTrampolineTemplate<bool, long>; | |
| templates["ll)l"] = callTrampolineTemplate<long, long, long>; | |
| //... autogenerate these! | |
| } | |
| return templates[signature]; | |
| } | |
| void* getCallTrampoline(const char* signature, void *f) { | |
| void *tmpl = getCallTrampolineTemplate(signature); | |
| if (!tmpl) { | |
| return nullptr; | |
| } | |
| return instantiateTemplateFunction1(tmpl, SIGIL_PTR_VALUE1, f); | |
| } | |
| void* getCallbackTrampolineTemplate(const char* signature) { | |
| static std::map<std::string, void*> templates; | |
| if (templates.empty()) { | |
| templates[")b"] = callbackTrampolineTemplate<bool>; | |
| templates["i)b"] = callbackTrampolineTemplate<bool, int>; | |
| templates["l)b"] = callbackTrampolineTemplate<bool, long>; | |
| templates["ll)l"] = callbackTrampolineTemplate<long, long, long>; | |
| //... autogenerate these! | |
| } | |
| return templates[signature]; | |
| } | |
| void* getCallbackTrampoline(const char* signature, JNIEnv *env, jobject obj, void *f) { | |
| void *tmpl = getCallTrampolineTemplate(signature); | |
| if (!tmpl) { | |
| return nullptr; | |
| } | |
| void *caller = nullptr; | |
| switch (getReturnSig(signature)) { | |
| case 'i': | |
| caller = env->CallIntMethod; | |
| break; | |
| //... | |
| default: | |
| return nullptr; | |
| } | |
| return instantiateTemplateFunction2(tmpl, SIGIL_PTR_VALUE1, caller, SIGIL_PTR_VALUE2, obj); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct JNIEnv {}; | |
| typedef void *jobject; | |
| typedef void *jobjectOrClass; | |
| jfieldID = callbackPointerFieldId | |
| // https://en.cppreference.com/w/cpp/language/parameter_pack | |
| template <class RetType, class... ArgTypes> | |
| RetType trampoline(JNIEnv* env, jobject obj, ArgTypes... args) { | |
| jlong fptr = env->GetLongField(obj, callbackPointerFieldId); | |
| typedef RetType (*FnType)(...ArgTypes); | |
| FnType f = (FnType)(size_t)fptr; | |
| return f(&args...); | |
| } | |
| void* org_bridj_JNI_getJNITampoline(JNIEnv *env, jclass clz, const char* signature) { | |
| static std::map<std::string, void*> trampolines; | |
| if (trampolines.empty()) { | |
| trampolines[")b"] = trampoline<bool>; | |
| trampolines["i)b"] = trampoline<bool, int>; | |
| trampolines["l)b"] = trampoline<bool, long>; | |
| trampolines["ll)l"] = trampoline<long, long, long>; | |
| //... autogenerate these! | |
| } | |
| return trampolines[signature]; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct JNIEnv {}; | |
| typedef void *jobjectOrClass; | |
| class JNITrampolineBase { | |
| virtual ~JNITrampolineBase() {} | |
| virtual void* getFunctionPointer() = 0; | |
| }; | |
| template <class RetType, class... ArgTypes> | |
| class JNITrampoline: public JNITrampolineBase { | |
| typedef std::function<RetType (...ArgTypes)> LambdaType; | |
| typedef RetType (*TargetFunctionType)(...ArgTypes); | |
| typedef RetType (*TrampolineFunctionType)(JNIEnv*, jobjectOrClass, ...ArgTypes); | |
| // FnType *fptr; | |
| LambdaType _lambda; | |
| JNITrampoline(LambdaType _lambda) : _lambda(lambda) {} | |
| static JNITrampoline<RetType, ArgTypes...>* create(const TargetFunctionType* target) { | |
| return new JNITrampoline<RetType, ArgTypes...>( | |
| [=target](JNIEnv*, jobjectOrClass, ArgTypes... args) -> RetType { | |
| return target(&args...); | |
| }); | |
| } | |
| // JNITrampoline(const LambdaType &lambda): _lambda(lambda) {} | |
| virtual void* getFunctionPointer() override { | |
| auto p = (size_t*)(void*)&_lambda; | |
| // Skip 1 pointer at the beginning of the object | |
| return p + 1; | |
| } | |
| virtual ~Trampoline() {} | |
| }; | |
| // https://en.cppreference.com/w/cpp/language/parameter_pack | |
| JNITrampolineBase* createJNITampoline(const char* signature, void *fptr) { | |
| typedef JNITrampolineBase* (*TrampolineFactory)(void *); | |
| static std::map<std::string, TrampolineFactory> factories; | |
| if (factories.empty()) { | |
| factories[")b"] = JNITrampoline<bool>::create; | |
| factories["i)b"] = JNITrampoline<bool, int>::create; | |
| factories["l)b"] = JNITrampoline<bool, long>::create; | |
| factories["ll)l"] = JNITrampoline<long, long, long>::create; | |
| //... autogenerate these! | |
| } | |
| auto factory = factories[signature]; | |
| if (!factory) { | |
| return nullptr; | |
| } | |
| return factory(fptr); | |
| // auto tramp = new Trampoline() | |
| } | |
| void deleteJNITampoline(JNITrampolineBase* p) { | |
| delete p; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment