arkanalyzer 1.0.90 → 1.0.91
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/config/arkanalyzer.json +0 -1
- package/lib/Config.d.ts +3 -0
- package/lib/Config.d.ts.map +1 -1
- package/lib/Scene.d.ts +99 -0
- package/lib/Scene.d.ts.map +1 -1
- package/lib/Scene.js +229 -13
- package/lib/callgraph/common/Statistics.js +2 -2
- package/lib/callgraph/model/CallGraph.d.ts +2 -2
- package/lib/callgraph/model/CallGraph.d.ts.map +1 -1
- package/lib/callgraph/model/CallGraph.js +6 -6
- package/lib/callgraph/model/CallSite.d.ts +1 -1
- package/lib/callgraph/model/CallSite.d.ts.map +1 -1
- package/lib/callgraph/model/CallSite.js +2 -2
- package/lib/core/base/Ref.d.ts.map +1 -1
- package/lib/core/base/Ref.js +6 -1
- package/lib/core/common/ArkIRTransformer.d.ts.map +1 -1
- package/lib/core/common/ArkIRTransformer.js +5 -0
- package/lib/core/common/ArkValueTransformer.d.ts.map +1 -1
- package/lib/core/common/ArkValueTransformer.js +2 -1
- package/lib/core/common/Const.d.ts +3 -0
- package/lib/core/common/Const.d.ts.map +1 -1
- package/lib/core/common/Const.js +5 -1
- package/lib/core/common/DummyMainCreater.d.ts +25 -12
- package/lib/core/common/DummyMainCreater.d.ts.map +1 -1
- package/lib/core/common/DummyMainCreater.js +90 -76
- package/lib/core/common/EtsConst.d.ts +2 -0
- package/lib/core/common/EtsConst.d.ts.map +1 -1
- package/lib/core/common/EtsConst.js +133 -125
- package/lib/core/common/SdkUtils.d.ts +1 -0
- package/lib/core/common/SdkUtils.d.ts.map +1 -1
- package/lib/core/common/SdkUtils.js +29 -0
- package/lib/core/graph/BaseExplicitGraph.d.ts +2 -0
- package/lib/core/graph/BaseExplicitGraph.d.ts.map +1 -1
- package/lib/core/graph/BaseExplicitGraph.js +12 -1
- package/lib/core/graph/BaseImplicitGraph.d.ts +16 -0
- package/lib/core/graph/BaseImplicitGraph.d.ts.map +1 -1
- package/lib/core/graph/BaseImplicitGraph.js +21 -0
- package/lib/core/graph/FileDepGraph.d.ts +75 -0
- package/lib/core/graph/FileDepGraph.d.ts.map +1 -0
- package/lib/core/graph/FileDepGraph.js +170 -0
- package/lib/core/graph/GraphTraits.d.ts +2 -0
- package/lib/core/graph/GraphTraits.d.ts.map +1 -1
- package/lib/core/graph/GraphTraits.js +1 -1
- package/lib/core/graph/ModuleDepGraph.d.ts +175 -0
- package/lib/core/graph/ModuleDepGraph.d.ts.map +1 -0
- package/lib/core/graph/ModuleDepGraph.js +421 -0
- package/lib/core/graph/Scc.d.ts +1 -3
- package/lib/core/graph/Scc.d.ts.map +1 -1
- package/lib/core/graph/Scc.js +6 -19
- package/lib/core/graph/builder/CfgBuilder.d.ts.map +1 -1
- package/lib/core/graph/builder/CfgBuilder.js +7 -1
- package/lib/core/graph/builder/TrapBuilder.d.ts +1 -0
- package/lib/core/graph/builder/TrapBuilder.d.ts.map +1 -1
- package/lib/core/graph/builder/TrapBuilder.js +27 -7
- package/lib/core/model/ArkBody.d.ts +1 -0
- package/lib/core/model/ArkBody.d.ts.map +1 -1
- package/lib/core/model/ArkBody.js +7 -0
- package/lib/core/model/ArkClass.d.ts +1 -0
- package/lib/core/model/ArkClass.d.ts.map +1 -1
- package/lib/core/model/ArkClass.js +37 -0
- package/lib/core/model/ArkExport.d.ts +1 -0
- package/lib/core/model/ArkExport.d.ts.map +1 -1
- package/lib/core/model/ArkExport.js +6 -0
- package/lib/core/model/ArkField.d.ts +1 -0
- package/lib/core/model/ArkField.d.ts.map +1 -1
- package/lib/core/model/ArkField.js +5 -0
- package/lib/core/model/ArkFile.d.ts +5 -0
- package/lib/core/model/ArkFile.d.ts.map +1 -1
- package/lib/core/model/ArkFile.js +30 -0
- package/lib/core/model/ArkImport.d.ts +1 -0
- package/lib/core/model/ArkImport.d.ts.map +1 -1
- package/lib/core/model/ArkImport.js +5 -0
- package/lib/core/model/ArkMethod.d.ts +8 -0
- package/lib/core/model/ArkMethod.d.ts.map +1 -1
- package/lib/core/model/ArkMethod.js +22 -0
- package/lib/core/model/ArkModule.d.ts +136 -0
- package/lib/core/model/ArkModule.d.ts.map +1 -0
- package/lib/core/model/ArkModule.js +250 -0
- package/lib/core/model/ArkNamespace.d.ts +1 -0
- package/lib/core/model/ArkNamespace.d.ts.map +1 -1
- package/lib/core/model/ArkNamespace.js +18 -0
- package/lib/core/model/builder/ArkFileBuilder.d.ts +19 -0
- package/lib/core/model/builder/ArkFileBuilder.d.ts.map +1 -1
- package/lib/core/model/builder/ArkFileBuilder.js +155 -51
- package/lib/frontend/FrontendBuilder.d.ts +116 -0
- package/lib/frontend/FrontendBuilder.d.ts.map +1 -1
- package/lib/frontend/FrontendBuilder.js +256 -0
- package/lib/frontend/arktsFrontend/ArktsFrontend.d.ts +11 -0
- package/lib/frontend/arktsFrontend/ArktsFrontend.d.ts.map +1 -1
- package/lib/frontend/arktsFrontend/ArktsFrontend.js +15 -0
- package/lib/frontend/common/MemoryMonitor.d.ts +62 -0
- package/lib/frontend/common/MemoryMonitor.d.ts.map +1 -0
- package/lib/frontend/common/MemoryMonitor.js +108 -0
- package/lib/frontend/common/ModuleAnalysisConfig.d.ts +92 -0
- package/lib/frontend/common/ModuleAnalysisConfig.d.ts.map +1 -0
- package/lib/frontend/common/ModuleAnalysisConfig.js +144 -0
- package/lib/frontend/common/ModuleBuilder.d.ts +497 -0
- package/lib/frontend/common/ModuleBuilder.d.ts.map +1 -0
- package/lib/frontend/common/ModuleBuilder.js +1458 -0
- package/lib/frontend/common/ModuleCache.d.ts +119 -0
- package/lib/frontend/common/ModuleCache.d.ts.map +1 -0
- package/lib/frontend/common/ModuleCache.js +197 -0
- package/lib/frontend/common/ModuleDepth.d.ts +28 -0
- package/lib/frontend/common/ModuleDepth.d.ts.map +1 -0
- package/lib/frontend/common/ModuleDepth.js +45 -0
- package/lib/frontend/cppFrontend/CppFrontend.d.ts +5 -0
- package/lib/frontend/cppFrontend/CppFrontend.d.ts.map +1 -1
- package/lib/frontend/cppFrontend/CppFrontend.js +11 -1
- package/lib/frontend/cppFrontend/model/builder/ArkFileBuilder.d.ts +8 -0
- package/lib/frontend/cppFrontend/model/builder/ArkFileBuilder.d.ts.map +1 -1
- package/lib/frontend/cppFrontend/model/builder/ArkFileBuilder.js +105 -2
- package/lib/index.d.ts +9 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +22 -3
- package/lib/utils/Canonicalizer.d.ts +105 -0
- package/lib/utils/Canonicalizer.d.ts.map +1 -0
- package/lib/utils/Canonicalizer.js +520 -0
- package/lib/utils/ModuleUtils.js +4 -2
- package/lib/utils/entryMethodUtils.d.ts +23 -0
- package/lib/utils/entryMethodUtils.d.ts.map +1 -1
- package/lib/utils/entryMethodUtils.js +53 -1
- package/package.json +1 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { Language } from '../core/model/ArkFile';
|
|
1
2
|
import { ModuleScene, Scene } from '../Scene';
|
|
2
3
|
import { ArkFile } from '../core/model/ArkFile';
|
|
4
|
+
import { ArkModule } from '../core/model/ArkModule';
|
|
5
|
+
import { ModuleDepthLevel } from './common/ModuleDepth';
|
|
3
6
|
export interface FrontendParseFailure {
|
|
4
7
|
filePath: string;
|
|
5
8
|
reason: unknown;
|
|
@@ -22,5 +25,118 @@ export declare class FrontendBuilder {
|
|
|
22
25
|
* Builds a single project file into a pre-allocated {@link ArkFile} (the former `if (CXX) … else …` in `Scene`).
|
|
23
26
|
*/
|
|
24
27
|
static buildProjectFileIntoArkFile(scene: Scene, filePath: string, arkFile: ArkFile): void;
|
|
28
|
+
/**
|
|
29
|
+
* Build all source files of an {@link ArkModule} up to the given {@link ModuleDepthLevel}.
|
|
30
|
+
*
|
|
31
|
+
* Scans the module directory for source files using scene options
|
|
32
|
+
* (supportFileExts / ignoreFileNames), creates an {@link ArkFile} for each file, registers it
|
|
33
|
+
* with the module and scene, and builds it to the requested level. Errors on individual files
|
|
34
|
+
* are logged and do not abort the loop.
|
|
35
|
+
*
|
|
36
|
+
* @param scene - The owning {@link Scene}.
|
|
37
|
+
* @param module - The module whose files are built.
|
|
38
|
+
* @param level - The target depth level.
|
|
39
|
+
*/
|
|
40
|
+
static buildModuleFilesToLevel(scene: Scene, module: ArkModule, level: ModuleDepthLevel): void;
|
|
41
|
+
/**
|
|
42
|
+
* Scan the module directory and create path-only {@link ArkFile} shells (no content parsed),
|
|
43
|
+
* registering each with the module and scene.
|
|
44
|
+
*
|
|
45
|
+
* Each shell has language, filePath, projectDir, and fileSignature set, but no ImportInfo /
|
|
46
|
+
* ExportInfo / ArkClass / ArkMethod. This is the META-level baseline; callers subsequently
|
|
47
|
+
* build content via {@link buildArkFileToLevel} (IMPORTS) or {@link upgradeArkFileToLevel}
|
|
48
|
+
* (SIGNATURES / BODIES).
|
|
49
|
+
*
|
|
50
|
+
* @param scene - The owning {@link Scene}.
|
|
51
|
+
* @param module - The module whose directory is scanned.
|
|
52
|
+
* @returns Array of created (and registered) ArkFile shells.
|
|
53
|
+
*/
|
|
54
|
+
static createModuleFileShells(scene: Scene, module: ArkModule): ArkFile[];
|
|
55
|
+
/**
|
|
56
|
+
* Dispatch level-aware building to the appropriate frontend.
|
|
57
|
+
*
|
|
58
|
+
* - META: no content is built (only the ArkFile path/basic info created by the caller).
|
|
59
|
+
* - IMPORTS: lightweight import/export parsing only.
|
|
60
|
+
* - SIGNATURES: full namespace/class/method signatures are built (parameters, return types)
|
|
61
|
+
* without method bodies, reusing {@link buildProjectFileIntoArkFile}. The mounted
|
|
62
|
+
* BodyBuilders are released here so the ArkFile holds signatures only (no ArkBody/CFG).
|
|
63
|
+
* - BODIES: same as SIGNATURES but the mounted BodyBuilders are **retained** (not released)
|
|
64
|
+
* so that {@link buildModuleMethodBody} can build method bodies in a subsequent phase.
|
|
65
|
+
*/
|
|
66
|
+
private static buildArkFileToLevel;
|
|
67
|
+
/**
|
|
68
|
+
* IMPORTS level: lightweight import/export parsing only.
|
|
69
|
+
*/
|
|
70
|
+
static buildImports(arkFile: ArkFile, language: Language): void;
|
|
71
|
+
/**
|
|
72
|
+
* Upgrade an existing ArkFile (whose ImportInfo/ExportInfo were already populated at IMPORTS
|
|
73
|
+
* level) to SIGNATURES or BODIES by building class/method/namespace signatures on top.
|
|
74
|
+
*
|
|
75
|
+
* For ArkTS files, this calls {@link ArktsFrontend.buildProjectFileForSignatures} which builds
|
|
76
|
+
* signatures with `skipImportExport = true`, preserving existing import/export data and
|
|
77
|
+
* avoiding duplication of `export *` re-export entries (whose temp clause keys are
|
|
78
|
+
* process-level auto-increment and cannot be overwritten by `Map.set`).
|
|
79
|
+
*
|
|
80
|
+
* For C++ files, {@link CppFrontend.buildProjectFile} is safe to re-call: C++ ImportInfo uses
|
|
81
|
+
* stable clause keys (`#include "..."` / namespace names) that are overwritten by `Map.set`,
|
|
82
|
+
* and C++ ExportInfo is not produced during the IMPORTS-only phase, so no duplication occurs.
|
|
83
|
+
*
|
|
84
|
+
* After signature building, BodyBuilders are released when the target level is SIGNATURES
|
|
85
|
+
* (no ArkBody/CFG retained). For BODIES, BodyBuilders are retained so that
|
|
86
|
+
* {@link buildModuleMethodBody} can build method bodies in a subsequent phase.
|
|
87
|
+
*
|
|
88
|
+
* @param scene - The owning {@link Scene}.
|
|
89
|
+
* @param arkFile - The ArkFile to upgrade (must already have ImportInfo/ExportInfo).
|
|
90
|
+
* @param language - The language of the file.
|
|
91
|
+
* @param targetLevel - The target depth level (must be > IMPORTS).
|
|
92
|
+
*/
|
|
93
|
+
static upgradeArkFileToLevel(scene: Scene, arkFile: ArkFile, language: Language, targetLevel: ModuleDepthLevel): void;
|
|
94
|
+
/**
|
|
95
|
+
* Release the BodyBuilder (or CxxBodyBuilder) mounted on a method, freeing the AST/build
|
|
96
|
+
* context.
|
|
97
|
+
*/
|
|
98
|
+
private static freeMethodBodyBuilder;
|
|
99
|
+
/**
|
|
100
|
+
* Release the BodyBuilders mounted during signature building so the ArkFile retains only
|
|
101
|
+
* signatures (no ArkBody/CFG) and does not retain AST/build context in memory. Mirrors the
|
|
102
|
+
* release pattern in {@link Scene.parseAndRegisterSdkFile}.
|
|
103
|
+
*/
|
|
104
|
+
private static freeBodyBuildersInFile;
|
|
105
|
+
/**
|
|
106
|
+
* Build method bodies (ArkBody/CFG/Stmt/Expr) for all ArkFiles in the given module, then
|
|
107
|
+
* run default-constructor post-processing. This is the module-scoped equivalent of
|
|
108
|
+
* {@link Scene.buildAllMethodBody} + {@link Scene.updateOrAddDefaultConstructors}, following
|
|
109
|
+
* the same two-phase pattern as {@link Scene.genArkFiles}.
|
|
110
|
+
*
|
|
111
|
+
* Phase 1 (signatures + mounted BodyBuilders) is performed earlier by
|
|
112
|
+
* {@link buildModuleFilesToLevel} at {@link ModuleDepthLevel.BODIES}, which retains the
|
|
113
|
+
* mounted BodyBuilders. This method performs phase 2:
|
|
114
|
+
*
|
|
115
|
+
* 1. Set {@link Scene.buildStage} to {@link SceneBuildStage.CLASS_DONE} (opening the
|
|
116
|
+
* {@link Scene.buildClassDone} gate) so that when BodyBuilder encounters nested/anonymous
|
|
117
|
+
* methods during body construction, their {@link ArkMethod.setBodyBuilder} calls
|
|
118
|
+
* immediately trigger {@link ArkMethod.buildBody} — recursively building nested method
|
|
119
|
+
* bodies. The previous buildStage is restored afterwards so that subsequent SIGNATURES-
|
|
120
|
+
* level module loading is unaffected.
|
|
121
|
+
* 2. Collect all methods in the module's files.
|
|
122
|
+
* 3. Call {@link ArkMethod.buildBody} on each (executes the retained BodyBuilder), then free
|
|
123
|
+
* the BodyBuilder to release AST/build context.
|
|
124
|
+
* 4. Run {@link buildDefaultConstructor} / {@link replaceSuper2Constructor} /
|
|
125
|
+
* {@link addInitInConstructor} on the module's files (gate still open).
|
|
126
|
+
*
|
|
127
|
+
* Calls {@link ModelUtils.dispose} after each module's method bodies are built to release
|
|
128
|
+
* global caches (implicitArkUIBuilderMethods, popMethodSignatureCache) that accumulate during
|
|
129
|
+
* body building.
|
|
130
|
+
*
|
|
131
|
+
* @param module - The module whose files' method bodies are to be built.
|
|
132
|
+
*/
|
|
133
|
+
static buildModuleMethodBody(module: ArkModule): void;
|
|
134
|
+
/**
|
|
135
|
+
* Run {@link buildDefaultConstructor} / {@link replaceSuper2Constructor} /
|
|
136
|
+
* {@link addInitInConstructor} on all classes in a file. These create/modify constructors;
|
|
137
|
+
* {@link buildDefaultConstructor} builds bodies directly (without BodyBuilder), and the
|
|
138
|
+
* other two only modify already-built bodies.
|
|
139
|
+
*/
|
|
140
|
+
private static processDefaultConstructors;
|
|
25
141
|
}
|
|
26
142
|
//# sourceMappingURL=FrontendBuilder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FrontendBuilder.d.ts","sourceRoot":"","sources":["../../src/frontend/FrontendBuilder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FrontendBuilder.d.ts","sourceRoot":"","sources":["../../src/frontend/FrontendBuilder.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAmB,MAAM,UAAU,CAAC;AAG/D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAOpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQxD,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAChC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACvC;AAED;;;;GAIG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAajC,OAAO,CAAC,MAAM,CAAC,sBAAsB;WAOvB,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;WAW/D,4BAA4B,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAe/F;;OAEG;WACW,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAQjG;;;;;;;;;;;OAWG;WACW,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAWrG;;;;;;;;;;;;OAYG;WACW,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,EAAE;IA+BhF;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAkBlC;;OAEG;WACW,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAQtE;;;;;;;;;;;;;;;;;;;;;OAqBG;WACW,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,GAAG,IAAI;IAW5H;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IASpC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAMrC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;WACW,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IA8B5D;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;CAc5C"}
|
|
@@ -36,13 +36,27 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
36
36
|
__setModuleDefault(result, mod);
|
|
37
37
|
return result;
|
|
38
38
|
};
|
|
39
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
+
};
|
|
39
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
43
|
exports.FrontendBuilder = void 0;
|
|
44
|
+
const path_1 = __importDefault(require("path"));
|
|
41
45
|
const ArkFile_1 = require("../core/model/ArkFile");
|
|
46
|
+
const Scene_1 = require("../Scene");
|
|
42
47
|
const ArktsFrontend_1 = require("./arktsFrontend/ArktsFrontend");
|
|
43
48
|
const CppFrontend_1 = require("./cppFrontend/CppFrontend");
|
|
49
|
+
const ArkFile_2 = require("../core/model/ArkFile");
|
|
50
|
+
const ArkSignature_1 = require("../core/model/ArkSignature");
|
|
51
|
+
const ModelUtils_1 = require("../core/common/ModelUtils");
|
|
44
52
|
const FileUtils_1 = require("../utils/FileUtils");
|
|
53
|
+
const getAllFiles_1 = require("../utils/getAllFiles");
|
|
45
54
|
const logger_1 = __importStar(require("../utils/logger"));
|
|
55
|
+
const ModuleDepth_1 = require("./common/ModuleDepth");
|
|
56
|
+
const ArkMethodBuilder_1 = require("../core/model/builder/ArkMethodBuilder");
|
|
57
|
+
const ArkMethodBuilder_2 = require("./cppFrontend/model/builder/ArkMethodBuilder");
|
|
58
|
+
const TSConst_1 = require("../core/common/TSConst");
|
|
59
|
+
const EtsConst_1 = require("../core/common/EtsConst");
|
|
46
60
|
const logger = logger_1.default.getLogger(logger_1.LOG_MODULE_TYPE.ARKANALYZER, 'FrontendBuilder');
|
|
47
61
|
/**
|
|
48
62
|
* Dispatches language front-ends and exposes a single build entry for {@link Scene} so the scene no longer
|
|
@@ -104,5 +118,247 @@ class FrontendBuilder {
|
|
|
104
118
|
new ArktsFrontend_1.ArktsFrontend().buildProjectFile(scene, filePath, arkFile);
|
|
105
119
|
}
|
|
106
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Build all source files of an {@link ArkModule} up to the given {@link ModuleDepthLevel}.
|
|
123
|
+
*
|
|
124
|
+
* Scans the module directory for source files using scene options
|
|
125
|
+
* (supportFileExts / ignoreFileNames), creates an {@link ArkFile} for each file, registers it
|
|
126
|
+
* with the module and scene, and builds it to the requested level. Errors on individual files
|
|
127
|
+
* are logged and do not abort the loop.
|
|
128
|
+
*
|
|
129
|
+
* @param scene - The owning {@link Scene}.
|
|
130
|
+
* @param module - The module whose files are built.
|
|
131
|
+
* @param level - The target depth level.
|
|
132
|
+
*/
|
|
133
|
+
static buildModuleFilesToLevel(scene, module, level) {
|
|
134
|
+
const arkFiles = FrontendBuilder.createModuleFileShells(scene, module);
|
|
135
|
+
for (const arkFile of arkFiles) {
|
|
136
|
+
try {
|
|
137
|
+
FrontendBuilder.buildArkFileToLevel(scene, arkFile.getFilePath(), arkFile, arkFile.getLanguage(), level);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
logger.error(`Error building ArkFile for ${arkFile.getFilePath()}: ${error}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Scan the module directory and create path-only {@link ArkFile} shells (no content parsed),
|
|
146
|
+
* registering each with the module and scene.
|
|
147
|
+
*
|
|
148
|
+
* Each shell has language, filePath, projectDir, and fileSignature set, but no ImportInfo /
|
|
149
|
+
* ExportInfo / ArkClass / ArkMethod. This is the META-level baseline; callers subsequently
|
|
150
|
+
* build content via {@link buildArkFileToLevel} (IMPORTS) or {@link upgradeArkFileToLevel}
|
|
151
|
+
* (SIGNATURES / BODIES).
|
|
152
|
+
*
|
|
153
|
+
* @param scene - The owning {@link Scene}.
|
|
154
|
+
* @param module - The module whose directory is scanned.
|
|
155
|
+
* @returns Array of created (and registered) ArkFile shells.
|
|
156
|
+
*/
|
|
157
|
+
static createModuleFileShells(scene, module) {
|
|
158
|
+
var _a, _b;
|
|
159
|
+
const modulePath = module.getModulePath();
|
|
160
|
+
const options = scene.getOptions();
|
|
161
|
+
const supportFileExts = (_a = options === null || options === void 0 ? void 0 : options.supportFileExts) !== null && _a !== void 0 ? _a : ['.ets', '.ts'];
|
|
162
|
+
// Always skip 'oh_modules' subdirectories within a module to avoid duplicate scanning
|
|
163
|
+
// via symlinks: oh_modules packages are registered as separate modules by
|
|
164
|
+
// registerOhModulesModules (which uses fs.readdirSync directly, not getAllFiles).
|
|
165
|
+
const ignoreFileNames = [...((_b = options === null || options === void 0 ? void 0 : options.ignoreFileNames) !== null && _b !== void 0 ? _b : []), EtsConst_1.OH_MODULES];
|
|
166
|
+
const filePaths = (0, getAllFiles_1.getAllFiles)(modulePath, supportFileExts, ignoreFileNames);
|
|
167
|
+
const arkFiles = [];
|
|
168
|
+
for (const filePath of filePaths) {
|
|
169
|
+
try {
|
|
170
|
+
const language = FileUtils_1.FileUtils.getFileLanguage(filePath, scene.getFileLanguages());
|
|
171
|
+
const arkFile = new ArkFile_2.ArkFile(language);
|
|
172
|
+
arkFile.setScene(scene);
|
|
173
|
+
arkFile.setFilePath(filePath);
|
|
174
|
+
arkFile.setProjectDir(scene.getRealProjectDir());
|
|
175
|
+
const fileSignature = new ArkSignature_1.FileSignature(scene.getProjectName(), path_1.default.relative(scene.getRealProjectDir(), filePath));
|
|
176
|
+
arkFile.setFileSignature(fileSignature);
|
|
177
|
+
module.addFile(arkFile);
|
|
178
|
+
arkFile.setArkModule(module);
|
|
179
|
+
scene.setFile(arkFile);
|
|
180
|
+
arkFiles.push(arkFile);
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
logger.error(`Error creating ArkFile shell for ${filePath}: ${error}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return arkFiles;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Dispatch level-aware building to the appropriate frontend.
|
|
190
|
+
*
|
|
191
|
+
* - META: no content is built (only the ArkFile path/basic info created by the caller).
|
|
192
|
+
* - IMPORTS: lightweight import/export parsing only.
|
|
193
|
+
* - SIGNATURES: full namespace/class/method signatures are built (parameters, return types)
|
|
194
|
+
* without method bodies, reusing {@link buildProjectFileIntoArkFile}. The mounted
|
|
195
|
+
* BodyBuilders are released here so the ArkFile holds signatures only (no ArkBody/CFG).
|
|
196
|
+
* - BODIES: same as SIGNATURES but the mounted BodyBuilders are **retained** (not released)
|
|
197
|
+
* so that {@link buildModuleMethodBody} can build method bodies in a subsequent phase.
|
|
198
|
+
*/
|
|
199
|
+
static buildArkFileToLevel(scene, filePath, arkFile, language, level) {
|
|
200
|
+
if (level <= ModuleDepth_1.ModuleDepthLevel.META) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (level === ModuleDepth_1.ModuleDepthLevel.IMPORTS) {
|
|
204
|
+
FrontendBuilder.buildImports(arkFile, language);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// SIGNATURES and BODIES: reuse the full file builder to build signatures and mount
|
|
208
|
+
// BodyBuilders on each method implementation.
|
|
209
|
+
FrontendBuilder.buildProjectFileIntoArkFile(scene, filePath, arkFile);
|
|
210
|
+
if (level < ModuleDepth_1.ModuleDepthLevel.BODIES) {
|
|
211
|
+
// SIGNATURES: release BodyBuilders so only signatures remain (no ArkBody/CFG).
|
|
212
|
+
FrontendBuilder.freeBodyBuildersInFile(arkFile);
|
|
213
|
+
}
|
|
214
|
+
// BODIES: keep BodyBuilders mounted for phase 2 (body building in buildModuleMethodBody).
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* IMPORTS level: lightweight import/export parsing only.
|
|
218
|
+
*/
|
|
219
|
+
static buildImports(arkFile, language) {
|
|
220
|
+
if (language === ArkFile_1.Language.CXX) {
|
|
221
|
+
new CppFrontend_1.CppFrontend().buildProjectFileForImports(arkFile);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
new ArktsFrontend_1.ArktsFrontend().buildProjectFileForImports(arkFile);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Upgrade an existing ArkFile (whose ImportInfo/ExportInfo were already populated at IMPORTS
|
|
229
|
+
* level) to SIGNATURES or BODIES by building class/method/namespace signatures on top.
|
|
230
|
+
*
|
|
231
|
+
* For ArkTS files, this calls {@link ArktsFrontend.buildProjectFileForSignatures} which builds
|
|
232
|
+
* signatures with `skipImportExport = true`, preserving existing import/export data and
|
|
233
|
+
* avoiding duplication of `export *` re-export entries (whose temp clause keys are
|
|
234
|
+
* process-level auto-increment and cannot be overwritten by `Map.set`).
|
|
235
|
+
*
|
|
236
|
+
* For C++ files, {@link CppFrontend.buildProjectFile} is safe to re-call: C++ ImportInfo uses
|
|
237
|
+
* stable clause keys (`#include "..."` / namespace names) that are overwritten by `Map.set`,
|
|
238
|
+
* and C++ ExportInfo is not produced during the IMPORTS-only phase, so no duplication occurs.
|
|
239
|
+
*
|
|
240
|
+
* After signature building, BodyBuilders are released when the target level is SIGNATURES
|
|
241
|
+
* (no ArkBody/CFG retained). For BODIES, BodyBuilders are retained so that
|
|
242
|
+
* {@link buildModuleMethodBody} can build method bodies in a subsequent phase.
|
|
243
|
+
*
|
|
244
|
+
* @param scene - The owning {@link Scene}.
|
|
245
|
+
* @param arkFile - The ArkFile to upgrade (must already have ImportInfo/ExportInfo).
|
|
246
|
+
* @param language - The language of the file.
|
|
247
|
+
* @param targetLevel - The target depth level (must be > IMPORTS).
|
|
248
|
+
*/
|
|
249
|
+
static upgradeArkFileToLevel(scene, arkFile, language, targetLevel) {
|
|
250
|
+
if (language === ArkFile_1.Language.CXX) {
|
|
251
|
+
new CppFrontend_1.CppFrontend().buildProjectFile(scene, arkFile.getFilePath(), arkFile);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
new ArktsFrontend_1.ArktsFrontend().buildProjectFileForSignatures(arkFile);
|
|
255
|
+
}
|
|
256
|
+
if (targetLevel < ModuleDepth_1.ModuleDepthLevel.BODIES) {
|
|
257
|
+
FrontendBuilder.freeBodyBuildersInFile(arkFile);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Release the BodyBuilder (or CxxBodyBuilder) mounted on a method, freeing the AST/build
|
|
262
|
+
* context.
|
|
263
|
+
*/
|
|
264
|
+
static freeMethodBodyBuilder(method) {
|
|
265
|
+
var _a;
|
|
266
|
+
const isCxxFile = ((_a = method.getDeclaringArkFile()) === null || _a === void 0 ? void 0 : _a.getLanguage()) === ArkFile_1.Language.CXX;
|
|
267
|
+
if (isCxxFile) {
|
|
268
|
+
method.freeCxxBodyBuilder();
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
method.freeBodyBuilder();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Release the BodyBuilders mounted during signature building so the ArkFile retains only
|
|
276
|
+
* signatures (no ArkBody/CFG) and does not retain AST/build context in memory. Mirrors the
|
|
277
|
+
* release pattern in {@link Scene.parseAndRegisterSdkFile}.
|
|
278
|
+
*/
|
|
279
|
+
static freeBodyBuildersInFile(arkFile) {
|
|
280
|
+
for (const method of ModelUtils_1.ModelUtils.getAllMethodsInFile(arkFile)) {
|
|
281
|
+
FrontendBuilder.freeMethodBodyBuilder(method);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Build method bodies (ArkBody/CFG/Stmt/Expr) for all ArkFiles in the given module, then
|
|
286
|
+
* run default-constructor post-processing. This is the module-scoped equivalent of
|
|
287
|
+
* {@link Scene.buildAllMethodBody} + {@link Scene.updateOrAddDefaultConstructors}, following
|
|
288
|
+
* the same two-phase pattern as {@link Scene.genArkFiles}.
|
|
289
|
+
*
|
|
290
|
+
* Phase 1 (signatures + mounted BodyBuilders) is performed earlier by
|
|
291
|
+
* {@link buildModuleFilesToLevel} at {@link ModuleDepthLevel.BODIES}, which retains the
|
|
292
|
+
* mounted BodyBuilders. This method performs phase 2:
|
|
293
|
+
*
|
|
294
|
+
* 1. Set {@link Scene.buildStage} to {@link SceneBuildStage.CLASS_DONE} (opening the
|
|
295
|
+
* {@link Scene.buildClassDone} gate) so that when BodyBuilder encounters nested/anonymous
|
|
296
|
+
* methods during body construction, their {@link ArkMethod.setBodyBuilder} calls
|
|
297
|
+
* immediately trigger {@link ArkMethod.buildBody} — recursively building nested method
|
|
298
|
+
* bodies. The previous buildStage is restored afterwards so that subsequent SIGNATURES-
|
|
299
|
+
* level module loading is unaffected.
|
|
300
|
+
* 2. Collect all methods in the module's files.
|
|
301
|
+
* 3. Call {@link ArkMethod.buildBody} on each (executes the retained BodyBuilder), then free
|
|
302
|
+
* the BodyBuilder to release AST/build context.
|
|
303
|
+
* 4. Run {@link buildDefaultConstructor} / {@link replaceSuper2Constructor} /
|
|
304
|
+
* {@link addInitInConstructor} on the module's files (gate still open).
|
|
305
|
+
*
|
|
306
|
+
* Calls {@link ModelUtils.dispose} after each module's method bodies are built to release
|
|
307
|
+
* global caches (implicitArkUIBuilderMethods, popMethodSignatureCache) that accumulate during
|
|
308
|
+
* body building.
|
|
309
|
+
*
|
|
310
|
+
* @param module - The module whose files' method bodies are to be built.
|
|
311
|
+
*/
|
|
312
|
+
static buildModuleMethodBody(module) {
|
|
313
|
+
const scene = module.getScene();
|
|
314
|
+
const prevStage = scene.getStage();
|
|
315
|
+
scene.setBuildStage(Scene_1.SceneBuildStage.CLASS_DONE);
|
|
316
|
+
try {
|
|
317
|
+
// Phase 2a: build method bodies for all methods in the module's files.
|
|
318
|
+
const methods = [];
|
|
319
|
+
for (const arkFile of module.getFilesMap().values()) {
|
|
320
|
+
methods.push(...ModelUtils_1.ModelUtils.getAllMethodsInFile(arkFile));
|
|
321
|
+
}
|
|
322
|
+
for (const method of methods) {
|
|
323
|
+
try {
|
|
324
|
+
method.buildBody();
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
logger.error('Error building body:', method.getSignature(), error);
|
|
328
|
+
}
|
|
329
|
+
finally {
|
|
330
|
+
FrontendBuilder.freeMethodBodyBuilder(method);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
// Phase 2b: default-constructor post-processing for the module's files.
|
|
334
|
+
for (const arkFile of module.getFilesMap().values()) {
|
|
335
|
+
FrontendBuilder.processDefaultConstructors(arkFile);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
finally {
|
|
339
|
+
scene.setBuildStage(prevStage);
|
|
340
|
+
ModelUtils_1.ModelUtils.dispose();
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Run {@link buildDefaultConstructor} / {@link replaceSuper2Constructor} /
|
|
345
|
+
* {@link addInitInConstructor} on all classes in a file. These create/modify constructors;
|
|
346
|
+
* {@link buildDefaultConstructor} builds bodies directly (without BodyBuilder), and the
|
|
347
|
+
* other two only modify already-built bodies.
|
|
348
|
+
*/
|
|
349
|
+
static processDefaultConstructors(arkFile) {
|
|
350
|
+
const initInConstructorFn = arkFile.getLanguage() === ArkFile_1.Language.CXX ? ArkMethodBuilder_2.addInitInConstructor : ArkMethodBuilder_1.addInitInConstructor;
|
|
351
|
+
for (const cls of ModelUtils_1.ModelUtils.getAllClassesInFile(arkFile)) {
|
|
352
|
+
(0, ArkMethodBuilder_1.buildDefaultConstructor)(cls);
|
|
353
|
+
if (cls.isDefaultArkClass()) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
const constructors = cls.getAllMethodsWithName(TSConst_1.CONSTRUCTOR_NAME);
|
|
357
|
+
constructors.forEach(constructor => {
|
|
358
|
+
(0, ArkMethodBuilder_1.replaceSuper2Constructor)(constructor);
|
|
359
|
+
initInConstructorFn(constructor);
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
107
363
|
}
|
|
108
364
|
exports.FrontendBuilder = FrontendBuilder;
|
|
@@ -7,6 +7,17 @@ import { FrontendParseResult } from '../FrontendBuilder';
|
|
|
7
7
|
export declare class ArktsFrontend {
|
|
8
8
|
/** Fills a project {@link ArkFile} from a source file; delegates to {@link buildArkFileFromFile}. */
|
|
9
9
|
buildProjectFile(scene: Scene, filePath: string, arkFile: ArkFile): void;
|
|
10
|
+
/**
|
|
11
|
+
* Imports-only build for a single ArkTS file: fills ImportInfo/ExportInfo
|
|
12
|
+
* without building ArkClass/ArkMethod/ArkBody.
|
|
13
|
+
*/
|
|
14
|
+
buildProjectFileForImports(arkFile: ArkFile): void;
|
|
15
|
+
/**
|
|
16
|
+
* Signatures-only upgrade for a single ArkTS file whose ImportInfo/ExportInfo were already
|
|
17
|
+
* populated by {@link buildProjectFileForImports}. Builds ArkClass/ArkMethod/ArkNamespace
|
|
18
|
+
* signatures on top, skipping the import/export branches to avoid duplicating `export *`.
|
|
19
|
+
*/
|
|
20
|
+
buildProjectFileForSignatures(arkFile: ArkFile): void;
|
|
10
21
|
/**
|
|
11
22
|
* Non-project SDK file load (e.g. OpenHarmony SDK sources); mirrors the former {@link Scene} path for SDK files.
|
|
12
23
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArktsFrontend.d.ts","sourceRoot":"","sources":["../../../src/frontend/arktsFrontend/ArktsFrontend.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,EAAwB,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"ArktsFrontend.d.ts","sourceRoot":"","sources":["../../../src/frontend/arktsFrontend/ArktsFrontend.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,EAAwB,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG/E;;GAEG;AACH,qBAAa,aAAa;IACtB,qGAAqG;IAC9F,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAI/E;;;OAGG;IACI,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIzD;;;;OAIG;IACI,6BAA6B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI5D;;OAEG;WACW,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlH,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,mBAAmB;CAenF"}
|
|
@@ -26,6 +26,21 @@ class ArktsFrontend {
|
|
|
26
26
|
buildProjectFile(scene, filePath, arkFile) {
|
|
27
27
|
(0, ArkFileBuilder_1.buildArkFileFromFile)(filePath, scene.getRealProjectDir(), arkFile, scene.getProjectName());
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Imports-only build for a single ArkTS file: fills ImportInfo/ExportInfo
|
|
31
|
+
* without building ArkClass/ArkMethod/ArkBody.
|
|
32
|
+
*/
|
|
33
|
+
buildProjectFileForImports(arkFile) {
|
|
34
|
+
(0, ArkFileBuilder_1.buildImportExportInfoFromFile)(arkFile);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Signatures-only upgrade for a single ArkTS file whose ImportInfo/ExportInfo were already
|
|
38
|
+
* populated by {@link buildProjectFileForImports}. Builds ArkClass/ArkMethod/ArkNamespace
|
|
39
|
+
* signatures on top, skipping the import/export branches to avoid duplicating `export *`.
|
|
40
|
+
*/
|
|
41
|
+
buildProjectFileForSignatures(arkFile) {
|
|
42
|
+
(0, ArkFileBuilder_1.buildArkFileSignaturesFromFile)(arkFile);
|
|
43
|
+
}
|
|
29
44
|
/**
|
|
30
45
|
* Non-project SDK file load (e.g. OpenHarmony SDK sources); mirrors the former {@link Scene} path for SDK files.
|
|
31
46
|
*/
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { SceneOptions } from '../../Config';
|
|
2
|
+
/**
|
|
3
|
+
* Monitors process memory usage (heapUsed) and determines whether the memory limit has been exceeded.
|
|
4
|
+
*
|
|
5
|
+
* Uses heapUsed (V8 heap used) as the memory metric for cache management. The configured RSS limit
|
|
6
|
+
* ({@link SceneOptions.memoryLimitMB}) is converted to a heapUsed limit via {@link RSS_TO_HEAPUSED_RATIO}.
|
|
7
|
+
*
|
|
8
|
+
* Sampling is throttled: if the last sample was taken less than {@link THROTTLE_MS}
|
|
9
|
+
* milliseconds ago, the cached result is reused to avoid excessive
|
|
10
|
+
* `process.memoryUsage()` calls during rapid module loading.
|
|
11
|
+
*
|
|
12
|
+
* Configuration is read from {@link SceneOptions}:
|
|
13
|
+
* - `memoryLimitMB`: max process memory (RSS) in MB; 0 or undefined disables monitoring.
|
|
14
|
+
* Internally converted to a heapUsed limit: `heapUsedLimit = memoryLimitMB * 1024 * 1024 * RSS_TO_HEAPUSED_RATIO`.
|
|
15
|
+
*
|
|
16
|
+
* @category frontend/common
|
|
17
|
+
*/
|
|
18
|
+
export declare class MemoryMonitor {
|
|
19
|
+
private readonly heapUsedLimitBytes;
|
|
20
|
+
private lastSampleTime;
|
|
21
|
+
private cachedUsage;
|
|
22
|
+
/** Minimum interval between consecutive memory samples, in milliseconds. */
|
|
23
|
+
private static readonly THROTTLE_MS;
|
|
24
|
+
/**
|
|
25
|
+
* Ratio for converting an RSS-based memory limit to a heapUsed-based limit.
|
|
26
|
+
* Calibrated from scene_board_ext BODIES-level run (no eviction, no GC):
|
|
27
|
+
* P50 of heapUsed/RSS = 0.911, rounded down to 0.85 for extra safety margin
|
|
28
|
+
* to reduce OOM risk when node --max-old-space-size is close to memoryLimitMB.
|
|
29
|
+
*/
|
|
30
|
+
private static readonly RSS_TO_HEAPUSED_RATIO;
|
|
31
|
+
constructor(options?: SceneOptions);
|
|
32
|
+
/** Whether memory monitoring is enabled (memoryLimitMB > 0). */
|
|
33
|
+
isEnabled(): boolean;
|
|
34
|
+
/** Returns the heapUsed limit in bytes (converted from the RSS-based memoryLimitMB). */
|
|
35
|
+
getHeapUsedLimitBytes(): number;
|
|
36
|
+
/**
|
|
37
|
+
* Check whether the current heapUsed exceeds the memory limit.
|
|
38
|
+
*
|
|
39
|
+
* Sampling is throttled: calls within {@link THROTTLE_MS} of the last sample
|
|
40
|
+
* return the cached result.
|
|
41
|
+
*/
|
|
42
|
+
isHeapUsedOverLimit(): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Check whether the current heapUsed exceeds the given target value.
|
|
45
|
+
*
|
|
46
|
+
* Sampling is throttled: calls within {@link THROTTLE_MS} of the last sample
|
|
47
|
+
* return the cached result.
|
|
48
|
+
*/
|
|
49
|
+
isHeapUsedOverTarget(targetBytes: number): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Get the current heapUsed in bytes, bypassing the throttle for one-shot measurements.
|
|
52
|
+
*
|
|
53
|
+
* Unlike {@link isHeapUsedOverTarget} / {@link isHeapUsedOverLimit} (which use throttled sampling),
|
|
54
|
+
* this method always calls `process.memoryUsage()` directly. It is intended for
|
|
55
|
+
* one-shot measurements such as heapUsed recording before/after module loading and
|
|
56
|
+
* real-time heapUsed checks during eviction (each unload/downgrade calls this to
|
|
57
|
+
* decide whether more eviction is needed).
|
|
58
|
+
*/
|
|
59
|
+
getCurrentHeapUsed(): number;
|
|
60
|
+
private getUsage;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=MemoryMonitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MemoryMonitor.d.ts","sourceRoot":"","sources":["../../../src/frontend/common/MemoryMonitor.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,WAAW,CAAkD;IAErE,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAM;IAEzC;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAQ;gBAEzC,OAAO,CAAC,EAAE,YAAY;IAOlC,gEAAgE;IACzD,SAAS,IAAI,OAAO;IAI3B,wFAAwF;IACjF,qBAAqB,IAAI,MAAM;IAItC;;;;;OAKG;IACI,mBAAmB,IAAI,OAAO;IAOrC;;;;;OAKG;IACI,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAOzD;;;;;;;;OAQG;IACI,kBAAkB,IAAI,MAAM;IAInC,OAAO,CAAC,QAAQ;CAUnB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.MemoryMonitor = void 0;
|
|
18
|
+
/**
|
|
19
|
+
* Monitors process memory usage (heapUsed) and determines whether the memory limit has been exceeded.
|
|
20
|
+
*
|
|
21
|
+
* Uses heapUsed (V8 heap used) as the memory metric for cache management. The configured RSS limit
|
|
22
|
+
* ({@link SceneOptions.memoryLimitMB}) is converted to a heapUsed limit via {@link RSS_TO_HEAPUSED_RATIO}.
|
|
23
|
+
*
|
|
24
|
+
* Sampling is throttled: if the last sample was taken less than {@link THROTTLE_MS}
|
|
25
|
+
* milliseconds ago, the cached result is reused to avoid excessive
|
|
26
|
+
* `process.memoryUsage()` calls during rapid module loading.
|
|
27
|
+
*
|
|
28
|
+
* Configuration is read from {@link SceneOptions}:
|
|
29
|
+
* - `memoryLimitMB`: max process memory (RSS) in MB; 0 or undefined disables monitoring.
|
|
30
|
+
* Internally converted to a heapUsed limit: `heapUsedLimit = memoryLimitMB * 1024 * 1024 * RSS_TO_HEAPUSED_RATIO`.
|
|
31
|
+
*
|
|
32
|
+
* @category frontend/common
|
|
33
|
+
*/
|
|
34
|
+
class MemoryMonitor {
|
|
35
|
+
constructor(options) {
|
|
36
|
+
var _a;
|
|
37
|
+
this.lastSampleTime = 0;
|
|
38
|
+
this.cachedUsage = null;
|
|
39
|
+
const limitMB = (_a = options === null || options === void 0 ? void 0 : options.memoryLimitMB) !== null && _a !== void 0 ? _a : 0;
|
|
40
|
+
this.heapUsedLimitBytes = limitMB > 0
|
|
41
|
+
? Math.floor(limitMB * 1024 * 1024 * MemoryMonitor.RSS_TO_HEAPUSED_RATIO)
|
|
42
|
+
: 0;
|
|
43
|
+
}
|
|
44
|
+
/** Whether memory monitoring is enabled (memoryLimitMB > 0). */
|
|
45
|
+
isEnabled() {
|
|
46
|
+
return this.heapUsedLimitBytes > 0;
|
|
47
|
+
}
|
|
48
|
+
/** Returns the heapUsed limit in bytes (converted from the RSS-based memoryLimitMB). */
|
|
49
|
+
getHeapUsedLimitBytes() {
|
|
50
|
+
return this.heapUsedLimitBytes;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check whether the current heapUsed exceeds the memory limit.
|
|
54
|
+
*
|
|
55
|
+
* Sampling is throttled: calls within {@link THROTTLE_MS} of the last sample
|
|
56
|
+
* return the cached result.
|
|
57
|
+
*/
|
|
58
|
+
isHeapUsedOverLimit() {
|
|
59
|
+
if (!this.isEnabled()) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return this.getUsage().heapUsed >= this.heapUsedLimitBytes;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check whether the current heapUsed exceeds the given target value.
|
|
66
|
+
*
|
|
67
|
+
* Sampling is throttled: calls within {@link THROTTLE_MS} of the last sample
|
|
68
|
+
* return the cached result.
|
|
69
|
+
*/
|
|
70
|
+
isHeapUsedOverTarget(targetBytes) {
|
|
71
|
+
if (!this.isEnabled()) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return this.getUsage().heapUsed >= targetBytes;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the current heapUsed in bytes, bypassing the throttle for one-shot measurements.
|
|
78
|
+
*
|
|
79
|
+
* Unlike {@link isHeapUsedOverTarget} / {@link isHeapUsedOverLimit} (which use throttled sampling),
|
|
80
|
+
* this method always calls `process.memoryUsage()` directly. It is intended for
|
|
81
|
+
* one-shot measurements such as heapUsed recording before/after module loading and
|
|
82
|
+
* real-time heapUsed checks during eviction (each unload/downgrade calls this to
|
|
83
|
+
* decide whether more eviction is needed).
|
|
84
|
+
*/
|
|
85
|
+
getCurrentHeapUsed() {
|
|
86
|
+
return process.memoryUsage().heapUsed;
|
|
87
|
+
}
|
|
88
|
+
getUsage() {
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
if (this.cachedUsage && now - this.lastSampleTime < MemoryMonitor.THROTTLE_MS) {
|
|
91
|
+
return this.cachedUsage;
|
|
92
|
+
}
|
|
93
|
+
this.lastSampleTime = now;
|
|
94
|
+
const usage = process.memoryUsage();
|
|
95
|
+
this.cachedUsage = { rss: usage.rss, heapUsed: usage.heapUsed };
|
|
96
|
+
return this.cachedUsage;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.MemoryMonitor = MemoryMonitor;
|
|
100
|
+
/** Minimum interval between consecutive memory samples, in milliseconds. */
|
|
101
|
+
MemoryMonitor.THROTTLE_MS = 50;
|
|
102
|
+
/**
|
|
103
|
+
* Ratio for converting an RSS-based memory limit to a heapUsed-based limit.
|
|
104
|
+
* Calibrated from scene_board_ext BODIES-level run (no eviction, no GC):
|
|
105
|
+
* P50 of heapUsed/RSS = 0.911, rounded down to 0.85 for extra safety margin
|
|
106
|
+
* to reduce OOM risk when node --max-old-space-size is close to memoryLimitMB.
|
|
107
|
+
*/
|
|
108
|
+
MemoryMonitor.RSS_TO_HEAPUSED_RATIO = 0.85;
|