Skip to content

Commit 67bf4ff

Browse files
committed
fix memory leaks and runtime cleanup
1 parent 6c670cd commit 67bf4ff

File tree

7 files changed

+127
-97
lines changed

7 files changed

+127
-97
lines changed

test-app/runtime/src/main/cpp/runtime/Runtime.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838
using namespace tns;
3939
using namespace std;
4040

41-
42-
4341
bool tns::LogEnabled = false;
4442

4543
void Runtime::Init(JavaVM *vm) {
@@ -219,6 +217,11 @@ void Runtime::Init(JNIEnv *_env, jstring filesPath, jstring nativeLibsDir,
219217
return mode;
220218
});
221219

220+
napi_util::napi_set_function(env, global, "napiFunction",
221+
[](napi_env _env, napi_callback_info) -> napi_value {
222+
return nullptr;
223+
});
224+
222225
SimpleProfiler::Init(env, global);
223226

224227
CallbackHandlers::CreateGlobalCastFunctions(env);
@@ -338,7 +341,6 @@ ObjectManager *Runtime::GetObjectManager() const {
338341
}
339342

340343
Runtime::~Runtime() {
341-
delete this->m_objectManager;
342344
delete this->m_loopTimer;
343345

344346
#ifdef __V8__
@@ -369,13 +371,16 @@ std::string Runtime::ReadFileText(const std::string &filePath) {
369371
}
370372

371373
void Runtime::DestroyRuntime() {
374+
MetadataNode::onDisposeEnv(env);
375+
ArgConverter::onDisposeEnv(env);
372376
this->js_method_cache->cleanupCache();
373377
delete this->js_method_cache;
374378
this->m_module.DeInit();
375379
Console::onDisposeEnv(env);
376380
CallbackHandlers::RemoveEnvEntries(env);
377381
tns::GlobalHelpers::onDisposeEnv(env);
378382
napi_close_handle_scope(env, this->global_scope);
383+
delete this->m_objectManager;
379384
js_free_napi_env(env);
380385
Runtime::thread_id_to_rt_cache.Remove(this->my_thread_id);
381386
id_to_runtime_cache.Remove(m_id);

test-app/runtime/src/main/cpp/runtime/conversion/ArgConverter.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,15 @@ u16string ArgConverter::ConvertToUtf16String(napi_env env, napi_value s) {
248248
}
249249
}
250250

251-
void ArgConverter::onDisposeIsolate(napi_env env) {
251+
void ArgConverter::onDisposeEnv(napi_env env) {
252252
auto itFound = s_type_long_operations_cache.find(env);
253253
if (itFound != s_type_long_operations_cache.end()) {
254+
if (itFound->second->LongNumberCtorFunc) {
255+
napi_delete_reference(env, itFound->second->LongNumberCtorFunc);
256+
}
257+
if (itFound->second->NanNumberObject) {
258+
napi_delete_reference(env, itFound->second->NanNumberObject);
259+
}
254260
delete itFound->second;
255261
s_type_long_operations_cache.erase(itFound);
256262
}

test-app/runtime/src/main/cpp/runtime/conversion/ArgConverter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ namespace tns {
9999
return result;
100100
}
101101

102-
static void onDisposeIsolate(napi_env env);
102+
static void onDisposeEnv(napi_env env);
103103

104104
private:
105105

test-app/runtime/src/main/cpp/runtime/metadata/MetadataNode.cpp

Lines changed: 88 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -652,14 +652,10 @@ MetadataNode::GetCachedExtendedClassData(napi_env env, const string &proxyClassN
652652
}
653653

654654
MetadataNode::MetadataNodeCache *MetadataNode::GetMetadataNodeCache(napi_env env) {
655-
MetadataNodeCache *cache;
656-
auto itFound = s_metadata_node_cache.find(env);
657-
if (itFound == s_metadata_node_cache.end()) {
658-
cache = new MetadataNodeCache;
659-
s_metadata_node_cache.emplace(env, cache);
660-
} else {
661-
cache = itFound->second;
662-
}
655+
auto cache = s_metadata_node_cache.Get(env);
656+
if (cache) return cache;
657+
cache = new MetadataNodeCache;
658+
s_metadata_node_cache.Insert(env, cache);
663659
return cache;
664660
}
665661

@@ -834,61 +830,45 @@ napi_value MetadataNode::CreateWrapper(napi_env env) {
834830
}
835831

836832
napi_value MetadataNode::PackageGetterCallback(napi_env env, napi_callback_info info) {
837-
size_t argc = 1;
838-
napi_value args[1];
839-
napi_value thisArg;
840-
void *data;
841-
842-
napi_get_cb_info(env, info, &argc, args, &thisArg, &data);
843-
833+
NAPI_CALLBACK_BEGIN(0)
844834
try {
845-
846-
auto *methodInfo = static_cast<PackageGetterMethodData *>(data);
847-
848-
if (methodInfo->value != nullptr) {
849-
napi_value value = napi_util::get_ref_value(env, methodInfo->value);
850-
if (!napi_util::is_null_or_undefined(env, value)) {
851-
return value;
852-
}
835+
auto childTreeNode = static_cast<MetadataTreeNode *>(data);
836+
auto node = GetOrCreateInternal(childTreeNode->parent);
837+
DEBUG_WRITE("Get package item: %s", childTreeNode->name.c_str());
838+
auto hiddenPropName = "__" + childTreeNode->name;
839+
napi_value hiddenValue;
840+
napi_get_named_property(env, jsThis, hiddenPropName.c_str(), &hiddenValue);
841+
842+
if (!napi_util::is_null_or_undefined(env, hiddenValue)) {
843+
DEBUG_WRITE("Get cached package item: %s", hiddenPropName.c_str());
844+
return hiddenValue;
853845
}
854846

855-
auto node = methodInfo->node;
856-
857-
uint8_t nodeType = s_metadataReader.GetNodeType(node->m_treeNode);
858-
859-
auto child = GetChildMetadataForPackage(node, methodInfo->utf8name);
860-
auto foundChild = child.treeNode != nullptr;
861-
napi_value cachedItem = nullptr;
862-
if (foundChild) {
863-
auto childNode = MetadataNode::GetOrCreateInternal(child.treeNode);
864-
auto cache = GetMetadataNodeCache(env);
865-
if (methodInfo->value != nullptr) {
866-
cache->CtorFuncCache.erase(childNode->m_treeNode);
867-
}
868-
cachedItem = childNode->CreateWrapper(env);
869-
methodInfo->value = napi_util::make_ref(env, cachedItem);
870-
871-
uint8_t childNodeType = s_metadataReader.GetNodeType(child.treeNode);
872-
bool isInterface = s_metadataReader.IsNodeTypeInterface(childNodeType);
873-
if (isInterface) {
874-
// For all java interfaces we register the special Symbol.hasInstance property
875-
// which is invoked by the instanceof operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance).
876-
// For example:
877-
//
878-
// Object.defineProperty(android.view.animation.Interpolator, Symbol.hasInstance, {
879-
// value: function(obj) {
880-
// return true;
881-
// }
882-
// });
883-
RegisterSymbolHasInstanceCallback(env, child, cachedItem);
884-
}
885-
886-
if (node->m_name == "org/json" && child.name == "JSONObject") {
887-
JSONObjectHelper::RegisterFromFunction(env, cachedItem);
888-
}
847+
auto childNode = MetadataNode::GetOrCreateInternal(childTreeNode);
848+
hiddenValue = childNode->CreateWrapper(env);
849+
850+
uint8_t childNodeType = s_metadataReader.GetNodeType(childTreeNode);
851+
bool isInterface = s_metadataReader.IsNodeTypeInterface(childNodeType);
852+
if (isInterface) {
853+
// For all java interfaces we register the special Symbol.hasInstance property
854+
// which is invoked by the instanceof operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance).
855+
// For example:
856+
//
857+
// Object.defineProperty(android.view.animation.Interpolator, Symbol.hasInstance, {
858+
// value: function(obj) {
859+
// return true;
860+
// }
861+
// });
862+
RegisterSymbolHasInstanceCallback(env, childTreeNode, hiddenValue);
863+
}
864+
auto parentNode = GetOrCreateInternal(childTreeNode->parent);
865+
if (parentNode->m_name == "org/json" && childTreeNode->name == "JSONObject") {
866+
JSONObjectHelper::RegisterFromFunction(env, hiddenValue);
889867
}
890868

891-
return cachedItem;
869+
napi_set_named_property(env, jsThis, hiddenPropName.c_str(), hiddenValue);
870+
871+
return hiddenValue;
892872

893873
} catch (NativeScriptException &e) {
894874
e.ReThrowToNapi(env);
@@ -901,18 +881,17 @@ napi_value MetadataNode::PackageGetterCallback(napi_env env, napi_callback_info
901881
NativeScriptException nsEx(std::string("Error: c++ exception!"));
902882
nsEx.ReThrowToNapi(env);
903883
}
904-
905-
return nullptr;
906884
}
907885

908-
void MetadataNode::RegisterSymbolHasInstanceCallback(napi_env env, const MetadataEntry &entry,
886+
void MetadataNode::RegisterSymbolHasInstanceCallback(napi_env env, const MetadataTreeNode* treeNode,
909887
napi_value interface) {
910888
if (napi_util::is_undefined(env, interface) || napi_util::is_null(env, interface)) {
911889
return;
912890
}
913891

914892
JEnv jEnv;
915-
auto className = GetJniClassName(entry);
893+
894+
auto className = GetJniClassName(treeNode);
916895
auto clazz = jEnv.FindClass(className);
917896
if (clazz == nullptr) {
918897
return;
@@ -976,9 +955,10 @@ napi_value MetadataNode::SymbolHasInstanceCallback(napi_env env, napi_callback_i
976955

977956
}
978957

979-
std::string MetadataNode::GetJniClassName(const MetadataEntry &entry) {
958+
959+
std::string MetadataNode::GetJniClassName(const MetadataTreeNode * node) {
980960
std::stack<string> s;
981-
MetadataTreeNode *node = entry.treeNode;
961+
982962
while (node != nullptr && !node->name.empty()) {
983963
s.push(node->name);
984964
node = node->parent;
@@ -1002,29 +982,21 @@ napi_value MetadataNode::CreatePackageObject(napi_env env) {
1002982

1003983
if (ptrChildren != nullptr) {
1004984
const auto &children = *ptrChildren;
1005-
1006985
auto lastChildName = "";
1007-
1008986
for (auto childNode: children) {
1009-
1010-
auto *info = new PackageGetterMethodData();
1011-
info->utf8name = childNode->name.c_str();
1012-
info->node = this;
1013-
info->value = nullptr;
1014-
1015-
if (strcmp(info->utf8name, lastChildName) == 0) {
987+
if (strcmp(childNode->name.c_str(), lastChildName) == 0) {
1016988
continue;
1017989
}
1018-
lastChildName = info->utf8name;
990+
lastChildName = childNode->name.c_str();
1019991
napi_property_descriptor descriptor{
1020992
childNode->name.c_str(),
1021993
nullptr,
1022994
nullptr,
1023995
PackageGetterCallback,
1024996
nullptr,
1025997
nullptr,
1026-
napi_default,
1027-
info};
998+
napi_default_jsproperty,
999+
childNode};
10281000
napi_define_properties(env, packageObj, 1, &descriptor);
10291001
}
10301002
}
@@ -1377,10 +1349,22 @@ napi_value MetadataNode::GetConstructorFunctionInternal(napi_env env, MetadataTr
13771349
auto itFound = cache->CtorFuncCache.find(treeNode);
13781350
if (itFound != cache->CtorFuncCache.end()) {
13791351
instanceMethodsCallbackData = itFound->second.instanceMethodCallbacks;
1380-
if (itFound->second.constructorFunction == nullptr)
1381-
return nullptr;
1382-
auto value = napi_util::get_ref_value(env, itFound->second.constructorFunction);
1383-
if (!napi_util::is_null_or_undefined(env, value)) return value;
1352+
if (itFound->second.constructorFunction != nullptr) {
1353+
auto value = napi_util::get_ref_value(env, itFound->second.constructorFunction);
1354+
if (!napi_util::is_null_or_undefined(env, value)) {
1355+
return value;
1356+
}
1357+
}
1358+
}
1359+
1360+
if (itFound != cache->CtorFuncCache.end()) {
1361+
if (itFound->second.constructorFunction != nullptr) {
1362+
napi_delete_reference(env, itFound->second.constructorFunction);
1363+
}
1364+
for (const auto &data: itFound->second.instanceMethodCallbacks) {
1365+
delete data;
1366+
}
1367+
cache->CtorFuncCache.erase(itFound);
13841368
}
13851369

13861370
auto node = GetOrCreateInternal(treeNode);
@@ -2075,15 +2059,34 @@ void MetadataNode::BuildMetadata(const std::string &filesPath) {
20752059

20762060
void MetadataNode::onDisposeEnv(napi_env env) {
20772061
{
2078-
auto it = s_metadata_node_cache.find(env);
2079-
if (it != s_metadata_node_cache.end()) {
2080-
delete it->second;
2081-
s_metadata_node_cache.erase(it);
2062+
auto it = s_metadata_node_cache.Get(env);
2063+
if (it != nullptr) {
2064+
for (const auto &entry: it->CtorFuncCache) {
2065+
if (entry.second.constructorFunction == nullptr) {
2066+
napi_delete_reference(env, entry.second.constructorFunction);
2067+
}
2068+
for (const auto data: entry.second.instanceMethodCallbacks) {
2069+
delete data;
2070+
}
2071+
}
2072+
it->CtorFuncCache.clear();
2073+
2074+
for (const auto &entry: it->ExtendedCtorFuncCache) {
2075+
if (entry.second.extendedCtorFunction == nullptr) {
2076+
napi_delete_reference(env, entry.second.extendedCtorFunction);
2077+
}
2078+
}
2079+
it->ExtendedCtorFuncCache.clear();
20822080
}
2081+
s_metadata_node_cache.Remove(env);
2082+
delete it;
20832083
}
20842084
{
20852085
auto it = s_arrayObjects.find(env);
20862086
if (it != s_arrayObjects.end()) {
2087+
if (it->second != nullptr) {
2088+
napi_delete_reference(env, it->second);
2089+
}
20872090
s_arrayObjects.erase(it);
20882091
}
20892092
}
@@ -2095,8 +2098,7 @@ MetadataReader MetadataNode::s_metadataReader;
20952098
robin_hood::unordered_map<std::string, MetadataNode *> MetadataNode::s_name2NodeCache;
20962099
robin_hood::unordered_map<std::string, MetadataTreeNode *> MetadataNode::s_name2TreeNodeCache;
20972100
robin_hood::unordered_map<MetadataTreeNode *, MetadataNode *> MetadataNode::s_treeNode2NodeCache;
2098-
robin_hood::unordered_map<napi_env, MetadataNode::MetadataNodeCache *> MetadataNode::s_metadata_node_cache;
2101+
tns::ConcurrentMap<napi_env, MetadataNode::MetadataNodeCache *> MetadataNode::s_metadata_node_cache;
20992102
robin_hood::unordered_map<napi_env, napi_ref> MetadataNode::s_arrayObjects;
21002103

2101-
// TODO
21022104
bool MetadataNode::s_profilerEnabled = false;

test-app/runtime/src/main/cpp/runtime/metadata/MetadataNode.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class MetadataNode {
104104
static bool IsValidExtendName(napi_env env, napi_value name);
105105
static bool GetExtendLocation(napi_env env, std::string& extendLocation, bool isTypeScriptExtend);
106106
static ExtendedClassCacheData GetCachedExtendedClassData(napi_env env, const std::string& proxyClassName);
107-
static std::string GetJniClassName(const MetadataEntry &entry);
107+
static std::string GetJniClassName(const MetadataTreeNode* node);
108108

109109

110110
static void SetClassAccessor(napi_env env, napi_value constructor);
@@ -178,7 +178,7 @@ class MetadataNode {
178178
static napi_value NullValueOfCallback(napi_env env, napi_callback_info info);
179179

180180

181-
static void RegisterSymbolHasInstanceCallback(napi_env env, const MetadataEntry &entry, napi_value interface);
181+
static void RegisterSymbolHasInstanceCallback(napi_env env, const MetadataTreeNode *treeNode, napi_value interface);
182182

183183
static napi_value SymbolHasInstanceCallback(napi_env env, napi_callback_info info);
184184

@@ -200,7 +200,7 @@ class MetadataNode {
200200
static robin_hood::unordered_map<std::string, MetadataNode *> s_name2NodeCache;
201201
static robin_hood::unordered_map<std::string, MetadataTreeNode *> s_name2TreeNodeCache;
202202
static robin_hood::unordered_map<MetadataTreeNode *, MetadataNode *> s_treeNode2NodeCache;
203-
static robin_hood::unordered_map<napi_env, MetadataNodeCache *> s_metadata_node_cache;
203+
static tns::ConcurrentMap<napi_env, MetadataNodeCache *> s_metadata_node_cache;
204204
static robin_hood::unordered_map<napi_env, napi_ref> s_arrayObjects;
205205

206206
struct CtorCacheData {
@@ -291,10 +291,7 @@ class MetadataNode {
291291
};
292292

293293
struct MetadataNodeCache {
294-
// napi_ref MetadataKey;
295-
296294
robin_hood::unordered_map<MetadataTreeNode *, CtorCacheData> CtorFuncCache;
297-
298295
robin_hood::unordered_map<std::string, MetadataNode::ExtendedClassCacheData> ExtendedCtorFuncCache;
299296
};
300297

test-app/runtime/src/main/cpp/runtime/objectmanager/ObjectManager.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,22 @@ void ObjectManager::Init(napi_env env) {
176176
this->m_jsObjectProxyCreator = ref;
177177
}
178178

179+
ObjectManager::~ObjectManager() {
180+
if (this->m_jsObjectCtor) napi_delete_reference(m_env, this->m_jsObjectCtor);
181+
if (this->m_jsObjectProxyCreator) napi_delete_reference(m_env, this->m_jsObjectProxyCreator);
182+
for (auto &entry: m_idToProxy) {
183+
if (!entry.second) continue;
184+
napi_delete_reference(m_env, entry.second);
185+
}
186+
m_idToProxy.clear();
187+
188+
for (auto &entry: m_idToObject) {
189+
if (!entry.second) continue;
190+
napi_delete_reference(m_env, entry.second);
191+
}
192+
m_idToObject.clear();
193+
}
194+
179195
napi_value ObjectManager::GetOrCreateProxy(jint javaObjectID, napi_value instance) {
180196
napi_value proxy = nullptr;
181197
auto it = m_idToProxy.find(javaObjectID);

0 commit comments

Comments
 (0)