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.
- package/lib/Scene.d.ts +15 -0
- package/lib/Scene.d.ts.map +1 -1
- package/lib/Scene.js +39 -0
- package/lib/core/graph/builder/ViewTreeBuilder.d.ts +13 -3
- package/lib/core/graph/builder/ViewTreeBuilder.d.ts.map +1 -1
- package/lib/core/graph/builder/ViewTreeBuilder.js +271 -86
- package/lib/core/model/ArkModule.d.ts +9 -12
- package/lib/core/model/ArkModule.d.ts.map +1 -1
- package/lib/core/model/ArkModule.js +7 -10
- package/lib/core/model/builder/ArkClassBuilder.js +6 -0
- package/lib/frontend/FrontendBuilder.d.ts +8 -10
- package/lib/frontend/FrontendBuilder.d.ts.map +1 -1
- package/lib/frontend/FrontendBuilder.js +9 -17
- package/lib/frontend/common/ModuleAnalysisConfig.d.ts +8 -1
- package/lib/frontend/common/ModuleAnalysisConfig.d.ts.map +1 -1
- package/lib/frontend/common/ModuleAnalysisConfig.js +10 -1
- package/lib/frontend/common/ModuleBuilder.d.ts +44 -33
- package/lib/frontend/common/ModuleBuilder.d.ts.map +1 -1
- package/lib/frontend/common/ModuleBuilder.js +195 -66
- package/lib/frontend/common/ModuleCache.d.ts +1 -0
- package/lib/frontend/common/ModuleCache.d.ts.map +1 -1
- package/lib/frontend/common/ModuleCache.js +1 -0
- package/lib/frontend/common/ModuleDepth.d.ts +19 -14
- package/lib/frontend/common/ModuleDepth.d.ts.map +1 -1
- package/lib/frontend/common/ModuleDepth.js +25 -15
- package/package.json +1 -1
|
@@ -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.
|
|
797
|
-
return ArkModule_1.ModuleLoadState.
|
|
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.
|
|
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.
|
|
815
|
-
return ModuleDepth_1.ModuleDepthLevel.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
1154
|
-
*
|
|
1155
|
-
*
|
|
1156
|
-
*
|
|
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
|
-
|
|
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
|
|
1230
|
-
*
|
|
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
|
|
1235
|
-
*
|
|
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
|
-
*
|
|
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 -
|
|
1383
|
+
* @param level - Must be SIGNATURES or BODIES.
|
|
1250
1384
|
*/
|
|
1251
1385
|
buildModuleToLevel(module, level) {
|
|
1252
|
-
|
|
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
|
-
//
|
|
1261
|
-
if (
|
|
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.
|
|
1278
|
-
if (level
|
|
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
|
|
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
|
|
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
|
-
* -
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
-
|
|
21
|
+
INDEX = 0,
|
|
18
22
|
/**
|
|
19
|
-
*
|
|
20
|
-
* (namespaces, classes, method signatures, parameters, return types).
|
|
23
|
+
* Export/import info + namespaces/classes/method signatures (no method bodies).
|
|
21
24
|
*/
|
|
22
|
-
SIGNATURES =
|
|
25
|
+
SIGNATURES = 1,
|
|
23
26
|
/**
|
|
24
|
-
*
|
|
27
|
+
* SIGNATURES + method bodies (ArkBody, CFG, Stmt/Expr).
|
|
25
28
|
*/
|
|
26
|
-
BODIES =
|
|
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
|
|
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
|
|
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
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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["
|
|
39
|
+
ModuleDepthLevel[ModuleDepthLevel["INDEX"] = 0] = "INDEX";
|
|
36
40
|
/**
|
|
37
|
-
*
|
|
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"] =
|
|
43
|
+
ModuleDepthLevel[ModuleDepthLevel["SIGNATURES"] = 1] = "SIGNATURES";
|
|
41
44
|
/**
|
|
42
|
-
*
|
|
45
|
+
* SIGNATURES + method bodies (ArkBody, CFG, Stmt/Expr).
|
|
43
46
|
*/
|
|
44
|
-
ModuleDepthLevel[ModuleDepthLevel["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;
|