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
|
@@ -0,0 +1,520 @@
|
|
|
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.Canonicalizer = void 0;
|
|
18
|
+
const MIN_TABLE_CAPACITY = 16;
|
|
19
|
+
const DEFAULT_LOAD_FACTOR = 0.7;
|
|
20
|
+
const MAX_TABLE_CAPACITY = 0x40000000;
|
|
21
|
+
function nextPowerOfTwoAtLeast(value) {
|
|
22
|
+
let capacity = MIN_TABLE_CAPACITY;
|
|
23
|
+
while (capacity < value) {
|
|
24
|
+
capacity *= 2;
|
|
25
|
+
if (capacity > MAX_TABLE_CAPACITY) {
|
|
26
|
+
throw new Error(`Canonicalizer table capacity ${value} exceeds supported capacity`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return capacity;
|
|
30
|
+
}
|
|
31
|
+
function mixNumber(value) {
|
|
32
|
+
let hash = Math.imul(value ^ 0x9e3779b9, 0x85ebca6b);
|
|
33
|
+
hash ^= hash >>> 16;
|
|
34
|
+
hash = Math.imul(hash, 0x7feb352d);
|
|
35
|
+
hash ^= hash >>> 15;
|
|
36
|
+
return hash;
|
|
37
|
+
}
|
|
38
|
+
function hashString(value) {
|
|
39
|
+
let hash = 0x811c9dc5;
|
|
40
|
+
for (let i = 0; i < value.length; i++) {
|
|
41
|
+
hash ^= value.charCodeAt(i);
|
|
42
|
+
hash = Math.imul(hash, 0x01000193);
|
|
43
|
+
}
|
|
44
|
+
hash ^= hash >>> 16;
|
|
45
|
+
return hash;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Utility class to map objects to dense integer IDs.
|
|
49
|
+
* Used for performance optimization to replace object-based maps/sets with array-based structures.
|
|
50
|
+
*
|
|
51
|
+
* @template T - The type of items to canonicalize
|
|
52
|
+
*/
|
|
53
|
+
class Canonicalizer {
|
|
54
|
+
/**
|
|
55
|
+
* @param keyExtractor - Function to extract a unique key from an item.
|
|
56
|
+
* Defaults to identity (using the item itself as key).
|
|
57
|
+
*/
|
|
58
|
+
constructor(keyExtractor, equalityComparer) {
|
|
59
|
+
// Array from integer ID to Item
|
|
60
|
+
this.list = [];
|
|
61
|
+
this.strategy = 'uninitialized';
|
|
62
|
+
this.objectIdSymbol = Symbol('HomeFlowCanonicalizerId');
|
|
63
|
+
this.numberKeys = new Int32Array(0);
|
|
64
|
+
this.numberHeads = new Int32Array(0);
|
|
65
|
+
this.numberOccupied = new Uint8Array(0);
|
|
66
|
+
this.stringHashes = new Int32Array(0);
|
|
67
|
+
this.stringHeads = new Int32Array(0);
|
|
68
|
+
this.stringOccupied = new Uint8Array(0);
|
|
69
|
+
this.nextById = new Int32Array(0);
|
|
70
|
+
this.bucketCount = 0;
|
|
71
|
+
this.threshold = 0;
|
|
72
|
+
this.mask = 0;
|
|
73
|
+
this.collisionCount = 0;
|
|
74
|
+
this.maxChainLength = 0;
|
|
75
|
+
this.unsupportedKeyFailures = 0;
|
|
76
|
+
this.scratchFoundStored = undefined;
|
|
77
|
+
this.usesDefaultKeyExtractor = keyExtractor === undefined;
|
|
78
|
+
this.keyExtractor = keyExtractor !== null && keyExtractor !== void 0 ? keyExtractor : ((i) => i);
|
|
79
|
+
this.equalityComparer = equalityComparer;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get the unique integer ID for an item.
|
|
83
|
+
* If the item (or its key) has been seen before, returns the existing ID.
|
|
84
|
+
* Otherwise, assigns a new ID.
|
|
85
|
+
*/
|
|
86
|
+
getId(item) {
|
|
87
|
+
const key = this.keyExtractor(item);
|
|
88
|
+
this.ensureStrategy(key, item);
|
|
89
|
+
if (this.strategy === 'objectIdentity') {
|
|
90
|
+
return this.getObjectIdentityId(item, key);
|
|
91
|
+
}
|
|
92
|
+
if (this.strategy === 'numberWithEquality') {
|
|
93
|
+
return this.getNumberKeyId(key, item);
|
|
94
|
+
}
|
|
95
|
+
if (this.strategy === 'stringIdentity') {
|
|
96
|
+
return this.getStringKeyId(key, item);
|
|
97
|
+
}
|
|
98
|
+
return this.failUnsupportedKey(key);
|
|
99
|
+
}
|
|
100
|
+
hasDuplicateKeyResolver(item) {
|
|
101
|
+
return (item !== null &&
|
|
102
|
+
item !== undefined &&
|
|
103
|
+
typeof item
|
|
104
|
+
.preferCanonicalRepresentative === 'function');
|
|
105
|
+
}
|
|
106
|
+
maybeUpdateRepresentative(id, incoming, stored) {
|
|
107
|
+
if (this.hasDuplicateKeyResolver(incoming)) {
|
|
108
|
+
this.list[id] = incoming.preferCanonicalRepresentative(stored);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get the integer ID of an item if it already exists.
|
|
113
|
+
* Returns -1 if the item has not been canonicalized.
|
|
114
|
+
*/
|
|
115
|
+
getExistingId(item) {
|
|
116
|
+
const key = this.keyExtractor(item);
|
|
117
|
+
this.ensureStrategy(key, item);
|
|
118
|
+
if (this.strategy === 'objectIdentity') {
|
|
119
|
+
return this.getExistingObjectIdentityId(item, key);
|
|
120
|
+
}
|
|
121
|
+
if (this.strategy === 'numberWithEquality') {
|
|
122
|
+
return this.getExistingNumberKeyId(key, item);
|
|
123
|
+
}
|
|
124
|
+
if (this.strategy === 'stringIdentity') {
|
|
125
|
+
return this.getExistingStringKeyId(key, item);
|
|
126
|
+
}
|
|
127
|
+
return this.failUnsupportedKey(key);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get the item associated with an integer ID.
|
|
131
|
+
*/
|
|
132
|
+
get(id) {
|
|
133
|
+
return this.list[id];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get the total number of unique items seen so far.
|
|
137
|
+
*/
|
|
138
|
+
size() {
|
|
139
|
+
return this.list.length;
|
|
140
|
+
}
|
|
141
|
+
getStats() {
|
|
142
|
+
return {
|
|
143
|
+
strategy: this.strategy,
|
|
144
|
+
size: this.list.length,
|
|
145
|
+
bucketCount: this.bucketCount,
|
|
146
|
+
collisionCount: this.collisionCount,
|
|
147
|
+
maxChainLength: this.maxChainLength,
|
|
148
|
+
unsupportedKeyFailures: this.unsupportedKeyFailures,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Clear all mappings.
|
|
153
|
+
*/
|
|
154
|
+
clear() {
|
|
155
|
+
if (this.strategy === 'objectIdentity') {
|
|
156
|
+
for (const item of this.list) {
|
|
157
|
+
const candidate = item;
|
|
158
|
+
if ((typeof candidate === 'object' && candidate !== null) || typeof candidate === 'function') {
|
|
159
|
+
delete candidate[this.objectIdSymbol];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
this.list = [];
|
|
164
|
+
this.strategy = 'uninitialized';
|
|
165
|
+
this.objectIdSymbol = Symbol('HomeFlowCanonicalizerId');
|
|
166
|
+
this.numberKeys = new Int32Array(0);
|
|
167
|
+
this.numberHeads = new Int32Array(0);
|
|
168
|
+
this.numberOccupied = new Uint8Array(0);
|
|
169
|
+
this.stringHashes = new Int32Array(0);
|
|
170
|
+
this.stringHeads = new Int32Array(0);
|
|
171
|
+
this.stringOccupied = new Uint8Array(0);
|
|
172
|
+
this.nextById = new Int32Array(0);
|
|
173
|
+
this.bucketCount = 0;
|
|
174
|
+
this.threshold = 0;
|
|
175
|
+
this.mask = 0;
|
|
176
|
+
this.collisionCount = 0;
|
|
177
|
+
this.maxChainLength = 0;
|
|
178
|
+
this.unsupportedKeyFailures = 0;
|
|
179
|
+
}
|
|
180
|
+
ensureStrategy(key, item) {
|
|
181
|
+
if (this.strategy !== 'uninitialized') {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (!this.equalityComparer && this.usesDefaultKeyExtractor && this.isObjectLike(key) && key === item) {
|
|
185
|
+
this.strategy = 'objectIdentity';
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (!this.equalityComparer && this.usesDefaultKeyExtractor && typeof key === 'string') {
|
|
189
|
+
this.strategy = 'stringIdentity';
|
|
190
|
+
this.initializeStringTable();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (this.equalityComparer && typeof key === 'number' && Number.isInteger(key)) {
|
|
194
|
+
this.strategy = 'numberWithEquality';
|
|
195
|
+
this.initializeNumberTable();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
this.failUnsupportedKey(key);
|
|
199
|
+
}
|
|
200
|
+
getObjectIdentityId(item, key) {
|
|
201
|
+
if (!this.isObjectLike(key) || key !== item) {
|
|
202
|
+
return this.failUnsupportedKey(key);
|
|
203
|
+
}
|
|
204
|
+
const objectKey = key;
|
|
205
|
+
const existing = objectKey[this.objectIdSymbol];
|
|
206
|
+
if (existing !== undefined) {
|
|
207
|
+
return existing;
|
|
208
|
+
}
|
|
209
|
+
if (!Object.isExtensible(key)) {
|
|
210
|
+
throw new Error('Canonicalizer objectIdentity strategy requires extensible objects');
|
|
211
|
+
}
|
|
212
|
+
const id = this.list.length;
|
|
213
|
+
objectKey[this.objectIdSymbol] = id;
|
|
214
|
+
this.list.push(item);
|
|
215
|
+
return id;
|
|
216
|
+
}
|
|
217
|
+
getExistingObjectIdentityId(item, key) {
|
|
218
|
+
if (!this.isObjectLike(key) || key !== item) {
|
|
219
|
+
return this.failUnsupportedKey(key);
|
|
220
|
+
}
|
|
221
|
+
const existing = key[this.objectIdSymbol];
|
|
222
|
+
return existing === undefined ? -1 : existing;
|
|
223
|
+
}
|
|
224
|
+
getNumberKeyId(key, item) {
|
|
225
|
+
if (!Number.isInteger(key)) {
|
|
226
|
+
return this.failUnsupportedKey(key);
|
|
227
|
+
}
|
|
228
|
+
const slot = this.findNumberSlot(key);
|
|
229
|
+
if (this.numberOccupied[slot] !== 0) {
|
|
230
|
+
let chainLength = 0;
|
|
231
|
+
let id = this.numberHeads[slot];
|
|
232
|
+
while (id !== -1) {
|
|
233
|
+
chainLength++;
|
|
234
|
+
const stored = this.list[id];
|
|
235
|
+
if (this.equalityComparer(item, stored)) {
|
|
236
|
+
this.scratchFoundStored = stored;
|
|
237
|
+
this.maybeUpdateRepresentative(id, item, stored);
|
|
238
|
+
this.updateMaxChainLength(chainLength);
|
|
239
|
+
return id;
|
|
240
|
+
}
|
|
241
|
+
id = this.nextById[id];
|
|
242
|
+
}
|
|
243
|
+
this.collisionCount++;
|
|
244
|
+
this.updateMaxChainLength(chainLength + 1);
|
|
245
|
+
return this.appendNumberId(slot, key, item);
|
|
246
|
+
}
|
|
247
|
+
return this.appendNumberBucket(slot, key, item);
|
|
248
|
+
}
|
|
249
|
+
getExistingNumberKeyId(key, item) {
|
|
250
|
+
if (!Number.isInteger(key)) {
|
|
251
|
+
return this.failUnsupportedKey(key);
|
|
252
|
+
}
|
|
253
|
+
const slot = this.findExistingNumberSlot(key);
|
|
254
|
+
if (slot < 0) {
|
|
255
|
+
return -1;
|
|
256
|
+
}
|
|
257
|
+
let id = this.numberHeads[slot];
|
|
258
|
+
while (id !== -1) {
|
|
259
|
+
if (this.equalityComparer(item, this.list[id])) {
|
|
260
|
+
return id;
|
|
261
|
+
}
|
|
262
|
+
id = this.nextById[id];
|
|
263
|
+
}
|
|
264
|
+
return -1;
|
|
265
|
+
}
|
|
266
|
+
getStringKeyId(key, item) {
|
|
267
|
+
const hash = hashString(key);
|
|
268
|
+
const slot = this.findStringSlot(hash, key);
|
|
269
|
+
if (this.stringOccupied[slot] !== 0) {
|
|
270
|
+
return this.findStringIdOrAppend(slot, key, item);
|
|
271
|
+
}
|
|
272
|
+
return this.appendStringBucket(slot, hash, item);
|
|
273
|
+
}
|
|
274
|
+
getExistingStringKeyId(key, item) {
|
|
275
|
+
if (!this.usesDefaultKeyExtractor || item !== key) {
|
|
276
|
+
return this.failUnsupportedKey(key);
|
|
277
|
+
}
|
|
278
|
+
const hash = hashString(key);
|
|
279
|
+
const slot = this.findExistingStringSlot(hash, key);
|
|
280
|
+
if (slot < 0) {
|
|
281
|
+
return -1;
|
|
282
|
+
}
|
|
283
|
+
let id = this.stringHeads[slot];
|
|
284
|
+
while (id !== -1) {
|
|
285
|
+
if (this.list[id] === key) {
|
|
286
|
+
return id;
|
|
287
|
+
}
|
|
288
|
+
id = this.nextById[id];
|
|
289
|
+
}
|
|
290
|
+
return -1;
|
|
291
|
+
}
|
|
292
|
+
findStringIdOrAppend(slot, key, item) {
|
|
293
|
+
if (!this.usesDefaultKeyExtractor || item !== key) {
|
|
294
|
+
return this.failUnsupportedKey(key);
|
|
295
|
+
}
|
|
296
|
+
let chainLength = 0;
|
|
297
|
+
let id = this.stringHeads[slot];
|
|
298
|
+
while (id !== -1) {
|
|
299
|
+
chainLength++;
|
|
300
|
+
if (this.list[id] === key) {
|
|
301
|
+
this.updateMaxChainLength(chainLength);
|
|
302
|
+
return id;
|
|
303
|
+
}
|
|
304
|
+
id = this.nextById[id];
|
|
305
|
+
}
|
|
306
|
+
this.collisionCount++;
|
|
307
|
+
this.updateMaxChainLength(chainLength + 1);
|
|
308
|
+
return this.appendStringId(slot, item);
|
|
309
|
+
}
|
|
310
|
+
appendNumberBucket(slot, key, item) {
|
|
311
|
+
this.ensureBucketCapacityForInsert('numberWithEquality');
|
|
312
|
+
const insertSlot = this.findNumberSlot(key);
|
|
313
|
+
const id = this.list.length;
|
|
314
|
+
this.ensureNextCapacity(id + 1);
|
|
315
|
+
this.numberKeys[insertSlot] = key | 0;
|
|
316
|
+
this.numberHeads[insertSlot] = id;
|
|
317
|
+
this.numberOccupied[insertSlot] = 1;
|
|
318
|
+
this.nextById[id] = -1;
|
|
319
|
+
this.bucketCount++;
|
|
320
|
+
this.updateMaxChainLength(1);
|
|
321
|
+
this.list.push(item);
|
|
322
|
+
return id;
|
|
323
|
+
}
|
|
324
|
+
appendNumberId(slot, key, item) {
|
|
325
|
+
const id = this.list.length;
|
|
326
|
+
this.ensureNextCapacity(id + 1);
|
|
327
|
+
this.nextById[id] = this.numberHeads[slot];
|
|
328
|
+
this.numberHeads[slot] = id;
|
|
329
|
+
this.list.push(item);
|
|
330
|
+
return id;
|
|
331
|
+
}
|
|
332
|
+
appendStringBucket(slot, hash, item) {
|
|
333
|
+
this.ensureBucketCapacityForInsert('stringIdentity');
|
|
334
|
+
const insertSlot = this.findStringSlot(hash, item);
|
|
335
|
+
const id = this.list.length;
|
|
336
|
+
this.ensureNextCapacity(id + 1);
|
|
337
|
+
this.stringHashes[insertSlot] = hash;
|
|
338
|
+
this.stringHeads[insertSlot] = id;
|
|
339
|
+
this.stringOccupied[insertSlot] = 1;
|
|
340
|
+
this.nextById[id] = -1;
|
|
341
|
+
this.bucketCount++;
|
|
342
|
+
this.updateMaxChainLength(1);
|
|
343
|
+
this.list.push(item);
|
|
344
|
+
return id;
|
|
345
|
+
}
|
|
346
|
+
appendStringId(slot, item) {
|
|
347
|
+
const id = this.list.length;
|
|
348
|
+
this.ensureNextCapacity(id + 1);
|
|
349
|
+
this.nextById[id] = this.stringHeads[slot];
|
|
350
|
+
this.stringHeads[slot] = id;
|
|
351
|
+
this.list.push(item);
|
|
352
|
+
return id;
|
|
353
|
+
}
|
|
354
|
+
initializeNumberTable(expectedEntries = 1024) {
|
|
355
|
+
const capacity = nextPowerOfTwoAtLeast(Math.ceil(expectedEntries / DEFAULT_LOAD_FACTOR));
|
|
356
|
+
this.numberKeys = new Int32Array(capacity);
|
|
357
|
+
this.numberHeads = new Int32Array(capacity).fill(-1);
|
|
358
|
+
this.numberOccupied = new Uint8Array(capacity);
|
|
359
|
+
this.nextById = new Int32Array(Math.max(16, expectedEntries)).fill(-1);
|
|
360
|
+
this.mask = capacity - 1;
|
|
361
|
+
this.threshold = Math.max(1, Math.floor(capacity * DEFAULT_LOAD_FACTOR));
|
|
362
|
+
}
|
|
363
|
+
initializeStringTable(expectedEntries = 1024) {
|
|
364
|
+
const capacity = nextPowerOfTwoAtLeast(Math.ceil(expectedEntries / DEFAULT_LOAD_FACTOR));
|
|
365
|
+
this.stringHashes = new Int32Array(capacity);
|
|
366
|
+
this.stringHeads = new Int32Array(capacity).fill(-1);
|
|
367
|
+
this.stringOccupied = new Uint8Array(capacity);
|
|
368
|
+
this.nextById = new Int32Array(Math.max(16, expectedEntries)).fill(-1);
|
|
369
|
+
this.mask = capacity - 1;
|
|
370
|
+
this.threshold = Math.max(1, Math.floor(capacity * DEFAULT_LOAD_FACTOR));
|
|
371
|
+
}
|
|
372
|
+
ensureBucketCapacityForInsert(strategy) {
|
|
373
|
+
if (this.bucketCount + 1 <= this.threshold) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (strategy === 'numberWithEquality') {
|
|
377
|
+
this.rehashNumberTable(this.numberKeys.length * 2);
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
this.rehashStringTable(this.stringHashes.length * 2);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
ensureNextCapacity(required) {
|
|
384
|
+
if (required <= this.nextById.length) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
let newCapacity = this.nextById.length === 0 ? 16 : this.nextById.length;
|
|
388
|
+
while (newCapacity < required) {
|
|
389
|
+
newCapacity *= 2;
|
|
390
|
+
}
|
|
391
|
+
const next = new Int32Array(newCapacity).fill(-1);
|
|
392
|
+
next.set(this.nextById);
|
|
393
|
+
this.nextById = next;
|
|
394
|
+
}
|
|
395
|
+
findNumberSlot(key) {
|
|
396
|
+
let slot = mixNumber(key | 0) & this.mask;
|
|
397
|
+
while (this.numberOccupied[slot] !== 0 && this.numberKeys[slot] !== (key | 0)) {
|
|
398
|
+
slot = (slot + 1) & this.mask;
|
|
399
|
+
}
|
|
400
|
+
return slot;
|
|
401
|
+
}
|
|
402
|
+
findExistingNumberSlot(key) {
|
|
403
|
+
let slot = mixNumber(key | 0) & this.mask;
|
|
404
|
+
while (this.numberOccupied[slot] !== 0) {
|
|
405
|
+
if (this.numberKeys[slot] === (key | 0)) {
|
|
406
|
+
return slot;
|
|
407
|
+
}
|
|
408
|
+
slot = (slot + 1) & this.mask;
|
|
409
|
+
}
|
|
410
|
+
return -1;
|
|
411
|
+
}
|
|
412
|
+
findStringSlot(hash, key) {
|
|
413
|
+
let slot = mixNumber(hash) & this.mask;
|
|
414
|
+
while (this.stringOccupied[slot] !== 0) {
|
|
415
|
+
if (this.stringHashes[slot] === hash && this.stringBucketContainsKey(slot, key)) {
|
|
416
|
+
return slot;
|
|
417
|
+
}
|
|
418
|
+
slot = (slot + 1) & this.mask;
|
|
419
|
+
}
|
|
420
|
+
return slot;
|
|
421
|
+
}
|
|
422
|
+
findExistingStringSlot(hash, key) {
|
|
423
|
+
let slot = mixNumber(hash) & this.mask;
|
|
424
|
+
while (this.stringOccupied[slot] !== 0) {
|
|
425
|
+
if (this.stringHashes[slot] === hash && this.stringBucketContainsKey(slot, key)) {
|
|
426
|
+
return slot;
|
|
427
|
+
}
|
|
428
|
+
slot = (slot + 1) & this.mask;
|
|
429
|
+
}
|
|
430
|
+
return -1;
|
|
431
|
+
}
|
|
432
|
+
stringBucketContainsKey(slot, key) {
|
|
433
|
+
let id = this.stringHeads[slot];
|
|
434
|
+
while (id !== -1) {
|
|
435
|
+
if (this.list[id] === key) {
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
id = this.nextById[id];
|
|
439
|
+
}
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
rehashNumberTable(newCapacity) {
|
|
443
|
+
this.initializeNumberTableWithCapacity(newCapacity);
|
|
444
|
+
const items = this.list;
|
|
445
|
+
this.list = [];
|
|
446
|
+
for (const item of items) {
|
|
447
|
+
const key = this.keyExtractor(item);
|
|
448
|
+
const slot = this.findNumberSlot(key);
|
|
449
|
+
if (this.numberOccupied[slot] === 0) {
|
|
450
|
+
this.appendNumberBucket(slot, key, item);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
this.appendNumberId(slot, key, item);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
rehashStringTable(newCapacity) {
|
|
458
|
+
this.initializeStringTableWithCapacity(newCapacity);
|
|
459
|
+
const items = this.list;
|
|
460
|
+
this.list = [];
|
|
461
|
+
for (const item of items) {
|
|
462
|
+
const key = this.keyExtractor(item);
|
|
463
|
+
const hash = hashString(key);
|
|
464
|
+
const slot = this.findStringSlot(hash, key);
|
|
465
|
+
if (this.stringOccupied[slot] === 0) {
|
|
466
|
+
this.appendStringBucket(slot, hash, item);
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
this.appendStringId(slot, item);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
initializeNumberTableWithCapacity(capacity) {
|
|
474
|
+
if (capacity > MAX_TABLE_CAPACITY) {
|
|
475
|
+
throw new Error(`Canonicalizer number table capacity ${capacity} exceeds supported capacity`);
|
|
476
|
+
}
|
|
477
|
+
this.numberKeys = new Int32Array(capacity);
|
|
478
|
+
this.numberHeads = new Int32Array(capacity).fill(-1);
|
|
479
|
+
this.numberOccupied = new Uint8Array(capacity);
|
|
480
|
+
this.nextById = new Int32Array(Math.max(16, this.list.length * 2)).fill(-1);
|
|
481
|
+
this.mask = capacity - 1;
|
|
482
|
+
this.threshold = Math.max(1, Math.floor(capacity * DEFAULT_LOAD_FACTOR));
|
|
483
|
+
this.bucketCount = 0;
|
|
484
|
+
}
|
|
485
|
+
initializeStringTableWithCapacity(capacity) {
|
|
486
|
+
if (capacity > MAX_TABLE_CAPACITY) {
|
|
487
|
+
throw new Error(`Canonicalizer string table capacity ${capacity} exceeds supported capacity`);
|
|
488
|
+
}
|
|
489
|
+
this.stringHashes = new Int32Array(capacity);
|
|
490
|
+
this.stringHeads = new Int32Array(capacity).fill(-1);
|
|
491
|
+
this.stringOccupied = new Uint8Array(capacity);
|
|
492
|
+
this.nextById = new Int32Array(Math.max(16, this.list.length * 2)).fill(-1);
|
|
493
|
+
this.mask = capacity - 1;
|
|
494
|
+
this.threshold = Math.max(1, Math.floor(capacity * DEFAULT_LOAD_FACTOR));
|
|
495
|
+
this.bucketCount = 0;
|
|
496
|
+
}
|
|
497
|
+
updateMaxChainLength(length) {
|
|
498
|
+
if (length > this.maxChainLength) {
|
|
499
|
+
this.maxChainLength = length;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
isObjectLike(value) {
|
|
503
|
+
return (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
504
|
+
}
|
|
505
|
+
failUnsupportedKey(key) {
|
|
506
|
+
this.unsupportedKeyFailures++;
|
|
507
|
+
const keyType = key === null ? 'null' : typeof key;
|
|
508
|
+
throw new Error(`Canonicalizer does not support key type '${keyType}' without an explicit optimized strategy`);
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Returns the stored item that was found during the last successful
|
|
512
|
+
* {@link getNumberKeyId} lookup, or `undefined` if no such lookup has
|
|
513
|
+
* occurred. This is a scratch field carried over from the homeflow
|
|
514
|
+
* implementation.
|
|
515
|
+
*/
|
|
516
|
+
getScratchFoundStored() {
|
|
517
|
+
return this.scratchFoundStored;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
exports.Canonicalizer = Canonicalizer;
|
package/lib/utils/ModuleUtils.js
CHANGED
|
@@ -183,8 +183,10 @@ class ModuleUtils {
|
|
|
183
183
|
const main = this.getFileRealPath(path_1.default.resolve(modulePath, entry));
|
|
184
184
|
ret.set(moduleName, new ModulePath(modulePath, main));
|
|
185
185
|
}
|
|
186
|
-
// process dependency items
|
|
187
|
-
|
|
186
|
+
// process dependency items when not override
|
|
187
|
+
if (!override) {
|
|
188
|
+
this.OH_PACKAGE_DEPENDENCY_KEYS.forEach((dependencyKey) => this.processDependency(content[dependencyKey], modulePath, ret, override, projectDir));
|
|
189
|
+
}
|
|
188
190
|
}
|
|
189
191
|
static processDependency(dependencies, modulePath, ret, override, projectDir) {
|
|
190
192
|
if (!dependencies) {
|
|
@@ -4,6 +4,29 @@ import { Stmt } from '../core/base/Stmt';
|
|
|
4
4
|
export declare const LIFECYCLE_METHOD_NAME: string[];
|
|
5
5
|
export declare const CALLBACK_METHOD_NAME: string[];
|
|
6
6
|
export declare const COMPONENT_LIFECYCLE_METHOD_NAME: string[];
|
|
7
|
+
/**
|
|
8
|
+
* 首块方法:创建阶段一次性执行、不可重复触发。
|
|
9
|
+
* 列表顺序严格遵循系统调度时序。
|
|
10
|
+
* Ability 创建 → 窗口/会话创建 → Component 创建
|
|
11
|
+
*/
|
|
12
|
+
export declare const LIFECYCLE_START_METHODS: string[];
|
|
13
|
+
/**
|
|
14
|
+
* 尾块方法:销毁阶段一次性执行、不可重复触发。
|
|
15
|
+
* 列表顺序严格遵循系统调度时序。
|
|
16
|
+
* 窗口开始销毁 → 组件清理 → 窗口销毁完成 → Ability 销毁
|
|
17
|
+
*/
|
|
18
|
+
export declare const LIFECYCLE_END_METHODS: string[];
|
|
19
|
+
/**
|
|
20
|
+
* 成对/成组出现的生命周期方法。
|
|
21
|
+
* 同一组中的方法在运行时交替循环出现,放入同一 basic block。
|
|
22
|
+
* 组内顺序严格遵循系统调度时序。
|
|
23
|
+
* 配对原则:交替循环出现 + 存在数据流依赖。
|
|
24
|
+
*/
|
|
25
|
+
export declare const LIFECYCLE_PAIRED_METHOD_GROUPS: string[][];
|
|
26
|
+
/**
|
|
27
|
+
* 返回方法名所属的配对组索引,不属于任何配对组则返回 -1。
|
|
28
|
+
*/
|
|
29
|
+
export declare function getPairedMethodGroupIndex(methodName: string): number;
|
|
7
30
|
export interface AbilityMessage {
|
|
8
31
|
srcEntry: string;
|
|
9
32
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entryMethodUtils.d.ts","sourceRoot":"","sources":["../../src/utils/entryMethodUtils.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzC,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAmCzC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAiBxC,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,MAAM,EAmBnD,CAAC;AAEF,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAoBpF;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CASnD"}
|
|
1
|
+
{"version":3,"file":"entryMethodUtils.d.ts","sourceRoot":"","sources":["../../src/utils/entryMethodUtils.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzC,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAmCzC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAiBxC,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,MAAM,EAmBnD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,EAK3C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAOzC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,EAAE,EASpD,CAAC;AAEF;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAOpE;AAED,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAoBpF;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CASnD"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.addCfg2Stmt = exports.getCallbackMethodFromStmt = exports.COMPONENT_LIFECYCLE_METHOD_NAME = exports.CALLBACK_METHOD_NAME = exports.LIFECYCLE_METHOD_NAME = void 0;
|
|
17
|
+
exports.addCfg2Stmt = exports.getCallbackMethodFromStmt = exports.getPairedMethodGroupIndex = exports.LIFECYCLE_PAIRED_METHOD_GROUPS = exports.LIFECYCLE_END_METHODS = exports.LIFECYCLE_START_METHODS = exports.COMPONENT_LIFECYCLE_METHOD_NAME = exports.CALLBACK_METHOD_NAME = exports.LIFECYCLE_METHOD_NAME = void 0;
|
|
18
18
|
const Type_1 = require("../core/base/Type");
|
|
19
19
|
exports.LIFECYCLE_METHOD_NAME = [
|
|
20
20
|
'onCreate',
|
|
@@ -90,6 +90,58 @@ exports.COMPONENT_LIFECYCLE_METHOD_NAME = [
|
|
|
90
90
|
'onMeasure',
|
|
91
91
|
'onMeasureSize',
|
|
92
92
|
];
|
|
93
|
+
/**
|
|
94
|
+
* 首块方法:创建阶段一次性执行、不可重复触发。
|
|
95
|
+
* 列表顺序严格遵循系统调度时序。
|
|
96
|
+
* Ability 创建 → 窗口/会话创建 → Component 创建
|
|
97
|
+
*/
|
|
98
|
+
exports.LIFECYCLE_START_METHODS = [
|
|
99
|
+
'onCreate',
|
|
100
|
+
'onWindowStageCreate',
|
|
101
|
+
'onSessionCreate',
|
|
102
|
+
'aboutToAppear', // Component 实例创建后、build() 前调用
|
|
103
|
+
];
|
|
104
|
+
/**
|
|
105
|
+
* 尾块方法:销毁阶段一次性执行、不可重复触发。
|
|
106
|
+
* 列表顺序严格遵循系统调度时序。
|
|
107
|
+
* 窗口开始销毁 → 组件清理 → 窗口销毁完成 → Ability 销毁
|
|
108
|
+
*/
|
|
109
|
+
exports.LIFECYCLE_END_METHODS = [
|
|
110
|
+
'onWindowStageWillDestroy',
|
|
111
|
+
'aboutToDisappear',
|
|
112
|
+
'onDetached',
|
|
113
|
+
'onWindowStageDestroy',
|
|
114
|
+
'onSessionDestory',
|
|
115
|
+
'onDestroy', // Ability 最终销毁
|
|
116
|
+
];
|
|
117
|
+
/**
|
|
118
|
+
* 成对/成组出现的生命周期方法。
|
|
119
|
+
* 同一组中的方法在运行时交替循环出现,放入同一 basic block。
|
|
120
|
+
* 组内顺序严格遵循系统调度时序。
|
|
121
|
+
* 配对原则:交替循环出现 + 存在数据流依赖。
|
|
122
|
+
*/
|
|
123
|
+
exports.LIFECYCLE_PAIRED_METHOD_GROUPS = [
|
|
124
|
+
// 组件复用:recycle(加入复用池)→ reuse(从池取出),交替循环
|
|
125
|
+
['aboutToRecycle', 'aboutToReuse'],
|
|
126
|
+
// 页面显示/隐藏:交替循环
|
|
127
|
+
['onPageShow', 'onPageHide'],
|
|
128
|
+
// 前台/后台切换:前台序列 → 后台序列,交替循环
|
|
129
|
+
['onWillForeground', 'onForeground', 'onDidForeground', 'onWillBackground', 'onBackground', 'onDidBackground'],
|
|
130
|
+
// 卡片回收/恢复:交替循环
|
|
131
|
+
['onFormRecycle', 'onFormRecover'],
|
|
132
|
+
];
|
|
133
|
+
/**
|
|
134
|
+
* 返回方法名所属的配对组索引,不属于任何配对组则返回 -1。
|
|
135
|
+
*/
|
|
136
|
+
function getPairedMethodGroupIndex(methodName) {
|
|
137
|
+
for (let i = 0; i < exports.LIFECYCLE_PAIRED_METHOD_GROUPS.length; i++) {
|
|
138
|
+
if (exports.LIFECYCLE_PAIRED_METHOD_GROUPS[i].includes(methodName)) {
|
|
139
|
+
return i;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return -1;
|
|
143
|
+
}
|
|
144
|
+
exports.getPairedMethodGroupIndex = getPairedMethodGroupIndex;
|
|
93
145
|
function getCallbackMethodFromStmt(stmt, scene) {
|
|
94
146
|
const invokeExpr = stmt.getInvokeExpr();
|
|
95
147
|
if (invokeExpr === undefined ||
|