Skip to content

Commit 64ceb38

Browse files
committed
Merge pull request #416 from NativeScript/pete/unify-method-constructor-pipeline
Change and normalize object instantiation in C++
2 parents 466619b + 7c4f2d4 commit 64ceb38

20 files changed

+1070
-848
lines changed

src/jni/CallbackHandlers.cpp

Lines changed: 56 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ void CallbackHandlers::Init(Isolate *isolate, ObjectManager *objectManager)
3939
RESOLVE_CLASS_METHOD_ID = env.GetMethodID(RUNTIME_CLASS, "resolveClass", "(Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/Class;");
4040
assert(RESOLVE_CLASS_METHOD_ID != nullptr);
4141

42-
CREATE_INSTANCE_METHOD_ID = env.GetMethodID(RUNTIME_CLASS, "createInstance", "([Ljava/lang/Object;II)Ljava/lang/Object;");
43-
assert(CREATE_INSTANCE_METHOD_ID != nullptr);
42+
CURRENT_OBJECTID_FIELD_ID = env.GetFieldID(RUNTIME_CLASS, "currentObjectId", "I");
43+
assert(CURRENT_OBJECTID_FIELD_ID != nullptr);
4444

45-
CACHE_CONSTRUCTOR_METHOD_ID = env.GetMethodID(RUNTIME_CLASS, "cacheConstructor", "(Ljava/lang/Class;[Ljava/lang/Object;)I");
46-
assert(CACHE_CONSTRUCTOR_METHOD_ID != nullptr);
45+
MAKE_INSTANCE_STRONG_ID = env.GetMethodID(RUNTIME_CLASS, "makeInstanceStrong", "(Ljava/lang/Object;I)V");
46+
assert(MAKE_INSTANCE_STRONG_ID != nullptr);
4747

