arkanalyzer 1.0.91 → 1.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -63,6 +63,9 @@ const getAllFiles_1 = require("../../utils/getAllFiles");
63
63
  const SdkUtils_1 = require("../../core/common/SdkUtils");
64
64
  const ArktsFrontend_1 = require("../arktsFrontend/ArktsFrontend");
65
65
  const ModelUtils_1 = require("../../core/common/ModelUtils");
66
+ const ArkClass_1 = require("../../core/model/ArkClass");
67
+ const ArkMethod_1 = require("../../core/model/ArkMethod");
68
+ const ArkNamespace_1 = require("../../core/model/ArkNamespace");
66
69
  const ModuleUtils_1 = require("../../utils/ModuleUtils");
67
70
  const Scene_1 = require("../../Scene");
68
71
  const logger = logger_1.default.getLogger(logger_1.LOG_MODULE_TYPE.ARKANALYZER, 'ModuleBuilder');
@@ -793,16 +796,14 @@ class ModuleBuilder {
793
796
  */
794
797
  depthLevelToLoadState(level) {
795
798
  switch (level) {
796
- case ModuleDepth_1.ModuleDepthLevel.META:
797
- return ArkModule_1.ModuleLoadState.META;
798
- case ModuleDepth_1.ModuleDepthLevel.IMPORTS:
799
- return ArkModule_1.ModuleLoadState.IMPORTS;
799
+ case ModuleDepth_1.ModuleDepthLevel.INDEX:
800
+ return ArkModule_1.ModuleLoadState.INDEX;
800
801
  case ModuleDepth_1.ModuleDepthLevel.SIGNATURES:
801
802
  return ArkModule_1.ModuleLoadState.SIGNATURES;
802
803
  case ModuleDepth_1.ModuleDepthLevel.BODIES:
803
804
  return ArkModule_1.ModuleLoadState.BODIES;
804
805
  default:
805
- return ArkModule_1.ModuleLoadState.META;
806
+ return ArkModule_1.ModuleLoadState.INDEX;
806
807
  }
807
808
  }
808
809
  /**
@@ -811,16 +812,14 @@ class ModuleBuilder {
811
812
  */
812
813
  loadStateToDepthLevel(loadState) {
813
814
  switch (loadState) {
814
- case ArkModule_1.ModuleLoadState.META:
815
- return ModuleDepth_1.ModuleDepthLevel.META;
816
- case ArkModule_1.ModuleLoadState.IMPORTS:
817
- return ModuleDepth_1.ModuleDepthLevel.IMPORTS;
815
+ case ArkModule_1.ModuleLoadState.INDEX:
816
+ return ModuleDepth_1.ModuleDepthLevel.INDEX;
818
817
  case ArkModule_1.ModuleLoadState.SIGNATURES:
819
818
  return ModuleDepth_1.ModuleDepthLevel.SIGNATURES;
820
819
  case ArkModule_1.ModuleLoadState.BODIES:
821
820
  return ModuleDepth_1.ModuleDepthLevel.BODIES;
822
821
  default:
823
- return ModuleDepth_1.ModuleDepthLevel.META;
822
+ return ModuleDepth_1.ModuleDepthLevel.INDEX;
824
823
  }
825
824
  }
826
825
  /**
@@ -898,8 +897,9 @@ class ModuleBuilder {
898
897
  * @param moduleId - ID of the module to load.
899
898
  * @param depthLevel - The depth level to load the module to.
900
899
  */
901
- loadModule(moduleId, depthLevel = ModuleDepth_1.ModuleDepthLevel.META) {
900
+ loadModule(moduleId, depthLevel = ModuleDepth_1.ModuleDepthLevel.SIGNATURES) {
902
901
  var _a, _b, _c, _d, _e;
902
+ (0, ModuleDepth_1.assertDirectLoadLevel)(depthLevel);
903
903
  const module = this.getModule(moduleId);
904
904
  if (!module) {
905
905
  return;
@@ -916,11 +916,14 @@ class ModuleBuilder {
916
916
  (_a = this.cache) === null || _a === void 0 ? void 0 : _a.register(moduleId);
917
917
  return;
918
918
  }
919
+ // INDEX hollow may have pruned non-exported IR; rebuild from disk when upgrading.
920
+ if (module.getLoadState() === ArkModule_1.ModuleLoadState.INDEX) {
921
+ this.resetModuleIrForRebuild(module);
922
+ }
919
923
  // Record heapUsed before actual build (for heapUsed table population)
920
924
  const recordHeapUsed = (_c = (_b = this.monitor) === null || _b === void 0 ? void 0 : _b.isEnabled()) !== null && _c !== void 0 ? _c : false;
921
925
  const heapUsedBefore = recordHeapUsed ? this.monitor.getCurrentHeapUsed() : 0;
922
- // Phase 1: build ArkFile objects to the effective level, with intra-module file
923
- // dependency analysis integrated (topological-order parsing for level > IMPORTS).
926
+ // Phase 1: build ArkFile IR to SIGNATURES/BODIES (imports + topo + signatures).
924
927
  this.buildModuleToLevel(module, depthLevel);
925
928
  // Phase 2: build method bodies when BODIES level was requested
926
929
  if (depthLevel >= ModuleDepth_1.ModuleDepthLevel.BODIES) {
@@ -942,17 +945,8 @@ class ModuleBuilder {
942
945
  (_e = this.cache) === null || _e === void 0 ? void 0 : _e.register(moduleId);
943
946
  }
944
947
  /**
945
- * Unload a module's data, releasing heavy data and resetting to NOT_LOADED state.
946
- *
947
- * Clears the module's filesMap (releasing ArkFile/ArkClass/ArkMethod objects), resets the
948
- * file dependency graph (so that the next {@link loadModule} rebuilds IMPORTS from scratch),
949
- * and sets the load state to NOT_LOADED. After unloading, {@link loadModule} can rebuild
950
- * the module from scratch.
951
- *
952
- * SDK modules are not unloaded (their data is built by {@link buildSdkModules} and shared
953
- * globally).
954
- *
955
- * @param moduleId - ID of the module to unload.
948
+ * Unload a module's data, releasing IR and resetting to NOT_LOADED.
949
+ * SDK modules are not unloaded (built by {@link buildSdkModules}).
956
950
  */
957
951
  unload(moduleId) {
958
952
  const module = this.getModule(moduleId);
@@ -962,10 +956,7 @@ class ModuleBuilder {
962
956
  if (module.getModuleType() === ArkModule_1.ModuleType.SDK) {
963
957
  return;
964
958
  }
965
- this.scene.disposeModule(module);
966
- this.breakInternalReferences(module);
967
- module.clearFilesMap();
968
- module.setFileDepGraph(undefined);
959
+ this.resetModuleIrForRebuild(module);
969
960
  module.setLoadState(ArkModule_1.ModuleLoadState.NOT_LOADED);
970
961
  }
971
962
  /**
@@ -999,6 +990,7 @@ class ModuleBuilder {
999
990
  this.monitor = this.scene.getMemoryMonitor();
1000
991
  this.cache = this.scene.getModuleCache();
1001
992
  this.topoOrder = topoOrder;
993
+ (0, ModuleDepth_1.assertDirectLoadLevel)(dependencyLoadLevel);
1002
994
  this.dependencyLoadLevel = dependencyLoadLevel;
1003
995
  this.topoOrderIndex = new Map();
1004
996
  for (let i = 0; i < topoOrder.length; i++) {
@@ -1016,7 +1008,7 @@ class ModuleBuilder {
1016
1008
  * During eviction, the heapUsed estimate is tracked via {@link HeapUsedEstimateState},
1017
1009
  * decremented by the heapUsed table value of each unloaded/downgraded module.
1018
1010
  */
1019
- evictIfNeeded(moduleId, depthLevel = ModuleDepth_1.ModuleDepthLevel.META) {
1011
+ evictIfNeeded(moduleId, depthLevel = ModuleDepth_1.ModuleDepthLevel.SIGNATURES) {
1020
1012
  if (!this.monitor || !this.cache || !this.topoOrderIndex) {
1021
1013
  return;
1022
1014
  }
@@ -1045,6 +1037,7 @@ class ModuleBuilder {
1045
1037
  const reverseTopo = [...this.topoOrder].reverse();
1046
1038
  this.runPhase1Eviction(hardProtected, softProtected, depGraph, heapUsedState);
1047
1039
  this.runPhase2Downgrade(protectedDeps, reverseTopo, heapUsedState);
1040
+ this.runPhase2bDowngradeToIndex(protectedDeps, reverseTopo, heapUsedState);
1048
1041
  this.runPhase3Eviction(protectedDeps, reverseTopo, heapUsedState);
1049
1042
  }
1050
1043
  runPhase1Eviction(hardProtected, softProtected, depGraph, heapUsedState) {
@@ -1056,7 +1049,8 @@ class ModuleBuilder {
1056
1049
  if (heapUsedState.estimate <= heapUsedState.limit) {
1057
1050
  return;
1058
1051
  }
1059
- const downgradeTarget = Math.max(this.dependencyLoadLevel, ModuleDepth_1.ModuleDepthLevel.SIGNATURES);
1052
+ // Prefer configured dependency load level (already coerced away from INDEX at init).
1053
+ const downgradeTarget = this.dependencyLoadLevel;
1060
1054
  const targetLoadState = this.depthLevelToLoadState(downgradeTarget);
1061
1055
  for (const id of reverseTopo) {
1062
1056
  if (heapUsedState.estimate <= heapUsedState.limit) {
@@ -1074,6 +1068,32 @@ class ModuleBuilder {
1074
1068
  heapUsedState.estimate -= decrease;
1075
1069
  }
1076
1070
  }
1071
+ /**
1072
+ * Eviction phase 2b: if still over limit after BODIES→SIGNATURES, downgrade protected
1073
+ * deps further to INDEX (hollow in-place IR; same lookup APIs as SIGNATURES).
1074
+ */
1075
+ runPhase2bDowngradeToIndex(protectedDeps, reverseTopo, heapUsedState) {
1076
+ var _a;
1077
+ if (heapUsedState.estimate <= heapUsedState.limit) {
1078
+ return;
1079
+ }
1080
+ const targetLoadState = ArkModule_1.ModuleLoadState.INDEX;
1081
+ for (const id of reverseTopo) {
1082
+ if (heapUsedState.estimate <= heapUsedState.limit) {
1083
+ break;
1084
+ }
1085
+ if (!protectedDeps.has(id) || !((_a = this.cache) === null || _a === void 0 ? void 0 : _a.has(id))) {
1086
+ continue;
1087
+ }
1088
+ const mod = this.getModule(id);
1089
+ if (!mod || mod.getLoadState() <= targetLoadState) {
1090
+ continue;
1091
+ }
1092
+ const decrease = this.estimateDowngradeHeapUsedDecrease(id, ModuleDepth_1.ModuleDepthLevel.INDEX);
1093
+ this.downgradeModule(id, ModuleDepth_1.ModuleDepthLevel.INDEX);
1094
+ heapUsedState.estimate -= decrease;
1095
+ }
1096
+ }
1077
1097
  runPhase3Eviction(protectedDeps, reverseTopo, heapUsedState) {
1078
1098
  var _a;
1079
1099
  if (heapUsedState.estimate <= heapUsedState.limit) {
@@ -1150,10 +1170,14 @@ class ModuleBuilder {
1150
1170
  return Math.max(0, Math.floor(currentHeapUsed * ModuleBuilder.DOWNGRADE_RELEASE_RATIO));
1151
1171
  }
1152
1172
  /**
1153
- * Downgrade a module's loaded data to the given target level (min SIGNATURES), releasing the
1154
- * heavy method-body/view-tree/AST data while keeping signatures (ArkClass/method signatures,
1155
- * filesMap, Scene index maps) so dependents can still resolve types. No-op if already at or
1156
- * below the target level. Used by eviction Phase 2.
1173
+ * Downgrade a module to the given target level. Used by eviction Phase 2 / 2b.
1174
+ *
1175
+ * - {@link ModuleDepthLevel.SIGNATURES}: clear method bodies / view trees / AST while keeping
1176
+ * full ArkFile signature IR.
1177
+ * - {@link ModuleDepthLevel.INDEX}: hollow in place (strip + prune non-exports). Use
1178
+ * {@link unload} to drop IR entirely.
1179
+ *
1180
+ * No-op if already at or below the target.
1157
1181
  */
1158
1182
  downgradeModule(moduleId, targetLevel) {
1159
1183
  const module = this.getModule(moduleId);
@@ -1164,6 +1188,19 @@ class ModuleBuilder {
1164
1188
  if (module.getLoadState() <= targetLoadState) {
1165
1189
  return;
1166
1190
  }
1191
+ if (targetLevel === ModuleDepth_1.ModuleDepthLevel.INDEX) {
1192
+ this.hollowModuleToIndex(module);
1193
+ return;
1194
+ }
1195
+ // SIGNATURES: strip bodies while keeping full signature IR.
1196
+ this.stripModuleBodiesAndAst(module);
1197
+ module.setLoadState(targetLoadState);
1198
+ }
1199
+ /**
1200
+ * Drop method bodies / view trees / AST / source text while keeping ArkFile shells.
1201
+ * Shared by SIGNATURES and INDEX downgrade paths.
1202
+ */
1203
+ stripModuleBodiesAndAst(module) {
1167
1204
  for (const arkFile of module.getFilesMap().values()) {
1168
1205
  for (const cls of ModelUtils_1.ModelUtils.getAllClassesInFile(arkFile)) {
1169
1206
  for (const mtd of cls.getMethods(true)) {
@@ -1177,7 +1214,114 @@ class ModuleBuilder {
1177
1214
  arkFile.setAST(null);
1178
1215
  arkFile.clearSourceCode();
1179
1216
  }
1180
- module.setLoadState(targetLoadState);
1217
+ }
1218
+ /**
1219
+ * INDEX retention: strip heavy payload in place, prune non-exported IR, keep export-reachable
1220
+ * shells registered on the module / Scene so existing lookup APIs still resolve.
1221
+ */
1222
+ hollowModuleToIndex(module) {
1223
+ if (module.getFilesMap().size === 0) {
1224
+ module.setFileDepGraph(undefined);
1225
+ module.setLoadState(ArkModule_1.ModuleLoadState.INDEX);
1226
+ return;
1227
+ }
1228
+ this.stripModuleBodiesAndAst(module);
1229
+ const { keepClasses, keepNamespaces } = this.collectExportReachableSets(module);
1230
+ this.pruneNonExportedIr(module, keepClasses, keepNamespaces);
1231
+ module.setFileDepGraph(undefined);
1232
+ module.setLoadState(ArkModule_1.ModuleLoadState.INDEX);
1233
+ }
1234
+ collectExportReachableSets(module) {
1235
+ const keepClasses = new Set();
1236
+ const keepNamespaces = new Set();
1237
+ for (const arkFile of module.getFilesMap().values()) {
1238
+ for (const exp of arkFile.getExportInfos()) {
1239
+ this.addExportToKeepSets(exp.getArkExport(), keepClasses, keepNamespaces);
1240
+ }
1241
+ }
1242
+ return { keepClasses, keepNamespaces };
1243
+ }
1244
+ addExportToKeepSets(arkExport, keepClasses, keepNamespaces) {
1245
+ if (!arkExport) {
1246
+ return;
1247
+ }
1248
+ if (arkExport instanceof ArkClass_1.ArkClass) {
1249
+ keepClasses.add(arkExport);
1250
+ const ns = arkExport.getDeclaringArkNamespace();
1251
+ if (ns) {
1252
+ keepNamespaces.add(ns);
1253
+ }
1254
+ return;
1255
+ }
1256
+ if (arkExport instanceof ArkMethod_1.ArkMethod) {
1257
+ const cls = arkExport.getDeclaringArkClass();
1258
+ keepClasses.add(cls);
1259
+ const ns = cls.getDeclaringArkNamespace();
1260
+ if (ns) {
1261
+ keepNamespaces.add(ns);
1262
+ }
1263
+ return;
1264
+ }
1265
+ if (arkExport instanceof ArkNamespace_1.ArkNamespace) {
1266
+ keepNamespaces.add(arkExport);
1267
+ }
1268
+ }
1269
+ pruneNonExportedIr(module, keepClasses, keepNamespaces) {
1270
+ for (const arkFile of module.getFilesMap().values()) {
1271
+ this.pruneNonKeptClasses(arkFile, keepClasses);
1272
+ this.pruneNonKeptNamespaces(arkFile, keepClasses, keepNamespaces);
1273
+ }
1274
+ }
1275
+ pruneNonKeptClasses(arkFile, keepClasses) {
1276
+ for (const cls of [...ModelUtils_1.ModelUtils.getAllClassesInFile(arkFile)]) {
1277
+ if (keepClasses.has(cls) || cls.isDefaultArkClass()) {
1278
+ continue;
1279
+ }
1280
+ for (const base of cls.getAllHeritageClasses()) {
1281
+ base.getExtendedClasses().delete(cls.getName());
1282
+ }
1283
+ for (const mtd of cls.getMethods(true)) {
1284
+ this.scene.removeMethod(mtd);
1285
+ mtd.clearBodyAndSupplementary();
1286
+ }
1287
+ const ns = cls.getDeclaringArkNamespace();
1288
+ if (ns) {
1289
+ ns.removeArkClass(cls);
1290
+ }
1291
+ else {
1292
+ arkFile.removeArkClass(cls);
1293
+ }
1294
+ }
1295
+ }
1296
+ pruneNonKeptNamespaces(arkFile, keepClasses, keepNamespaces) {
1297
+ for (const ns of [...arkFile.getNamespaces()]) {
1298
+ if (keepNamespaces.has(ns) || this.namespaceOwnsKeptClass(ns, keepClasses)) {
1299
+ continue;
1300
+ }
1301
+ arkFile.removeNamespace(ns);
1302
+ }
1303
+ }
1304
+ namespaceOwnsKeptClass(ns, keepClasses) {
1305
+ for (const cls of keepClasses) {
1306
+ if (cls.getDeclaringArkNamespace() === ns) {
1307
+ return true;
1308
+ }
1309
+ }
1310
+ return false;
1311
+ }
1312
+ /**
1313
+ * Clear module IR from Scene maps and the module's filesMap so the next load rebuilds
1314
+ * from disk. Used by {@link unload} and when upgrading out of hollow INDEX.
1315
+ */
1316
+ resetModuleIrForRebuild(module) {
1317
+ if (module.getFilesMap().size === 0) {
1318
+ module.setFileDepGraph(undefined);
1319
+ return;
1320
+ }
1321
+ this.scene.disposeModule(module);
1322
+ this.breakInternalReferences(module);
1323
+ module.clearFilesMap();
1324
+ module.setFileDepGraph(undefined);
1181
1325
  }
1182
1326
  /**
1183
1327
  * Get the number of source files in a module. If the module's filesMap is empty
@@ -1226,30 +1370,21 @@ class ModuleBuilder {
1226
1370
  return { hardProtected, softProtected };
1227
1371
  }
1228
1372
  /**
1229
- * Build module data to the specified depth level, integrating intra-module file dependency
1230
- * analysis into the build flow.
1373
+ * Build module ArkFile IR up to SIGNATURES or BODIES.
1374
+ * {@link ModuleDepthLevel.INDEX} is rejected ({@link assertDirectLoadLevel}).
1231
1375
  *
1232
- * Two-phase build for level > IMPORTS:
1233
1376
  * 1. Ensure ArkFile shells exist (create if filesMap is empty, reuse otherwise).
1234
- * 2. Build all files to IMPORTS level (lightweight import/export parsing, no dependency on
1235
- * other files in the module).
1236
- * 3. Analyze intra-module file dependencies → compute topological order (moved here from
1237
- * {@link loadModule} so it is part of the build-to-level flow).
1238
- * 4. For level > IMPORTS: upgrade each file to the target level (SIGNATURES/BODIES) in
1239
- * topological order, so that depended-on files are parsed first.
1240
- *
1241
- * For level == META: only shells are created (no content).
1242
- * For level == IMPORTS: steps 1-3 (topoOrder available for later type inference).
1243
- * For level >= SIGNATURES: steps 1-4 (signatures built in topoOrder).
1377
+ * 2. Build import/export info (if not already done) + analyze intra-module file dependencies.
1378
+ * 3. Upgrade each file to the target level in topological order.
1244
1379
  *
1245
- * The {@link ArkModule.hasFileTopoOrder} flag is used to detect whether IMPORTS was already
1246
- * built (e.g. when upgrading from IMPORTS to SIGNATURES), avoiding redundant re-parsing.
1380
+ * Method bodies are built later by {@link loadModule} when the target is BODIES.
1247
1381
  *
1248
1382
  * @param module - The module to build.
1249
- * @param level - The target depth level.
1383
+ * @param level - Must be SIGNATURES or BODIES.
1250
1384
  */
1251
1385
  buildModuleToLevel(module, level) {
1252
- // 1. Ensure ArkFile shells exist (reuse if already created, e.g. from a prior META load)
1386
+ (0, ModuleDepth_1.assertDirectLoadLevel)(level);
1387
+ // 1. Ensure ArkFile shells exist (reuse if already created)
1253
1388
  let arkFiles;
1254
1389
  if (module.getFilesMap().size === 0) {
1255
1390
  arkFiles = FrontendBuilder_1.FrontendBuilder.createModuleFileShells(this.scene, module);
@@ -1257,13 +1392,8 @@ class ModuleBuilder {
1257
1392
  else {
1258
1393
  arkFiles = Array.from(module.getFilesMap().values());
1259
1394
  }
1260
- // META: no content to build
1261
- if (level <= ModuleDepth_1.ModuleDepthLevel.META) {
1262
- return;
1263
- }
1264
- // 2. Build IMPORTS level (if not already done) + analyze file dependencies
1265
- // Use fileDepGraph existence as indicator that IMPORTS was already built.
1266
- if (level >= ModuleDepth_1.ModuleDepthLevel.IMPORTS && !module.hasFileTopoOrder()) {
1395
+ // 2. Build import/export (if not already done) + analyze file dependencies
1396
+ if (!module.hasFileTopoOrder()) {
1267
1397
  for (const arkFile of arkFiles) {
1268
1398
  try {
1269
1399
  FrontendBuilder_1.FrontendBuilder.buildImports(arkFile, arkFile.getLanguage());
@@ -1274,8 +1404,8 @@ class ModuleBuilder {
1274
1404
  }
1275
1405
  this.analyzeFileDependencies(module);
1276
1406
  }
1277
- // 3. For level > IMPORTS: upgrade to target level in topological order
1278
- if (level > ModuleDepth_1.ModuleDepthLevel.IMPORTS) {
1407
+ // 3. Upgrade to target level in topological order
1408
+ if (level >= ModuleDepth_1.ModuleDepthLevel.SIGNATURES) {
1279
1409
  const fileDepGraph = module.getFileDepGraph();
1280
1410
  let sortedFiles;
1281
1411
  if (fileDepGraph && fileDepGraph.getTopoOrder().length > 0) {
@@ -1285,7 +1415,7 @@ class ModuleBuilder {
1285
1415
  .filter((f) => f !== undefined);
1286
1416
  }
1287
1417
  else {
1288
- // Fallback: no file dep graph available (e.g. empty module or analyzeFileDependencies produced no edges)
1418
+ // Fallback: no file dep graph available
1289
1419
  sortedFiles = arkFiles;
1290
1420
  }
1291
1421
  for (const arkFile of sortedFiles) {
@@ -1301,7 +1431,7 @@ class ModuleBuilder {
1301
1431
  // --- Intra-module file dependency analysis ---
1302
1432
  /**
1303
1433
  * Analyze file-to-file dependencies within a module using the import/export `from` specifiers
1304
- * populated at IMPORTS level.
1434
+ * populated during the import/export parse step of {@link buildModuleToLevel}.
1305
1435
  *
1306
1436
  * Builds a {@link FileDepGraph}, resolves relative `from` specifiers to file paths within the
1307
1437
  * same module, adds dependency edges, computes a topological order via SCC detection, and
@@ -1435,7 +1565,7 @@ exports.ModuleBuilder = ModuleBuilder;
1435
1565
  * Calibrated from scene_board_ext measurements (no-eviction, no GC runs):
1436
1566
  * - BODIES: P75 of per-module heapUsed-per-file at BODIES level = ~1.7MB/file
1437
1567
  * - SIGNATURES: P75 of per-module heapUsed-per-file at SIGNATURES level = ~700KB/file
1438
- * - IMPORTS/META: negligible (metadata only).
1568
+ * - INDEX: hollow in-place IR (export-reachable shells); lighter than full SIGNATURES.
1439
1569
  *
1440
1570
  * No-GC calibration matches production conditions (no forced GC). Without GC,
1441
1571
  * heapUsed increments include uncollected garbage from parsing and type inference,
@@ -1445,8 +1575,7 @@ exports.ModuleBuilder = ModuleBuilder;
1445
1575
  * and as a fallback for unload estimation when the heapUsed table has no entry.
1446
1576
  */
1447
1577
  ModuleBuilder.HEAPUSED_PER_FILE = new Map([
1448
- [ModuleDepth_1.ModuleDepthLevel.META, 0],
1449
- [ModuleDepth_1.ModuleDepthLevel.IMPORTS, 0],
1578
+ [ModuleDepth_1.ModuleDepthLevel.INDEX, 250000],
1450
1579
  [ModuleDepth_1.ModuleDepthLevel.SIGNATURES, 700000],
1451
1580
  [ModuleDepth_1.ModuleDepthLevel.BODIES, 1700000],
1452
1581
  ]);
@@ -21,6 +21,7 @@ export interface HeapUsedEstimateState {
21
21
  * caller ({@link ModuleBuilder.evictIfNeeded}) handles the subsequent phases:
22
22
  * - **Phase 2** — downgrade protected dependencies to dependencyLoadLevel (release method
23
23
  * bodies/AST, keep signatures), in reverse-topo order.
24
+ * - **Phase 2b** — further downgrade protected deps to INDEX (hollow in-place IR).
24
25
  * - **Phase 3** — if still over threshold, evict the protected dependencies (full unload),
25
26
  * in reverse-topo order.
26
27
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ModuleCache.d.ts","sourceRoot":"","sources":["../../../src/frontend/common/ModuleCache.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,WAAW,CAAkB;IAErC;;;;OAIG;IACH,OAAO,CAAC,aAAa,CAA2D;IAEhF,mCAAmC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAOzC,kGAAkG;IAC3F,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAS3C,oDAAoD;IAC7C,GAAG,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO;IAIvC,0CAA0C;IACnC,IAAI,IAAI,MAAM;IAIrB,uCAAuC;IAChC,gBAAgB,IAAI,QAAQ,EAAE;IAIrC,uEAAuE;IAChE,KAAK,IAAI,IAAI;IAMpB;;;;;;;;;OASG;IACI,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAW/F;;;;OAIG;IACI,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS;IAInF;;;;;;;;;;;;;;;;;;;OAmBG;IACI,KAAK,CACR,gBAAgB,EAAE,GAAG,CAAC,QAAQ,CAAC,EAC/B,gBAAgB,EAAE,GAAG,CAAC,QAAQ,CAAC,EAC/B,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,EACtC,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,EAChD,aAAa,EAAE,qBAAqB,EACpC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,MAAM,GACpD,IAAI;IAUP,OAAO,CAAC,aAAa;IA2BrB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;CAwB3B"}
1
+ {"version":3,"file":"ModuleCache.d.ts","sourceRoot":"","sources":["../../../src/frontend/common/ModuleCache.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,WAAW,CAAkB;IAErC;;;;OAIG;IACH,OAAO,CAAC,aAAa,CAA2D;IAEhF,mCAAmC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAOzC,kGAAkG;IAC3F,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAS3C,oDAAoD;IAC7C,GAAG,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO;IAIvC,0CAA0C;IACnC,IAAI,IAAI,MAAM;IAIrB,uCAAuC;IAChC,gBAAgB,IAAI,QAAQ,EAAE;IAIrC,uEAAuE;IAChE,KAAK,IAAI,IAAI;IAMpB;;;;;;;;;OASG;IACI,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAW/F;;;;OAIG;IACI,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS;IAInF;;;;;;;;;;;;;;;;;;;OAmBG;IACI,KAAK,CACR,gBAAgB,EAAE,GAAG,CAAC,QAAQ,CAAC,EAC/B,gBAAgB,EAAE,GAAG,CAAC,QAAQ,CAAC,EAC/B,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,EACtC,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,EAChD,aAAa,EAAE,qBAAqB,EACpC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,MAAM,GACpD,IAAI;IAUP,OAAO,CAAC,aAAa;IA2BrB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;CAwB3B"}
@@ -24,6 +24,7 @@ exports.ModuleCache = void 0;
24
24
  * caller ({@link ModuleBuilder.evictIfNeeded}) handles the subsequent phases:
25
25
  * - **Phase 2** — downgrade protected dependencies to dependencyLoadLevel (release method
26
26
  * bodies/AST, keep signatures), in reverse-topo order.
27
+ * - **Phase 2b** — further downgrade protected deps to INDEX (hollow in-place IR).
27
28
  * - **Phase 3** — if still over threshold, evict the protected dependencies (full unload),
28
29
  * in reverse-topo order.
29
30
  *
@@ -1,28 +1,33 @@
1
1
  /**
2
- * Module data depth levels controlling how much data is built for ArkFile objects.
2
+ * Module data depth levels controlling how much data is retained for an {@link ArkModule}.
3
3
  * Higher levels are supersets of lower levels (incremental relationship).
4
4
  *
5
+ * Valid direct load targets ({@link ModuleAnalysisConfig} / {@link ModuleBuilder.loadModule}):
6
+ * {@link SIGNATURES} and {@link BODIES} only.
7
+ *
8
+ * {@link INDEX} is downgrade/fallback only: hollowed in-place ArkFile IR (export-reachable
9
+ * shells kept so import/type/RTA lookup APIs still work). Passing it to setLoadLevel /
10
+ * setDependencyLoadLevel / loadModule throws — do not use as a load target.
11
+ *
5
12
  * @category core/model
6
13
  */
7
14
  export declare enum ModuleDepthLevel {
8
15
  /**
9
- * Level 0: Module metadata + dependency topology + ArkFile (path-only basic info).
10
- * Index files (index.ets/index.ts) are exceptions: their ArkFile includes export/import info.
11
- * Other files are NOT read or parsed.
12
- */
13
- META = 0,
14
- /**
15
- * Level 1: META + export/import info for ALL ArkFiles + intra-module file dependencies.
16
+ * Downgrade / fallback only: in-place hollow IR — bodies/AST/source stripped and
17
+ * non-exported classes pruned; {@link ArkFile}/{@link ArkClass}/{@link ArkMethod}
18
+ * shells remain queryable via the same Scene APIs as SIGNATURES.
19
+ * Not a valid direct load target.
16
20
  */
17
- IMPORTS = 1,
21
+ INDEX = 0,
18
22
  /**
19
- * Level 2: IMPORTS + ArkFile content excluding method bodies
20
- * (namespaces, classes, method signatures, parameters, return types).
23
+ * Export/import info + namespaces/classes/method signatures (no method bodies).
21
24
  */
22
- SIGNATURES = 2,
25
+ SIGNATURES = 1,
23
26
  /**
24
- * Level 3: SIGNATURES + method bodies (ArkBody, CFG, Stmt/Expr).
27
+ * SIGNATURES + method bodies (ArkBody, CFG, Stmt/Expr).
25
28
  */
26
- BODIES = 3
29
+ BODIES = 2
27
30
  }
31
+ /** Throws if `level` is {@link ModuleDepthLevel.INDEX} (downgrade-only). */
32
+ export declare function assertDirectLoadLevel(level: ModuleDepthLevel): void;
28
33
  //# sourceMappingURL=ModuleDepth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModuleDepth.d.ts","sourceRoot":"","sources":["../../../src/frontend/common/ModuleDepth.ts"],"names":[],"mappings":"AAeA;;;;;GAKG;AACH,oBAAY,gBAAgB;IACxB;;;;OAIG;IACH,IAAI,IAAI;IAER;;OAEG;IACH,OAAO,IAAI;IAEX;;;OAGG;IACH,UAAU,IAAI;IAEd;;OAEG;IACH,MAAM,IAAI;CACb"}
1
+ {"version":3,"file":"ModuleDepth.d.ts","sourceRoot":"","sources":["../../../src/frontend/common/ModuleDepth.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;GAYG;AACH,oBAAY,gBAAgB;IACxB;;;;;OAKG;IACH,KAAK,IAAI;IAET;;OAEG;IACH,UAAU,IAAI;IAEd;;OAEG;IACH,MAAM,IAAI;CACb;AAED,4EAA4E;AAC5E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAInE"}
@@ -14,32 +14,42 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.ModuleDepthLevel = void 0;
17
+ exports.assertDirectLoadLevel = exports.ModuleDepthLevel = void 0;
18
18
  /**
19
- * Module data depth levels controlling how much data is built for ArkFile objects.
19
+ * Module data depth levels controlling how much data is retained for an {@link ArkModule}.
20
20
  * Higher levels are supersets of lower levels (incremental relationship).
21
21
  *
22
+ * Valid direct load targets ({@link ModuleAnalysisConfig} / {@link ModuleBuilder.loadModule}):
23
+ * {@link SIGNATURES} and {@link BODIES} only.
24
+ *
25
+ * {@link INDEX} is downgrade/fallback only: hollowed in-place ArkFile IR (export-reachable
26
+ * shells kept so import/type/RTA lookup APIs still work). Passing it to setLoadLevel /
27
+ * setDependencyLoadLevel / loadModule throws — do not use as a load target.
28
+ *
22
29
  * @category core/model
23
30
  */
24
31
  var ModuleDepthLevel;
25
32
  (function (ModuleDepthLevel) {
26
33
  /**
27
- * Level 0: Module metadata + dependency topology + ArkFile (path-only basic info).
28
- * Index files (index.ets/index.ts) are exceptions: their ArkFile includes export/import info.
29
- * Other files are NOT read or parsed.
30
- */
31
- ModuleDepthLevel[ModuleDepthLevel["META"] = 0] = "META";
32
- /**
33
- * Level 1: META + export/import info for ALL ArkFiles + intra-module file dependencies.
34
+ * Downgrade / fallback only: in-place hollow IR — bodies/AST/source stripped and
35
+ * non-exported classes pruned; {@link ArkFile}/{@link ArkClass}/{@link ArkMethod}
36
+ * shells remain queryable via the same Scene APIs as SIGNATURES.
37
+ * Not a valid direct load target.
34
38
  */
35
- ModuleDepthLevel[ModuleDepthLevel["IMPORTS"] = 1] = "IMPORTS";
39
+ ModuleDepthLevel[ModuleDepthLevel["INDEX"] = 0] = "INDEX";
36
40
  /**
37
- * Level 2: IMPORTS + ArkFile content excluding method bodies
38
- * (namespaces, classes, method signatures, parameters, return types).
41
+ * Export/import info + namespaces/classes/method signatures (no method bodies).
39
42
  */
40
- ModuleDepthLevel[ModuleDepthLevel["SIGNATURES"] = 2] = "SIGNATURES";
43
+ ModuleDepthLevel[ModuleDepthLevel["SIGNATURES"] = 1] = "SIGNATURES";
41
44
  /**
42
- * Level 3: SIGNATURES + method bodies (ArkBody, CFG, Stmt/Expr).
45
+ * SIGNATURES + method bodies (ArkBody, CFG, Stmt/Expr).
43
46
  */
44
- ModuleDepthLevel[ModuleDepthLevel["BODIES"] = 3] = "BODIES";
47
+ ModuleDepthLevel[ModuleDepthLevel["BODIES"] = 2] = "BODIES";
45
48
  })(ModuleDepthLevel = exports.ModuleDepthLevel || (exports.ModuleDepthLevel = {}));
49
+ /** Throws if `level` is {@link ModuleDepthLevel.INDEX} (downgrade-only). */
50
+ function assertDirectLoadLevel(level) {
51
+ if (level === ModuleDepthLevel.INDEX) {
52
+ throw new Error('ModuleDepthLevel.INDEX is not a direct load target; use SIGNATURES or BODIES');
53
+ }
54
+ }
55
+ exports.assertDirectLoadLevel = assertDirectLoadLevel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkanalyzer",
3
- "version": "1.0.91",
3
+ "version": "1.0.92",
4
4
  "files": [
5
5
  "lib",
6
6
  "config"