Skip to content

Commit 93760a0

Browse files
Merge pull request #829 from NativeScript/marking-mode-none
Marking mode none
2 parents 2e0f581 + 1708cba commit 93760a0

File tree

7 files changed

+194
-70
lines changed

7 files changed

+194
-70
lines changed

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,10 @@ obj/
1515
bin/
1616
.svn/
1717

18-
**/.vscode/
18+
**/.vscode/
19+
20+
.project
21+
.DS_Store
22+
.settings
23+
24+
build-artifacts/
Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package com.tns;
22

33
import java.io.File;
4-
54
import org.json.JSONObject;
6-
75
import android.os.Build;
86
import android.util.Log;
97

108
class AppConfig {
11-
private enum KnownKeys {
9+
protected enum KnownKeys {
1210
V8FlagsKey("v8Flags", "--expose_gc"),
1311
CodeCacheKey("codeCache", false),
1412
HeapSnapshotScriptKey("heapSnapshotScript", ""),
@@ -17,19 +15,8 @@ private enum KnownKeys {
1715
GcThrottleTime("gcThrottleTime", 0),
1816
MemoryCheckInterval("memoryCheckInterval", 0),
1917
FreeMemoryRatio("freeMemoryRatio", 0.0),
20-
Profiling("profiling", "");
21-
22-
public static final KnownKeys[] asArray = {
23-
V8FlagsKey,
24-
CodeCacheKey,
25-
HeapSnapshotScriptKey,
26-
SnapshotFile,
27-
ProfilerOutputDirKey,
28-
GcThrottleTime,
29-
MemoryCheckInterval,
30-
FreeMemoryRatio,
31-
Profiling
32-
};
18+
Profiling("profiling", ""),
19+
MarkingMode("markingMode", com.tns.MarkingMode.full);
3320

3421
private final String name;
3522
private final Object defaultValue;
@@ -42,19 +29,9 @@ private enum KnownKeys {
4229
public String getName() {
4330
return name;
4431
}
45-
4632
public Object getDefaultValue() {
4733
return defaultValue;
4834
}
49-
50-
int getIndex() {
51-
for (int i=0; i<asArray.length; i++) {
52-
if (asArray[i] == this) {
53-
return i;
54-
}
55-
}
56-
return -1;
57-
}
5835
}
5936

6037
private final static String AndroidKey = "android";
@@ -75,19 +52,19 @@ public AppConfig(File appDir) {
7552
if (rootObject != null) {
7653
if (rootObject.has(KnownKeys.Profiling.getName())) {
7754
String profiling = rootObject.getString(KnownKeys.Profiling.getName());
78-
values[KnownKeys.Profiling.getIndex()] = profiling;
55+
values[KnownKeys.Profiling.ordinal()] = profiling;
7956
}
8057
if (rootObject.has(AndroidKey)) {
8158
JSONObject androidObject = rootObject.getJSONObject(AndroidKey);
8259
if (androidObject.has(KnownKeys.V8FlagsKey.getName())) {
83-
values[KnownKeys.V8FlagsKey.getIndex()] = androidObject.getString(KnownKeys.V8FlagsKey.getName());
60+
values[KnownKeys.V8FlagsKey.ordinal()] = androidObject.getString(KnownKeys.V8FlagsKey.getName());
8461
}
8562
if (androidObject.has(KnownKeys.CodeCacheKey.getName())) {
86-
values[KnownKeys.CodeCacheKey.getIndex()] = androidObject.getBoolean(KnownKeys.CodeCacheKey.getName());
63+
values[KnownKeys.CodeCacheKey.ordinal()] = androidObject.getBoolean(KnownKeys.CodeCacheKey.getName());
8764
}
8865
if (androidObject.has(KnownKeys.HeapSnapshotScriptKey.getName())) {
8966
String value = androidObject.getString(KnownKeys.HeapSnapshotScriptKey.getName());
90-
values[KnownKeys.HeapSnapshotScriptKey.getIndex()] = FileSystem.resolveRelativePath(appDir.getPath(), value, appDir + "/app/");
67+
values[KnownKeys.HeapSnapshotScriptKey.ordinal()] = FileSystem.resolveRelativePath(appDir.getPath(), value, appDir + "/app/");
9168
}
9269
if (androidObject.has(HeapSnapshotBlobKey)) {
9370
String value = androidObject.getString(HeapSnapshotBlobKey);
@@ -96,20 +73,30 @@ public AppConfig(File appDir) {
9673
if (dir.exists() && dir.isDirectory()) {
9774
// this path is expected to be a directory, containing three sub-directories: armeabi-v7a, x86 and arm64-v8a
9875
path = path + "/" + Build.CPU_ABI + "/" + KnownKeys.SnapshotFile.getName();
99-
values[KnownKeys.SnapshotFile.getIndex()] = path;
76+
values[KnownKeys.SnapshotFile.ordinal()] = path;
10077
}
10178
}
10279
if (androidObject.has(KnownKeys.ProfilerOutputDirKey.getName())) {
103-
values[KnownKeys.ProfilerOutputDirKey.getIndex()] = androidObject.getString(KnownKeys.ProfilerOutputDirKey.getName());
80+
values[KnownKeys.ProfilerOutputDirKey.ordinal()] = androidObject.getString(KnownKeys.ProfilerOutputDirKey.getName());
10481
}
10582
if (androidObject.has(KnownKeys.GcThrottleTime.getName())) {
106-
values[KnownKeys.GcThrottleTime.getIndex()] = androidObject.getInt(KnownKeys.GcThrottleTime.getName());
83+
values[KnownKeys.GcThrottleTime.ordinal()] = androidObject.getInt(KnownKeys.GcThrottleTime.getName());
10784
}
10885
if (androidObject.has(KnownKeys.MemoryCheckInterval.getName())) {
109-
values[KnownKeys.MemoryCheckInterval.getIndex()] = androidObject.getInt(KnownKeys.MemoryCheckInterval.getName());
86+
values[KnownKeys.MemoryCheckInterval.ordinal()] = androidObject.getInt(KnownKeys.MemoryCheckInterval.getName());
11087
}
11188
if (androidObject.has(KnownKeys.FreeMemoryRatio.getName())) {
112-
values[KnownKeys.FreeMemoryRatio.getIndex()] = androidObject.getDouble(KnownKeys.FreeMemoryRatio.getName());
89+
values[KnownKeys.FreeMemoryRatio.ordinal()] = androidObject.getDouble(KnownKeys.FreeMemoryRatio.getName());
90+
}
91+
if (androidObject.has(KnownKeys.MarkingMode.getName())) {
92+
try {
93+
String markingModeString = androidObject.getString(KnownKeys.MarkingMode.getName());
94+
MarkingMode markingMode = MarkingMode.valueOf(markingModeString);
95+
values[KnownKeys.MarkingMode.ordinal()] = markingMode;
96+
} catch(Exception e) {
97+
e.printStackTrace();
98+
Log.v("JS", "Failed to parse marking mode. The default " + ((MarkingMode)KnownKeys.MarkingMode.getDefaultValue()).name() + " will be used.");
99+
}
113100
}
114101
}
115102
}
@@ -123,27 +110,28 @@ public Object[] getAsArray() {
123110
}
124111

125112
private static Object[] makeDefaultOptions() {
126-
Object[] result = new Object[KnownKeys.asArray.length];
127-
int index = 0;
128-
for (KnownKeys key: KnownKeys.asArray) {
129-
result[index++] = key.getDefaultValue();
113+
Object[] result = new Object[KnownKeys.values().length];
114+
for (KnownKeys key: KnownKeys.values()) {
115+
result[key.ordinal()] = key.getDefaultValue();
130116
}
131117
return result;
132118
}
133119

134120
public int getGcThrottleTime() {
135-
return (int)values[KnownKeys.GcThrottleTime.getIndex()];
121+
return (int)values[KnownKeys.GcThrottleTime.ordinal()];
136122
}
137123

138124
public int getMemoryCheckInterval() {
139-
return (int)values[KnownKeys.MemoryCheckInterval.getIndex()];
125+
return (int)values[KnownKeys.MemoryCheckInterval.ordinal()];
140126
}
141127

142128
public double getFreeMemoryRatio() {
143-
return (double)values[KnownKeys.FreeMemoryRatio.getIndex()];
129+
return (double)values[KnownKeys.FreeMemoryRatio.ordinal()];
144130
}
145131

146132
public String getProfilingMode() {
147-
return (String)values[KnownKeys.Profiling.getIndex()];
133+
return (String)values[KnownKeys.Profiling.ordinal()];
148134
}
135+
136+
public MarkingMode getMarkingMode() { return (MarkingMode)values[KnownKeys.MarkingMode.ordinal()]; }
149137
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.tns;
2+
3+
/**
4+
* Created by cankov on 24/08/2017.
5+
*/
6+
enum MarkingMode {
7+
full,
8+
none
9+
}

runtime/src/main/java/com/tns/Runtime.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,17 @@ public DynamicConfiguration getDynamicConfig() {
202202
return dynamicConfig;
203203
}
204204

205+
@RuntimeCallable
206+
public int getMarkingModeOrdinal() {
207+
if (staticConfiguration != null && staticConfiguration.appConfig != null) {
208+
return staticConfiguration.appConfig.getMarkingMode().ordinal();
209+
} else {
210+
return ((MarkingMode)AppConfig.KnownKeys.MarkingMode.getDefaultValue()).ordinal();
211+
}
212+
}
213+
205214
public static boolean isInitialized() {
206215
Runtime runtime = Runtime.getCurrentRuntime();
207-
208216
return (runtime != null) ? runtime.isInitializedImpl() : false;
209217
}
210218

@@ -806,6 +814,38 @@ private void makeInstanceWeak(ByteBuffer buff, int length, boolean keepAsWeak) {
806814
}
807815
}
808816

817+
@RuntimeCallable
818+
private boolean makeInstanceWeakAndCheckIfAlive(int javaObjectID) {
819+
if (logger.isEnabled()) {
820+
logger.write("makeInstanceWeakAndCheckIfAlive instance " + javaObjectID);
821+
}
822+
Object instance = strongInstances.get(javaObjectID);
823+
if (instance == null) {
824+
WeakReference<Object> ref = weakInstances.get(javaObjectID);
825+
if (ref == null) {
826+
return false;
827+
} else {
828+
instance = ref.get();
829+
if (instance == null) {
830+
// The Java was moved from strong to weak, and then the Java instance was collected.
831+
weakInstances.remove(javaObjectID);
832+
weakJavaObjectToID.remove(Integer.valueOf(javaObjectID));
833+
return false;
834+
} else {
835+
return true;
836+
}
837+
}
838+
} else {
839+
strongInstances.delete(javaObjectID);
840+
strongJavaObjectToID.remove(instance);
841+
842+
weakJavaObjectToID.put(instance, Integer.valueOf(javaObjectID));
843+
weakInstances.put(javaObjectID, new WeakReference<Object>(instance));
844+
845+
return true;
846+
}
847+
}
848+
809849
@RuntimeCallable
810850
private void checkWeakObjectAreAlive(ByteBuffer input, ByteBuffer output, int length) {
811851
input.position(0);

runtime/src/main/jni/ObjectManager.cpp

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@ using namespace v8;
1717
using namespace std;
1818
using namespace tns;
1919

20-
ObjectManager::ObjectManager(jobject javaRuntimeObject)
21-
: m_javaRuntimeObject(javaRuntimeObject), m_env(JEnv()), m_numberOfGC(0), m_currentObjectId(0), m_cache(NewWeakGlobalRefCallback, DeleteWeakGlobalRefCallback, 1000, this) {
20+
ObjectManager::ObjectManager(jobject javaRuntimeObject) :
21+
m_javaRuntimeObject(javaRuntimeObject),
22+
m_env(JEnv()),
23+
m_numberOfGC(0),
24+
m_currentObjectId(0),
25+
m_cache(NewWeakGlobalRefCallback, DeleteWeakGlobalRefCallback, 1000, this) {
26+
2227
auto runtimeClass = m_env.FindClass("com/tns/Runtime");
2328
assert(runtimeClass != nullptr);
2429

@@ -31,6 +36,9 @@ ObjectManager::ObjectManager(jobject javaRuntimeObject)
3136
MAKE_INSTANCE_WEAK_BATCH_METHOD_ID = m_env.GetMethodID(runtimeClass, "makeInstanceWeak", "(Ljava/nio/ByteBuffer;IZ)V");
3237
assert(MAKE_INSTANCE_WEAK_BATCH_METHOD_ID != nullptr);
3338

39+
MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID = m_env.GetMethodID(runtimeClass, "makeInstanceWeakAndCheckIfAlive", "(I)Z");
40+
assert(MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID != nullptr);
41+
3442
CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID = m_env.GetMethodID(runtimeClass, "checkWeakObjectAreAlive", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;I)V");
3543
assert(CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID != nullptr);
3644

@@ -45,6 +53,10 @@ ObjectManager::ObjectManager(jobject javaRuntimeObject)
4553

4654
auto useGlobalRefs = m_env.CallStaticBooleanMethod(runtimeClass, useGlobalRefsMethodID);
4755
m_useGlobalRefs = useGlobalRefs == JNI_TRUE;
56+
57+
auto getMarkingModeOrdinalMethodID = m_env.GetMethodID(runtimeClass, "getMarkingModeOrdinal", "()I");
58+
jint markingMode = m_env.CallIntMethod(m_javaRuntimeObject, getMarkingModeOrdinalMethodID);
59+
m_markingMode = static_cast<JavaScriptMarkingMode>(markingMode);
4860
}
4961

5062
void ObjectManager::SetInstanceIsolate(Isolate* isolate) {
@@ -57,8 +69,10 @@ void ObjectManager::Init(Isolate* isolate) {
5769
auto jsWrapperFunc = jsWrapperFuncTemplate->GetFunction();
5870
m_poJsWrapperFunc = new Persistent<Function>(isolate, jsWrapperFunc);
5971

60-
isolate->AddGCPrologueCallback(ObjectManager::OnGcStartedStatic, kGCTypeAll);
61-
isolate->AddGCEpilogueCallback(ObjectManager::OnGcFinishedStatic, kGCTypeAll);
72+
if (m_markingMode != JavaScriptMarkingMode::None) {
73+
isolate->AddGCPrologueCallback(ObjectManager::OnGcStartedStatic, kGCTypeAll);
74+
isolate->AddGCEpilogueCallback(ObjectManager::OnGcFinishedStatic, kGCTypeAll);
75+
}
6276
}
6377

6478

@@ -80,32 +94,35 @@ JniLocalRef ObjectManager::GetJavaObjectByJsObject(const Local<Object>& object)
8094

8195
ObjectManager::JSInstanceInfo* ObjectManager::GetJSInstanceInfo(const Local<Object>& object) {
8296
JSInstanceInfo* jsInstanceInfo = nullptr;
97+
if (IsJsRuntimeObject(object)) {
98+
return GetJSInstanceInfoFromRuntimeObject(object);
99+
}
100+
return nullptr;
101+
}
83102

84-
auto isolate = m_isolate;
85-
HandleScope handleScope(isolate);
103+
ObjectManager::JSInstanceInfo* ObjectManager::GetJSInstanceInfoFromRuntimeObject(const Local<Object>& object) {
104+
HandleScope handleScope(m_isolate);
86105

87-
if (IsJsRuntimeObject(object)) {
88-
const int jsInfoIdx = static_cast<int>(MetadataNodeKeys::JsInfo);
89-
auto jsInfo = object->GetInternalField(jsInfoIdx);
90-
if (jsInfo->IsUndefined()) {
91-
//Typescript object layout has an object instance as child of the actual registered instance. checking for that
92-
auto prototypeObject = object->GetPrototype().As<Object>();
93-
94-
if (!prototypeObject.IsEmpty() && prototypeObject->IsObject()) {
95-
DEBUG_WRITE("GetJSInstanceInfo: need to check prototype :%d", prototypeObject->GetIdentityHash());
96-
if (IsJsRuntimeObject(prototypeObject)) {
97-
jsInfo = prototypeObject->GetInternalField(jsInfoIdx);
98-
}
106+
const int jsInfoIdx = static_cast<int>(MetadataNodeKeys::JsInfo);
107+
auto jsInfo = object->GetInternalField(jsInfoIdx);
108+
if (jsInfo->IsUndefined()) {
109+
//Typescript object layout has an object instance as child of the actual registered instance. checking for that
110+
auto prototypeObject = object->GetPrototype().As<Object>();
111+
112+
if (!prototypeObject.IsEmpty() && prototypeObject->IsObject()) {
113+
DEBUG_WRITE("GetJSInstanceInfo: need to check prototype :%d", prototypeObject->GetIdentityHash());
114+
if (IsJsRuntimeObject(prototypeObject)) {
115+
jsInfo = prototypeObject->GetInternalField(jsInfoIdx);
99116
}
100117
}
118+
}
101119

102-
if (!jsInfo.IsEmpty() && jsInfo->IsExternal()) {
103-
auto external = jsInfo.As<External>();
104-
jsInstanceInfo = static_cast<JSInstanceInfo*>(external->Value());
105-
}
120+
if (!jsInfo.IsEmpty() && jsInfo->IsExternal()) {
121+
auto external = jsInfo.As<External>();
122+
return static_cast<JSInstanceInfo*>(external->Value());
106123
}
107124

108-
return jsInstanceInfo;
125+
return nullptr;
109126
}
110127

111128
bool ObjectManager::IsJsRuntimeObject(const v8::Local<v8::Object>& object) {
@@ -211,7 +228,11 @@ void ObjectManager::Link(const Local<Object>& object, uint32_t javaObjectID, jcl
211228
auto state = new ObjectWeakCallbackState(this, jsInstanceInfo, objectHandle);
212229

213230
// subscribe for JS GC event
214-
objectHandle->SetWeak(state, JSObjectWeakCallbackStatic, WeakCallbackType::kFinalizer);
231+
if (m_markingMode == JavaScriptMarkingMode::None) {
232+
objectHandle->SetWeak(state, JSObjectFinalizerStatic, WeakCallbackType::kFinalizer);
233+
} else {
234+
objectHandle->SetWeak(state, JSObjectWeakCallbackStatic, WeakCallbackType::kFinalizer);
235+
}
215236

216237
auto jsInfoIdx = static_cast<int>(MetadataNodeKeys::JsInfo);
217238

@@ -263,6 +284,40 @@ void ObjectManager::JSObjectWeakCallbackStatic(const WeakCallbackInfo<ObjectWeak
263284
thisPtr->JSObjectWeakCallback(isolate, callbackState);
264285
}
265286

287+
void ObjectManager::JSObjectFinalizerStatic(const WeakCallbackInfo<ObjectWeakCallbackState>& data) {
288+
ObjectWeakCallbackState* callbackState = data.GetParameter();
289+
290+
ObjectManager* thisPtr = callbackState->thisPtr;
291+
292+
auto isolate = data.GetIsolate();
293+
294+
thisPtr->JSObjectFinalizer(isolate, callbackState);
295+
}
296+
297+
void ObjectManager::JSObjectFinalizer(Isolate* isolate, ObjectWeakCallbackState* callbackState) {
298+
HandleScope handleScope(m_isolate);
299+
Persistent<Object>* po = callbackState->target;
300+
auto jsInstanceInfo = GetJSInstanceInfoFromRuntimeObject(po->Get(m_isolate));
301+
302+
if (jsInstanceInfo == nullptr) {
303+
po->Reset();
304+
return;
305+
}
306+
307+
auto javaObjectID = jsInstanceInfo->JavaObjectID;
308+
jboolean isJavaInstanceAlive = m_env.CallBooleanMethod(m_javaRuntimeObject, MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID, javaObjectID);
309+
if (isJavaInstanceAlive) {
310+
// If the Java instance is alive, keep the JavaScript instance alive.
311+
po->SetWeak(callbackState, JSObjectFinalizerStatic, WeakCallbackType::kFinalizer);
312+
} else {
313+
// If the Java instance is dead, this JavaScript instance can be let die.
314+
delete jsInstanceInfo;
315+
auto jsInfoIdx = static_cast<int>(MetadataNodeKeys::JsInfo);
316+
po->Get(m_isolate)->SetInternalField(jsInfoIdx, Undefined(m_isolate));
317+
po->Reset();
318+
}
319+
}
320+
266321
/*
267322
* When JS GC happens change state of the java counterpart to mirror state of JS object and REVIVE the JS object unconditionally
268323
* "Regular" js objects are pushed into the "regular objects" array

0 commit comments

Comments
 (0)