已合并
fix:clean sourceModuleText metadata #15077
fix:clean sourceModuleText metadata #15077
已合并
leesin创建于 13 天前
8 个文件变更+467-76
Mecmascript/ecma_vm.h+18-0
@@ -233,6 +233,12 @@ private:
233 IcuFormatter icuObjCache_[static_cast<uint32_t>(IcuFormatterType::ICU_FORMATTER_TYPE_COUNT)];233 IcuFormatter icuObjCache_[static_cast<uint32_t>(IcuFormatterType::ICU_FORMATTER_TYPE_COUNT)];
234};234};
235 235 
236+enum class ModuleRequestsClearState : uint8_t {
237+ UNINITIALIZED = 0,
238+ CAN_CLEAR = 1,
239+ CANNOT_CLEAR = 2,
240+};
241+ 
236class EcmaVM {242class EcmaVM {
237public:243public:
238 static EcmaVM *Create(const JSRuntimeOptions &options);244 static EcmaVM *Create(const JSRuntimeOptions &options);
@@ -345,6 +351,16 @@ public:
345 return options_;351 return options_;
346 }352 }
347 353 
354+ ModuleRequestsClearState GetModuleRequestsClearState()
355+ {
356+ return moduleRequestsClearState_;
357+ }
358+ 
359+ void SetModuleRequestsClearState(ModuleRequestsClearState state)
360+ {
361+ moduleRequestsClearState_ = state;
362+ }
363+ 
348 const EcmaParamConfiguration &GetEcmaParamConfiguration() const364 const EcmaParamConfiguration &GetEcmaParamConfiguration() const
349 {365 {
350 return ecmaParamConfiguration_;366 return ecmaParamConfiguration_;
@@ -1776,6 +1792,8 @@ private:
1776 //apiVersion states1792 //apiVersion states
1777 uint32_t apiVersion_ = 8;1793 uint32_t apiVersion_ = 8;
1778 1794 
1795+ ModuleRequestsClearState moduleRequestsClearState_ {ModuleRequestsClearState::UNINITIALIZED};
1796+ 
1779 // VM memory management.1797 // VM memory management.
1780 std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_;1798 std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_;
1781 std::unique_ptr<HeapRegionAllocator> heapRegionAllocator_;1799 std::unique_ptr<HeapRegionAllocator> heapRegionAllocator_;
Mecmascript/jspandafile/tests/js_pandafile_snapshot_test.cpp+6-0
@@ -260,6 +260,9 @@ public:
260 260 
261HWTEST_F_L0(JSPandaFileSnapshotTest, SerializeAndDeserializeTest)261HWTEST_F_L0(JSPandaFileSnapshotTest, SerializeAndDeserializeTest)
262{262{
263+ // Reset global snapshot state: earlier tests may have triggered
264+ // UpdateFromStateFile with non-existent paths, leaving featureState=disableAll.
265+ ModulesSnapshotHelper::ResetStateForTest();
263 // construct JSPandaFile266 // construct JSPandaFile
264 CString path = GetSnapshotPath();267 CString path = GetSnapshotPath();
265 CString version = "version 205.0.1.120(SP20)";268 CString version = "version 205.0.1.120(SP20)";
@@ -471,6 +474,9 @@ HWTEST_F_L0(JSPandaFileSnapshotTest, ShouldDeSerializeFailedWhenModuleNameIsNotM
471 474 
472HWTEST_F_L0(JSPandaFileSnapshotTest, WriteAndReadRecordInfoSectionWithMergedPF)475HWTEST_F_L0(JSPandaFileSnapshotTest, WriteAndReadRecordInfoSectionWithMergedPF)
473{476{
477+ // Reset global snapshot state: earlier tests may have triggered
478+ // UpdateFromStateFile with non-existent paths, leaving featureState=disableAll.
479+ ModulesSnapshotHelper::ResetStateForTest();
474 // serialize480 // serialize
475 CString path = GetSnapshotPath();481 CString path = GetSnapshotPath();
476 CString version = "version 205.0.1.120(SP20)";482 CString version = "version 205.0.1.120(SP20)";
Mecmascript/jspandafile/tests/js_pandafile_test.cpp+3-0
@@ -800,6 +800,9 @@ HWTEST_F_L0(JSPandaFileTest, GetClassAndMethodIndexes_UseMinCount)
800 */800 */
801HWTEST_F_L0(JSPandaFileTest, ConstructorWithThread_SnapshotReadSuccess)801HWTEST_F_L0(JSPandaFileTest, ConstructorWithThread_SnapshotReadSuccess)
802{802{
803+ // Reset global snapshot state: earlier tests may have triggered
804+ // UpdateFromStateFile with non-existent paths, leaving featureState=disableAll.
805+ ModulesSnapshotHelper::ResetStateForTest();
803 CString path = GetCurrentDirPath();806 CString path = GetCurrentDirPath();
804 const char *abcFilename = "/data/storage/el1/bundle/entry/ets/main/modules.abc";807 const char *abcFilename = "/data/storage/el1/bundle/entry/ets/main/modules.abc";
805 const char *source = R"(808 const char *source = R"(
Mecmascript/module/js_module_source_text.cpp+54-12
@@ -25,7 +25,9 @@
25#include "ecmascript/module/module_data_extractor.h"25#include "ecmascript/module/module_data_extractor.h"
26#include "ecmascript/module/module_message_helper.h"26#include "ecmascript/module/module_message_helper.h"
27#include "ecmascript/module/module_path_helper.h"27#include "ecmascript/module/module_path_helper.h"
28+#include "ecmascript/snapshot/common/modules_snapshot_helper.h"
28#include "ecmascript/platform/file.h"29#include "ecmascript/platform/file.h"
30+#include "ecmascript/ohos/ohos_constants.h"
29#include "ecmascript/module/module_value_accessor.h"31#include "ecmascript/module/module_value_accessor.h"
30#include "ecmascript/module/module_resolver.h"32#include "ecmascript/module/module_resolver.h"
31#include "ecmascript/module/module_tools.h"33#include "ecmascript/module/module_tools.h"
@@ -643,7 +645,7 @@ void SourceTextModule::DFSModuleInstantiation(JSThread *thread, JSHandle<SourceT
643 // iii. Set requiredModule.[[Status]] to "instantiated".645 // iii. Set requiredModule.[[Status]] to "instantiated".
644 requiredModule->SetStatus(ModuleStatus::INSTANTIATED);646 requiredModule->SetStatus(ModuleStatus::INSTANTIATED);
645#if ENABLE_MODULE_MEMORY_OPTIMIZATION647#if ENABLE_MODULE_MEMORY_OPTIMIZATION
646- ClearInstantiationFieldsIfNeeded(thread, requiredModule);648+ ClearImportEntriesIfNeeded(thread, requiredModule);
647#endif649#endif
648 // iv. If requiredModule and module are the same Module Record, set done to true.650 // iv. If requiredModule and module are the same Module Record, set done to true.
649 if (JSTaggedValue::SameValue(thread, module.GetTaggedValue(), requiredModule.GetTaggedValue())) {651 if (JSTaggedValue::SameValue(thread, module.GetTaggedValue(), requiredModule.GetTaggedValue())) {
@@ -1165,8 +1167,9 @@ int SourceTextModule::InnerModuleEvaluationUnsafe(JSThread *thread, JSHandle<Sou
1165 requiredModule->SetStatus(ModuleStatus::EVALUATED);1167 requiredModule->SetStatus(ModuleStatus::EVALUATED);
1166#if ENABLE_MODULE_MEMORY_OPTIMIZATION1168#if ENABLE_MODULE_MEMORY_OPTIMIZATION
1167 ClearTopLevelCapabilityIfNeeded(thread, requiredModule);1169 ClearTopLevelCapabilityIfNeeded(thread, requiredModule);
1170+ ClearModuleRequestsIfNeeded(thread, requiredModule);
1168#else1171#else
1169- ClearInstantiationFieldsIfNeeded(thread, requiredModule);1172+ ClearImportEntriesIfNeeded(thread, requiredModule);
1170#endif1173#endif
1171 } else {1174 } else {
1172 requiredModule->SetStatus(ModuleStatus::EVALUATING_ASYNC);1175 requiredModule->SetStatus(ModuleStatus::EVALUATING_ASYNC);
@@ -1184,7 +1187,7 @@ int SourceTextModule::InnerModuleEvaluationUnsafe(JSThread *thread, JSHandle<Sou
1184 return index;1187 return index;
1185}1188}
1186 1189 
1187-void SourceTextModule::ClearInstantiationFieldsIfNeeded(JSThread *thread, JSHandle<SourceTextModule> &module)1190+void SourceTextModule::ClearImportEntriesIfNeeded(JSThread *thread, JSHandle<SourceTextModule> &module)
1188{1191{
1189#if ENABLE_MODULE_MEMORY_OPTIMIZATION1192#if ENABLE_MODULE_MEMORY_OPTIMIZATION
1190 ASSERT(module->GetStatus() >= ModuleStatus::INSTANTIATED);1193 ASSERT(module->GetStatus() >= ModuleStatus::INSTANTIATED);
@@ -1197,14 +1200,6 @@ void SourceTextModule::ClearInstantiationFieldsIfNeeded(JSThread *thread, JSHand
1197 if (thread->GetModuleLogger() == nullptr) {1200 if (thread->GetModuleLogger() == nullptr) {
1198 module->SetImportEntries(thread, undefinedValue);1201 module->SetImportEntries(thread, undefinedValue);
1199 }1202 }
1200-#if ENABLE_MODULE_MEMORY_OPTIMIZATION
1201- // ModuleRequests is only cleared for non-shared modules.
1202- // Shared modules need ModuleRequests for cross-thread fallback resolve.
1203- if (!IsSharedModule(module) &&
1204- (!vm->GetJSOptions().EnableSnapshotSerialize() || module->GetLazyImportStatusArray() == nullptr)) {
1205- module->SetModuleRequests(thread, undefinedValue);
1206- }
1207-#endif
1208 }1203 }
1209}1204}
1210 1205 
@@ -1221,6 +1216,47 @@ void SourceTextModule::ClearTopLevelCapabilityIfNeeded(JSThread *thread, const J
1221 }1216 }
1222}1217}
1223 1218 
1219+bool CanClearModuleRequests(EcmaVM *vm)
1220+{
1221+ auto state = vm->GetModuleRequestsClearState();
1222+ if (state == ModuleRequestsClearState::UNINITIALIZED) {
1223+ if (vm->GetJSOptions().DisableModuleSnapshot() ||
1224+ ModulesSnapshotHelper::IsModuleSnapshotDisabled(
1225+ ohos::OhosConstants::PANDAFILE_AND_MODULE_SNAPSHOT_DIR)) {
1226+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
1227+ return true;
1228+ }
1229+ if (ModulesSnapshotHelper::GetFeatureLoaded() & static_cast<int>(SnapshotFeatureState::MODULE)) {
1230+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
1231+ return true;
1232+ }
1233+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CANNOT_CLEAR);
1234+ return false;
1235+ } else if (state == ModuleRequestsClearState::CAN_CLEAR) {
1236+ return true;
1237+ } else {
1238+ return false;
1239+ }
1240+}
1241+ 
1242+ 
1243+void SourceTextModule::ClearModuleRequestsIfNeeded(JSThread *thread, const JSHandle<SourceTextModule> &module)
1244+{
1245+ ASSERT(module->GetStatus() >= ModuleStatus::EVALUATED);
1246+ if (module->GetModuleRequests(thread).IsUndefined() || IsSharedModule(module) ||
1247+ module->GetLazyImportStatusArray() != nullptr) {
1248+ return;
1249+ }
1250+ EcmaVM *vm = thread->GetEcmaVM();
1251+ if (vm->GetJsDebuggerManager()->IsDebugApp()) {
1252+ return;
1253+ }
1254+ if (CanClearModuleRequests(vm)) {
1255+ JSTaggedValue undefinedValue = thread->GlobalConstants()->GetUndefined();
1256+ module->SetModuleRequests(thread, undefinedValue);
1257+ }
1258+}
1259+ 
1224bool SourceTextModule::IsEvaluatedModule(JSThread *thread, StateVisit &stateVisit,1260bool SourceTextModule::IsEvaluatedModule(JSThread *thread, StateVisit &stateVisit,
1225 const JSHandle<SourceTextModule> &module)1261 const JSHandle<SourceTextModule> &module)
1226{1262{
@@ -2025,6 +2061,9 @@ void SourceTextModule::AsyncModuleExecutionFulfilled(JSThread *thread, const JSH
2025#endif2061#endif
2026 RETURN_IF_ABRUPT_COMPLETION(thread);2062 RETURN_IF_ABRUPT_COMPLETION(thread);
2027 }2063 }
2064+#if ENABLE_MODULE_MEMORY_OPTIMIZATION
2065+ ClearModuleRequestsIfNeeded(thread, module);
2066+#endif
2028 // 8. Let execList be a new empty List.2067 // 8. Let execList be a new empty List.
2029 AsyncParentCompletionSet execList;2068 AsyncParentCompletionSet execList;
2030 // 9. Perform GatherAvailableAncestors(module, execList).2069 // 9. Perform GatherAvailableAncestors(module, execList).
@@ -2070,6 +2109,9 @@ void SourceTextModule::AsyncModuleExecutionFulfilled(JSThread *thread, const JSH
2070#endif2109#endif
2071 RETURN_IF_ABRUPT_COMPLETION(thread);2110 RETURN_IF_ABRUPT_COMPLETION(thread);
2072 }2111 }
2112+#if ENABLE_MODULE_MEMORY_OPTIMIZATION
2113+ ClearModuleRequestsIfNeeded(thread, m);
2114+#endif
2073 }2115 }
2074 }2116 }
2075 }2117 }
@@ -2175,7 +2217,7 @@ void SourceTextModule::SearchCircularImport(JSThread *thread, const CString &cir
2175 CString &requiredModuleName, bool printOtherCircular)2217 CString &requiredModuleName, bool printOtherCircular)
2176{2218{
2177 // Use RequestedModules instead of ModuleRequests, because ModuleRequests may be2219 // Use RequestedModules instead of ModuleRequests, because ModuleRequests may be
2178- // cleared by ClearInstantiationFieldsIfNeeded after instantiation.2220+ // cleared after evaluation.
2179 if (module->GetRequestedModules(thread).IsUndefined()) {2221 if (module->GetRequestedModules(thread).IsUndefined()) {
2180 return;2222 return;
2181 }2223 }
Mecmascript/module/js_module_source_text.h+3-1
@@ -564,10 +564,12 @@ private:
564 const JSHandle<SourceTextModule> module,564 const JSHandle<SourceTextModule> module,
565 const int index);565 const int index);
566 566 
567- static void ClearInstantiationFieldsIfNeeded(JSThread *thread, JSHandle<SourceTextModule> &module);567+ static void ClearImportEntriesIfNeeded(JSThread *thread, JSHandle<SourceTextModule> &module);
568 568 
569 static void ClearTopLevelCapabilityIfNeeded(JSThread *thread, const JSHandle<SourceTextModule> &module);569 static void ClearTopLevelCapabilityIfNeeded(JSThread *thread, const JSHandle<SourceTextModule> &module);
570 570 
571+ static void ClearModuleRequestsIfNeeded(JSThread *thread, const JSHandle<SourceTextModule> &module);
572+ 
571 static void EvaluateJsonModule(JSThread *thread, JSHandle<SourceTextModule> module,573 static void EvaluateJsonModule(JSThread *thread, JSHandle<SourceTextModule> module,
572 const JSPandaFile *jsPandaFile, CString recordName);574 const JSPandaFile *jsPandaFile, CString recordName);
573 575 
Mecmascript/module/tests/ecma_module_test.cpp+368-61
@@ -23,6 +23,7 @@
23#include "ecmascript/jspandafile/js_pandafile.h"23#include "ecmascript/jspandafile/js_pandafile.h"
24#include "ecmascript/jspandafile/js_pandafile_executor.h"24#include "ecmascript/jspandafile/js_pandafile_executor.h"
25#include "ecmascript/jspandafile/js_pandafile_manager.h"25#include "ecmascript/jspandafile/js_pandafile_manager.h"
26+#include "ecmascript/snapshot/common/modules_snapshot_helper.h"
26#include "ecmascript/jspandafile/program_object.h"27#include "ecmascript/jspandafile/program_object.h"
27#include "ecmascript/js_object-inl.h"28#include "ecmascript/js_object-inl.h"
28#include "ecmascript/module/js_module_manager.h"29#include "ecmascript/module/js_module_manager.h"
@@ -105,15 +106,20 @@ public:
105 106 
106 // Wrappers for private SourceTextModule methods — friendship is not inherited,107 // Wrappers for private SourceTextModule methods — friendship is not inherited,
107 // so gtest-derived classes cannot call them directly.108 // so gtest-derived classes cannot call them directly.
108- static void ClearInstantiationFieldsIfNeeded(JSThread *thread, JSHandle<SourceTextModule> &module)109+ static void ClearImportEntriesIfNeeded(JSThread *thread, JSHandle<SourceTextModule> &module)
109 {110 {
110- SourceTextModule::ClearInstantiationFieldsIfNeeded(thread, module);111+ SourceTextModule::ClearImportEntriesIfNeeded(thread, module);
111 }112 }
112 113 
113 static void ClearTopLevelCapabilityIfNeeded(JSThread *thread, const JSHandle<SourceTextModule> &module)114 static void ClearTopLevelCapabilityIfNeeded(JSThread *thread, const JSHandle<SourceTextModule> &module)
114 {115 {
115 SourceTextModule::ClearTopLevelCapabilityIfNeeded(thread, module);116 SourceTextModule::ClearTopLevelCapabilityIfNeeded(thread, module);
116 }117 }
118+ 
119+ static void ClearModuleRequestsIfNeeded(JSThread *thread, const JSHandle<SourceTextModule> &module)
120+ {
121+ SourceTextModule::ClearModuleRequestsIfNeeded(thread, module);
122+ }
117};123};
118 124 
119JSHandle<JSTaggedValue> EcmaModuleTest::MockRequireNapiFailure(JsiRuntimeCallInfo *runtimeCallInfo)125JSHandle<JSTaggedValue> EcmaModuleTest::MockRequireNapiFailure(JsiRuntimeCallInfo *runtimeCallInfo)
@@ -7107,13 +7113,13 @@ HWTEST_F_L0(EcmaModuleTest, ModuleValueAccessor_GetNativeOrCjsExports_OtherModul
7107 7113 
7108/*7114/*
7109 * Feature: Module Memory Optimization7115 * Feature: Module Memory Optimization
7110- * Function: ClearInstantiationFieldsIfNeeded7116+ * Function: ClearImportEntriesIfNeeded
7111 * SubFunction: ImportEntries cleared after Instantiate7117 * SubFunction: ImportEntries cleared after Instantiate
7112 * FunctionPoints: Verify ImportEntries is set to Undefined7118 * FunctionPoints: Verify ImportEntries is set to Undefined
7113 * CaseDescription: Create a module at INSTANTIATED status, add ImportEntries, call cleanup,7119 * CaseDescription: Create a module at INSTANTIATED status, add ImportEntries, call cleanup,
7114 * verify ImportEntries is cleared7120 * verify ImportEntries is cleared
7115 */7121 */
7116-HWTEST_F_L0(EcmaModuleTest, ClearInstantiationFields_ImportEntries_Cleared)7122+HWTEST_F_L0(EcmaModuleTest, ClearImportEntries_ImportEntries_Cleared)
7117{7123{
7118 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();7124 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
7119 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();7125 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
@@ -7124,18 +7130,18 @@ HWTEST_F_L0(EcmaModuleTest, ClearInstantiationFields_ImportEntries_Cleared)
7124 SourceTextModule::AddImportEntry(thread, module, importEntry, 0, 1);7130 SourceTextModule::AddImportEntry(thread, module, importEntry, 0, 1);
7125 EXPECT_FALSE(module->GetImportEntries(thread).IsUndefined());7131 EXPECT_FALSE(module->GetImportEntries(thread).IsUndefined());
7126 7132 
7127- ClearInstantiationFieldsIfNeeded(thread, module);7133+ ClearImportEntriesIfNeeded(thread, module);
7128 EXPECT_TRUE(module->GetImportEntries(thread).IsUndefined());7134 EXPECT_TRUE(module->GetImportEntries(thread).IsUndefined());
7129}7135}
7130 7136 
7131/*7137/*
7132 * Feature: Module Memory Optimization7138 * Feature: Module Memory Optimization
7133- * Function: ClearInstantiationFieldsIfNeeded7139+ * Function: ClearImportEntriesIfNeeded
7134- * SubFunction: ModuleRequests NOT cleared for shared module7140+ * SubFunction: ImportEntries NOT cleared for shared module
7135- * FunctionPoints: Verify ModuleRequests is preserved for shared modules7141+ * FunctionPoints: Verify ImportEntries is preserved for shared modules
7136- * CaseDescription: Shared module needs ModuleRequests for cross-thread fallback resolve7142+ * CaseDescription: Shared module ImportEntries should not be cleared by ClearImportEntriesIfNeeded
7137 */7143 */
7138-HWTEST_F_L0(EcmaModuleTest, ClearInstantiationFields_ModuleRequests_NotCleared_Shared)7144+HWTEST_F_L0(EcmaModuleTest, ClearImportEntries_NotCleared_Shared)
7139{7145{
7140 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();7146 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
7141 JSHandle<SourceTextModule> module = factory->NewSSourceTextModule();7147 JSHandle<SourceTextModule> module = factory->NewSSourceTextModule();
@@ -7143,23 +7149,24 @@ HWTEST_F_L0(EcmaModuleTest, ClearInstantiationFields_ModuleRequests_NotCleared_S
7143 module->SetSharedType(SharedTypes::SHARED_MODULE);7149 module->SetSharedType(SharedTypes::SHARED_MODULE);
7144 7150 
7145 // Shared module fields cannot be populated with non-shared-heap values7151 // Shared module fields cannot be populated with non-shared-heap values
7146- // (WriteBarrier ASSERT in debug mode). ModuleRequests is initially undefined7152+ // (WriteBarrier ASSERT in debug mode). ImportEntries is initially undefined
7147- // and should remain undefined after cleanup i.e., shared modules are skipped.7153+ // and should remain undefined — ClearImportEntriesIfNeeded does not have
7148- EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());7154+ // IsSharedModule check, but shared module ImportEntries starts as undefined.
7155+ EXPECT_TRUE(module->GetImportEntries(thread).IsUndefined());
7149 7156 
7150- ClearInstantiationFieldsIfNeeded(thread, module);7157+ ClearImportEntriesIfNeeded(thread, module);
7151- EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());7158+ EXPECT_TRUE(module->GetImportEntries(thread).IsUndefined());
7152}7159}
7153 7160 
7154/*7161/*
7155 * Feature: Module Memory Optimization7162 * Feature: Module Memory Optimization
7156- * Function: ClearInstantiationFieldsIfNeeded7163+ * Function: ClearImportEntriesIfNeeded
7157 * SubFunction: ImportEntries preserved when ModuleLogger is enabled7164 * SubFunction: ImportEntries preserved when ModuleLogger is enabled
7158 * FunctionPoints: Verify ImportEntries is NOT cleared when ModuleLogger is active7165 * FunctionPoints: Verify ImportEntries is NOT cleared when ModuleLogger is active
7159 * CaseDescription: ModuleLogger reads ImportEntries for diagnostics, so it must be7166 * CaseDescription: ModuleLogger reads ImportEntries for diagnostics, so it must be
7160 * preserved even after Instantiate when logging is on.7167 * preserved even after Instantiate when logging is on.
7161 */7168 */
7162-HWTEST_F_L0(EcmaModuleTest, ClearInstantiationFields_ImportEntries_Preserved_WithModuleLogger)7169+HWTEST_F_L0(EcmaModuleTest, ClearImportEntries_ImportEntries_Preserved_WithModuleLogger)
7163{7170{
7164 EcmaVM *vm = thread->GetEcmaVM();7171 EcmaVM *vm = thread->GetEcmaVM();
7165 ObjectFactory *factory = vm->GetFactory();7172 ObjectFactory *factory = vm->GetFactory();
@@ -7175,7 +7182,7 @@ HWTEST_F_L0(EcmaModuleTest, ClearInstantiationFields_ImportEntries_Preserved_Wit
7175 ModuleLogger *moduleLogger = new ModuleLogger(vm);7182 ModuleLogger *moduleLogger = new ModuleLogger(vm);
7176 thread->SetModuleLogger(moduleLogger);7183 thread->SetModuleLogger(moduleLogger);
7177 7184 
7178- ClearInstantiationFieldsIfNeeded(thread, module);7185+ ClearImportEntriesIfNeeded(thread, module);
7179 EXPECT_FALSE(module->GetImportEntries(thread).IsUndefined());7186 EXPECT_FALSE(module->GetImportEntries(thread).IsUndefined());
7180 7187 
7181 // Cleanup7188 // Cleanup
@@ -7190,7 +7197,7 @@ HWTEST_F_L0(EcmaModuleTest, ClearInstantiationFields_ImportEntries_Preserved_Wit
7190 * FunctionPoints: Verify TopLevelCapability is set to Undefined after Evaluate7197 * FunctionPoints: Verify TopLevelCapability is set to Undefined after Evaluate
7191 * CaseDescription: Non-shared module at EVALUATED status, TopLevelCapability should be cleared7198 * CaseDescription: Non-shared module at EVALUATED status, TopLevelCapability should be cleared
7192 */7199 */
7193-HWTEST_F_L0(EcmaModuleTest, ClearPostEvaluationFields_TopLevelCapability_Cleared)7200+HWTEST_F_L0(EcmaModuleTest, ClearTopLevelCapability_Cleared)
7194{7201{
7195 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();7202 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
7196 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();7203 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
@@ -7212,7 +7219,7 @@ HWTEST_F_L0(EcmaModuleTest, ClearPostEvaluationFields_TopLevelCapability_Cleared
7212 * FunctionPoints: Verify shared module preserves TopLevelCapability7219 * FunctionPoints: Verify shared module preserves TopLevelCapability
7213 * CaseDescription: Shared module needs TopLevelCapability for cross-thread Evaluate redirect7220 * CaseDescription: Shared module needs TopLevelCapability for cross-thread Evaluate redirect
7214 */7221 */
7215-HWTEST_F_L0(EcmaModuleTest, ClearPostEvaluationFields_TopLevelCapability_NotCleared_Shared)7222+HWTEST_F_L0(EcmaModuleTest, ClearTopLevelCapability_NotCleared_Shared)
7216{7223{
7217 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();7224 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
7218 JSHandle<SourceTextModule> module = factory->NewSSourceTextModule();7225 JSHandle<SourceTextModule> module = factory->NewSSourceTextModule();
@@ -7228,6 +7235,68 @@ HWTEST_F_L0(EcmaModuleTest, ClearPostEvaluationFields_TopLevelCapability_NotClea
7228 EXPECT_TRUE(module->GetTopLevelCapability(thread).IsUndefined());7235 EXPECT_TRUE(module->GetTopLevelCapability(thread).IsUndefined());
7229}7236}
7230 7237 
7238+/*
7239+ * Feature: Module Memory Optimization
7240+ * Function: ClearModuleRequestsIfNeeded
7241+ * SubFunction: ModuleRequests NOT cleared when VM state is CANNOT_CLEAR
7242+ * FunctionPoints: Verify ModuleRequests is preserved when snapshot is active
7243+ * CaseDescription: Non-shared module, snapshot active (CANNOT_CLEAR state),
7244+ * ModuleRequests should not be cleared until serialization completes
7245+ */
7246+HWTEST_F_L0(EcmaModuleTest, ClearModuleRequests_NotCleared_CannotClearState)
7247+{
7248+ EcmaVM *vm = thread->GetEcmaVM();
7249+ ObjectFactory *factory = vm->GetFactory();
7250+ JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7251+ module->SetStatus(ModuleStatus::EVALUATED);
7252+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7253+ 
7254+ JSHandle<EcmaString> requestStr = factory->NewFromASCII("./module_a");
7255+ JSHandle<TaggedArray> moduleRequests = factory->NewTaggedArray(1);
7256+ moduleRequests->Set(thread, 0, requestStr);
7257+ module->SetModuleRequests(thread, moduleRequests);
7258+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7259+ 
7260+ // CANNOT_CLEAR: ModuleRequests not cleared
7261+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CANNOT_CLEAR);
7262+ ClearModuleRequestsIfNeeded(thread, module);
7263+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7264+ 
7265+ // Transition to CAN_CLEAR: now cleared
7266+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
7267+ ClearModuleRequestsIfNeeded(thread, module);
7268+ EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());
7269+ 
7270+ // Cleanup
7271+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7272+}
7273+ 
7274+/*
7275+ * Feature: Module Memory Optimization
7276+ * Function: ClearModuleRequestsIfNeeded
7277+ * SubFunction: ModuleRequests NOT cleared for shared module regardless of VM state
7278+ * FunctionPoints: Verify shared modules skip ModuleRequests clearing entirely
7279+ * CaseDescription: Shared module needs ModuleRequests for cross-thread fallback resolve
7280+ */
7281+HWTEST_F_L0(EcmaModuleTest, ClearModuleRequests_NotCleared_Shared)
7282+{
7283+ EcmaVM *vm = thread->GetEcmaVM();
7284+ ObjectFactory *factory = vm->GetFactory();
7285+ JSHandle<SourceTextModule> module = factory->NewSSourceTextModule();
7286+ module->SetStatus(ModuleStatus::EVALUATED);
7287+ module->SetSharedType(SharedTypes::SHARED_MODULE);
7288+ 
7289+ // Shared module fields cannot be populated with non-shared-heap values
7290+ // (WriteBarrier ASSERT in debug mode). ModuleRequests is initially undefined
7291+ // and should remain undefined after cleanup — i.e., shared modules are skipped.
7292+ EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());
7293+ 
7294+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
7295+ 
7296+ ClearModuleRequestsIfNeeded(thread, module);
7297+ EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());
7298+}
7299+ 
7231/*7300/*
7232 * Feature: Module Memory Optimization7301 * Feature: Module Memory Optimization
7233 * Function: InnerModuleEvaluationUnsafe line 1059 guard7302 * Function: InnerModuleEvaluationUnsafe line 1059 guard
@@ -7251,14 +7320,17 @@ HWTEST_F_L0(EcmaModuleTest, EvaluatedModule_SkipsCycleRootErrorCheck)
7251 7320 
7252/*7321/*
7253 * Feature: Module Memory Optimization7322 * Feature: Module Memory Optimization
7254- * Function: ClearInstantiationFieldsIfNeeded + ClearTopLevelCapabilityIfNeeded7323+ * Function: ClearImportEntriesIfNeeded + ClearTopLevelCapabilityIfNeeded
7255 * SubFunction: Full cleanup lifecycle for non-shared module7324 * SubFunction: Full cleanup lifecycle for non-shared module
7256- * FunctionPoints: Verify both cleanup phases work correctly7325+ * FunctionPoints: Verify both sync and async cleanup phases work correctly with VM state
7257- * CaseDescription: Instantiate phase clears ImportEntries, Evaluate phase clears TopLevelCapability7326+ * CaseDescription: Sync path (InnerModuleEvaluationUnsafe): ImportEntries + TopLevelCapability
7327+ * Async path (AsyncModuleExecutionFulfilled): TopLevelCapability + ModuleRequests
7328+ * ModuleRequests clearing depends on VM ModuleRequestsClearState
7258 */7329 */
7259HWTEST_F_L0(EcmaModuleTest, FullLifecycle_NonSharedModule_FieldsCleared)7330HWTEST_F_L0(EcmaModuleTest, FullLifecycle_NonSharedModule_FieldsCleared)
7260{7331{
7261- ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();7332+ EcmaVM *vm = thread->GetEcmaVM();
7333+ ObjectFactory *factory = vm->GetFactory();
7262 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();7334 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7263 module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);7335 module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7264 7336 
@@ -7266,75 +7338,310 @@ HWTEST_F_L0(EcmaModuleTest, FullLifecycle_NonSharedModule_FieldsCleared)
7266 module->SetStatus(ModuleStatus::INSTANTIATED);7338 module->SetStatus(ModuleStatus::INSTANTIATED);
7267 JSHandle<ImportEntry> importEntry = factory->NewImportEntry();7339 JSHandle<ImportEntry> importEntry = factory->NewImportEntry();
7268 SourceTextModule::AddImportEntry(thread, module, importEntry, 0, 1);7340 SourceTextModule::AddImportEntry(thread, module, importEntry, 0, 1);
7341+ JSHandle<EcmaString> requestStr = factory->NewFromASCII("./module_a");
7342+ JSHandle<TaggedArray> moduleRequests = factory->NewTaggedArray(1);
7343+ moduleRequests->Set(thread, 0, requestStr);
7344+ module->SetModuleRequests(thread, moduleRequests);
7269 EXPECT_FALSE(module->GetImportEntries(thread).IsUndefined());7345 EXPECT_FALSE(module->GetImportEntries(thread).IsUndefined());
7346+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7270 7347 
7271- ClearInstantiationFieldsIfNeeded(thread, module);7348+ ClearImportEntriesIfNeeded(thread, module);
7272 EXPECT_TRUE(module->GetImportEntries(thread).IsUndefined());7349 EXPECT_TRUE(module->GetImportEntries(thread).IsUndefined());
7350+ // ModuleRequests NOT cleared by ClearImportEntriesIfNeeded (only ImportEntries)
7351+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7273 7352 
7274- // Phase 2: Evaluate clear TopLevelCapability7353+ // Phase 2: Evaluate sync path (InnerModuleEvaluationUnsafe)
7354+ // TopLevelCapability cleared, ModuleRequests NOT cleared (CANNOT_CLEAR state)
7275 module->SetStatus(ModuleStatus::EVALUATED);7355 module->SetStatus(ModuleStatus::EVALUATED);
7276 JSHandle<JSPromise> capability = factory->NewJSPromise();7356 JSHandle<JSPromise> capability = factory->NewJSPromise();
7277 module->SetTopLevelCapability(thread, capability);7357 module->SetTopLevelCapability(thread, capability);
7278 EXPECT_FALSE(module->GetTopLevelCapability(thread).IsUndefined());7358 EXPECT_FALSE(module->GetTopLevelCapability(thread).IsUndefined());
7279 7359 
7360+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CANNOT_CLEAR);
7361+ ClearTopLevelCapabilityIfNeeded(thread, module);
7362+ EXPECT_TRUE(module->GetTopLevelCapability(thread).IsUndefined());
7363+ 
7364+ // ModuleRequests NOT cleared in CANNOT_CLEAR state
7365+ ClearModuleRequestsIfNeeded(thread, module);
7366+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7367+ 
7368+ // Phase 3: Simulate second launch — state CAN_CLEAR (directly set for test)
7369+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
7370+ ClearModuleRequestsIfNeeded(thread, module);
7371+ EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());
7372+ 
7373+ // Cleanup
7374+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7375+}
7376+ 
7377+/*
7378+ * Feature: Module Memory Optimization
7379+ * Function: ClearModuleRequestsIfNeeded
7380+ * SubFunction: UNINITIALIZED lazy init — DisableModuleSnapshot sets CAN_CLEAR
7381+ * FunctionPoints: Verify lazy init path evaluates DisableModuleSnapshot and caches state
7382+ * CaseDescription: VM state is UNINITIALIZED, DisableModuleSnapshot is true,
7383+ * first call should init state to CAN_CLEAR and clear ModuleRequests
7384+ */
7385+HWTEST_F_L0(EcmaModuleTest, ClearModuleRequests_LazyInit_DisableModuleSnapshot)
7386+{
7387+ EcmaVM *vm = thread->GetEcmaVM();
7388+ ObjectFactory *factory = vm->GetFactory();
7389+ JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7390+ module->SetStatus(ModuleStatus::EVALUATED);
7391+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7392+ 
7393+ JSHandle<EcmaString> requestStr = factory->NewFromASCII("./module_a");
7394+ JSHandle<TaggedArray> moduleRequests = factory->NewTaggedArray(1);
7395+ moduleRequests->Set(thread, 0, requestStr);
7396+ module->SetModuleRequests(thread, moduleRequests);
7397+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7398+ 
7399+ // UNINITIALIZED state — lazy init evaluates DisableModuleSnapshot + IsModuleSnapshotDisabled
7400+ // and caches the result. After init, state should not be UNINITIALIZED.
7401+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7402+ ClearModuleRequestsIfNeeded(thread, module);
7403+ EXPECT_NE(vm->GetModuleRequestsClearState(), ModuleRequestsClearState::UNINITIALIZED);
7404+ 
7405+ // Cleanup
7406+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7407+}
7408+ 
7409+/*
7410+ * Feature: Module Memory Optimization
7411+ * Function: ClearModuleRequestsIfNeeded
7412+ * SubFunction: IsUndefined early return skips redundant clearing
7413+ * FunctionPoints: Verify already-cleared module is skipped without side effects
7414+ * CaseDescription: ModuleRequests already undefined, second call should return immediately
7415+ */
7416+HWTEST_F_L0(EcmaModuleTest, ClearModuleRequests_SkipAlreadyCleared)
7417+{
7418+ EcmaVM *vm = thread->GetEcmaVM();
7419+ ObjectFactory *factory = vm->GetFactory();
7420+ JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7421+ module->SetStatus(ModuleStatus::EVALUATED);
7422+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7423+ 
7424+ // ModuleRequests starts as undefined (no SetModuleRequests call)
7425+ EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());
7426+ 
7427+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
7428+ // Should return immediately — no crash, no side effects
7429+ ClearModuleRequestsIfNeeded(thread, module);
7430+ EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());
7431+ 
7432+ // Cleanup
7433+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7434+}
7435+ 
7436+/*
7437+ * Feature: Module Memory Optimization
7438+ * Function: ClearModuleRequestsIfNeeded
7439+ * SubFunction: UNINITIALIZED lazy init with g_featureLoaded_ MODULE bit set
7440+ * FunctionPoints: Verify lazy init path checks g_featureLoaded_ and sets CAN_CLEAR
7441+ * CaseDescription: VM state UNINITIALIZED, g_featureLoaded_ MODULE bit set
7442+ * (simulating second launch after serialization), should clear ModuleRequests
7443+ */
7444+HWTEST_F_L0(EcmaModuleTest, ClearModuleRequests_LazyInit_FeatureLoaded)
7445+{
7446+ EcmaVM *vm = thread->GetEcmaVM();
7447+ ObjectFactory *factory = vm->GetFactory();
7448+ JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7449+ module->SetStatus(ModuleStatus::EVALUATED);
7450+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7451+ 
7452+ JSHandle<EcmaString> requestStr = factory->NewFromASCII("./module_a");
7453+ JSHandle<TaggedArray> moduleRequests = factory->NewTaggedArray(1);
7454+ moduleRequests->Set(thread, 0, requestStr);
7455+ module->SetModuleRequests(thread, moduleRequests);
7456+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7457+ 
7458+ // Simulate second launch: DisableModuleSnapshot=true triggers CAN_CLEAR in CanClearModuleRequests
7459+ vm->GetJSOptions().SetDisableModuleSnapshot(true);
7460+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7461+ ModulesSnapshotHelper::MarkModuleSnapshotLoaded();
7462+ ClearModuleRequestsIfNeeded(thread, module);
7463+ EXPECT_EQ(vm->GetModuleRequestsClearState(), ModuleRequestsClearState::CAN_CLEAR);
7464+ EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());
7465+ 
7466+ // Cleanup
7467+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7468+ vm->GetJSOptions().SetDisableModuleSnapshot(false);
7469+}
7470+ 
7471+/*
7472+ * Feature: Module Memory Optimization
7473+ * Function: ClearImportEntriesIfNeeded
7474+ * SubFunction: ImportEntries preserved when IsDebugApp is true
7475+ * FunctionPoints: Verify ImportEntries is NOT cleared when debugger is attached
7476+ * CaseDescription: Debug app needs ImportEntries for debugging, so it must be preserved.
7477+ */
7478+HWTEST_F_L0(EcmaModuleTest, ClearImportEntries_NotCleared_DebugApp)
7479+{
7480+ EcmaVM *vm = thread->GetEcmaVM();
7481+ ObjectFactory *factory = vm->GetFactory();
7482+ JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7483+ module->SetStatus(ModuleStatus::INSTANTIATED);
7484+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7485+ 
7486+ JSHandle<ImportEntry> importEntry = factory->NewImportEntry();
7487+ SourceTextModule::AddImportEntry(thread, module, importEntry, 0, 1);
7488+ EXPECT_FALSE(module->GetImportEntries(thread).IsUndefined());
7489+ 
7490+ vm->GetJsDebuggerManager()->SetIsDebugApp(true);
7491+ ClearImportEntriesIfNeeded(thread, module);
7492+ EXPECT_FALSE(module->GetImportEntries(thread).IsUndefined());
7493+ 
7494+ // Cleanup
7495+ vm->GetJsDebuggerManager()->SetIsDebugApp(false);
7496+}
7497+ 
7498+/*
7499+ * Feature: Module Memory Optimization
7500+ * Function: ClearTopLevelCapabilityIfNeeded
7501+ * SubFunction: TopLevelCapability preserved when IsDebugApp is true
7502+ * FunctionPoints: Verify TopLevelCapability is NOT cleared when debugger is attached
7503+ * CaseDescription: Debug app needs TopLevelCapability for debugging, so it must be preserved.
7504+ */
7505+HWTEST_F_L0(EcmaModuleTest, ClearTopLevelCapability_NotCleared_DebugApp)
7506+{
7507+ EcmaVM *vm = thread->GetEcmaVM();
7508+ ObjectFactory *factory = vm->GetFactory();
7509+ JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7510+ module->SetStatus(ModuleStatus::EVALUATED);
7511+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7512+ 
7513+ JSHandle<JSPromise> capability = factory->NewJSPromise();
7514+ module->SetTopLevelCapability(thread, capability);
7515+ EXPECT_FALSE(module->GetTopLevelCapability(thread).IsUndefined());
7516+ 
7517+ vm->GetJsDebuggerManager()->SetIsDebugApp(true);
7518+ ClearTopLevelCapabilityIfNeeded(thread, module);
7519+ EXPECT_FALSE(module->GetTopLevelCapability(thread).IsUndefined());
7520+ 
7521+ // Cleanup
7522+ vm->GetJsDebuggerManager()->SetIsDebugApp(false);
7523+}
7524+ 
7525+/*
7526+ * Feature: Module Memory Optimization
7527+ * Function: ClearModuleRequestsIfNeeded
7528+ * SubFunction: ModuleRequests preserved when IsDebugApp is true
7529+ * FunctionPoints: Verify ModuleRequests is NOT cleared when debugger is attached
7530+ * CaseDescription: Debug app needs ModuleRequests for debugging, so it must be preserved.
7531+ */
7532+HWTEST_F_L0(EcmaModuleTest, ClearModuleRequests_NotCleared_DebugApp)
7533+{
7534+ EcmaVM *vm = thread->GetEcmaVM();
7535+ ObjectFactory *factory = vm->GetFactory();
7536+ JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7537+ module->SetStatus(ModuleStatus::EVALUATED);
7538+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7539+ 
7540+ JSHandle<EcmaString> requestStr = factory->NewFromASCII("./module_a");
7541+ JSHandle<TaggedArray> moduleRequests = factory->NewTaggedArray(1);
7542+ moduleRequests->Set(thread, 0, requestStr);
7543+ module->SetModuleRequests(thread, moduleRequests);
7544+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7545+ 
7546+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
7547+ vm->GetJsDebuggerManager()->SetIsDebugApp(true);
7548+ ClearModuleRequestsIfNeeded(thread, module);
7549+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7550+ 
7551+ // Cleanup
7552+ vm->GetJsDebuggerManager()->SetIsDebugApp(false);
7553+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7554+}
7555+ 
7556+/*
7557+ * Feature: Module Memory Optimization
7558+ * Function: ClearTopLevelCapabilityIfNeeded
7559+ * SubFunction: TopLevelCapability IsUndefined early return
7560+ * FunctionPoints: Verify already-undefined TopLevelCapability is skipped without side effects
7561+ * CaseDescription: TopLevelCapability already undefined, call should return immediately.
7562+ */
7563+HWTEST_F_L0(EcmaModuleTest, ClearTopLevelCapability_SkipAlreadyUndefined)
7564+{
7565+ EcmaVM *vm = thread->GetEcmaVM();
7566+ ObjectFactory *factory = vm->GetFactory();
7567+ JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7568+ module->SetStatus(ModuleStatus::EVALUATED);
7569+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7570+ 
7571+ // TopLevelCapability starts as undefined (no SetTopLevelCapability call)
7572+ EXPECT_TRUE(module->GetTopLevelCapability(thread).IsUndefined());
7573+ 
7280 ClearTopLevelCapabilityIfNeeded(thread, module);7574 ClearTopLevelCapabilityIfNeeded(thread, module);
7281 EXPECT_TRUE(module->GetTopLevelCapability(thread).IsUndefined());7575 EXPECT_TRUE(module->GetTopLevelCapability(thread).IsUndefined());
7282}7576}
7283 7577 
7284/*7578/*
7285 * Feature: Module Memory Optimization7579 * Feature: Module Memory Optimization
7286- * Function: SerializeModuleCNativeObjects7580+ * Function: ClearModuleRequestsIfNeeded
7287- * SubFunction: ModuleRequests=Undefined serialization skips gracefully7581+ * SubFunction: ModuleRequests NOT cleared when LazyImportStatusArray exists
7288- * FunctionPoints: Verify no crash when serializing module with cleaned ModuleRequests7582+ * FunctionPoints: Verify ModuleRequests is preserved when lazyArray is non-null
7289- * CaseDescription: After ClearInstantiationFieldsIfNeeded, ModuleRequests is Undefined.7583+ * CaseDescription: Serialization depends on lazyArray && ModuleRequests.IsTaggedArray(),
7290- * Serialization should skip lazy-import array traversal safely.7584+ * so ModuleRequests must not be cleared while lazyArray exists.
7291 */7585 */
7292-HWTEST_F_L0(EcmaModuleTest, ModuleRequestsUndefined_SnapshotSerializeNoCrash)7586+HWTEST_F_L0(EcmaModuleTest, ClearModuleRequests_NotCleared_LazyArrayExists)
7293{7587{
7294- ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();7588+ EcmaVM *vm = thread->GetEcmaVM();
7589+ ObjectFactory *factory = vm->GetFactory();
7295 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();7590 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7296- module->SetEcmaModuleRecordNameString("test");7591+ module->SetStatus(ModuleStatus::EVALUATED);
7297 module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);7592 module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7298 7593 
7299- // Simulate cleaned ModuleRequests after ClearInstantiationFieldsIfNeeded7594+ JSHandle<EcmaString> requestStr = factory->NewFromASCII("./module_a");
7300- module->SetModuleRequests(thread, JSTaggedValue::Undefined());7595+ JSHandle<TaggedArray> moduleRequests = factory->NewTaggedArray(1);
7596+ moduleRequests->Set(thread, 0, requestStr);
7597+ module->SetModuleRequests(thread, moduleRequests);
7598+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7301 7599 
7302- // Verify serialization code can read Undefined ModuleRequests without crash:7600+ // Simulate lazy import array present
7303- // lazyArray && requests.IsTaggedArray() false → skip traversal7601+ bool *lazyArray = new bool[1] {false};
7304- JSTaggedValue requests = module->GetModuleRequests(thread);7602+ module->SetLazyImportArray(lazyArray);
7305- EXPECT_TRUE(requests.IsUndefined());7603+ 
7306- EXPECT_FALSE(requests.IsTaggedArray());7604+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
7605+ ClearModuleRequestsIfNeeded(thread, module);
7606+ // ModuleRequests NOT cleared because lazyArray exists
7607+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7608+ 
7609+ // Cleanup
7610+ module->DestroyLazyImportArray();
7611+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7307}7612}
7308 7613 
7309/*7614/*
7310 * Feature: Module Memory Optimization7615 * Feature: Module Memory Optimization
7311- * Function: ClearInstantiationFieldsIfNeeded7616+ * Function: ClearModuleRequestsIfNeeded
7312- * SubFunction: Module variable access via Environment unaffected by ModuleRequests cleanup7617+ * SubFunction: ModuleRequests cleared when LazyImportStatusArray is null
7313- * FunctionPoints: Verify Environment binding is preserved after ModuleRequests is cleared7618+ * FunctionPoints: Verify ModuleRequests is cleared when lazyArray is null and VM state allows
7314- * CaseDescription: Module variable access goes through Environment, not ModuleRequests.7619+ * CaseDescription: When lazyArray is null, serialization does not depend on ModuleRequests,
7315- * Clearing ModuleRequests after Instantiate must not affect variable access.7620+ * so it can be safely cleared.
7316 */7621 */
7317-HWTEST_F_L0(EcmaModuleTest, ModuleVariableAccess_AfterModuleRequestsCleared)7622+HWTEST_F_L0(EcmaModuleTest, ClearModuleRequests_Cleared_LazyArrayNull)
7318{7623{
7319- ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();7624+ EcmaVM *vm = thread->GetEcmaVM();
7625+ ObjectFactory *factory = vm->GetFactory();
7320 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();7626 JSHandle<SourceTextModule> module = factory->NewSourceTextModule();
7321- module->SetEcmaModuleRecordNameString("test");
7322- module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7323 module->SetStatus(ModuleStatus::EVALUATED);7627 module->SetStatus(ModuleStatus::EVALUATED);
7628+ module->SetSharedType(SharedTypes::UNSENDABLE_MODULE);
7324 7629 
7325- // Set up Environment binding (simulates Instantiate result)7630+ JSHandle<EcmaString> requestStr = factory->NewFromASCII("./module_a");
7326- JSHandle<TaggedArray> environment = factory->NewTaggedArray(1);7631+ JSHandle<TaggedArray> moduleRequests = factory->NewTaggedArray(1);
7327- environment->Set(thread, 0, JSTaggedValue(42));7632+ moduleRequests->Set(thread, 0, requestStr);
7328- module->SetEnvironment(thread, environment);7633+ module->SetModuleRequests(thread, moduleRequests);
7634+ EXPECT_FALSE(module->GetModuleRequests(thread).IsUndefined());
7329 7635 
7330- // Clear ModuleRequests7636+ // lazyArray is null by default (NewSourceTextModule does not set it)
7331- module->SetModuleRequests(thread, JSTaggedValue::Undefined());7637+ EXPECT_EQ(module->GetLazyImportStatusArray(), nullptr);
7332 7638 
7333- // Environment still accessible7639+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::CAN_CLEAR);
7334- JSTaggedValue envValue = module->GetEnvironment(thread);7640+ ClearModuleRequestsIfNeeded(thread, module);
7335- EXPECT_FALSE(envValue.IsUndefined());7641+ EXPECT_TRUE(module->GetModuleRequests(thread).IsUndefined());
7336- JSHandle<TaggedArray> env(thread, envValue);7642+ 
7337- EXPECT_EQ(env->Get(thread, 0), JSTaggedValue(42));7643+ // Cleanup
7644+ vm->SetModuleRequestsClearState(ModuleRequestsClearState::UNINITIALIZED);
7338}7645}
7339 7646 
7340/*7647/*
Mecmascript/module/tests/module_snapshot_test.cpp+2-2
@@ -801,13 +801,13 @@ HWTEST_F_L0(ModuleSnapshotTest, SerializeSlicedString)
801 801 
802HWTEST_F_L0(ModuleSnapshotTest, DisableSnapshotFeatureByOption)802HWTEST_F_L0(ModuleSnapshotTest, DisableSnapshotFeatureByOption)
803{803{
804- auto oldLoaded = ModulesSnapshotHelper::g_featureState_;804+ auto oldFeatureLoaded = ModulesSnapshotHelper::g_featureLoaded_;
805 ModulesSnapshotHelper::g_featureState_ = 0;805 ModulesSnapshotHelper::g_featureState_ = 0;
806 ModulesSnapshotHelper::MarkSnapshotDisabledByOption();806 ModulesSnapshotHelper::MarkSnapshotDisabledByOption();
807 ASSERT_EQ(ModulesSnapshotHelper::g_featureState_,807 ASSERT_EQ(ModulesSnapshotHelper::g_featureState_,
808 static_cast<int>(SnapshotFeatureState::MODULE) |808 static_cast<int>(SnapshotFeatureState::MODULE) |
809 static_cast<int>(SnapshotFeatureState::PANDAFILE));809 static_cast<int>(SnapshotFeatureState::PANDAFILE));
810- ASSERT_EQ(ModulesSnapshotHelper::g_featureLoaded_, oldLoaded);810+ ASSERT_EQ(ModulesSnapshotHelper::g_featureLoaded_, oldFeatureLoaded);
811}811}
812 812 
813HWTEST_F_L0(ModuleSnapshotTest, ShouldDisableModuleSnapshot)813HWTEST_F_L0(ModuleSnapshotTest, ShouldDisableModuleSnapshot)
Mecmascript/snapshot/common/modules_snapshot_helper.h+13-0
@@ -156,6 +156,19 @@ public:
156 static bool WriteFileHeader(FileMemMapWriter& writer, const SnapshotVersionInfo::UniquePtr &header);156 static bool WriteFileHeader(FileMemMapWriter& writer, const SnapshotVersionInfo::UniquePtr &header);
157 static std::string ReadFileHeader(FileMemMapReader& reader, const SnapshotVersionInfo::UniquePtr &header);157 static std::string ReadFileHeader(FileMemMapReader& reader, const SnapshotVersionInfo::UniquePtr &header);
158 158 
159+ static int GetFeatureLoaded()
160+ {
161+ return g_featureLoaded_;
162+ }
163+ 
164+ // For unit tests ONLY — avoids cross-test contamination from paths that
165+ // trigger UpdateFromStateFile. Do NOT call in production code: it resets
166+ // the global snapshot feature state.
167+ static void ResetStateForTest()
168+ {
169+ g_featureState_ = static_cast<int>(SnapshotFeatureState::DEFAULT);
170+ }
171+ 
159private:172private:
160 struct alignas(sizeof(uint64_t)) SerializeDataInfo {173 struct alignas(sizeof(uint64_t)) SerializeDataInfo {
161 uint32_t dataIndex_;174 uint32_t dataIndex_;