@markw65/monkeyc-optimizer 1.1.11 → 1.1.12
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 +8 -0
- package/build/api.cjs +150 -153
- package/build/optimizer.cjs +152 -155
- package/build/src/api.d.ts +1 -1
- package/build/src/type-flow/type-flow-util.d.ts +1 -1
- package/build/src/type-flow/types.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -703,3 +703,11 @@ Bug Fixes
|
|
|
703
703
|
- Propagate any :typecheck annotations from inlined functions to their callers
|
|
704
704
|
- Fix some issues keeping track of function calls used as arguments to inlined functions, that could result in bogus diagnostics.
|
|
705
705
|
- Implement [Single Use Copy Propagation](https://github.com/markw65/monkeyc-optimizer/wiki/Local-variable-elimination#single-use-copy-propagation)
|
|
706
|
+
|
|
707
|
+
### 1.1.12
|
|
708
|
+
|
|
709
|
+
- Update to [@markw65/prettier-plugin-monkeyc@1.0.45](https://github.com/markw65/prettier-plugin-monkeyc#1045)
|
|
710
|
+
- fixes some bugs that could cause comments to go missing, resulting in an internal error from the formatter
|
|
711
|
+
- Streamline some of the data structures used for `Minimise Locals` and `Single Copy Prop` to reduce memory use, and speed things up a little.
|
|
712
|
+
- Fix a bug that could cause incorrect copy propagation in loops
|
|
713
|
+
- Add support for update assignments in copy propagation (so that `var x = a; x += b; return x` goes to `return a + b`)
|
package/build/api.cjs
CHANGED
|
@@ -1507,9 +1507,10 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
|
|
|
1507
1507
|
decl,
|
|
1508
1508
|
mayThrow,
|
|
1509
1509
|
};
|
|
1510
|
-
if (wantsAllRefs
|
|
1511
|
-
if (node.right.type === "Identifier" ||
|
|
1512
|
-
node.right.type === "MemberExpression")
|
|
1510
|
+
if (wantsAllRefs) {
|
|
1511
|
+
if ((node.right.type === "Identifier" ||
|
|
1512
|
+
node.right.type === "MemberExpression") &&
|
|
1513
|
+
node.operator === "=") {
|
|
1513
1514
|
const rhs = findDecl(node.right);
|
|
1514
1515
|
if (rhs)
|
|
1515
1516
|
def.rhs = rhs;
|
|
@@ -4955,74 +4956,43 @@ function addEquiv(ts, key, equiv) {
|
|
|
4955
4956
|
if (!keyVal || !equivVal)
|
|
4956
4957
|
return false;
|
|
4957
4958
|
if (equivVal.equivSet) {
|
|
4958
|
-
if (
|
|
4959
|
-
|
|
4960
|
-
// equiv is part of it.
|
|
4961
|
-
let s = keyVal.equivSet.next;
|
|
4962
|
-
do {
|
|
4963
|
-
if (s === equiv) {
|
|
4964
|
-
// these two are already equivalent
|
|
4965
|
-
return true;
|
|
4966
|
-
}
|
|
4967
|
-
const next = ts.get(s);
|
|
4968
|
-
if (!next || !next.equivSet) {
|
|
4969
|
-
throw new Error(`Inconsistent equivSet for ${tsKey(key)}: missing value for ${tsKey(s)}`);
|
|
4970
|
-
}
|
|
4971
|
-
s = next.equivSet.next;
|
|
4972
|
-
} while (s !== key);
|
|
4959
|
+
if (equivVal.equivSet.has(key)) {
|
|
4960
|
+
return true;
|
|
4973
4961
|
}
|
|
4974
4962
|
// equiv is already a member of a set. remove it
|
|
4975
4963
|
removeEquiv(ts, equiv);
|
|
4976
4964
|
}
|
|
4977
4965
|
// equiv is not (or no longer) part of an equivSet
|
|
4978
|
-
keyVal = { ...keyVal };
|
|
4979
4966
|
if (!keyVal.equivSet) {
|
|
4980
|
-
keyVal
|
|
4967
|
+
keyVal = { ...keyVal };
|
|
4968
|
+
keyVal.equivSet = new Set([key, equiv]);
|
|
4969
|
+
ts.set(key, keyVal);
|
|
4970
|
+
}
|
|
4971
|
+
else {
|
|
4972
|
+
keyVal.equivSet.add(equiv);
|
|
4981
4973
|
}
|
|
4982
4974
|
equivVal = { ...equivVal, equivSet: keyVal.equivSet };
|
|
4983
|
-
keyVal.equivSet = { next: equiv };
|
|
4984
|
-
ts.set(key, keyVal);
|
|
4985
4975
|
ts.set(equiv, equivVal);
|
|
4986
4976
|
return false;
|
|
4987
4977
|
}
|
|
4988
4978
|
function removeEquiv(ts, equiv) {
|
|
4989
|
-
|
|
4979
|
+
let equivVal = ts.get(equiv);
|
|
4990
4980
|
if (!equivVal?.equivSet)
|
|
4991
4981
|
return;
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
const
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
ts.set(s, rest);
|
|
5003
|
-
}
|
|
5004
|
-
else {
|
|
5005
|
-
ts.set(s, { ...rest, equivSet: equivVal.equivSet });
|
|
5006
|
-
}
|
|
5007
|
-
break;
|
|
5008
|
-
}
|
|
5009
|
-
s = next.equivSet.next;
|
|
5010
|
-
} while (true);
|
|
5011
|
-
const newVal = { ...equivVal };
|
|
5012
|
-
delete newVal.equivSet;
|
|
5013
|
-
ts.set(equiv, newVal);
|
|
4982
|
+
equivVal.equivSet.delete(equiv);
|
|
4983
|
+
if (equivVal.equivSet.size === 1) {
|
|
4984
|
+
const other = Array.from(equivVal.equivSet)[0];
|
|
4985
|
+
const otherVal = { ...ts.get(other) };
|
|
4986
|
+
delete otherVal.equivSet;
|
|
4987
|
+
ts.set(other, otherVal);
|
|
4988
|
+
}
|
|
4989
|
+
equivVal = { ...equivVal };
|
|
4990
|
+
delete equivVal.equivSet;
|
|
4991
|
+
ts.set(equiv, equivVal);
|
|
5014
4992
|
}
|
|
5015
4993
|
function getEquivSet(ts, k) {
|
|
5016
|
-
const keys =
|
|
5017
|
-
|
|
5018
|
-
do {
|
|
5019
|
-
const next = ts.get(s);
|
|
5020
|
-
if (!next || !next.equivSet) {
|
|
5021
|
-
throw new Error(`Inconsistent equivSet for ${tsKey(k)}: missing value for ${tsKey(s)}`);
|
|
5022
|
-
}
|
|
5023
|
-
keys.add(s);
|
|
5024
|
-
s = next.equivSet.next;
|
|
5025
|
-
} while (s !== k);
|
|
4994
|
+
const keys = ts.get(k)?.equivSet;
|
|
4995
|
+
assert(keys);
|
|
5026
4996
|
return keys;
|
|
5027
4997
|
}
|
|
5028
4998
|
function intersectEquiv(ts1, ts2, k) {
|
|
@@ -5034,21 +5004,26 @@ function intersectEquiv(ts1, ts2, k) {
|
|
|
5034
5004
|
removeEquiv(ts1, k);
|
|
5035
5005
|
return true;
|
|
5036
5006
|
}
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
if (!keys.has(s)) {
|
|
5046
|
-
ret = true;
|
|
5047
|
-
removeEquiv(ts1, s);
|
|
5007
|
+
let removed = null;
|
|
5008
|
+
eq1.equivSet.forEach((key) => {
|
|
5009
|
+
if (!eq2.equivSet.has(key)) {
|
|
5010
|
+
eq1.equivSet.delete(key);
|
|
5011
|
+
if (!removed) {
|
|
5012
|
+
removed = new Set();
|
|
5013
|
+
}
|
|
5014
|
+
removed.add(key);
|
|
5048
5015
|
}
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5016
|
+
});
|
|
5017
|
+
if (eq1.equivSet.size === 1) {
|
|
5018
|
+
assert(eq1.equivSet.has(k));
|
|
5019
|
+
delete eq1.equivSet;
|
|
5020
|
+
}
|
|
5021
|
+
if (removed) {
|
|
5022
|
+
removed.forEach((k) => removed.size === 1
|
|
5023
|
+
? delete ts1.get(k).equivSet
|
|
5024
|
+
: (ts1.get(k).equivSet = removed));
|
|
5025
|
+
}
|
|
5026
|
+
return false;
|
|
5052
5027
|
}
|
|
5053
5028
|
function clearAssocPaths(blockState, decl, v) {
|
|
5054
5029
|
if (v.assocPaths?.size) {
|
|
@@ -5066,6 +5041,12 @@ function clearAssocPaths(blockState, decl, v) {
|
|
|
5066
5041
|
function cloneTypeState(blockState) {
|
|
5067
5042
|
const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
|
|
5068
5043
|
const clone = { map: new Map(map), ...rest };
|
|
5044
|
+
clone.map.forEach((value, key) => {
|
|
5045
|
+
if (value.equivSet && key === Array.from(value.equivSet)[0]) {
|
|
5046
|
+
const equivSet = new Set(value.equivSet);
|
|
5047
|
+
equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
|
|
5048
|
+
}
|
|
5049
|
+
});
|
|
5069
5050
|
if (trackedMemberDecls) {
|
|
5070
5051
|
clone.trackedMemberDecls = new Map();
|
|
5071
5052
|
trackedMemberDecls.forEach((value, key) => {
|
|
@@ -5266,17 +5247,6 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
|
|
|
5266
5247
|
});
|
|
5267
5248
|
return changes;
|
|
5268
5249
|
}
|
|
5269
|
-
function tsEquivs(state, key) {
|
|
5270
|
-
const result = [];
|
|
5271
|
-
let s = key;
|
|
5272
|
-
do {
|
|
5273
|
-
result.push(tsKey(s));
|
|
5274
|
-
const next = state.get(s);
|
|
5275
|
-
assert(next && next.equivSet);
|
|
5276
|
-
s = next.equivSet.next;
|
|
5277
|
-
} while (s !== key);
|
|
5278
|
-
return `[(${result.join(", ")})]`;
|
|
5279
|
-
}
|
|
5280
5250
|
function typeStateEntry(value, key) {
|
|
5281
5251
|
return `${tsKey(key)} = ${display(value.curType)}`;
|
|
5282
5252
|
}
|
|
@@ -5287,7 +5257,9 @@ function printBlockState(block, state, indent = "") {
|
|
|
5287
5257
|
return;
|
|
5288
5258
|
}
|
|
5289
5259
|
state.map.forEach((value, key) => {
|
|
5290
|
-
console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet
|
|
5260
|
+
console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet
|
|
5261
|
+
? " " + `[(${Array.from(value.equivSet).map(tsKey).join(", ")})]`
|
|
5262
|
+
: ""}`);
|
|
5291
5263
|
});
|
|
5292
5264
|
}
|
|
5293
5265
|
function updateAffected(blockState, objectType, baseDecl, assignedPath, affectedName, affected, assignedType) {
|
|
@@ -5565,15 +5537,11 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
5565
5537
|
*/
|
|
5566
5538
|
const v = blockState.map.get(decl);
|
|
5567
5539
|
if (v?.equivSet) {
|
|
5568
|
-
|
|
5569
|
-
do {
|
|
5540
|
+
v.equivSet.forEach((s) => {
|
|
5570
5541
|
const next = blockState.map.get(s);
|
|
5571
|
-
|
|
5572
|
-
throw new Error(`Inconsistent equivSet for ${tsKey(decl)}: missing value for ${tsKey(s)}`);
|
|
5573
|
-
}
|
|
5542
|
+
assert(next && next.equivSet?.has(s));
|
|
5574
5543
|
blockState.map.set(s, { ...next, curType: value });
|
|
5575
|
-
|
|
5576
|
-
} while (s !== decl);
|
|
5544
|
+
});
|
|
5577
5545
|
}
|
|
5578
5546
|
else {
|
|
5579
5547
|
blockState.map.set(decl, { ...v, curType: value });
|
|
@@ -5986,12 +5954,13 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
5986
5954
|
}
|
|
5987
5955
|
});
|
|
5988
5956
|
}
|
|
5957
|
+
let calleeEffects;
|
|
5989
5958
|
curState.map.forEach((tsv, decl) => {
|
|
5990
5959
|
let type = tsv.curType;
|
|
5991
|
-
if (
|
|
5992
|
-
(
|
|
5993
|
-
|
|
5994
|
-
|
|
5960
|
+
if ((type.value == null ||
|
|
5961
|
+
!(type.type &
|
|
5962
|
+
(32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */))) &&
|
|
5963
|
+
!some(decl, (d) => d.type === "VariableDeclarator" && !isLocal(d))) {
|
|
5995
5964
|
return;
|
|
5996
5965
|
}
|
|
5997
5966
|
if (modifiableDecl(decl, callees)) {
|
|
@@ -6007,9 +5976,14 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
6007
5976
|
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
6008
5977
|
curState.map.set(decl, { curType: typeConstraint(decl) });
|
|
6009
5978
|
}
|
|
6010
|
-
else if (type.
|
|
6011
|
-
(
|
|
6012
|
-
|
|
5979
|
+
else if (type.type &
|
|
5980
|
+
(32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */) &&
|
|
5981
|
+
(calleeEffects == null
|
|
5982
|
+
? (calleeEffects =
|
|
5983
|
+
!callees ||
|
|
5984
|
+
!every(callees, (callee) => callee.info === false))
|
|
5985
|
+
: calleeEffects)) {
|
|
5986
|
+
if (type.value != null && type.type & 32768 /* TypeTag.Object */) {
|
|
6013
5987
|
const odata = getObjectValue(tsv.curType);
|
|
6014
5988
|
if (odata?.obj) {
|
|
6015
5989
|
type = cloneType(type);
|
|
@@ -6020,15 +5994,10 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
6020
5994
|
tsv = { ...tsv };
|
|
6021
5995
|
delete tsv.assocPaths;
|
|
6022
5996
|
}
|
|
6023
|
-
if (tsv.copyPropItem) {
|
|
6024
|
-
copyPropFailed(curState, tsv.copyPropItem, nodeCopyProp);
|
|
6025
|
-
tsv = { ...tsv };
|
|
6026
|
-
delete tsv.copyPropItem;
|
|
6027
|
-
}
|
|
6028
|
-
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
6029
5997
|
curState.map.set(decl, { ...tsv, curType: type });
|
|
6030
5998
|
}
|
|
6031
5999
|
}
|
|
6000
|
+
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
6032
6001
|
}
|
|
6033
6002
|
});
|
|
6034
6003
|
return true;
|
|
@@ -6147,22 +6116,41 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
6147
6116
|
decl.type === "BinaryExpression" ||
|
|
6148
6117
|
decl.type === "Identifier"))) {
|
|
6149
6118
|
const key = event.decl ?? null;
|
|
6150
|
-
if (key &&
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6119
|
+
if (key && declIsLocal(key)) {
|
|
6120
|
+
if (nodeCopyProp.has(event.node)) {
|
|
6121
|
+
// we might have
|
|
6122
|
+
//
|
|
6123
|
+
// var x = foo();
|
|
6124
|
+
// var y = x + 1;
|
|
6125
|
+
// bar();
|
|
6126
|
+
// return y;
|
|
6127
|
+
//
|
|
6128
|
+
// In that case, its ok to drop "x = foo()" and rewrite as y = foo() + 1"
|
|
6129
|
+
// OR its ok to drop "y = x + 1" and rewrite as "return x + 1".
|
|
6130
|
+
// But we can't do both, and rewrite as "bar(); return foo() + 1;"
|
|
6131
|
+
// So just disable copy prop for *this* node. We'll re-run and have a
|
|
6132
|
+
// second chance later.
|
|
6133
|
+
return false;
|
|
6134
|
+
}
|
|
6135
|
+
else if (event.node.type === "AssignmentExpression" &&
|
|
6136
|
+
event.node.operator !== "=" &&
|
|
6137
|
+
nodeCopyProp.has(event.node.left)) {
|
|
6138
|
+
// If we're copy proping into the lhs of an update
|
|
6139
|
+
// assignment, we're going to have to rewrite it.
|
|
6140
|
+
// similar to the above, don't also do forward copy
|
|
6141
|
+
// prop. eg
|
|
6142
|
+
//
|
|
6143
|
+
// var x = a + b;
|
|
6144
|
+
// x += c;
|
|
6145
|
+
// return x;
|
|
6146
|
+
//
|
|
6147
|
+
// becomes
|
|
6148
|
+
//
|
|
6149
|
+
// var x;
|
|
6150
|
+
// x = (a + b) + c;
|
|
6151
|
+
// return x; // <- dont propagate to here (yet), in case a+b has changed.
|
|
6152
|
+
return false;
|
|
6153
|
+
}
|
|
6166
6154
|
}
|
|
6167
6155
|
const item = contained.get(key);
|
|
6168
6156
|
if (!item) {
|
|
@@ -6351,7 +6339,22 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
6351
6339
|
}
|
|
6352
6340
|
}
|
|
6353
6341
|
}));
|
|
6354
|
-
traverseAst(func.node.body,
|
|
6342
|
+
traverseAst(func.node.body, (node) => {
|
|
6343
|
+
if (node.type === "AssignmentExpression" &&
|
|
6344
|
+
node.operator !== "=" &&
|
|
6345
|
+
nodeCopyProp.has(node.left)) {
|
|
6346
|
+
const left = cloneDeep(node.left);
|
|
6347
|
+
const right = withLoc({
|
|
6348
|
+
type: "BinaryExpression",
|
|
6349
|
+
operator: node.operator.slice(0, -1),
|
|
6350
|
+
left: withLocDeep(node.left, node.right, false, true),
|
|
6351
|
+
right: node.right,
|
|
6352
|
+
}, node.left, node.right);
|
|
6353
|
+
node.operator = "=";
|
|
6354
|
+
node.left = left;
|
|
6355
|
+
node.right = right;
|
|
6356
|
+
}
|
|
6357
|
+
}, (node) => {
|
|
6355
6358
|
const copyNode = nodeCopyProp.get(node);
|
|
6356
6359
|
if (copyNode) {
|
|
6357
6360
|
if (node.type === "AssignmentExpression") {
|
|
@@ -6370,10 +6373,18 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
6370
6373
|
return dup;
|
|
6371
6374
|
}
|
|
6372
6375
|
if (copyNode.type === "AssignmentExpression") {
|
|
6376
|
+
const replacement = copyNode.operator === "="
|
|
6377
|
+
? copyNode.right
|
|
6378
|
+
: {
|
|
6379
|
+
type: "BinaryExpression",
|
|
6380
|
+
operator: copyNode.operator.slice(0, -1),
|
|
6381
|
+
left: copyNode.left,
|
|
6382
|
+
right: copyNode.right,
|
|
6383
|
+
};
|
|
6373
6384
|
if (logThisRun) {
|
|
6374
|
-
console.log(`copy-prop ${formatAstLongLines(node)} => ${formatAstLongLines(
|
|
6385
|
+
console.log(`copy-prop ${formatAstLongLines(node)} => ${formatAstLongLines(replacement)}`);
|
|
6375
6386
|
}
|
|
6376
|
-
return withLocDeep(
|
|
6387
|
+
return withLocDeep(replacement, node, node, false);
|
|
6377
6388
|
}
|
|
6378
6389
|
else if (copyNode.type === "VariableDeclarator") {
|
|
6379
6390
|
assert(copyNode.init);
|
|
@@ -6715,18 +6726,18 @@ function couldBeObj(a, b) {
|
|
|
6715
6726
|
|
|
6716
6727
|
|
|
6717
6728
|
function cloneAnt(antMap) {
|
|
6718
|
-
|
|
6719
|
-
antMap.forEach((s, k) => ant.set(k, new Set(s)));
|
|
6720
|
-
return ant;
|
|
6729
|
+
return new Map(antMap);
|
|
6721
6730
|
}
|
|
6722
6731
|
function addAnt(antMap, decl, node) {
|
|
6723
6732
|
assert(node.type === "Identifier");
|
|
6724
6733
|
const ant = antMap.get(decl);
|
|
6725
|
-
if (
|
|
6726
|
-
|
|
6734
|
+
if (ant === false || ant === node)
|
|
6735
|
+
return;
|
|
6736
|
+
if (ant === undefined) {
|
|
6737
|
+
antMap.set(decl, node);
|
|
6727
6738
|
}
|
|
6728
6739
|
else {
|
|
6729
|
-
|
|
6740
|
+
antMap.set(decl, false);
|
|
6730
6741
|
}
|
|
6731
6742
|
}
|
|
6732
6743
|
function cloneState(blockState) {
|
|
@@ -6762,18 +6773,10 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
6762
6773
|
else {
|
|
6763
6774
|
changed = Array.from(to.anticipated).reduce((changed, [decl, toant]) => {
|
|
6764
6775
|
const fromant = from.anticipated.get(decl);
|
|
6765
|
-
if (
|
|
6776
|
+
if (toant !== fromant) {
|
|
6766
6777
|
to.anticipated.delete(decl);
|
|
6767
6778
|
changed = true;
|
|
6768
6779
|
}
|
|
6769
|
-
else {
|
|
6770
|
-
toant.forEach((node) => {
|
|
6771
|
-
if (!fromant.has(node)) {
|
|
6772
|
-
toant.delete(node);
|
|
6773
|
-
changed = true;
|
|
6774
|
-
}
|
|
6775
|
-
});
|
|
6776
|
-
}
|
|
6777
6780
|
return changed;
|
|
6778
6781
|
}, changed);
|
|
6779
6782
|
}
|
|
@@ -6786,17 +6789,15 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
6786
6789
|
else {
|
|
6787
6790
|
changed = Array.from(from.partiallyAnticipated).reduce((changed, [decl, fromant]) => {
|
|
6788
6791
|
const toant = to.partiallyAnticipated.get(decl);
|
|
6789
|
-
if (
|
|
6792
|
+
if (toant === undefined) {
|
|
6790
6793
|
to.partiallyAnticipated.set(decl, fromant);
|
|
6791
6794
|
changed = true;
|
|
6792
6795
|
}
|
|
6793
6796
|
else {
|
|
6794
|
-
fromant
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
}
|
|
6799
|
-
});
|
|
6797
|
+
if (toant !== fromant) {
|
|
6798
|
+
changed = true;
|
|
6799
|
+
to.partiallyAnticipated.set(decl, false);
|
|
6800
|
+
}
|
|
6800
6801
|
}
|
|
6801
6802
|
return changed;
|
|
6802
6803
|
}, changed);
|
|
@@ -6860,7 +6861,7 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
6860
6861
|
}
|
|
6861
6862
|
addAnt(curState.partiallyAnticipated, event.decl, event.node);
|
|
6862
6863
|
if (logThisRun) {
|
|
6863
|
-
console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl)
|
|
6864
|
+
console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl) !== false} ${curState.anticipated.get(event.decl) !== false}`);
|
|
6864
6865
|
}
|
|
6865
6866
|
}
|
|
6866
6867
|
curState.dead.delete(event.decl);
|
|
@@ -6881,25 +6882,21 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
6881
6882
|
}
|
|
6882
6883
|
else {
|
|
6883
6884
|
deadStores.delete(event.node);
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
curState.partiallyAnticipated) {
|
|
6885
|
+
copyPropStores.delete(event.node);
|
|
6886
|
+
if (declIsLocal(event.decl) && curState.partiallyAnticipated) {
|
|
6887
6887
|
const pant = curState.partiallyAnticipated.get(event.decl);
|
|
6888
|
-
if (pant
|
|
6888
|
+
if (pant) {
|
|
6889
6889
|
if (logThisRun) {
|
|
6890
|
-
console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl)
|
|
6890
|
+
console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl) === pant}`);
|
|
6891
6891
|
}
|
|
6892
6892
|
copyPropStores.set(event.node, {
|
|
6893
|
-
ref:
|
|
6894
|
-
ant: curState.anticipated?.get(event.decl)
|
|
6893
|
+
ref: pant,
|
|
6894
|
+
ant: curState.anticipated?.get(event.decl) === pant,
|
|
6895
6895
|
});
|
|
6896
6896
|
}
|
|
6897
6897
|
curState.partiallyAnticipated.delete(event.decl);
|
|
6898
6898
|
curState.anticipated?.delete(event.decl);
|
|
6899
6899
|
}
|
|
6900
|
-
else {
|
|
6901
|
-
copyPropStores.delete(event.node);
|
|
6902
|
-
}
|
|
6903
6900
|
}
|
|
6904
6901
|
if (nodeConflicts) {
|
|
6905
6902
|
const conflicts = new Set(locals);
|
package/build/optimizer.cjs
CHANGED
|
@@ -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;
|
|
@@ -11183,18 +11184,18 @@ const external_node_assert_namespaceObject = require("node:assert");
|
|
|
11183
11184
|
|
|
11184
11185
|
|
|
11185
11186
|
function cloneAnt(antMap) {
|
|
11186
|
-
|
|
11187
|
-
antMap.forEach((s, k) => ant.set(k, new Set(s)));
|
|
11188
|
-
return ant;
|
|
11187
|
+
return new Map(antMap);
|
|
11189
11188
|
}
|
|
11190
11189
|
function addAnt(antMap, decl, node) {
|
|
11191
11190
|
external_node_assert_namespaceObject(node.type === "Identifier");
|
|
11192
11191
|
const ant = antMap.get(decl);
|
|
11193
|
-
if (
|
|
11194
|
-
|
|
11192
|
+
if (ant === false || ant === node)
|
|
11193
|
+
return;
|
|
11194
|
+
if (ant === undefined) {
|
|
11195
|
+
antMap.set(decl, node);
|
|
11195
11196
|
}
|
|
11196
11197
|
else {
|
|
11197
|
-
|
|
11198
|
+
antMap.set(decl, false);
|
|
11198
11199
|
}
|
|
11199
11200
|
}
|
|
11200
11201
|
function cloneState(blockState) {
|
|
@@ -11230,18 +11231,10 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
11230
11231
|
else {
|
|
11231
11232
|
changed = Array.from(to.anticipated).reduce((changed, [decl, toant]) => {
|
|
11232
11233
|
const fromant = from.anticipated.get(decl);
|
|
11233
|
-
if (
|
|
11234
|
+
if (toant !== fromant) {
|
|
11234
11235
|
to.anticipated.delete(decl);
|
|
11235
11236
|
changed = true;
|
|
11236
11237
|
}
|
|
11237
|
-
else {
|
|
11238
|
-
toant.forEach((node) => {
|
|
11239
|
-
if (!fromant.has(node)) {
|
|
11240
|
-
toant.delete(node);
|
|
11241
|
-
changed = true;
|
|
11242
|
-
}
|
|
11243
|
-
});
|
|
11244
|
-
}
|
|
11245
11238
|
return changed;
|
|
11246
11239
|
}, changed);
|
|
11247
11240
|
}
|
|
@@ -11254,17 +11247,15 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
11254
11247
|
else {
|
|
11255
11248
|
changed = Array.from(from.partiallyAnticipated).reduce((changed, [decl, fromant]) => {
|
|
11256
11249
|
const toant = to.partiallyAnticipated.get(decl);
|
|
11257
|
-
if (
|
|
11250
|
+
if (toant === undefined) {
|
|
11258
11251
|
to.partiallyAnticipated.set(decl, fromant);
|
|
11259
11252
|
changed = true;
|
|
11260
11253
|
}
|
|
11261
11254
|
else {
|
|
11262
|
-
fromant
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
}
|
|
11267
|
-
});
|
|
11255
|
+
if (toant !== fromant) {
|
|
11256
|
+
changed = true;
|
|
11257
|
+
to.partiallyAnticipated.set(decl, false);
|
|
11258
|
+
}
|
|
11268
11259
|
}
|
|
11269
11260
|
return changed;
|
|
11270
11261
|
}, changed);
|
|
@@ -11328,7 +11319,7 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
11328
11319
|
}
|
|
11329
11320
|
addAnt(curState.partiallyAnticipated, event.decl, event.node);
|
|
11330
11321
|
if (logThisRun) {
|
|
11331
|
-
console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl)
|
|
11322
|
+
console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl) !== false} ${curState.anticipated.get(event.decl) !== false}`);
|
|
11332
11323
|
}
|
|
11333
11324
|
}
|
|
11334
11325
|
curState.dead.delete(event.decl);
|
|
@@ -11349,25 +11340,21 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
|
|
|
11349
11340
|
}
|
|
11350
11341
|
else {
|
|
11351
11342
|
deadStores.delete(event.node);
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
curState.partiallyAnticipated) {
|
|
11343
|
+
copyPropStores.delete(event.node);
|
|
11344
|
+
if (declIsLocal(event.decl) && curState.partiallyAnticipated) {
|
|
11355
11345
|
const pant = curState.partiallyAnticipated.get(event.decl);
|
|
11356
|
-
if (pant
|
|
11346
|
+
if (pant) {
|
|
11357
11347
|
if (logThisRun) {
|
|
11358
|
-
console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl)
|
|
11348
|
+
console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl) === pant}`);
|
|
11359
11349
|
}
|
|
11360
11350
|
copyPropStores.set(event.node, {
|
|
11361
|
-
ref:
|
|
11362
|
-
ant: curState.anticipated?.get(event.decl)
|
|
11351
|
+
ref: pant,
|
|
11352
|
+
ant: curState.anticipated?.get(event.decl) === pant,
|
|
11363
11353
|
});
|
|
11364
11354
|
}
|
|
11365
11355
|
curState.partiallyAnticipated.delete(event.decl);
|
|
11366
11356
|
curState.anticipated?.delete(event.decl);
|
|
11367
11357
|
}
|
|
11368
|
-
else {
|
|
11369
|
-
copyPropStores.delete(event.node);
|
|
11370
|
-
}
|
|
11371
11358
|
}
|
|
11372
11359
|
if (nodeConflicts) {
|
|
11373
11360
|
const conflicts = new Set(locals);
|
|
@@ -11596,74 +11583,43 @@ function addEquiv(ts, key, equiv) {
|
|
|
11596
11583
|
if (!keyVal || !equivVal)
|
|
11597
11584
|
return false;
|
|
11598
11585
|
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);
|
|
11586
|
+
if (equivVal.equivSet.has(key)) {
|
|
11587
|
+
return true;
|
|
11614
11588
|
}
|
|
11615
11589
|
// equiv is already a member of a set. remove it
|
|
11616
11590
|
removeEquiv(ts, equiv);
|
|
11617
11591
|
}
|
|
11618
11592
|
// equiv is not (or no longer) part of an equivSet
|
|
11619
|
-
keyVal = { ...keyVal };
|
|
11620
11593
|
if (!keyVal.equivSet) {
|
|
11621
|
-
keyVal
|
|
11594
|
+
keyVal = { ...keyVal };
|
|
11595
|
+
keyVal.equivSet = new Set([key, equiv]);
|
|
11596
|
+
ts.set(key, keyVal);
|
|
11597
|
+
}
|
|
11598
|
+
else {
|
|
11599
|
+
keyVal.equivSet.add(equiv);
|
|
11622
11600
|
}
|
|
11623
11601
|
equivVal = { ...equivVal, equivSet: keyVal.equivSet };
|
|
11624
|
-
keyVal.equivSet = { next: equiv };
|
|
11625
|
-
ts.set(key, keyVal);
|
|
11626
11602
|
ts.set(equiv, equivVal);
|
|
11627
11603
|
return false;
|
|
11628
11604
|
}
|
|
11629
11605
|
function removeEquiv(ts, equiv) {
|
|
11630
|
-
|
|
11606
|
+
let equivVal = ts.get(equiv);
|
|
11631
11607
|
if (!equivVal?.equivSet)
|
|
11632
11608
|
return;
|
|
11633
|
-
|
|
11634
|
-
|
|
11635
|
-
const
|
|
11636
|
-
|
|
11637
|
-
|
|
11638
|
-
|
|
11639
|
-
|
|
11640
|
-
|
|
11641
|
-
|
|
11642
|
-
|
|
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);
|
|
11609
|
+
equivVal.equivSet.delete(equiv);
|
|
11610
|
+
if (equivVal.equivSet.size === 1) {
|
|
11611
|
+
const other = Array.from(equivVal.equivSet)[0];
|
|
11612
|
+
const otherVal = { ...ts.get(other) };
|
|
11613
|
+
delete otherVal.equivSet;
|
|
11614
|
+
ts.set(other, otherVal);
|
|
11615
|
+
}
|
|
11616
|
+
equivVal = { ...equivVal };
|
|
11617
|
+
delete equivVal.equivSet;
|
|
11618
|
+
ts.set(equiv, equivVal);
|
|
11655
11619
|
}
|
|
11656
11620
|
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);
|
|
11621
|
+
const keys = ts.get(k)?.equivSet;
|
|
11622
|
+
external_node_assert_namespaceObject(keys);
|
|
11667
11623
|
return keys;
|
|
11668
11624
|
}
|
|
11669
11625
|
function intersectEquiv(ts1, ts2, k) {
|
|
@@ -11675,21 +11631,26 @@ function intersectEquiv(ts1, ts2, k) {
|
|
|
11675
11631
|
removeEquiv(ts1, k);
|
|
11676
11632
|
return true;
|
|
11677
11633
|
}
|
|
11678
|
-
|
|
11679
|
-
|
|
11680
|
-
|
|
11681
|
-
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
11686
|
-
if (!keys.has(s)) {
|
|
11687
|
-
ret = true;
|
|
11688
|
-
removeEquiv(ts1, s);
|
|
11634
|
+
let removed = null;
|
|
11635
|
+
eq1.equivSet.forEach((key) => {
|
|
11636
|
+
if (!eq2.equivSet.has(key)) {
|
|
11637
|
+
eq1.equivSet.delete(key);
|
|
11638
|
+
if (!removed) {
|
|
11639
|
+
removed = new Set();
|
|
11640
|
+
}
|
|
11641
|
+
removed.add(key);
|
|
11689
11642
|
}
|
|
11690
|
-
|
|
11691
|
-
|
|
11692
|
-
|
|
11643
|
+
});
|
|
11644
|
+
if (eq1.equivSet.size === 1) {
|
|
11645
|
+
external_node_assert_namespaceObject(eq1.equivSet.has(k));
|
|
11646
|
+
delete eq1.equivSet;
|
|
11647
|
+
}
|
|
11648
|
+
if (removed) {
|
|
11649
|
+
removed.forEach((k) => removed.size === 1
|
|
11650
|
+
? delete ts1.get(k).equivSet
|
|
11651
|
+
: (ts1.get(k).equivSet = removed));
|
|
11652
|
+
}
|
|
11653
|
+
return false;
|
|
11693
11654
|
}
|
|
11694
11655
|
function clearAssocPaths(blockState, decl, v) {
|
|
11695
11656
|
if (v.assocPaths?.size) {
|
|
@@ -11707,6 +11668,12 @@ function clearAssocPaths(blockState, decl, v) {
|
|
|
11707
11668
|
function cloneTypeState(blockState) {
|
|
11708
11669
|
const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
|
|
11709
11670
|
const clone = { map: new Map(map), ...rest };
|
|
11671
|
+
clone.map.forEach((value, key) => {
|
|
11672
|
+
if (value.equivSet && key === Array.from(value.equivSet)[0]) {
|
|
11673
|
+
const equivSet = new Set(value.equivSet);
|
|
11674
|
+
equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
|
|
11675
|
+
}
|
|
11676
|
+
});
|
|
11710
11677
|
if (trackedMemberDecls) {
|
|
11711
11678
|
clone.trackedMemberDecls = new Map();
|
|
11712
11679
|
trackedMemberDecls.forEach((value, key) => {
|
|
@@ -11907,17 +11874,6 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
|
|
|
11907
11874
|
});
|
|
11908
11875
|
return changes;
|
|
11909
11876
|
}
|
|
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
11877
|
function typeStateEntry(value, key) {
|
|
11922
11878
|
return `${tsKey(key)} = ${display(value.curType)}`;
|
|
11923
11879
|
}
|
|
@@ -11928,7 +11884,9 @@ function printBlockState(block, state, indent = "") {
|
|
|
11928
11884
|
return;
|
|
11929
11885
|
}
|
|
11930
11886
|
state.map.forEach((value, key) => {
|
|
11931
|
-
console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet
|
|
11887
|
+
console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet
|
|
11888
|
+
? " " + `[(${Array.from(value.equivSet).map(tsKey).join(", ")})]`
|
|
11889
|
+
: ""}`);
|
|
11932
11890
|
});
|
|
11933
11891
|
}
|
|
11934
11892
|
function updateAffected(blockState, objectType, baseDecl, assignedPath, affectedName, affected, assignedType) {
|
|
@@ -12206,15 +12164,11 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12206
12164
|
*/
|
|
12207
12165
|
const v = blockState.map.get(decl);
|
|
12208
12166
|
if (v?.equivSet) {
|
|
12209
|
-
|
|
12210
|
-
do {
|
|
12167
|
+
v.equivSet.forEach((s) => {
|
|
12211
12168
|
const next = blockState.map.get(s);
|
|
12212
|
-
|
|
12213
|
-
throw new Error(`Inconsistent equivSet for ${tsKey(decl)}: missing value for ${tsKey(s)}`);
|
|
12214
|
-
}
|
|
12169
|
+
external_node_assert_namespaceObject(next && next.equivSet?.has(s));
|
|
12215
12170
|
blockState.map.set(s, { ...next, curType: value });
|
|
12216
|
-
|
|
12217
|
-
} while (s !== decl);
|
|
12171
|
+
});
|
|
12218
12172
|
}
|
|
12219
12173
|
else {
|
|
12220
12174
|
blockState.map.set(decl, { ...v, curType: value });
|
|
@@ -12627,12 +12581,13 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12627
12581
|
}
|
|
12628
12582
|
});
|
|
12629
12583
|
}
|
|
12584
|
+
let calleeEffects;
|
|
12630
12585
|
curState.map.forEach((tsv, decl) => {
|
|
12631
12586
|
let type = tsv.curType;
|
|
12632
|
-
if (
|
|
12633
|
-
(
|
|
12634
|
-
|
|
12635
|
-
|
|
12587
|
+
if ((type.value == null ||
|
|
12588
|
+
!(type.type &
|
|
12589
|
+
(32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */))) &&
|
|
12590
|
+
!(0,external_util_cjs_namespaceObject.some)(decl, (d) => d.type === "VariableDeclarator" && !(0,external_api_cjs_namespaceObject.isLocal)(d))) {
|
|
12636
12591
|
return;
|
|
12637
12592
|
}
|
|
12638
12593
|
if (modifiableDecl(decl, callees)) {
|
|
@@ -12648,9 +12603,14 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12648
12603
|
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
12649
12604
|
curState.map.set(decl, { curType: typeConstraint(decl) });
|
|
12650
12605
|
}
|
|
12651
|
-
else if (type.
|
|
12652
|
-
(
|
|
12653
|
-
|
|
12606
|
+
else if (type.type &
|
|
12607
|
+
(32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */) &&
|
|
12608
|
+
(calleeEffects == null
|
|
12609
|
+
? (calleeEffects =
|
|
12610
|
+
!callees ||
|
|
12611
|
+
!(0,external_util_cjs_namespaceObject.every)(callees, (callee) => callee.info === false))
|
|
12612
|
+
: calleeEffects)) {
|
|
12613
|
+
if (type.value != null && type.type & 32768 /* TypeTag.Object */) {
|
|
12654
12614
|
const odata = getObjectValue(tsv.curType);
|
|
12655
12615
|
if (odata?.obj) {
|
|
12656
12616
|
type = cloneType(type);
|
|
@@ -12661,15 +12621,10 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12661
12621
|
tsv = { ...tsv };
|
|
12662
12622
|
delete tsv.assocPaths;
|
|
12663
12623
|
}
|
|
12664
|
-
if (tsv.copyPropItem) {
|
|
12665
|
-
copyPropFailed(curState, tsv.copyPropItem, nodeCopyProp);
|
|
12666
|
-
tsv = { ...tsv };
|
|
12667
|
-
delete tsv.copyPropItem;
|
|
12668
|
-
}
|
|
12669
|
-
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
12670
12624
|
curState.map.set(decl, { ...tsv, curType: type });
|
|
12671
12625
|
}
|
|
12672
12626
|
}
|
|
12627
|
+
clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
|
|
12673
12628
|
}
|
|
12674
12629
|
});
|
|
12675
12630
|
return true;
|
|
@@ -12788,22 +12743,41 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12788
12743
|
decl.type === "BinaryExpression" ||
|
|
12789
12744
|
decl.type === "Identifier"))) {
|
|
12790
12745
|
const key = event.decl ?? null;
|
|
12791
|
-
if (key &&
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
12804
|
-
|
|
12805
|
-
|
|
12806
|
-
|
|
12746
|
+
if (key && declIsLocal(key)) {
|
|
12747
|
+
if (nodeCopyProp.has(event.node)) {
|
|
12748
|
+
// we might have
|
|
12749
|
+
//
|
|
12750
|
+
// var x = foo();
|
|
12751
|
+
// var y = x + 1;
|
|
12752
|
+
// bar();
|
|
12753
|
+
// return y;
|
|
12754
|
+
//
|
|
12755
|
+
// In that case, its ok to drop "x = foo()" and rewrite as y = foo() + 1"
|
|
12756
|
+
// OR its ok to drop "y = x + 1" and rewrite as "return x + 1".
|
|
12757
|
+
// But we can't do both, and rewrite as "bar(); return foo() + 1;"
|
|
12758
|
+
// So just disable copy prop for *this* node. We'll re-run and have a
|
|
12759
|
+
// second chance later.
|
|
12760
|
+
return false;
|
|
12761
|
+
}
|
|
12762
|
+
else if (event.node.type === "AssignmentExpression" &&
|
|
12763
|
+
event.node.operator !== "=" &&
|
|
12764
|
+
nodeCopyProp.has(event.node.left)) {
|
|
12765
|
+
// If we're copy proping into the lhs of an update
|
|
12766
|
+
// assignment, we're going to have to rewrite it.
|
|
12767
|
+
// similar to the above, don't also do forward copy
|
|
12768
|
+
// prop. eg
|
|
12769
|
+
//
|
|
12770
|
+
// var x = a + b;
|
|
12771
|
+
// x += c;
|
|
12772
|
+
// return x;
|
|
12773
|
+
//
|
|
12774
|
+
// becomes
|
|
12775
|
+
//
|
|
12776
|
+
// var x;
|
|
12777
|
+
// x = (a + b) + c;
|
|
12778
|
+
// return x; // <- dont propagate to here (yet), in case a+b has changed.
|
|
12779
|
+
return false;
|
|
12780
|
+
}
|
|
12807
12781
|
}
|
|
12808
12782
|
const item = contained.get(key);
|
|
12809
12783
|
if (!item) {
|
|
@@ -12992,7 +12966,22 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
12992
12966
|
}
|
|
12993
12967
|
}
|
|
12994
12968
|
}));
|
|
12995
|
-
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body,
|
|
12969
|
+
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
|
|
12970
|
+
if (node.type === "AssignmentExpression" &&
|
|
12971
|
+
node.operator !== "=" &&
|
|
12972
|
+
nodeCopyProp.has(node.left)) {
|
|
12973
|
+
const left = cloneDeep(node.left);
|
|
12974
|
+
const right = withLoc({
|
|
12975
|
+
type: "BinaryExpression",
|
|
12976
|
+
operator: node.operator.slice(0, -1),
|
|
12977
|
+
left: withLocDeep(node.left, node.right, false, true),
|
|
12978
|
+
right: node.right,
|
|
12979
|
+
}, node.left, node.right);
|
|
12980
|
+
node.operator = "=";
|
|
12981
|
+
node.left = left;
|
|
12982
|
+
node.right = right;
|
|
12983
|
+
}
|
|
12984
|
+
}, (node) => {
|
|
12996
12985
|
const copyNode = nodeCopyProp.get(node);
|
|
12997
12986
|
if (copyNode) {
|
|
12998
12987
|
if (node.type === "AssignmentExpression") {
|
|
@@ -13011,10 +13000,18 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
|
|
|
13011
13000
|
return dup;
|
|
13012
13001
|
}
|
|
13013
13002
|
if (copyNode.type === "AssignmentExpression") {
|
|
13003
|
+
const replacement = copyNode.operator === "="
|
|
13004
|
+
? copyNode.right
|
|
13005
|
+
: {
|
|
13006
|
+
type: "BinaryExpression",
|
|
13007
|
+
operator: copyNode.operator.slice(0, -1),
|
|
13008
|
+
left: copyNode.left,
|
|
13009
|
+
right: copyNode.right,
|
|
13010
|
+
};
|
|
13014
13011
|
if (logThisRun) {
|
|
13015
|
-
console.log(`copy-prop ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(node)} => ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(
|
|
13012
|
+
console.log(`copy-prop ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(node)} => ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(replacement)}`);
|
|
13016
13013
|
}
|
|
13017
|
-
return withLocDeep(
|
|
13014
|
+
return withLocDeep(replacement, node, node, false);
|
|
13018
13015
|
}
|
|
13019
13016
|
else if (copyNode.type === "VariableDeclarator") {
|
|
13020
13017
|
external_node_assert_namespaceObject(copyNode.init);
|
|
@@ -16640,7 +16637,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
|
|
|
16640
16637
|
// the oldest optimized file, we don't need to regenerate
|
|
16641
16638
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
16642
16639
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
16643
|
-
if (source_time < opt_time &&
|
|
16640
|
+
if (source_time < opt_time && 1676156189652 < opt_time) {
|
|
16644
16641
|
return { hasTests, diagnostics: prevDiagnostics };
|
|
16645
16642
|
}
|
|
16646
16643
|
}
|
|
@@ -16667,7 +16664,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
|
|
|
16667
16664
|
return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
|
|
16668
16665
|
hasTests,
|
|
16669
16666
|
diagnostics,
|
|
16670
|
-
optimizerVersion: "1.1.
|
|
16667
|
+
optimizerVersion: "1.1.12",
|
|
16671
16668
|
...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
|
|
16672
16669
|
}))
|
|
16673
16670
|
.then(() => ({ hasTests, diagnostics }));
|
package/build/src/api.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare function findNamesInScope(declStack: StateNode[][], pattern: stri
|
|
|
26
26
|
parent: StateNode;
|
|
27
27
|
depth: number;
|
|
28
28
|
}][];
|
|
29
|
-
export declare function mapVarDeclsByType(state: ProgramStateAnalysis, decls: StateNodeDecl[], node: mctree.Node, typeMap: TypeMap | null | undefined): (ModuleStateNode | FunctionStateNode | ClassStateNode | TypedefStateNode | ProgramStateNode |
|
|
29
|
+
export declare function mapVarDeclsByType(state: ProgramStateAnalysis, decls: StateNodeDecl[], node: mctree.Node, typeMap: TypeMap | null | undefined): (ModuleStateNode | FunctionStateNode | ClassStateNode | TypedefStateNode | ProgramStateNode | mctree.Identifier | mctree.EnumStringMember | mctree.AsIdentifier | import("./optimizer-types").BlockStateNode | VariableStateNode | EnumStateNode)[];
|
|
30
30
|
export declare function formatAstLongLines(node: mctree.Node): string;
|
|
31
31
|
export declare function createDocumentationMap(functionDocumentation: {
|
|
32
32
|
name: string;
|
|
@@ -17,7 +17,7 @@ export declare function printBlockHeader(block: TypeFlowBlock): void;
|
|
|
17
17
|
export declare function describeEvent(event: Event): string;
|
|
18
18
|
export declare function printBlockEvents(block: TypeFlowBlock, extra?: (event: Event) => string): void;
|
|
19
19
|
export declare function printBlockTrailer(block: TypeFlowBlock): void;
|
|
20
|
-
export declare function findObjectDeclsByProperty(state: ProgramStateAnalysis, object: ExactOrUnion, next: mctree.DottedMemberExpression):
|
|
20
|
+
export declare function findObjectDeclsByProperty(state: ProgramStateAnalysis, object: ExactOrUnion, next: mctree.DottedMemberExpression): [StateNode[], StateNode[]] | readonly [null, null];
|
|
21
21
|
export declare function refineObjectTypeByDecls(istate: InterpState, object: ExactOrUnion, trueDecls: StateNode[]): ExactOrUnion;
|
|
22
22
|
export declare function findNextObjectType(istate: InterpState, trueDecls: StateNode[], next: mctree.DottedMemberExpression): import("./types").UnionType | import("./types").NumberType | import("./types").LongType | import("./types").FloatType | import("./types").DoubleType | import("./types").CharType | import("./types").StringType | import("./types").ArrayType | import("./types").DictionaryType | import("./types").MethodType | import("./types").ModuleType | import("./types").FunctionType | import("./types").ClassType | import("./types").ObjectType | import("./types").EnumType | import("./types").SymbolType | import("./types").TypedefType | null;
|
|
23
23
|
export declare function resolveDottedMember(istate: InterpState, object: ExactOrUnion, next: mctree.DottedMemberExpression): {
|
|
@@ -26,7 +26,7 @@ export declare const enum TypeTag {
|
|
|
26
26
|
Typedef = 262144,
|
|
27
27
|
Any = 524287
|
|
28
28
|
}
|
|
29
|
-
export declare function typeTagName(tag: TypeTag): "
|
|
29
|
+
export declare function typeTagName(tag: TypeTag): "Number" | "Float" | "Double" | "Long" | "String" | "Char" | "Boolean" | "Null" | "Object" | "Symbol" | "Never" | "False" | "True" | "Decimal" | "Numeric" | "Array" | "Dictionary" | "Method" | "Module" | "Function" | "Class" | "Enum" | "Typedef" | "Any";
|
|
30
30
|
export declare const LastTypeTag = TypeTag.Typedef;
|
|
31
31
|
export declare const SingletonTypeTagsConst: number;
|
|
32
32
|
export declare const UnionDataTypeTagsConst: number;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markw65/monkeyc-optimizer",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.12",
|
|
5
5
|
"description": "Source to source optimizer for Garmin Monkey C code",
|
|
6
6
|
"main": "build/optimizer.cjs",
|
|
7
7
|
"types": "build/src/optimizer.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"author": "markw65",
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@markw65/prettier-plugin-monkeyc": "^1.0.
|
|
43
|
+
"@markw65/prettier-plugin-monkeyc": "^1.0.45"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/chai": "^4.3.4",
|