@markw65/monkeyc-optimizer 1.1.11 → 1.1.13
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/README.md +12 -0
- package/build/api.cjs +522 -346
- package/build/optimizer.cjs +504 -341
- package/build/src/api.d.ts +1 -1
- package/build/src/optimizer-types.d.ts +1 -0
- package/build/src/type-flow/mimimize-modules.d.ts +3 -0
- package/build/src/type-flow/minimize-locals.d.ts +2 -0
- package/build/src/type-flow/minimize-modules.d.ts +3 -0
- package/build/src/type-flow/type-flow-util.d.ts +1 -1
- package/package.json +2 -2
package/build/optimizer.cjs
CHANGED
|
@@ -6029,7 +6029,7 @@ function pragmaChecker(state, ast, diagnostics) {
|
|
|
6029
6029
|
if (kind === "match") {
|
|
6030
6030
|
const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node)
|
|
6031
6031
|
.replace(/([\r\n]|\s)+/g, " ")
|
|
6032
|
-
.replace(/\b\w+\s\/\*>(\w+)<\*\//g, "$1");
|
|
6032
|
+
.replace(/\b\w+\s\/\*>([\w.]+)<\*\//g, "$1");
|
|
6033
6033
|
if (!matcher(quote, needle, haystack)) {
|
|
6034
6034
|
matcher(quote, needle, haystack);
|
|
6035
6035
|
(0,external_api_cjs_namespaceObject.diagnostic)(state, comment, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
|
|
@@ -10954,9 +10954,10 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
|
|
|
10954
10954
|
decl,
|
|
10955
10955
|
mayThrow,
|
|
10956
10956
|
};
|
|
10957
|
-
if (wantsAllRefs
|
|
10958
|
-
if (node.right.type === "Identifier" ||
|
|
10959
|
-
node.right.type === "MemberExpression")
|
|
10957
|
+
if (wantsAllRefs) {
|
|
10958
|
+
if ((node.right.type === "Identifier" ||
|
|
10959
|
+
node.right.type === "MemberExpression") &&
|
|
10960
|
+
node.operator === "=") {
|
|
10960
10961
|
const rhs = findDecl(node.right);
|
|
10961
10962
|
if (rhs)
|
|
10962
10963
|
def.rhs = rhs;
|
|
@@ -11182,19 +11183,20 @@ const external_node_assert_namespaceObject = require("node:assert");
|
|
|
11182
11183
|
|
|
11183
11184
|
|
|
11184
11185
|
|
|
11186
|
+
|
|
11185
11187
|
function cloneAnt(antMap) {
|
|
11186
|
-
|
|
11187
|
-
antMap.forEach((s, k) => ant.set(k, new Set(s)));
|
|
11188
|
-
return ant;
|
|
11188
|
+
return new Map(antMap);
|
|
11189
11189
|
}
|
|
11190
11190
|
function addAnt(antMap, decl, node) {
|
|
11191
11191
|
external_node_assert_namespaceObject(node.type === "Identifier");
|
|
11192
11192
|
const ant = antMap.get(decl);
|
|
11193
|
-
if (
|
|
11194
|
-
|
|
11193
|
+
if (ant === false || ant === node)
|
|
11194
|
+
return;
|
|
11195
|
+
if (ant === undefined) {
|
|
11196
|
+
antMap.set(decl, node);
|
|
11195
11197
|
}
|
|
11196
11198
|
else {
|
|
11197
|
-
|
|
11199
|
+
antMap.set(decl, false);
|
|
11198
11200
|
}
|
|
11199
11201
|
}
|
|
11200
11202
|
function cloneState(blockState) {
|
|
@@ -11230,18 +11232,10 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
11230
11232
|
else {
|
|
11231
11233
|
changed = Array.from(to.anticipated).reduce((changed, [decl, toant]) => {
|
|
11232
11234
|
const fromant = from.anticipated.get(decl);
|
|
11233
|
-
if (
|
|
11235
|
+
if (toant !== fromant) {
|
|
11234
11236
|
to.anticipated.delete(decl);
|
|
11235
11237
|
changed = true;
|
|
11236
11238
|
}
|
|
11237
|
-
else {
|
|
11238
|
-
toant.forEach((node) => {
|
|
11239
|
-
if (!fromant.has(node)) {
|
|
11240
|
-
toant.delete(node);
|
|
11241
|
-
changed = true;
|
|
11242
|
-
}
|
|
11243
|
-
});
|
|
11244
|
-
}
|
|
11245
11239
|
return changed;
|
|
11246
11240
|
}, changed);
|
|
11247
11241
|
}
|
|
@@ -11254,17 +11248,15 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
11254
11248
|
else {
|
|
11255
11249
|
changed = Array.from(from.partiallyAnticipated).reduce((changed, [decl, fromant]) => {
|
|
11256
11250
|
const toant = to.partiallyAnticipated.get(decl);
|
|
11257
|
-
if (
|
|
11251
|
+
if (toant === undefined) {
|
|
11258
11252
|
to.partiallyAnticipated.set(decl, fromant);
|
|
11259
11253
|
changed = true;
|
|
11260
11254
|
}
|
|
11261
11255
|
else {
|
|
11262
|
-
fromant
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
}
|
|
11267
|
-
});
|
|
11256
|
+
if (toant !== fromant) {
|
|
11257
|
+
changed = true;
|
|
11258
|
+
to.partiallyAnticipated.set(decl, false);
|
|
11259
|
+
}
|
|
11268
11260
|
}
|
|
11269
11261
|
return changed;
|
|
11270
11262
|
}, changed);
|
|
@@ -11328,7 +11320,7 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
11328
11320
|
}
|
|
11329
11321
|
addAnt(curState.partiallyAnticipated, event.decl, event.node);
|
|
11330
11322
|
if (logThisRun) {
|
|
11331
|
-
console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl)
|
|
11323
|
+
console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl) !== false} ${curState.anticipated.get(event.decl) !== false}`);
|
|
11332
11324
|
}
|
|
11333
11325
|
}
|
|
11334
11326
|
curState.dead.delete(event.decl);
|
|
@@ -11349,25 +11341,21 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
11349
11341
|
}
|
|
11350
11342
|
else {
|
|
11351
11343
|
deadStores.delete(event.node);
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
curState.partiallyAnticipated) {
|
|
11344
|
+
copyPropStores.delete(event.node);
|
|
11345
|
+
if (declIsLocal(event.decl) && curState.partiallyAnticipated) {
|
|
11355
11346
|
const pant = curState.partiallyAnticipated.get(event.decl);
|
|
11356
|
-
if (pant
|
|
11347
|
+
if (pant) {
|
|
11357
11348
|
if (logThisRun) {
|
|
11358
|
-
console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl)
|
|
11349
|
+
console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl) === pant}`);
|
|
11359
11350
|
}
|
|
11360
11351
|
copyPropStores.set(event.node, {
|
|
11361
|
-
ref:
|
|
11362
|
-
ant: curState.anticipated?.get(event.decl)
|
|
11352
|
+
ref: pant,
|
|
11353
|
+
ant: curState.anticipated?.get(event.decl) === pant,
|
|
11363
11354
|
});
|
|
11364
11355
|
}
|
|
11365
11356
|
curState.partiallyAnticipated.delete(event.decl);
|
|
11366
11357
|
curState.anticipated?.delete(event.decl);
|
|
11367
11358
|
}
|
|
11368
|
-
else {
|
|
11369
|
-
copyPropStores.delete(event.node);
|
|
11370
|
-
}
|
|
11371
11359
|
}
|
|
11372
11360
|
if (nodeConflicts) {
|
|
11373
11361
|
const conflicts = new Set(locals);
|
|
@@ -11456,7 +11444,10 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
|
|
|
11456
11444
|
console.log(`${(0,external_api_cjs_namespaceObject.formatAst)(dead)} (${sourceLocation(dead.loc)})`));
|
|
11457
11445
|
}
|
|
11458
11446
|
let changes = false;
|
|
11459
|
-
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node
|
|
11447
|
+
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node) => {
|
|
11448
|
+
const cleaned = variableCleanup(node);
|
|
11449
|
+
if (cleaned !== null)
|
|
11450
|
+
return cleaned;
|
|
11460
11451
|
if (node.type === "ExpressionStatement" &&
|
|
11461
11452
|
node.expression.type === "AssignmentExpression" &&
|
|
11462
11453
|
deadStores.has(node.expression)) {
|
|
@@ -11478,40 +11469,17 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
|
|
|
11478
11469
|
changes = true;
|
|
11479
11470
|
return { type: "Literal", value: null, raw: "null" };
|
|
11480
11471
|
}
|
|
11481
|
-
if (node.type === "
|
|
11482
|
-
const
|
|
11483
|
-
|
|
11484
|
-
const
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
(parent.type !== "BlockStatement" && parent.type !== "SwitchCase")) {
|
|
11490
|
-
// Must be the init in a for statement. Fixing
|
|
11491
|
-
// it would be complicated, so just punt for now.
|
|
11492
|
-
break;
|
|
11493
|
-
}
|
|
11494
|
-
const newDeclaration = withLoc({ ...node }, node, decl.id);
|
|
11495
|
-
if (i + 1 < node.declarations.length) {
|
|
11496
|
-
newDeclaration.declarations = node.declarations.splice(0, i + 1);
|
|
11497
|
-
result.push(newDeclaration);
|
|
11498
|
-
withLoc(node, node.declarations[0], node);
|
|
11499
|
-
i = -1;
|
|
11500
|
-
}
|
|
11501
|
-
else {
|
|
11502
|
-
result.push(node);
|
|
11503
|
-
}
|
|
11504
|
-
result.push(...body);
|
|
11505
|
-
}
|
|
11506
|
-
changes = true;
|
|
11507
|
-
delete decl.init;
|
|
11508
|
-
}
|
|
11509
|
-
}
|
|
11510
|
-
if (result.length) {
|
|
11511
|
-
if (!result.includes(node)) {
|
|
11512
|
-
result.push(node);
|
|
11472
|
+
if (node.type === "VariableDeclarator") {
|
|
11473
|
+
const decl = node;
|
|
11474
|
+
if (decl.init && deadStores.has(decl)) {
|
|
11475
|
+
const body = unused(state, decl.init);
|
|
11476
|
+
delete decl.init;
|
|
11477
|
+
changes = true;
|
|
11478
|
+
if (!body.length) {
|
|
11479
|
+
return null;
|
|
11513
11480
|
}
|
|
11514
|
-
|
|
11481
|
+
body.unshift(decl);
|
|
11482
|
+
return body;
|
|
11515
11483
|
}
|
|
11516
11484
|
}
|
|
11517
11485
|
return null;
|
|
@@ -11591,79 +11559,42 @@ function buildConflictGraph(state, func) {
|
|
|
11591
11559
|
function addEquiv(ts, key, equiv) {
|
|
11592
11560
|
if (key === equiv)
|
|
11593
11561
|
return true;
|
|
11594
|
-
|
|
11595
|
-
|
|
11562
|
+
const keyVal = ts.get(key);
|
|
11563
|
+
const equivVal = ts.get(equiv);
|
|
11596
11564
|
if (!keyVal || !equivVal)
|
|
11597
11565
|
return false;
|
|
11598
11566
|
if (equivVal.equivSet) {
|
|
11599
|
-
if (
|
|
11600
|
-
|
|
11601
|
-
// equiv is part of it.
|
|
11602
|
-
let s = keyVal.equivSet.next;
|
|
11603
|
-
do {
|
|
11604
|
-
if (s === equiv) {
|
|
11605
|
-
// these two are already equivalent
|
|
11606
|
-
return true;
|
|
11607
|
-
}
|
|
11608
|
-
const next = ts.get(s);
|
|
11609
|
-
if (!next || !next.equivSet) {
|
|
11610
|
-
throw new Error(`Inconsistent equivSet for ${tsKey(key)}: missing value for ${tsKey(s)}`);
|
|
11611
|
-
}
|
|
11612
|
-
s = next.equivSet.next;
|
|
11613
|
-
} while (s !== key);
|
|
11567
|
+
if (equivVal.equivSet.has(key)) {
|
|
11568
|
+
return true;
|
|
11614
11569
|
}
|
|
11615
11570
|
// equiv is already a member of a set. remove it
|
|
11616
11571
|
removeEquiv(ts, equiv);
|
|
11617
11572
|
}
|
|
11618
11573
|
// equiv is not (or no longer) part of an equivSet
|
|
11619
|
-
keyVal = { ...keyVal };
|
|
11620
11574
|
if (!keyVal.equivSet) {
|
|
11621
|
-
keyVal.equivSet =
|
|
11575
|
+
keyVal.equivSet = new Set([key, equiv]);
|
|
11576
|
+
}
|
|
11577
|
+
else {
|
|
11578
|
+
keyVal.equivSet.add(equiv);
|
|
11622
11579
|
}
|
|
11623
|
-
equivVal =
|
|
11624
|
-
keyVal.equivSet = { next: equiv };
|
|
11625
|
-
ts.set(key, keyVal);
|
|
11626
|
-
ts.set(equiv, equivVal);
|
|
11580
|
+
equivVal.equivSet = keyVal.equivSet;
|
|
11627
11581
|
return false;
|
|
11628
11582
|
}
|
|
11629
11583
|
function removeEquiv(ts, equiv) {
|
|
11630
11584
|
const equivVal = ts.get(equiv);
|
|
11631
11585
|
if (!equivVal?.equivSet)
|
|
11632
11586
|
return;
|
|
11633
|
-
|
|
11634
|
-
|
|
11635
|
-
const
|
|
11636
|
-
|
|
11637
|
-
|
|
11638
|
-
|
|
11639
|
-
|
|
11640
|
-
const { equivSet: _e, ...rest } = next;
|
|
11641
|
-
if (equivVal.equivSet.next === s) {
|
|
11642
|
-
// this is a pair. just kill both
|
|
11643
|
-
ts.set(s, rest);
|
|
11644
|
-
}
|
|
11645
|
-
else {
|
|
11646
|
-
ts.set(s, { ...rest, equivSet: equivVal.equivSet });
|
|
11647
|
-
}
|
|
11648
|
-
break;
|
|
11649
|
-
}
|
|
11650
|
-
s = next.equivSet.next;
|
|
11651
|
-
} while (true);
|
|
11652
|
-
const newVal = { ...equivVal };
|
|
11653
|
-
delete newVal.equivSet;
|
|
11654
|
-
ts.set(equiv, newVal);
|
|
11587
|
+
equivVal.equivSet.delete(equiv);
|
|
11588
|
+
if (equivVal.equivSet.size === 1) {
|
|
11589
|
+
const other = Array.from(equivVal.equivSet)[0];
|
|
11590
|
+
const otherVal = ts.get(other);
|
|
11591
|
+
delete otherVal.equivSet;
|
|
11592
|
+
}
|
|
11593
|
+
delete equivVal.equivSet;
|
|
11655
11594
|
}
|
|
11656
11595
|
function getEquivSet(ts, k) {
|
|
11657
|
-
const keys =
|
|
11658
|
-
|
|
11659
|
-
do {
|
|
11660
|
-
const next = ts.get(s);
|
|
11661
|
-
if (!next || !next.equivSet) {
|
|
11662
|
-
throw new Error(`Inconsistent equivSet for ${tsKey(k)}: missing value for ${tsKey(s)}`);
|
|
11663
|
-
}
|
|
11664
|
-
keys.add(s);
|
|
11665
|
-
s = next.equivSet.next;
|
|
11666
|
-
} while (s !== k);
|
|
11596
|
+
const keys = ts.get(k)?.equivSet;
|
|
11597
|
+
external_node_assert_namespaceObject(keys);
|
|
11667
11598
|
return keys;
|
|
11668
11599
|
}
|
|
11669
11600
|
function intersectEquiv(ts1, ts2, k) {
|
|
@@ -11675,21 +11606,26 @@ function intersectEquiv(ts1, ts2, k) {
|
|
|
11675
11606
|
removeEquiv(ts1, k);
|
|
11676
11607
|
return true;
|
|
11677
11608
|
}
|
|
11678
|
-
|
|
11679
|
-
|
|
11680
|
-
|
|
11681
|
-
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
11686
|
-
if (!keys.has(s)) {
|
|
11687
|
-
ret = true;
|
|
11688
|
-
removeEquiv(ts1, s);
|
|
11609
|
+
let removed = null;
|
|
11610
|
+
eq1.equivSet.forEach((key) => {
|
|
11611
|
+
if (!eq2.equivSet.has(key)) {
|
|
11612
|
+
eq1.equivSet.delete(key);
|
|
11613
|
+
if (!removed) {
|
|
11614
|
+
removed = new Set();
|
|
11615
|
+
}
|
|
11616
|
+
removed.add(key);
|
|
11689
11617
|
}
|
|
11690
|
-
|
|
11691
|
-
|
|
11692
|
-
|
|
11618
|
+
});
|
|
11619
|
+
if (eq1.equivSet.size === 1) {
|
|
11620
|
+
external_node_assert_namespaceObject(eq1.equivSet.has(k));
|
|
11621
|
+
delete eq1.equivSet;
|
|
11622
|
+
}
|
|
11623
|
+
if (removed) {
|
|
11624
|
+
removed.forEach((k) => removed.size === 1
|
|
11625
|
+
? delete ts1.get(k).equivSet
|
|
11626
|
+
: (ts1.get(k).equivSet = removed));
|
|
11627
|
+
}
|
|
11628
|
+
return false;
|
|
11693
11629
|
}
|
|
11694
11630
|
function clearAssocPaths(blockState, decl, v) {
|
|
11695
11631
|
if (v.assocPaths?.size) {
|
|
@@ -11707,6 +11643,17 @@ function clearAssocPaths(blockState, decl, v) {
|
|
|
11707
11643
|
function cloneTypeState(blockState) {
|
|
11708
11644
|
const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
|
|
11709
11645
|
const clone = { map: new Map(map), ...rest };
|
|
11646
|
+
clone.map.forEach((value, key) => {
|
|
11647
|
+
if (value.equivSet) {
|
|
11648
|
+
if (key === Array.from(value.equivSet)[0]) {
|
|
11649
|
+
const equivSet = new Set(value.equivSet);
|
|
11650
|
+
equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
|
|
11651
|
+
}
|
|
11652
|
+
}
|
|
11653
|
+
else {
|
|
11654
|
+
clone.map.set(key, { ...value });
|
|
11655
|
+
}
|
|
11656
|
+
});
|
|
11710
11657
|
if (trackedMemberDecls) {
|
|
11711
11658
|
clone.trackedMemberDecls = new Map();
|
|
11712
11659
|
trackedMemberDecls.forEach((value, key) => {
|
|
@@ -11741,12 +11688,9 @@ function addCopyPropEvent(blockState, item) {
|
|
|
11741
11688
|
const liveCopyPropEvents = blockState.liveCopyPropEvents;
|
|
11742
11689
|
const decl = item.event.decl;
|
|
11743
11690
|
external_node_assert_namespaceObject(declIsLocal(decl));
|
|
11744
|
-
|
|
11691
|
+
const tov = blockState.map.get(decl);
|
|
11745
11692
|
external_node_assert_namespaceObject(tov);
|
|
11746
|
-
|
|
11747
|
-
tov = { ...tov, copyPropItem: item };
|
|
11748
|
-
blockState.map.set(decl, tov);
|
|
11749
|
-
}
|
|
11693
|
+
tov.copyPropItem = item;
|
|
11750
11694
|
item.contained.forEach((value, key) => {
|
|
11751
11695
|
const decls = liveCopyPropEvents.get(key);
|
|
11752
11696
|
if (!decls) {
|
|
@@ -11779,15 +11723,13 @@ function clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp) {
|
|
|
11779
11723
|
blockState.liveCopyPropEvents
|
|
11780
11724
|
?.get(decl)
|
|
11781
11725
|
?.forEach((cpDecl) => {
|
|
11782
|
-
|
|
11726
|
+
const value = blockState.map.get(cpDecl);
|
|
11783
11727
|
external_node_assert_namespaceObject(value && value.copyPropItem);
|
|
11784
11728
|
external_node_assert_namespaceObject(Array.from(value.copyPropItem.contained).some(([key]) => {
|
|
11785
11729
|
return decl === key;
|
|
11786
11730
|
}));
|
|
11787
11731
|
copyPropFailed(blockState, value.copyPropItem, nodeCopyProp);
|
|
11788
|
-
value = { ...value };
|
|
11789
11732
|
delete value.copyPropItem;
|
|
11790
|
-
blockState.map.set(cpDecl, value);
|
|
11791
11733
|
});
|
|
11792
11734
|
}
|
|
11793
11735
|
function validateTypeState(curState) {
|
|
@@ -11830,11 +11772,9 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
|
|
|
11830
11772
|
if (tov.equivSet) {
|
|
11831
11773
|
if (intersectEquiv(to.map, from.map, k)) {
|
|
11832
11774
|
changes = true;
|
|
11833
|
-
tov = to.map.get(k);
|
|
11834
11775
|
}
|
|
11835
11776
|
}
|
|
11836
11777
|
if (tov.assocPaths) {
|
|
11837
|
-
tov = { ...tov };
|
|
11838
11778
|
if (!fromv.assocPaths) {
|
|
11839
11779
|
changes = true;
|
|
11840
11780
|
delete tov.assocPaths;
|
|
@@ -11857,7 +11797,6 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
|
|
|
11857
11797
|
delete tov.assocPaths;
|
|
11858
11798
|
}
|
|
11859
11799
|
}
|
|
11860
|
-
to.map.set(k, tov);
|
|
11861
11800
|
}
|
|
11862
11801
|
// if both from and to have copyPropEvents, we can only
|
|
11863
11802
|
// keep it if they're the same event.
|
|
@@ -11875,10 +11814,8 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
|
|
|
11875
11814
|
}
|
|
11876
11815
|
nodeCopyProp.set(fromv.copyPropItem.event.node, false);
|
|
11877
11816
|
}
|
|
11878
|
-
tov = { ...tov };
|
|
11879
11817
|
delete tov.copyPropItem;
|
|
11880
11818
|
changes = true;
|
|
11881
|
-
to.map.set(k, tov);
|
|
11882
11819
|
}
|
|
11883
11820
|
else {
|
|
11884
11821
|
external_node_assert_namespaceObject(k === tov.copyPropItem.event.decl);
|
|
@@ -11889,7 +11826,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
|
|
|
11889
11826
|
if (subtypeOf(fromv.curType, tov.curType))
|
|
11890
11827
|
return;
|
|
11891
11828
|
if (subtypeOf(tov.curType, fromv.curType)) {
|
|
11892
|
-
|
|
11829
|
+
tov.curType = fromv.curType;
|
|
11893
11830
|
changes = true;
|
|
11894
11831
|
return;
|
|
11895
11832
|
}
|
|
@@ -11902,22 +11839,11 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
|
|
|
11902
11839
|
if (wide)
|
|
11903
11840
|
result = wide;
|
|
11904
11841
|
}
|
|
11905
|
-
|
|
11842
|
+
tov.curType = result;
|
|
11906
11843
|
changes = true;
|
|
11907
11844
|
});
|
|
11908
11845
|
return changes;
|
|
11909
11846
|
}
|
|
11910
|
-
function tsEquivs(state, key) {
|
|
11911
|
-
const result = [];
|
|
11912
|
-
let s = key;
|
|
11913
|
-
do {
|
|
11914
|
-
result.push(tsKey(s));
|
|
11915
|
-
const next = state.get(s);
|
|
11916
|
-
external_node_assert_namespaceObject(next && next.equivSet);
|
|
11917
|
-
s = next.equivSet.next;
|
|
11918
|
-
} while (s !== key);
|
|
11919
|
-
return `[(${result.join(", ")})]`;
|
|
11920
|
-
}
|
|
11921
11847
|
function typeStateEntry(value, key) {
|
|
11922
11848
|
return `${tsKey(key)} = ${display(value.curType)}`;
|
|
11923
11849
|
}
|
|
@@ -11928,7 +11854,9 @@ function printBlockState(block, state, indent = "") {
|
|
|
11928
11854
|
return;
|
|
11929
11855
|
}
|
|
11930
11856
|
state.map.forEach((value, key) => {
|
|
11931
|
-
console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet
|
|
11857
|
+
console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet
|
|
11858
|
+
? " " + `[(${Array.from(value.equivSet).map(tsKey).join(", ")})]`
|
|
11859
|
+
: ""}`);
|
|
11932
11860
|
});
|
|
11933
11861
|
}
|
|
11934
11862
|
function updateAffected(blockState, objectType, baseDecl, assignedPath, affectedName, affected, assignedType) {
|
|
@@ -11936,7 +11864,6 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
|
|
|
11936
11864
|
let droppedComponents = null;
|
|
11937
11865
|
const entry = blockState.map.get(key);
|
|
11938
11866
|
external_node_assert_namespaceObject(entry && entry.assocPaths);
|
|
11939
|
-
let newEntry = entry;
|
|
11940
11867
|
entry.assocPaths.forEach((path) => {
|
|
11941
11868
|
if (key === baseDecl && path === assignedPath) {
|
|
11942
11869
|
return;
|
|
@@ -11955,12 +11882,9 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
|
|
|
11955
11882
|
});
|
|
11956
11883
|
if (pathItem === affectedName && couldBeShallow(type, objectType)) {
|
|
11957
11884
|
const newAssocKey = assocPath.map((av) => av.name ?? "*").join(".");
|
|
11958
|
-
if (newEntry === entry) {
|
|
11959
|
-
newEntry = { ...entry };
|
|
11960
|
-
}
|
|
11961
11885
|
if (newAssocKey !== path) {
|
|
11962
|
-
|
|
11963
|
-
|
|
11886
|
+
entry.assocPaths = new Set(entry.assocPaths);
|
|
11887
|
+
entry.assocPaths.delete(path);
|
|
11964
11888
|
// the "extra" path components will also have entries
|
|
11965
11889
|
// in blockState.trackedMemberDecls. Since they're gone
|
|
11966
11890
|
// from here, we (may) need to remove them from there
|
|
@@ -11972,8 +11896,7 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
|
|
|
11972
11896
|
}
|
|
11973
11897
|
break;
|
|
11974
11898
|
}
|
|
11975
|
-
|
|
11976
|
-
newEntry.curType = baseType;
|
|
11899
|
+
entry.curType = updateByAssocPath(assocPath, assignedType, true);
|
|
11977
11900
|
break;
|
|
11978
11901
|
}
|
|
11979
11902
|
if (pathItem === "*") {
|
|
@@ -12003,14 +11926,11 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
|
|
|
12003
11926
|
}
|
|
12004
11927
|
}
|
|
12005
11928
|
});
|
|
12006
|
-
if (
|
|
12007
|
-
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
|
|
12011
|
-
droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
|
|
12012
|
-
}
|
|
12013
|
-
blockState.map.set(key, newEntry);
|
|
11929
|
+
if (droppedComponents) {
|
|
11930
|
+
entry.assocPaths.forEach((path) => path
|
|
11931
|
+
.split(".")
|
|
11932
|
+
.forEach((pathComponent) => droppedComponents.delete(pathComponent)));
|
|
11933
|
+
droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
|
|
12014
11934
|
}
|
|
12015
11935
|
});
|
|
12016
11936
|
}
|
|
@@ -12117,10 +12037,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12117
12037
|
const assocKey = assocValue.map((av) => av.name ?? "*").join(".");
|
|
12118
12038
|
const newType = updateByAssocPath(assocValue, next, false);
|
|
12119
12039
|
setStateEvent(blockState, decl.base, newType, newValue ? 1 /* UpdateKind.Inner */ : 0 /* UpdateKind.None */);
|
|
12120
|
-
const tsv =
|
|
12040
|
+
const tsv = blockState.map.get(decl.base);
|
|
12121
12041
|
tsv.assocPaths = new Set(tsv.assocPaths);
|
|
12122
12042
|
tsv.assocPaths.add(assocKey);
|
|
12123
|
-
blockState.map.set(decl.base, tsv);
|
|
12124
12043
|
addTrackedMemberDecl(blockState, decl.base, assocKey);
|
|
12125
12044
|
if (newValue) {
|
|
12126
12045
|
const baseElem = assocValue[decl.path.length - 1];
|
|
@@ -12198,38 +12117,39 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12198
12117
|
// that foo is side-effect free, and accesses no globals.
|
|
12199
12118
|
clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp);
|
|
12200
12119
|
}
|
|
12120
|
+
const v = blockState.map.get(decl);
|
|
12121
|
+
if (!v) {
|
|
12122
|
+
blockState.map.set(decl, { curType: value });
|
|
12123
|
+
return;
|
|
12124
|
+
}
|
|
12201
12125
|
if (updateKind !== 2 /* UpdateKind.Reassign */) {
|
|
12202
12126
|
/*
|
|
12203
12127
|
* If we're not re-assigning, the equivalencies don't
|
|
12204
12128
|
* change, so this update must be applied to every
|
|
12205
12129
|
* element of the set
|
|
12206
12130
|
*/
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
let s = decl;
|
|
12210
|
-
do {
|
|
12131
|
+
if (v.equivSet) {
|
|
12132
|
+
v.equivSet.forEach((s) => {
|
|
12211
12133
|
const next = blockState.map.get(s);
|
|
12212
|
-
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
blockState.map.set(s, { ...next, curType: value });
|
|
12216
|
-
s = next.equivSet.next;
|
|
12217
|
-
} while (s !== decl);
|
|
12134
|
+
external_node_assert_namespaceObject(next && next.equivSet?.has(s));
|
|
12135
|
+
next.curType = value;
|
|
12136
|
+
});
|
|
12218
12137
|
}
|
|
12219
12138
|
else {
|
|
12220
|
-
|
|
12139
|
+
v.curType = value;
|
|
12221
12140
|
}
|
|
12222
12141
|
}
|
|
12223
12142
|
else {
|
|
12224
|
-
const v = blockState.map.get(decl);
|
|
12225
12143
|
removeEquiv(blockState.map, decl);
|
|
12226
|
-
if (v
|
|
12144
|
+
if (v.assocPaths?.size) {
|
|
12227
12145
|
clearAssocPaths(blockState, decl, v);
|
|
12146
|
+
delete v.assocPaths;
|
|
12228
12147
|
}
|
|
12229
|
-
if (v
|
|
12148
|
+
if (v.copyPropItem) {
|
|
12230
12149
|
copyPropFailed(blockState, v.copyPropItem, nodeCopyProp);
|
|
12150
|
+
delete v.copyPropItem;
|
|
12231
12151
|
}
|
|
12232
|
-
|
|
12152
|
+
v.curType = value;
|
|
12233
12153
|
}
|
|
12234
12154
|
return;
|
|
12235
12155
|
}
|
|
@@ -12563,7 +12483,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12563
12483
|
break;
|
|
12564
12484
|
}
|
|
12565
12485
|
case "ref": {
|
|
12566
|
-
|
|
12486
|
+
const curEntry = getStateEntry(curState, event.decl);
|
|
12567
12487
|
typeMap.set(event.node, curEntry.curType);
|
|
12568
12488
|
nodeEquivs.delete(event.node);
|
|
12569
12489
|
if (curEntry.equivSet) {
|
|
@@ -12587,9 +12507,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12587
12507
|
nodeCopyProp.set(curEntry.copyPropItem.event.node, event.node);
|
|
12588
12508
|
}
|
|
12589
12509
|
clearCopyProp(curState, curEntry.copyPropItem);
|
|
12590
|
-
curEntry = { ...curEntry };
|
|
12591
12510
|
delete curEntry.copyPropItem;
|
|
12592
|
-
curState.map.set(event.decl, curEntry);
|
|
12593
12511
|
}
|
|
12594
12512
|
else if (declIsNonLocal(event.decl)) {
|
|
12595
12513
|
clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
|
|
@@ -12627,12 +12545,13 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12627
12545
|
}
|
|
12628
12546
|
});
|
|
12629
12547
|
}
|
|
12548
|
+
let calleeEffects;
|
|
12630
12549
|
curState.map.forEach((tsv, decl) => {
|
|
12631
12550
|
let type = tsv.curType;
|
|
12632
|
-
if (
|
|
12633
|
-
(
|
|
12634
|
-
|
|
12635
|
-
|
|
12551
|
+
if ((type.value == null ||
|
|
12552
|
+
!(type.type &
|
|
12553
|
+
(32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */))) &&
|
|
12554
|
+
!(0,external_util_cjs_namespaceObject.some)(decl, (d) => d.type === "VariableDeclarator" && !(0,external_api_cjs_namespaceObject.isLocal)(d))) {
|
|
12636
12555
|
return;
|
|
12637
12556
|
}
|
|
12638
12557
|
if (modifiableDecl(decl, callees)) {
|
|
@@ -12648,9 +12567,14 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12648
12567
|
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
12649
12568
|
curState.map.set(decl, { curType: typeConstraint(decl) });
|
|
12650
12569
|
}
|
|
12651
|
-
else if (type.
|
|
12652
|
-
(
|
|
12653
|
-
|
|
12570
|
+
else if (type.type &
|
|
12571
|
+
(32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */) &&
|
|
12572
|
+
(calleeEffects == null
|
|
12573
|
+
? (calleeEffects =
|
|
12574
|
+
!callees ||
|
|
12575
|
+
!(0,external_util_cjs_namespaceObject.every)(callees, (callee) => callee.info === false))
|
|
12576
|
+
: calleeEffects)) {
|
|
12577
|
+
if (type.value != null && type.type & 32768 /* TypeTag.Object */) {
|
|
12654
12578
|
const odata = getObjectValue(tsv.curType);
|
|
12655
12579
|
if (odata?.obj) {
|
|
12656
12580
|
type = cloneType(type);
|
|
@@ -12658,18 +12582,12 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12658
12582
|
setUnionComponent(type, 32768 /* TypeTag.Object */, newData);
|
|
12659
12583
|
if (tsv.assocPaths) {
|
|
12660
12584
|
clearAssocPaths(curState, decl, tsv);
|
|
12661
|
-
tsv = { ...tsv };
|
|
12662
12585
|
delete tsv.assocPaths;
|
|
12663
12586
|
}
|
|
12664
|
-
|
|
12665
|
-
copyPropFailed(curState, tsv.copyPropItem, nodeCopyProp);
|
|
12666
|
-
tsv = { ...tsv };
|
|
12667
|
-
delete tsv.copyPropItem;
|
|
12668
|
-
}
|
|
12669
|
-
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
12670
|
-
curState.map.set(decl, { ...tsv, curType: type });
|
|
12587
|
+
tsv.curType = type;
|
|
12671
12588
|
}
|
|
12672
12589
|
}
|
|
12590
|
+
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
12673
12591
|
}
|
|
12674
12592
|
});
|
|
12675
12593
|
return true;
|
|
@@ -12691,10 +12609,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12691
12609
|
(event.node.type !== "AssignmentExpression" ||
|
|
12692
12610
|
event.node.operator !== "=")) {
|
|
12693
12611
|
copyPropFailed(curState, before.copyPropItem, nodeCopyProp);
|
|
12694
|
-
|
|
12695
|
-
delete v.copyPropItem;
|
|
12696
|
-
external_node_assert_namespaceObject(isTypeStateKey(event.decl));
|
|
12697
|
-
curState.map.set(event.decl, v);
|
|
12612
|
+
delete before.copyPropItem;
|
|
12698
12613
|
}
|
|
12699
12614
|
}
|
|
12700
12615
|
const expr = event.node.type === "VariableDeclarator"
|
|
@@ -12788,22 +12703,41 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12788
12703
|
decl.type === "BinaryExpression" ||
|
|
12789
12704
|
decl.type === "Identifier"))) {
|
|
12790
12705
|
const key = event.decl ?? null;
|
|
12791
|
-
if (key &&
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
12804
|
-
|
|
12805
|
-
|
|
12806
|
-
|
|
12706
|
+
if (key && declIsLocal(key)) {
|
|
12707
|
+
if (nodeCopyProp.has(event.node)) {
|
|
12708
|
+
// we might have
|
|
12709
|
+
//
|
|
12710
|
+
// var x = foo();
|
|
12711
|
+
// var y = x + 1;
|
|
12712
|
+
// bar();
|
|
12713
|
+
// return y;
|
|
12714
|
+
//
|
|
12715
|
+
// In that case, its ok to drop "x = foo()" and rewrite as y = foo() + 1"
|
|
12716
|
+
// OR its ok to drop "y = x + 1" and rewrite as "return x + 1".
|
|
12717
|
+
// But we can't do both, and rewrite as "bar(); return foo() + 1;"
|
|
12718
|
+
// So just disable copy prop for *this* node. We'll re-run and have a
|
|
12719
|
+
// second chance later.
|
|
12720
|
+
return false;
|
|
12721
|
+
}
|
|
12722
|
+
else if (event.node.type === "AssignmentExpression" &&
|
|
12723
|
+
event.node.operator !== "=" &&
|
|
12724
|
+
nodeCopyProp.has(event.node.left)) {
|
|
12725
|
+
// If we're copy proping into the lhs of an update
|
|
12726
|
+
// assignment, we're going to have to rewrite it.
|
|
12727
|
+
// similar to the above, don't also do forward copy
|
|
12728
|
+
// prop. eg
|
|
12729
|
+
//
|
|
12730
|
+
// var x = a + b;
|
|
12731
|
+
// x += c;
|
|
12732
|
+
// return x;
|
|
12733
|
+
//
|
|
12734
|
+
// becomes
|
|
12735
|
+
//
|
|
12736
|
+
// var x;
|
|
12737
|
+
// x = (a + b) + c;
|
|
12738
|
+
// return x; // <- dont propagate to here (yet), in case a+b has changed.
|
|
12739
|
+
return false;
|
|
12740
|
+
}
|
|
12807
12741
|
}
|
|
12808
12742
|
const item = contained.get(key);
|
|
12809
12743
|
if (!item) {
|
|
@@ -12992,7 +12926,22 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12992
12926
|
}
|
|
12993
12927
|
}
|
|
12994
12928
|
}));
|
|
12995
|
-
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body,
|
|
12929
|
+
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
|
|
12930
|
+
if (node.type === "AssignmentExpression" &&
|
|
12931
|
+
node.operator !== "=" &&
|
|
12932
|
+
nodeCopyProp.has(node.left)) {
|
|
12933
|
+
const left = cloneDeep(node.left);
|
|
12934
|
+
const right = withLoc({
|
|
12935
|
+
type: "BinaryExpression",
|
|
12936
|
+
operator: node.operator.slice(0, -1),
|
|
12937
|
+
left: withLocDeep(node.left, node.right, false, true),
|
|
12938
|
+
right: node.right,
|
|
12939
|
+
}, node.left, node.right);
|
|
12940
|
+
node.operator = "=";
|
|
12941
|
+
node.left = left;
|
|
12942
|
+
node.right = right;
|
|
12943
|
+
}
|
|
12944
|
+
}, (node) => {
|
|
12996
12945
|
const copyNode = nodeCopyProp.get(node);
|
|
12997
12946
|
if (copyNode) {
|
|
12998
12947
|
if (node.type === "AssignmentExpression") {
|
|
@@ -13011,10 +12960,18 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
13011
12960
|
return dup;
|
|
13012
12961
|
}
|
|
13013
12962
|
if (copyNode.type === "AssignmentExpression") {
|
|
12963
|
+
const replacement = copyNode.operator === "="
|
|
12964
|
+
? copyNode.right
|
|
12965
|
+
: {
|
|
12966
|
+
type: "BinaryExpression",
|
|
12967
|
+
operator: copyNode.operator.slice(0, -1),
|
|
12968
|
+
left: copyNode.left,
|
|
12969
|
+
right: copyNode.right,
|
|
12970
|
+
};
|
|
13014
12971
|
if (logThisRun) {
|
|
13015
|
-
console.log(`copy-prop ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(node)} => ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(
|
|
12972
|
+
console.log(`copy-prop ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(node)} => ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(replacement)}`);
|
|
13016
12973
|
}
|
|
13017
|
-
return withLocDeep(
|
|
12974
|
+
return withLocDeep(replacement, node, node, false);
|
|
13018
12975
|
}
|
|
13019
12976
|
else if (copyNode.type === "VariableDeclarator") {
|
|
13020
12977
|
external_node_assert_namespaceObject(copyNode.init);
|
|
@@ -13321,11 +13278,6 @@ function minimizeLocals(state, func) {
|
|
|
13321
13278
|
return null;
|
|
13322
13279
|
}
|
|
13323
13280
|
break;
|
|
13324
|
-
case "ExpressionStatement":
|
|
13325
|
-
if (node.expression.type === "Literal") {
|
|
13326
|
-
return false;
|
|
13327
|
-
}
|
|
13328
|
-
break;
|
|
13329
13281
|
case "UpdateExpression":
|
|
13330
13282
|
if (info) {
|
|
13331
13283
|
external_node_assert_namespaceObject(node.argument.type === "Identifier");
|
|
@@ -13346,7 +13298,7 @@ function minimizeLocals(state, func) {
|
|
|
13346
13298
|
}
|
|
13347
13299
|
// VariableDeclarations aren't allowed to have
|
|
13348
13300
|
// AssignmentExpressions in them, but we'll fix that
|
|
13349
|
-
//
|
|
13301
|
+
// via variableCleanup
|
|
13350
13302
|
return withLoc({
|
|
13351
13303
|
type: "AssignmentExpression",
|
|
13352
13304
|
operator: "=",
|
|
@@ -13359,79 +13311,92 @@ function minimizeLocals(state, func) {
|
|
|
13359
13311
|
}, node, node);
|
|
13360
13312
|
}
|
|
13361
13313
|
break;
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
|
|
13374
|
-
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
}, decl, decl));
|
|
13382
|
-
}
|
|
13383
|
-
});
|
|
13384
|
-
node.declarations = node.declarations.filter((decl) => {
|
|
13385
|
-
if (decl.type === "VariableDeclarator") {
|
|
13386
|
-
delete decl.init;
|
|
13387
|
-
return true;
|
|
13388
|
-
}
|
|
13389
|
-
return false;
|
|
13390
|
-
});
|
|
13391
|
-
if (node.declarations.length) {
|
|
13392
|
-
withLocDeep(node, node, false);
|
|
13393
|
-
results.unshift(node);
|
|
13314
|
+
}
|
|
13315
|
+
external_node_assert_namespaceObject(!info);
|
|
13316
|
+
return variableCleanup(node);
|
|
13317
|
+
});
|
|
13318
|
+
return;
|
|
13319
|
+
}
|
|
13320
|
+
function variableCleanup(node) {
|
|
13321
|
+
switch (node.type) {
|
|
13322
|
+
case "ExpressionStatement":
|
|
13323
|
+
if (node.expression.type === "Literal") {
|
|
13324
|
+
return false;
|
|
13325
|
+
}
|
|
13326
|
+
break;
|
|
13327
|
+
case "VariableDeclaration":
|
|
13328
|
+
if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
|
|
13329
|
+
const results = [];
|
|
13330
|
+
node.declarations.forEach((decl) => {
|
|
13331
|
+
if (isStatement(decl)) {
|
|
13332
|
+
results.push(decl);
|
|
13394
13333
|
}
|
|
13395
|
-
|
|
13396
|
-
|
|
13397
|
-
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
// where result ended, and result's end to be where the for
|
|
13412
|
-
// ends (since that block now encloses the for)
|
|
13413
|
-
node.start = result.end;
|
|
13414
|
-
node.loc.start = result.loc.end;
|
|
13415
|
-
result.end = node.end;
|
|
13416
|
-
result.loc.end = node.loc.end;
|
|
13417
|
-
}
|
|
13418
|
-
return result;
|
|
13334
|
+
else if (isExpression(decl)) {
|
|
13335
|
+
results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
|
|
13336
|
+
}
|
|
13337
|
+
else if (decl.init) {
|
|
13338
|
+
results.push(withLoc({
|
|
13339
|
+
type: "ExpressionStatement",
|
|
13340
|
+
expression: withLoc({
|
|
13341
|
+
type: "AssignmentExpression",
|
|
13342
|
+
operator: "=",
|
|
13343
|
+
left: withLoc({
|
|
13344
|
+
type: "Identifier",
|
|
13345
|
+
name: (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id),
|
|
13346
|
+
}, decl.id, decl.id),
|
|
13347
|
+
right: decl.init,
|
|
13348
|
+
}, decl, decl),
|
|
13349
|
+
}, decl, decl));
|
|
13419
13350
|
}
|
|
13420
|
-
|
|
13421
|
-
|
|
13351
|
+
});
|
|
13352
|
+
node.declarations = node.declarations.filter((decl) => {
|
|
13353
|
+
if (decl.type === "VariableDeclarator") {
|
|
13354
|
+
delete decl.init;
|
|
13355
|
+
return true;
|
|
13422
13356
|
}
|
|
13357
|
+
return false;
|
|
13358
|
+
});
|
|
13359
|
+
if (node.declarations.length) {
|
|
13360
|
+
withLocDeep(node, node, false);
|
|
13361
|
+
results.unshift(node);
|
|
13423
13362
|
}
|
|
13424
|
-
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13363
|
+
// if this was the init of a ForStatement, this will
|
|
13364
|
+
// replace its init with a BlockStatement, so we have to
|
|
13365
|
+
// fix that below.
|
|
13366
|
+
return results;
|
|
13367
|
+
}
|
|
13368
|
+
break;
|
|
13369
|
+
case "ForStatement":
|
|
13370
|
+
if (node.init) {
|
|
13371
|
+
if (node.init.type === "BlockStatement") {
|
|
13372
|
+
const result = node.init;
|
|
13373
|
+
delete node.init;
|
|
13374
|
+
result.body.push(node);
|
|
13375
|
+
if (node.loc && result.loc) {
|
|
13376
|
+
// result has the range of the original VariableDeclaration
|
|
13377
|
+
// but now we're moving that ahead of the 'for', so to keep
|
|
13378
|
+
// things straight, we need to set the for's start to be
|
|
13379
|
+
// where result ended, and result's end to be where the for
|
|
13380
|
+
// ends (since that block now encloses the for)
|
|
13381
|
+
node.start = result.end;
|
|
13382
|
+
node.loc.start = result.loc.end;
|
|
13383
|
+
result.end = node.end;
|
|
13384
|
+
result.loc.end = node.loc.end;
|
|
13385
|
+
}
|
|
13386
|
+
return result;
|
|
13428
13387
|
}
|
|
13429
|
-
|
|
13430
|
-
|
|
13431
|
-
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13388
|
+
if (node.init.type === "Literal") {
|
|
13389
|
+
delete node.init;
|
|
13390
|
+
}
|
|
13391
|
+
}
|
|
13392
|
+
break;
|
|
13393
|
+
case "SequenceExpression":
|
|
13394
|
+
if (node.expressions.some((e) => e.type === "Literal")) {
|
|
13395
|
+
node.expressions = node.expressions.filter((e) => e.type !== "Literal");
|
|
13396
|
+
}
|
|
13397
|
+
break;
|
|
13398
|
+
}
|
|
13399
|
+
return null;
|
|
13435
13400
|
}
|
|
13436
13401
|
|
|
13437
13402
|
;// CONCATENATED MODULE: ./src/pre.ts
|
|
@@ -14184,6 +14149,199 @@ function applyReplacements(func, nodeMap, declMap) {
|
|
|
14184
14149
|
});
|
|
14185
14150
|
}
|
|
14186
14151
|
|
|
14152
|
+
;// CONCATENATED MODULE: ./src/type-flow/minimize-modules.ts
|
|
14153
|
+
|
|
14154
|
+
|
|
14155
|
+
|
|
14156
|
+
function minimizeModules(ast, state) {
|
|
14157
|
+
const { pre, post } = state;
|
|
14158
|
+
try {
|
|
14159
|
+
const replacementMap = new Map();
|
|
14160
|
+
const conflictingNames = new Set();
|
|
14161
|
+
state.pre = (node) => {
|
|
14162
|
+
if (state.inType)
|
|
14163
|
+
return null;
|
|
14164
|
+
switch (node.type) {
|
|
14165
|
+
case "ModuleDeclaration":
|
|
14166
|
+
case "ClassDeclaration":
|
|
14167
|
+
case "FunctionDeclaration":
|
|
14168
|
+
return ["body"];
|
|
14169
|
+
case "Using":
|
|
14170
|
+
conflictingNames.add(node.as?.name ??
|
|
14171
|
+
(node.id.type === "Identifier"
|
|
14172
|
+
? node.id.name
|
|
14173
|
+
: node.id.property.name));
|
|
14174
|
+
return [];
|
|
14175
|
+
case "ImportModule":
|
|
14176
|
+
conflictingNames.add(node.id.type === "Identifier" ? node.id.name : node.id.property.name);
|
|
14177
|
+
return [];
|
|
14178
|
+
case "Identifier":
|
|
14179
|
+
case "MemberExpression": {
|
|
14180
|
+
let current = node;
|
|
14181
|
+
const parts = [];
|
|
14182
|
+
while (current.type === "MemberExpression" && !current.computed) {
|
|
14183
|
+
parts.unshift(current);
|
|
14184
|
+
current = current.object;
|
|
14185
|
+
}
|
|
14186
|
+
if (current.type !== "Identifier" &&
|
|
14187
|
+
current.type !== "ThisExpression") {
|
|
14188
|
+
break;
|
|
14189
|
+
}
|
|
14190
|
+
let toReplace = null;
|
|
14191
|
+
let module = null;
|
|
14192
|
+
let addImport = false;
|
|
14193
|
+
let [, results] = state.lookupValue(current, null);
|
|
14194
|
+
let i = 0;
|
|
14195
|
+
for (; results &&
|
|
14196
|
+
results.length === 1 &&
|
|
14197
|
+
results[0].results.length === 1 &&
|
|
14198
|
+
(results[0].results[0].type === "Program" ||
|
|
14199
|
+
results[0].results[0].type === "ClassDeclaration" ||
|
|
14200
|
+
results[0].results[0].type === "ModuleDeclaration"); i++) {
|
|
14201
|
+
if (current.type === "Identifier" &&
|
|
14202
|
+
results[0].results[0].type === "ModuleDeclaration" &&
|
|
14203
|
+
isImportCandidate(results[0].results[0])) {
|
|
14204
|
+
const directResults = i
|
|
14205
|
+
? state.lookupValue(current, null)
|
|
14206
|
+
: results;
|
|
14207
|
+
if (directResults &&
|
|
14208
|
+
directResults.length === 1 &&
|
|
14209
|
+
directResults[0].results.length === 1 &&
|
|
14210
|
+
directResults[0].results[0] === results[0].results[0]) {
|
|
14211
|
+
// we would find the same thing if we just looked up
|
|
14212
|
+
// current directly.
|
|
14213
|
+
toReplace = (i ? parts[i - 1] : current);
|
|
14214
|
+
module = results[0].results[0];
|
|
14215
|
+
if ((0,external_api_cjs_namespaceObject.findUsingForNode)(state, state.stack, state.stack.length - 1, current) === directResults[0].results[0]) {
|
|
14216
|
+
// we already find it via an import, so we don't need
|
|
14217
|
+
// a new import.
|
|
14218
|
+
addImport = false;
|
|
14219
|
+
}
|
|
14220
|
+
else {
|
|
14221
|
+
addImport = true;
|
|
14222
|
+
}
|
|
14223
|
+
}
|
|
14224
|
+
else {
|
|
14225
|
+
toReplace = parts[i - 1];
|
|
14226
|
+
module = results[0].results[0];
|
|
14227
|
+
addImport = true;
|
|
14228
|
+
}
|
|
14229
|
+
}
|
|
14230
|
+
if (i === parts.length)
|
|
14231
|
+
break;
|
|
14232
|
+
current = parts[i].property;
|
|
14233
|
+
results = (0,external_api_cjs_namespaceObject.lookupNext)(state, results, "decls", current);
|
|
14234
|
+
}
|
|
14235
|
+
if (toReplace) {
|
|
14236
|
+
external_node_assert_namespaceObject(module);
|
|
14237
|
+
replacementMap.set(toReplace, { module, addImport });
|
|
14238
|
+
}
|
|
14239
|
+
else if (parts.length === 0) {
|
|
14240
|
+
external_node_assert_namespaceObject(node.type === "Identifier");
|
|
14241
|
+
conflictingNames.add(node.name);
|
|
14242
|
+
}
|
|
14243
|
+
else if (parts[0].object.type === "Identifier") {
|
|
14244
|
+
conflictingNames.add(parts[0].object.name);
|
|
14245
|
+
}
|
|
14246
|
+
return [];
|
|
14247
|
+
}
|
|
14248
|
+
}
|
|
14249
|
+
return null;
|
|
14250
|
+
};
|
|
14251
|
+
(0,external_api_cjs_namespaceObject.collectNamespaces)(ast, state);
|
|
14252
|
+
const mappedNames = new Map();
|
|
14253
|
+
replacementMap.forEach((value, key) => {
|
|
14254
|
+
let name;
|
|
14255
|
+
if (value.addImport) {
|
|
14256
|
+
name = mappedNames.get(value.module);
|
|
14257
|
+
if (!name) {
|
|
14258
|
+
name = value.module.name;
|
|
14259
|
+
for (let i = 0; conflictingNames.has(name); i++) {
|
|
14260
|
+
name = `${value.module.name}_${i}`;
|
|
14261
|
+
}
|
|
14262
|
+
mappedNames.set(value.module, name);
|
|
14263
|
+
conflictingNames.add(name);
|
|
14264
|
+
}
|
|
14265
|
+
}
|
|
14266
|
+
else {
|
|
14267
|
+
name = key.type === "Identifier" ? key.name : key.property.name;
|
|
14268
|
+
}
|
|
14269
|
+
const original = (0,external_api_cjs_namespaceObject.formatAstLongLines)(key);
|
|
14270
|
+
const repl = key;
|
|
14271
|
+
repl.type = "Identifier";
|
|
14272
|
+
repl.name = name;
|
|
14273
|
+
if (name !== original) {
|
|
14274
|
+
repl.original = original;
|
|
14275
|
+
}
|
|
14276
|
+
delete repl.property;
|
|
14277
|
+
delete repl.object;
|
|
14278
|
+
delete repl.computed;
|
|
14279
|
+
});
|
|
14280
|
+
mappedNames.forEach((name, module) => {
|
|
14281
|
+
const id = makeScopedName(module.fullName.slice(2));
|
|
14282
|
+
const as = name !== (id.type === "Identifier" ? id : id.property).name &&
|
|
14283
|
+
makeIdentifier(name);
|
|
14284
|
+
const using = withLocDeep(as ? { type: "Using", id, as } : { type: "Using", id }, ast, false, true);
|
|
14285
|
+
ast.body.unshift(using);
|
|
14286
|
+
});
|
|
14287
|
+
}
|
|
14288
|
+
finally {
|
|
14289
|
+
state.pre = pre;
|
|
14290
|
+
state.post = post;
|
|
14291
|
+
}
|
|
14292
|
+
}
|
|
14293
|
+
/**
|
|
14294
|
+
* There's a bug in garmin's runtime (although the compiler could
|
|
14295
|
+
* work around it). See
|
|
14296
|
+
*
|
|
14297
|
+
* https://forums.garmin.com/developer/connect-iq/i/bug-reports/referencing-an-imported-module-doesn-t-run-its-parent-s-init
|
|
14298
|
+
*
|
|
14299
|
+
* What this means is that if a module's parent isn't `globals`
|
|
14300
|
+
* and it needs to be initialized, then we can't risk
|
|
14301
|
+
* importing it, because the parent module might not get initialized
|
|
14302
|
+
* in time.
|
|
14303
|
+
*/
|
|
14304
|
+
function isImportCandidate(module) {
|
|
14305
|
+
if (module.fullName.startsWith("$.Toybox."))
|
|
14306
|
+
return true;
|
|
14307
|
+
if (module.fullName.startsWith("$.Rez."))
|
|
14308
|
+
return false;
|
|
14309
|
+
external_node_assert_namespaceObject(module.stack);
|
|
14310
|
+
if (module.stack.length === 1)
|
|
14311
|
+
return true;
|
|
14312
|
+
return module.stack.every((elem) => {
|
|
14313
|
+
if (!elem.sn.decls)
|
|
14314
|
+
return false;
|
|
14315
|
+
if (elem.sn.type === "Program")
|
|
14316
|
+
return true;
|
|
14317
|
+
if (elem.sn.type !== "ModuleDeclaration")
|
|
14318
|
+
return false;
|
|
14319
|
+
return Object.values(elem.sn.decls).every((decls) => decls.every((decl) => {
|
|
14320
|
+
if (decl.type !== "VariableDeclarator")
|
|
14321
|
+
return true;
|
|
14322
|
+
if (!decl.node.init)
|
|
14323
|
+
return true;
|
|
14324
|
+
if (decl.node.init.type === "UnaryExpression" &&
|
|
14325
|
+
decl.node.init.operator === ":") {
|
|
14326
|
+
return true;
|
|
14327
|
+
}
|
|
14328
|
+
if (decl.node.init.type !== "Literal")
|
|
14329
|
+
return false;
|
|
14330
|
+
switch (typeof decl.node.init.value) {
|
|
14331
|
+
case "boolean":
|
|
14332
|
+
return true;
|
|
14333
|
+
case "bigint":
|
|
14334
|
+
return false;
|
|
14335
|
+
case "number":
|
|
14336
|
+
return !/[dl]$/i.test(decl.node.init.raw);
|
|
14337
|
+
case "object":
|
|
14338
|
+
return decl.node.init.value === null;
|
|
14339
|
+
}
|
|
14340
|
+
return false;
|
|
14341
|
+
}));
|
|
14342
|
+
});
|
|
14343
|
+
}
|
|
14344
|
+
|
|
14187
14345
|
;// CONCATENATED MODULE: ./src/type-flow/optimize.ts
|
|
14188
14346
|
|
|
14189
14347
|
|
|
@@ -15034,6 +15192,7 @@ function cleanupUnusedVars(state, node) {
|
|
|
15034
15192
|
|
|
15035
15193
|
|
|
15036
15194
|
|
|
15195
|
+
|
|
15037
15196
|
/*
|
|
15038
15197
|
* Map each name to the list of StateNodes that declare that
|
|
15039
15198
|
* name (excluding Functions, which are already in allFunctions)
|
|
@@ -15621,32 +15780,30 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
|
|
|
15621
15780
|
break;
|
|
15622
15781
|
case "Identifier": {
|
|
15623
15782
|
const map = topLocals().map;
|
|
15624
|
-
if (map) {
|
|
15625
|
-
|
|
15626
|
-
|
|
15627
|
-
|
|
15628
|
-
|
|
15783
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(map, node.name)) {
|
|
15784
|
+
const name = map[node.name];
|
|
15785
|
+
if (typeof name === "string") {
|
|
15786
|
+
renameIdentifier(node, name);
|
|
15787
|
+
}
|
|
15788
|
+
const [, results] = state.lookupValue(node);
|
|
15789
|
+
if (results) {
|
|
15790
|
+
if (results.length !== 1 || results[0].results.length !== 1) {
|
|
15791
|
+
throw new Error(`Local ${node.name} had multiple lookup results`);
|
|
15629
15792
|
}
|
|
15630
|
-
const
|
|
15631
|
-
if (
|
|
15632
|
-
|
|
15633
|
-
|
|
15634
|
-
|
|
15635
|
-
|
|
15636
|
-
|
|
15637
|
-
|
|
15638
|
-
|
|
15639
|
-
const decl = results[0].results[0];
|
|
15640
|
-
if (parent.type === "FunctionDeclaration" ||
|
|
15641
|
-
decl.type !== "VariableDeclarator") {
|
|
15642
|
-
// we can't optimize away function or catch parameters
|
|
15643
|
-
return [];
|
|
15644
|
-
}
|
|
15645
|
-
if (parent.type !== "BlockStatement") {
|
|
15646
|
-
throw new Error(`Local ${node.name} was not declared at block scope(??)`);
|
|
15647
|
-
}
|
|
15648
|
-
decl.used = true;
|
|
15793
|
+
const parent = results[0].parent;
|
|
15794
|
+
if (!parent) {
|
|
15795
|
+
throw new Error(`Local ${node.name} had no parent`);
|
|
15796
|
+
}
|
|
15797
|
+
const decl = results[0].results[0];
|
|
15798
|
+
if (parent.type === "FunctionDeclaration" ||
|
|
15799
|
+
decl.type !== "VariableDeclarator") {
|
|
15800
|
+
// we can't optimize away function or catch parameters
|
|
15801
|
+
return [];
|
|
15649
15802
|
}
|
|
15803
|
+
if (parent.type !== "BlockStatement") {
|
|
15804
|
+
throw new Error(`Local ${node.name} was not declared at block scope(??)`);
|
|
15805
|
+
}
|
|
15806
|
+
decl.used = true;
|
|
15650
15807
|
}
|
|
15651
15808
|
}
|
|
15652
15809
|
return [];
|
|
@@ -15934,6 +16091,11 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
|
|
|
15934
16091
|
state.nextExposed = {};
|
|
15935
16092
|
delete state.pre;
|
|
15936
16093
|
delete state.post;
|
|
16094
|
+
if (state.config?.minimizeModules ?? true) {
|
|
16095
|
+
Object.values(fnMap).forEach((f) => {
|
|
16096
|
+
minimizeModules(f.ast, state);
|
|
16097
|
+
});
|
|
16098
|
+
}
|
|
15937
16099
|
Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
|
|
15938
16100
|
const cleanup = (node) => {
|
|
15939
16101
|
switch (node.type) {
|
|
@@ -16579,6 +16741,7 @@ const configOptionsToCheck = [
|
|
|
16579
16741
|
"propagateTypes",
|
|
16580
16742
|
"singleUseCopyProp",
|
|
16581
16743
|
"minimizeLocals",
|
|
16744
|
+
"minimizeModules",
|
|
16582
16745
|
"extensionVersion",
|
|
16583
16746
|
"typeCheckLevel",
|
|
16584
16747
|
"covarianceWarnings",
|
|
@@ -16640,7 +16803,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
|
|
|
16640
16803
|
// the oldest optimized file, we don't need to regenerate
|
|
16641
16804
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
16642
16805
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
16643
|
-
if (source_time < opt_time &&
|
|
16806
|
+
if (source_time < opt_time && 1676335488374 < opt_time) {
|
|
16644
16807
|
return { hasTests, diagnostics: prevDiagnostics };
|
|
16645
16808
|
}
|
|
16646
16809
|
}
|
|
@@ -16667,7 +16830,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
|
|
|
16667
16830
|
return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
|
|
16668
16831
|
hasTests,
|
|
16669
16832
|
diagnostics,
|
|
16670
|
-
optimizerVersion: "1.1.
|
|
16833
|
+
optimizerVersion: "1.1.13",
|
|
16671
16834
|
...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
|
|
16672
16835
|
}))
|
|
16673
16836
|
.then(() => ({ hasTests, diagnostics }));
|