88#include < string>
99#include < vector>
1010#include < algorithm>
11+ #include < atomic>
1112
1213using namespace v8 ;
1314using namespace std ;
@@ -16,6 +17,39 @@ using namespace tns;
1617// External global module registry declared in ModuleInternal.cpp
1718extern std::unordered_map<std::string, v8::Global<v8::Module>> g_moduleRegistry;
1819
20+ // Forward declaration used by logging helper
21+ std::string GetApplicationPath ();
22+
23+ // Cached toggle for verbose script loading logs sourced from Java AppConfig via JNI
24+ static bool ShouldLogScriptLoading () {
25+ static std::atomic<int > cached{-1 }; // -1 unknown, 0 false, 1 true
26+ int v = cached.load (std::memory_order_acquire);
27+ if (v != -1 ) {
28+ return v == 1 ;
29+ }
30+
31+ static std::once_flag initFlag;
32+ std::call_once (initFlag, []() {
33+ bool enabled = false ;
34+ try {
35+ JEnv env;
36+ jclass runtimeClass = env.FindClass (" com/tns/Runtime" );
37+ if (runtimeClass != nullptr ) {
38+ jmethodID mid = env.GetStaticMethodID (runtimeClass, " getLogScriptLoadingEnabled" , " ()Z" );
39+ if (mid != nullptr ) {
40+ jboolean res = env.CallStaticBooleanMethod (runtimeClass, mid);
41+ enabled = (res == JNI_TRUE);
42+ }
43+ }
44+ } catch (...) {
45+ // ignore and keep default false
46+ }
47+ cached.store (enabled ? 1 : 0 , std::memory_order_release);
48+ });
49+
50+ return cached.load (std::memory_order_acquire) == 1 ;
51+ }
52+
1953// Import meta callback to support import.meta.url and import.meta.dirname
2054void InitializeImportMetaObject (Local<Context> context, Local<Module> module , Local<Object> meta) {
2155 Isolate* isolate = context->GetIsolate ();
@@ -41,9 +75,11 @@ void InitializeImportMetaObject(Local<Context> context, Local<Module> module, Lo
4175 modulePath = " " ; // Will use fallback path
4276 }
4377
44- DEBUG_WRITE (" InitializeImportMetaObject: Module lookup: found path = %s" ,
45- modulePath.empty () ? " (empty)" : modulePath.c_str ());
46- DEBUG_WRITE (" InitializeImportMetaObject: Registry size: %zu" , g_moduleRegistry.size ());
78+ if (ShouldLogScriptLoading ()) {
79+ DEBUG_WRITE (" InitializeImportMetaObject: Module lookup: found path = %s" ,
80+ modulePath.empty () ? " (empty)" : modulePath.c_str ());
81+ DEBUG_WRITE (" InitializeImportMetaObject: Registry size: %zu" , g_moduleRegistry.size ());
82+ }
4783
4884 // Convert file path to file:// URL
4985 std::string moduleUrl;
@@ -55,7 +91,9 @@ void InitializeImportMetaObject(Local<Context> context, Local<Module> module, Lo
5591 moduleUrl = " file:///android_asset/app/" ;
5692 }
5793
58- DEBUG_WRITE (" InitializeImportMetaObject: Final URL: %s" , moduleUrl.c_str ());
94+ if (ShouldLogScriptLoading ()) {
95+ DEBUG_WRITE (" InitializeImportMetaObject: Final URL: %s" , moduleUrl.c_str ());
96+ }
5997
6098 Local<String> url = ArgConverter::ConvertToV8String (isolate, moduleUrl);
6199
@@ -128,8 +166,9 @@ v8::MaybeLocal<v8::Module> ResolveModuleCallback(v8::Local<v8::Context> context,
128166 }
129167
130168 // Debug logging
131- DEBUG_WRITE (" ResolveModuleCallback: Resolving '%s'" , spec.c_str ());
132- __android_log_print (ANDROID_LOG_DEBUG, " TNS.ResolveCallback" , " Resolving module: '%s'" , spec.c_str ());
169+ if (ShouldLogScriptLoading ()) {
170+ DEBUG_WRITE (" ResolveModuleCallback: Resolving '%s'" , spec.c_str ());
171+ }
133172
134173 // 2) Find which filepath the referrer was compiled under
135174 std::string referrerPath;
@@ -161,8 +200,10 @@ v8::MaybeLocal<v8::Module> ResolveModuleCallback(v8::Local<v8::Context> context,
161200 std::string cleanSpec = spec.substr (0 , 2 ) == " ./" ? spec.substr (2 ) : spec;
162201 std::string candidate = baseDir + cleanSpec;
163202 candidateBases.push_back (candidate);
164- DEBUG_WRITE (" ResolveModuleCallback: Relative import: '%s' + '%s' -> '%s'" ,
165- baseDir.c_str (), cleanSpec.c_str (), candidate.c_str ());
203+ if (ShouldLogScriptLoading ()) {
204+ DEBUG_WRITE (" ResolveModuleCallback: Relative import: '%s' + '%s' -> '%s'" ,
205+ baseDir.c_str (), cleanSpec.c_str (), candidate.c_str ());
206+ }
166207 } else if (spec.size () > 7 && spec.substr (0 , 7 ) == " file://" ) {
167208 // Absolute file URL
168209 std::string tail = spec.substr (7 ); // strip file://
@@ -178,19 +219,27 @@ v8::MaybeLocal<v8::Module> ResolveModuleCallback(v8::Local<v8::Context> context,
178219 if (tail.rfind (appVirtualRoot, 0 ) == 0 ) {
179220 // Drop the leading "/app/" and prepend real appPath
180221 candidate = appPath + " /" + tail.substr (appVirtualRoot.size ());
181- DEBUG_WRITE (" ResolveModuleCallback: file:// to appPath mapping: '%s' -> '%s'" , tail.c_str (), candidate.c_str ());
222+ if (ShouldLogScriptLoading ()) {
223+ DEBUG_WRITE (" ResolveModuleCallback: file:// to appPath mapping: '%s' -> '%s'" , tail.c_str (), candidate.c_str ());
224+ }
182225 } else if (tail.rfind (androidAssetAppRoot, 0 ) == 0 ) {
183226 // Replace "/android_asset/app/" with the real appPath
184227 candidate = appPath + " /" + tail.substr (androidAssetAppRoot.size ());
185- DEBUG_WRITE (" ResolveModuleCallback: file:// android_asset mapping: '%s' -> '%s'" , tail.c_str (), candidate.c_str ());
228+ if (ShouldLogScriptLoading ()) {
229+ DEBUG_WRITE (" ResolveModuleCallback: file:// android_asset mapping: '%s' -> '%s'" , tail.c_str (), candidate.c_str ());
230+ }
186231 } else if (tail.rfind (appPath, 0 ) == 0 ) {
187232 // Already an absolute on-disk path to the app folder
188233 candidate = tail;
189- DEBUG_WRITE (" ResolveModuleCallback: file:// absolute path preserved: '%s'" , candidate.c_str ());
234+ if (ShouldLogScriptLoading ()) {
235+ DEBUG_WRITE (" ResolveModuleCallback: file:// absolute path preserved: '%s'" , candidate.c_str ());
236+ }
190237 } else {
191238 // Fallback: treat as absolute on-disk path
192239 candidate = tail;
193- DEBUG_WRITE (" ResolveModuleCallback: file:// generic absolute: '%s'" , candidate.c_str ());
240+ if (ShouldLogScriptLoading ()) {
241+ DEBUG_WRITE (" ResolveModuleCallback: file:// generic absolute: '%s'" , candidate.c_str ());
242+ }
194243 }
195244
196245 candidateBases.push_back (candidate);
@@ -423,7 +472,9 @@ v8::MaybeLocal<v8::Module> ResolveModuleCallback(v8::Local<v8::Context> context,
423472
424473 // 7) Handle JSON modules
425474 if (absPath.size () >= 5 && absPath.compare (absPath.size () - 5 , 5 , " .json" ) == 0 ) {
426- DEBUG_WRITE (" ResolveModuleCallback: Handling JSON module '%s'" , absPath.c_str ());
475+ if (ShouldLogScriptLoading ()) {
476+ DEBUG_WRITE (" ResolveModuleCallback: Handling JSON module '%s'" , absPath.c_str ());
477+ }
427478
428479 // Read JSON file content
429480 std::string jsonText = Runtime::GetRuntime (isolate)->ReadFileText (absPath);
@@ -475,12 +526,16 @@ v8::MaybeLocal<v8::Module> ResolveModuleCallback(v8::Local<v8::Context> context,
475526 // 8) Check if we've already compiled this module
476527 auto it = g_moduleRegistry.find (absPath);
477528 if (it != g_moduleRegistry.end ()) {
478- DEBUG_WRITE (" ResolveModuleCallback: Found cached module '%s'" , absPath.c_str ());
529+ if (ShouldLogScriptLoading ()) {
530+ DEBUG_WRITE (" ResolveModuleCallback: Found cached module '%s'" , absPath.c_str ());
531+ }
479532 return v8::MaybeLocal<v8::Module>(it->second .Get (isolate));
480533 }
481534
482535 // 9) Compile and register the new module
483- DEBUG_WRITE (" ResolveModuleCallback: Compiling new module '%s'" , absPath.c_str ());
536+ if (ShouldLogScriptLoading ()) {
537+ DEBUG_WRITE (" ResolveModuleCallback: Compiling new module '%s'" , absPath.c_str ());
538+ }
484539 try {
485540 // Use our existing LoadESModule function to compile the module
486541 tns::ModuleInternal::LoadESModule (isolate, absPath);
@@ -513,8 +568,9 @@ v8::MaybeLocal<v8::Promise> ImportModuleDynamicallyCallback(
513568 v8::String::Utf8Value specUtf8 (isolate, specifier);
514569 std::string spec = *specUtf8 ? *specUtf8 : " " ;
515570
516- DEBUG_WRITE (" ImportModuleDynamicallyCallback: Dynamic import for '%s'" , spec.c_str ());
517- __android_log_print (ANDROID_LOG_DEBUG, " TNS.ImportCallback" , " Dynamic import: '%s'" , spec.c_str ());
571+ if (ShouldLogScriptLoading ()) {
572+ DEBUG_WRITE (" ImportModuleDynamicallyCallback: Dynamic import for '%s'" , spec.c_str ());
573+ }
518574
519575 v8::EscapableHandleScope scope (isolate);
520576
@@ -537,7 +593,9 @@ v8::MaybeLocal<v8::Promise> ImportModuleDynamicallyCallback(
537593 v8::Local<v8::Module> module ;
538594 if (!maybeModule.ToLocal (&module )) {
539595 // Resolution failed; reject to avoid leaving a pending Promise (white screen)
540- DEBUG_WRITE (" ImportModuleDynamicallyCallback: Resolution failed for '%s'" , spec.c_str ());
596+ if (ShouldLogScriptLoading ()) {
597+ DEBUG_WRITE (" ImportModuleDynamicallyCallback: Resolution failed for '%s'" , spec.c_str ());
598+ }
541599 v8::Local<v8::Value> ex = v8::Exception::Error (
542600 ArgConverter::ConvertToV8String (isolate, std::string (" Failed to resolve module: " ) + spec));
543601 resolver->Reject (context, ex).Check ();
@@ -547,7 +605,9 @@ v8::MaybeLocal<v8::Promise> ImportModuleDynamicallyCallback(
547605 // If not yet instantiated/evaluated, do it now
548606 if (module ->GetStatus () == v8::Module::kUninstantiated ) {
549607 if (!module ->InstantiateModule (context, &ResolveModuleCallback).FromMaybe (false )) {
550- DEBUG_WRITE (" ImportModuleDynamicallyCallback: Instantiate failed for '%s'" , spec.c_str ());
608+ if (ShouldLogScriptLoading ()) {
609+ DEBUG_WRITE (" ImportModuleDynamicallyCallback: Instantiate failed for '%s'" , spec.c_str ());
610+ }
551611 resolver
552612 ->Reject (context,
553613 v8::Exception::Error (ArgConverter::ConvertToV8String (isolate, " Failed to instantiate module" )))
@@ -558,7 +618,9 @@ v8::MaybeLocal<v8::Promise> ImportModuleDynamicallyCallback(
558618
559619 if (module ->GetStatus () != v8::Module::kEvaluated ) {
560620 if (module ->Evaluate (context).IsEmpty ()) {
561- DEBUG_WRITE (" ImportModuleDynamicallyCallback: Evaluation failed for '%s'" , spec.c_str ());
621+ if (ShouldLogScriptLoading ()) {
622+ DEBUG_WRITE (" ImportModuleDynamicallyCallback: Evaluation failed for '%s'" , spec.c_str ());
623+ }
562624 v8::Local<v8::Value> ex =
563625 v8::Exception::Error (ArgConverter::ConvertToV8String (isolate, " Evaluation failed" ));
564626 resolver->Reject (context, ex).Check ();
@@ -567,10 +629,14 @@ v8::MaybeLocal<v8::Promise> ImportModuleDynamicallyCallback(
567629 }
568630
569631 resolver->Resolve (context, module ->GetModuleNamespace ()).Check ();
570- DEBUG_WRITE (" ImportModuleDynamicallyCallback: Successfully resolved '%s'" , spec.c_str ());
632+ if (ShouldLogScriptLoading ()) {
633+ DEBUG_WRITE (" ImportModuleDynamicallyCallback: Successfully resolved '%s'" , spec.c_str ());
634+ }
571635 } catch (NativeScriptException& ex) {
572636 ex.ReThrowToV8 ();
573- DEBUG_WRITE (" ImportModuleDynamicallyCallback: Native exception for '%s'" , spec.c_str ());
637+ if (ShouldLogScriptLoading ()) {
638+ DEBUG_WRITE (" ImportModuleDynamicallyCallback: Native exception for '%s'" , spec.c_str ());
639+ }
574640 resolver
575641 ->Reject (context, v8::Exception::Error (
576642 ArgConverter::ConvertToV8String (isolate, " Native error during dynamic import" )))
0 commit comments