4848
GET_TYPE_METADATA = env.GetStaticMethodID(RUNTIME_CLASS, "getTypeMetadata", "(Ljava/lang/String;I)[Ljava/lang/String;");
4949
assert(GET_TYPE_METADATA != nullptr);
@@ -80,7 +80,31 @@ bool CallbackHandlers::RegisterInstance(Isolate *isolate, const Local<Object>& j
8080
DEBUG_WRITE("RegisterInstance: Linking new instance");
8181
objectManager->Link(jsObject, javaObjectID, nullptr);
8282

83-
jobject instance = CreateJavaInstance(javaObjectID, fullClassName, argWrapper, generatedJavaClass, isInterface);
83+
// resolve constructor
84+
auto mi = MethodCache::ResolveConstructorSignature(argWrapper, fullClassName, generatedJavaClass, isInterface);
85+
86+
jobject instance;
87+
88+
{
89+
JavaObjectIdScope objIdScope(env, CURRENT_OBJECTID_FIELD_ID, runtime->GetJavaRuntime(), javaObjectID);
90+
91+
if(argWrapper.type == ArgType::Interface)
92+
{
93+
instance = env.NewObject(generatedJavaClass, mi.mid);
94+
}
95+
else
96+
{
97+
// resolve arguments before passing them on to the constructor
98+
JsArgConverter argConverter(argWrapper.args, mi.signature, argWrapper.outerThis);
99+
auto ctorArgs = argConverter.ToArgs();
100+
101+
instance = env.NewObjectA(generatedJavaClass, mi.mid, ctorArgs);
102+
}
103+
}
104+
105+
env.CallVoidMethod(runtime->GetJavaRuntime(), MAKE_INSTANCE_STRONG_ID, instance, javaObjectID);
106+
107+
AdjustAmountOfExternalAllocatedMemory(env, isolate);
84108

85109
JniLocalRef localInstance(instance);
86110
success = !localInstance.IsNull();
@@ -113,14 +137,14 @@ jclass CallbackHandlers::ResolveClass(Isolate *isolate, const string& fullClassn
113137
{
114138
JEnv env;
115139

116-
//get needed arguments in order to load binding
140+
// get needed arguments in order to load binding
117141
JniLocalRef javaFullClassName(env.NewStringUTF(fullClassname.c_str()));
118142

119143
jobjectArray methodOverrides = GetMethodOverrides(env, implementationObject);
120144

121145
auto runtime = Runtime::GetRuntime(isolate);
122146

123-
//create or load generated binding (java class)
147+
// create or load generated binding (java class)
124148
JniLocalRef generatedClass(env.CallObjectMethod(runtime->GetJavaRuntime(), RESOLVE_CLASS_METHOD_ID, (jstring) javaFullClassName, methodOverrides));
125149
globalRefToGeneratedClass = static_cast<jclass>(env.NewGlobalRef(generatedClass));
126150

@@ -196,8 +220,8 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
196220
}
197221

198222
entry->memberId = isStatic ?
199-
env.GetStaticMethodID(clazz, methodName, entry->sig) :
200-
env.GetMethodID(clazz, methodName, entry->sig);
223+
env.GetStaticMethodID(clazz, methodName, entry->sig) :
224+
env.GetMethodID(clazz, methodName, entry->sig);
201225

202226
if (entry->memberId == nullptr)
203227
{
@@ -209,8 +233,8 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
209233
else
210234
{
211235
entry->memberId = isStatic ?
212-
env.GetStaticMethodID(clazz, methodName, entry->sig) :
213-
env.GetMethodID(clazz, methodName, entry->sig);
236+
env.GetStaticMethodID(clazz, methodName, entry->sig) :
237+
env.GetMethodID(clazz, methodName, entry->sig);
214238

215239
if (entry->memberId == nullptr)
216240
{
@@ -302,7 +326,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
302326
switch (retType)
303327
{
304328
case MethodReturnType::Void:
305-
{
329+
{
306330
if (isStatic)
307331
{
308332
env.CallStaticVoidMethodA(clazz, mid, javaArgs);
@@ -318,7 +342,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
318342
break;
319343
}
320344
case MethodReturnType::Boolean:
321-
{
345+
{
322346
jboolean result;
323347
if (isStatic)
324348
{
@@ -336,7 +360,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
336360
break;
337361
}
338362
case MethodReturnType::Byte:
339-
{
363+
{
340364
jbyte result;
341365
if (isStatic)
342366
{
@@ -354,7 +378,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
354378
break;
355379
}
356380
case MethodReturnType::Char:
357-
{
381+
{
358382
jchar result;
359383
if (isStatic)
360384
{
@@ -377,7 +401,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
377401
break;
378402
}
379403
case MethodReturnType::Short:
380-
{
404+
{
381405
jshort result;
382406
if (isStatic)
383407
{
@@ -395,7 +419,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
395419
break;
396420
}
397421
case MethodReturnType::Int:
398-
{
422+
{
399423
jint result;
400424
if (isStatic)
401425
{
@@ -414,7 +438,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
414438

415439
}
416440
case MethodReturnType::Long:
417-
{
441+
{
418442
jlong result;
419443
if (isStatic)
420444
{
@@ -433,7 +457,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
433457
break;
434458
}
435459
case MethodReturnType::Float:
436-
{
460+
{
437461
jfloat result;
438462
if (isStatic)
439463
{
@@ -451,7 +475,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
451475
break;
452476
}
453477
case MethodReturnType::Double:
454-
{
478+
{
455479
jdouble result;
456480
if (isStatic)
457481
{
@@ -469,7 +493,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
469493
break;
470494
}
471495
case MethodReturnType::String:
472-
{
496+
{
473497
jobject result = nullptr;
474498
bool exceptionOccurred;
475499

@@ -500,7 +524,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
500524
break;
501525
}
502526
case MethodReturnType::Object:
503-
{
527+
{
504528
jobject result = nullptr;
505529
bool exceptionOccurred;
506530

@@ -548,7 +572,7 @@ void CallbackHandlers::CallJavaMethod(const Local<Object>& caller, const string&
548572
break;
549573
}
550574
default:
551-
{
575+
{
552576
assert(false);
553577
break;
554578
}
@@ -569,9 +593,9 @@ int64_t CallbackHandlers::AdjustAmountOfExternalAllocatedMemory(JEnv& env, Isola
569593
int64_t changeInBytes = env.CallLongMethod(runtime->GetJavaRuntime(), GET_CHANGE_IN_BYTES_OF_USED_MEMORY_METHOD_ID);
570594

571595
int64_t adjustedValue = (changeInBytes != 0)
572-
? isolate->AdjustAmountOfExternalAllocatedMemory(changeInBytes)
573-
:
574-
0;
596+
? isolate->AdjustAmountOfExternalAllocatedMemory(changeInBytes)
597+
:
598+
0;
575599

576600
return adjustedValue;
577601
}
@@ -584,68 +608,6 @@ Local<Object> CallbackHandlers::CreateJSWrapper(Isolate *isolate, jint javaObjec
584608
return objectManager->CreateJSWrapper(javaObjectID, typeName);
585609
}
586610

587-
jobject CallbackHandlers::CreateJavaInstance(int objectID, const std::string& fullClassName, const ArgsWrapper& argWrapper, jclass javaClass, bool isInterface)
588-
{
589-
SET_PROFILER_FRAME();
590-
591-
jobject instance = nullptr;
592-
DEBUG_WRITE("CreateJavaInstance: %s", fullClassName.c_str());
593-
594-
JEnv env;
595-
auto& args = argWrapper.args;
596-
597-
JsArgToArrayConverter argConverter(args, isInterface, argWrapper.outerThis);
598-
if (argConverter.IsValid())
599-
{
600-
jobjectArray javaArgs = argConverter.ToJavaArray();
601-
602-
int ctorId = GetCachedConstructorId(env, args, fullClassName, javaArgs, javaClass);
603-
604-
auto runtime = Runtime::GetRuntime(args.GetIsolate());
605-
606-
jobject obj = env.CallObjectMethod(runtime->GetJavaRuntime(),
607-
CREATE_INSTANCE_METHOD_ID,
608-
javaArgs,
609-
(jint) objectID,
610-
ctorId);
611-
612-
instance = obj;
613-
}
614-
else
615-
{
616-
JsArgToArrayConverter::Error err = argConverter.GetError();
617-
throw NativeScriptException(err.msg);
618-
}
619-
620-
return instance;
621-
}
622-
623-
int CallbackHandlers::GetCachedConstructorId(JEnv& env, const FunctionCallbackInfo<Value>& args, const string& fullClassName, jobjectArray javaArgs, jclass javaClass)
624-
{
625-
int ctorId = -1;
626-
string encodedCtorArgs = MethodCache::EncodeSignature(fullClassName, "<init>", args, false);
627-
auto itFound = s_constructorCache.find(encodedCtorArgs);
628-
629-
if (itFound != s_constructorCache.end())
630-
{
631-
ctorId = itFound->second;
632-
}
633-
else
634-
{
635-
auto runtime = Runtime::GetRuntime(args.GetIsolate());
636-
jint id = env.CallIntMethod(runtime->GetJavaRuntime(), CACHE_CONSTRUCTOR_METHOD_ID, javaClass, javaArgs);
637-
638-
if (env.ExceptionCheck() == JNI_FALSE)
639-
{
640-
ctorId = id;
641-
s_constructorCache.insert(make_pair(encodedCtorArgs, ctorId));
642-
}
643-
}
644-
645-
DEBUG_WRITE("GetCachedConstructorId: encodedCtorArgs=%s, ctorId=%d", encodedCtorArgs.c_str(), ctorId);
646-
return ctorId;
647-
}
648-
649611
//delete the returned local reference after use
650612
jobjectArray CallbackHandlers::GetMethodOverrides(JEnv& env, const Local<Object>& implementationObject)
651613
{
@@ -702,7 +664,7 @@ void CallbackHandlers::LogMethodCallback(const v8::FunctionCallbackInfo<v8::Valu
702664
e.ReThrowToV8();
703665
}
704666
catch (std::exception e) {
705-
stringstream ss;
667+
stringstream ss;
706668
ss << "Error: c++ exception: " << e.what() << endl;
707669
NativeScriptException nsEx(ss.str());
708670
nsEx.ReThrowToV8();
@@ -738,7 +700,7 @@ void CallbackHandlers::DumpReferenceTablesMethod()
738700
e.ReThrowToV8();
739701
}
740702
catch (std::exception e) {
741-
stringstream ss;
703+
stringstream ss;
742704
ss << "Error: c++ exception: " << e.what() << endl;
743705
NativeScriptException nsEx(ss.str());
744706
nsEx.ReThrowToV8();
@@ -764,7 +726,7 @@ void CallbackHandlers::EnableVerboseLoggingMethodCallback(const v8::FunctionCall
764726
e.ReThrowToV8();
765727
}
766728
catch (std::exception e) {
767-
stringstream ss;
729+
stringstream ss;
768730
ss << "Error: c++ exception: " << e.what() << endl;
769731
NativeScriptException nsEx(ss.str());
770732
nsEx.ReThrowToV8();
@@ -790,7 +752,7 @@ void CallbackHandlers::DisableVerboseLoggingMethodCallback(const v8::FunctionCal
790752
e.ReThrowToV8();
791753
}
792754
catch (std::exception e) {
793-
stringstream ss;
755+
stringstream ss;
794756
ss << "Error: c++ exception: " << e.what() << endl;
795757
NativeScriptException nsEx(ss.str());
796758
nsEx.ReThrowToV8();
@@ -939,9 +901,9 @@ int CallbackHandlers::GetArrayLength(Isolate *isolate, const Local<Object>& arr)
939901

940902
jclass CallbackHandlers::RUNTIME_CLASS = nullptr;
941903
jclass CallbackHandlers::JAVA_LANG_STRING = nullptr;
904+
jfieldID CallbackHandlers::CURRENT_OBJECTID_FIELD_ID = nullptr;
942905
jmethodID CallbackHandlers::RESOLVE_CLASS_METHOD_ID = nullptr;
943-
jmethodID CallbackHandlers::CREATE_INSTANCE_METHOD_ID = nullptr;
944-
jmethodID CallbackHandlers::CACHE_CONSTRUCTOR_METHOD_ID = nullptr;
906+
jmethodID CallbackHandlers::MAKE_INSTANCE_STRONG_ID = nullptr;
945907
jmethodID CallbackHandlers::GET_TYPE_METADATA = nullptr;
946908
jmethodID CallbackHandlers::ENABLE_VERBOSE_LOGGING_METHOD_ID = nullptr;
947909
jmethodID CallbackHandlers::DISABLE_VERBOSE_LOGGING_METHOD_ID = nullptr;

src/jni/CallbackHandlers.h

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,13 @@ namespace tns
2727

2828
static v8::Local<v8::Object> CreateJSWrapper(v8::Isolate *isolate, jint javaObjectID, const std::string& typeName);
2929

30-
static jobject CreateJavaInstance(int objectID, const std::string& fullClassName, const ArgsWrapper& argWrapper, jclass javaClass, bool isInterface);
31-
3230
static bool RegisterInstance(v8::Isolate *isolate, const v8::Local<v8::Object>& jsObject, const std::string& fullClassName, const ArgsWrapper& argWrapper, const v8::Local<v8::Object>& implementationObject, bool isInterface);
3331

32+
static std::string ResolveConstructor(v8::Isolate *isolate, const ArgsWrapper& argWrapper, const std::string& fullClassName, jclass javaClass, bool isInterface);
33+
3434
static jclass ResolveClass(v8::Isolate *isolate, const std::string& fullClassname, const v8::Local<v8::Object>& implementationObject);
3535

3636
static std::string ResolveClassName(v8::Isolate *isolate, const std::string& fullClassname, const v8::Local<v8::Object>& implementationObject);
37-
//
3837

3938
static v8::Local<v8::Value> GetArrayElement(v8::Isolate *isolate, const v8::Local<v8::Object>& array, uint32_t index, const std::string& arraySignature);
4039

@@ -101,9 +100,9 @@ namespace tns
101100

102101
static jmethodID RESOLVE_CLASS_METHOD_ID;
103102

104-
static jmethodID CREATE_INSTANCE_METHOD_ID;
103+
static jfieldID CURRENT_OBJECTID_FIELD_ID;
105104

106-
static jmethodID CACHE_CONSTRUCTOR_METHOD_ID;
105+
static jmethodID MAKE_INSTANCE_STRONG_ID;
107106

108107
static jmethodID GET_TYPE_METADATA;
109108

@@ -124,6 +123,25 @@ namespace tns
124123
static std::map<std::string, int> s_constructorCache;
125124

126125
static std::map<std::string, jclass> s_classCache;
126+
127+
struct JavaObjectIdScope
128+
{
129+
JavaObjectIdScope(JEnv& env, jfieldID fieldId, jobject runtime, int javaObjectId)
130+
: _env(env), _fieldID(fieldId), _runtime(runtime)
131+
{
132+
_env.SetIntField(_runtime, _fieldID, javaObjectId);
133+
}
134+
135+
~JavaObjectIdScope()
136+
{
137+
_env.SetIntField(_runtime, _fieldID, -1);
138+
}
139+
140+
private:
141+
JEnv _env;
142+
jfieldID _fieldID;
143+
jobject _runtime;
144+
};
127145
};
128146
}
129147

src/jni/JEnv.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,13 @@ namespace tns
316316

317317
}
318318

319+
jobject NewObjectA(jclass clazz, jmethodID methodID, jvalue *args)
320+
{
321+
jobject jo = m_env->NewObjectA(clazz, methodID, args);
322+
CheckForJavaException();
323+
return jo;
324+
}
325+
319326
static void Init(JavaVM *jvm);
320327

321328
private:

0 commit comments

Comments
 (0)