@@ -82,19 +82,17 @@ JniLocalRef ObjectManager::GetJavaObjectByJsObject(const Local<Object>& object)
82
82
return JniLocalRef ();
83
83
}
84
84
85
- JSInstanceInfo* ObjectManager::GetJSInstanceInfo (const Local<Object>& object)
85
+ ObjectManager:: JSInstanceInfo* ObjectManager::GetJSInstanceInfo (const Local<Object>& object)
86
86
{
87
87
DEBUG_WRITE (" ObjectManager::GetJSInstanceInfo: called" );
88
88
JSInstanceInfo *jsInstanceInfo = nullptr ;
89
89
90
90
auto isolate = Isolate::GetCurrent ();
91
91
HandleScope handleScope (isolate);
92
92
93
- int internalFieldCound = NativeScriptExtension::GetInternalFieldCount (object);
94
- const int count = static_cast <int >(MetadataNodeKeys::END);
95
- const int jsInfoIdx = static_cast <int >(MetadataNodeKeys::JsInfo);
96
- if (internalFieldCound == count)
93
+ if (IsJsRuntimeObject (object))
97
94
{
95
+ const int jsInfoIdx = static_cast <int >(MetadataNodeKeys::JsInfo);
98
96
auto jsInfo = object->GetInternalField (jsInfoIdx);
99
97
if (jsInfo->IsUndefined ())
100
98
{
@@ -104,8 +102,7 @@ JSInstanceInfo* ObjectManager::GetJSInstanceInfo(const Local<Object>& object)
104
102
if (!prototypeObject.IsEmpty () && prototypeObject->IsObject ())
105
103
{
106
104
DEBUG_WRITE (" GetJSInstanceInfo: need to check prototype :%d" , prototypeObject->GetIdentityHash ());
107
- internalFieldCound = NativeScriptExtension::GetInternalFieldCount (prototypeObject);
108
- if (internalFieldCound == count)
105
+ if (IsJsRuntimeObject (prototypeObject))
109
106
{
110
107
jsInfo = prototypeObject->GetInternalField (jsInfoIdx);
111
108
}
@@ -122,6 +119,12 @@ JSInstanceInfo* ObjectManager::GetJSInstanceInfo(const Local<Object>& object)
122
119
return jsInstanceInfo;
123
120
}
124
121
122
+ bool ObjectManager::IsJsRuntimeObject (const v8::Local<v8::Object>& object) {
123
+ int internalFieldCount = NativeScriptExtension::GetInternalFieldCount (object);
124
+ const int count = static_cast <int >(MetadataNodeKeys::END);
125
+ return internalFieldCount == count;
126
+ }
127
+
125
128
jweak ObjectManager::GetJavaObjectByID (uint32_t javaObjectID)
126
129
{
127
130
jweak obj = m_cache (javaObjectID);
@@ -145,7 +148,7 @@ jclass ObjectManager::GetJavaClass(const Local<Object>& instance)
145
148
DEBUG_WRITE (" GetClass called" );
146
149
147
150
JSInstanceInfo *jsInfo = GetJSInstanceInfo (instance);
148
- jclass clazz = jsInfo->clazz ;
151
+ jclass clazz = jsInfo->ObjectClazz ;
149
152
150
153
return clazz;
151
154
}
@@ -155,7 +158,7 @@ void ObjectManager::SetJavaClass(const Local<Object>& instance, jclass clazz)
155
158
DEBUG_WRITE (" SetClass called" );
156
159
157
160
JSInstanceInfo *jsInfo = GetJSInstanceInfo (instance);
158
- jsInfo->clazz = clazz;
161
+ jsInfo->ObjectClazz = clazz;
159
162
}
160
163
161
164
int ObjectManager::GetOrCreateObjectId (jobject object)
@@ -213,11 +216,13 @@ Local<Object> ObjectManager::CreateJSWrapperHelper(jint javaObjectID, const stri
213
216
return jsWrapper;
214
217
}
215
218
219
+
220
+ /* *
221
+ * Link the JavaScript object and it's java counterpart with an ID
222
+ */
216
223
void ObjectManager::Link (const Local<Object>& object, uint32_t javaObjectID, jclass clazz)
217
224
{
218
- int internalFieldCound = NativeScriptExtension::GetInternalFieldCount (object);
219
- const int count = static_cast <int >(MetadataNodeKeys::END);
220
- if (internalFieldCound != count)
225
+ if (!IsJsRuntimeObject (object))
221
226
{
222
227
string errMsg (" Trying to link invalid 'this' to a Java object" );
223
228
throw NativeScriptException (errMsg);
@@ -227,19 +232,19 @@ void ObjectManager::Link(const Local<Object>& object, uint32_t javaObjectID, jcl
227
232
228
233
DEBUG_WRITE (" Linking js object: %d and java instance id: %d" , object->GetIdentityHash (), javaObjectID);
229
234
230
- auto jsInstanceInfo = new JSInstanceInfo ();
231
- jsInstanceInfo->JavaObjectID = javaObjectID;
232
- jsInstanceInfo->clazz = clazz;
235
+ auto jsInstanceInfo = new JSInstanceInfo (false /* isJavaObjWeak*/ , javaObjectID, clazz);
233
236
234
237
auto objectHandle = new Persistent<Object>(isolate, object);
235
238
auto state = new ObjectWeakCallbackState (this , jsInstanceInfo, objectHandle);
239
+
240
+ // subscribe for JS GC event
236
241
objectHandle->SetWeak (state, JSObjectWeakCallbackStatic);
237
242
238
243
auto jsInfoIdx = static_cast <int >(MetadataNodeKeys::JsInfo);
239
- bool alreadyLinked = !object->GetInternalField (jsInfoIdx)->IsUndefined ();
240
- // TODO: fail if alreadyLinked is true?
241
244
242
245
auto jsInfo = External::New (isolate, jsInstanceInfo);
246
+
247
+ // link
243
248
object->SetInternalField (jsInfoIdx, jsInfo);
244
249
245
250
idToObject.insert (make_pair (javaObjectID, objectHandle));
@@ -290,6 +295,14 @@ void ObjectManager::JSObjectWeakCallbackStatic(const WeakCallbackData<Object, Ob
290
295
thisPtr->JSObjectWeakCallback (isolate, callbackState);
291
296
}
292
297
298
+ /*
299
+ * When JS GC happens change state of the java counterpart to mirror state of JS object and REVIVE the JS object unconditionally
300
+ * "Regular" js objects are pushed into the "regular objects" array
301
+ * "Callback" js objects (ones that have implementation object) are pushed into two "special objects" array:
302
+ * -ones called for the first time which are originally strong in java
303
+ * -ones called for the second or next time which are already weak in java too
304
+ * These objects are categorized by "regular" and "callback" and saved in different arrays for performance optimizations during GC
305
+ * */
293
306
void ObjectManager::JSObjectWeakCallback (Isolate *isolate, ObjectWeakCallbackState *callbackState)
294
307
{
295
308
DEBUG_WRITE (" JSObjectWeakCallback called" );
@@ -305,7 +318,6 @@ void ObjectManager::JSObjectWeakCallback(Isolate *isolate, ObjectWeakCallbackSta
305
318
m_visitedPOs.insert (po);
306
319
307
320
auto obj = Local<Object>::New (isolate, *po);
308
-
309
321
JSInstanceInfo *jsInstanceInfo = GetJSInstanceInfo (obj);
310
322
int javaObjectID = jsInstanceInfo->JavaObjectID ;
311
323
@@ -370,6 +382,9 @@ void ObjectManager::ReleaseJSInstance(Persistent<Object> *po, JSInstanceInfo *js
370
382
DEBUG_WRITE (" ReleaseJSObject instance disposed. id:%d" , javaObjectID);
371
383
}
372
384
385
+ /*
386
+ * The "regular" JS objects added on ObjectManager::JSObjectWeakCallback are dealt with(released) here.
387
+ * */
373
388
void ObjectManager::ReleaseRegularObjects ()
374
389
{
375
390
Isolate *isolate = Isolate::GetCurrent ();
@@ -399,6 +414,7 @@ void ObjectManager::ReleaseRegularObjects()
399
414
{
400
415
int objGcNum = gcNum->Int32Value ();
401
416
417
+ // done so we can release only java objects from this GC stack and pass all objects that will be released in parent GC stacks
402
418
isReachableFromImplementationObject = objGcNum >= numberOfGC;
403
419
}
404
420
@@ -427,6 +443,10 @@ bool ObjectManager::HasImplObject(Isolate *isolate, const Local<Object>& obj)
427
443
return hasImplObj;
428
444
}
429
445
446
+ /*
447
+ * When "MarkReachableObjects" is called V8 has marked all JS objects that can be released.
448
+ * This method builds on top of V8s marking phase, because we need to consider the JAVA counterpart objects (is it "regular" or "callback"), when marking JS ones.
449
+ * */
430
450
void ObjectManager::MarkReachableObjects (Isolate *isolate, const Local<Object>& obj)
431
451
{
432
452
stack<Local<Value> > s;
@@ -461,6 +481,9 @@ void ObjectManager::MarkReachableObjects(Isolate *isolate, const Local<Object>&
461
481
auto hasImplObject = HasImplObject (isolate, o);
462
482
if (hasImplObject)
463
483
{
484
+ // this is a special case when one "callback1" object (one we are currently traversing)
485
+ // can reach another "callback2" object (jsInfo->JavaObjectID)
486
+ // here we are leaving "callback2" object to remain strong in java
464
487
m_implObjStrong[jsInfo->JavaObjectID ] = nullptr ;
465
488
}
466
489
o->SetHiddenValue (propName, curGCNumValue);
@@ -615,10 +638,14 @@ void ObjectManager::OnGcStarted(GCType type, GCCallbackFlags flags)
615
638
m_markedForGC.push (gcInfo);
616
639
}
617
640
641
+ /*
642
+ * When GC is called we need to evaluate the situation and decide what js objects to release
643
+ * */
618
644
void ObjectManager::OnGcFinished (GCType type, GCCallbackFlags flags)
619
645
{
620
646
assert (!m_markedForGC.empty ());
621
647
648
+ // deal with all "callback" objects
622
649
auto isolate = Isolate::GetCurrent ();
623
650
for (auto weakObj : m_implObjWeak)
624
651
{
@@ -635,6 +662,7 @@ void ObjectManager::OnGcFinished(GCType type, GCCallbackFlags flags)
635
662
}
636
663
}
637
664
665
+ // deal with regular objects
638
666
ReleaseRegularObjects ();
639
667
640
668
m_markedForGC.pop ();
@@ -656,6 +684,10 @@ void ObjectManager::OnGcFinished(GCType type, GCCallbackFlags flags)
656
684
}
657
685
}
658
686
687
+ /*
688
+ * We have all the JS "regular" objects that JS has made weak and ready to by GC'd,
689
+ * so we tell java to take the JAVA objects out of strong reference so they can be collected by JAVA GC
690
+ * */
659
691
void ObjectManager::MakeRegularObjectsWeak (const set<int >& instances, DirectBuffer& inputBuff)
660
692
{
661
693
jboolean keepAsWeak = JNI_FALSE;
@@ -682,6 +714,11 @@ void ObjectManager::MakeRegularObjectsWeak(const set<int>& instances, DirectBuff
682
714
inputBuff.Reset ();
683
715
}
684
716
717
+ /*
718
+ * We have all the JS "callback" objects that JS has made weak and ready to by GC'd,
719
+ * so we tell java to take the JAVA objects out of strong, BUT KEEP THEM AS WEEK REFERENCES,
720
+ * so that if java needs to release them, it can, on a later stage.
721
+ * */
685
722
void ObjectManager::MakeImplObjectsWeak (const map<int , Persistent<Object>*>& instances, DirectBuffer& inputBuff)
686
723
{
687
724
jboolean keepAsWeak = JNI_TRUE;
@@ -715,6 +752,10 @@ void ObjectManager::MakeImplObjectsWeak(const map<int, Persistent<Object>*>& ins
715
752
inputBuff.Reset ();
716
753
}
717
754
755
+ /*
756
+ * Consult with JAVA world to check if a java object is still in kept as a strong or weak reference
757
+ * If the JAVA objects are released, we can release the their counterpart JS objects
758
+ * */
718
759
void ObjectManager::CheckWeakObjectsAreAlive (const vector<PersistentObjectIdPair>& instances, DirectBuffer& inputBuff, DirectBuffer& outputBuff)
719
760
{
720
761
for (const auto & poIdPair : instances)
0 commit comments