@markw65/monkeyc-optimizer 1.0.25 → 1.0.28
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 +18 -0
- package/build/api.cjs +69 -39
- package/build/optimizer.cjs +63 -39
- package/build/src/pre.d.ts +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -285,3 +285,21 @@ More fixes found via open source projects.
|
|
|
285
285
|
|
|
286
286
|
- Bug fix
|
|
287
287
|
- estree-types was missing the returnType on FunctionDeclaration. Update to latest prettier-plugin, and fix ast.ts.
|
|
288
|
+
|
|
289
|
+
### 1.0.26
|
|
290
|
+
|
|
291
|
+
- Bug fixes
|
|
292
|
+
- Use `self.` rather than `ClassName.` to qualify names that would otherwise collide with locals, since that works with both public and private variables
|
|
293
|
+
- Fix a bug that caused the inliner to fail to qualify certain names, even if there was a collision with an existing local variables
|
|
294
|
+
- Fix some name lookup issues relating to whether the lookup is done as a type or a value.
|
|
295
|
+
|
|
296
|
+
### 1.0.27
|
|
297
|
+
|
|
298
|
+
- Bug fixes
|
|
299
|
+
- Update to `@markw65/prettier-plugin-monkeyc@1.0.29` to fix certain obscure comment related bugs
|
|
300
|
+
- When replacing a node (espcially when inlining), delete any comments contained in the old node.
|
|
301
|
+
|
|
302
|
+
### 1.0.28
|
|
303
|
+
|
|
304
|
+
- Bug fixes
|
|
305
|
+
- In some circumstances, while inlining, a parameter could be substituted, and then reprocessed. During reprocessing, it would attempt to lookup the replacement symbol, and if that was a local from the calling function it would fail (since an inline function never has access to the caller's locals). Prevent the reprocessing step from happening.
|
package/build/api.cjs
CHANGED
|
@@ -441,11 +441,29 @@ function inliner_shouldInline(state, func, call, context) {
|
|
|
441
441
|
}
|
|
442
442
|
return false;
|
|
443
443
|
}
|
|
444
|
-
|
|
444
|
+
// We still need to keep track of every local name that was
|
|
445
|
+
// already in use before we started inlining, but we don't want to
|
|
446
|
+
// use any of its renames. We also want to know whether a local is
|
|
447
|
+
// from the function being inlined, or the calling function, so
|
|
448
|
+
// set every element to false.
|
|
449
|
+
function fixupLocalsMap(state) {
|
|
450
|
+
if (!state.localsStack)
|
|
451
|
+
throw new Error("No local variable map!");
|
|
452
|
+
const locals = state.localsStack[state.localsStack.length - 1];
|
|
453
|
+
const { map } = locals;
|
|
454
|
+
if (!map)
|
|
455
|
+
throw new Error("No local variable map!");
|
|
456
|
+
const original = { ...map };
|
|
457
|
+
Object.keys(map).forEach((key) => (map[key] = false));
|
|
458
|
+
return original;
|
|
459
|
+
}
|
|
460
|
+
function processInlineBody(state, func, call, root, params) {
|
|
445
461
|
let failed = false;
|
|
446
462
|
const pre = state.pre;
|
|
447
463
|
const post = state.post;
|
|
448
464
|
state.inlining = true;
|
|
465
|
+
let insertedVariableDecls = null;
|
|
466
|
+
const replacements = new Set();
|
|
449
467
|
try {
|
|
450
468
|
state.pre = (node) => {
|
|
451
469
|
if (failed)
|
|
@@ -453,19 +471,14 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
453
471
|
node.start = call.start;
|
|
454
472
|
node.end = call.end;
|
|
455
473
|
node.loc = call.loc;
|
|
456
|
-
if (node
|
|
474
|
+
if (replacements.has(node))
|
|
457
475
|
return false;
|
|
458
476
|
const result = pre(node, state);
|
|
459
477
|
if (!insertedVariableDecls && node.type === "BlockStatement") {
|
|
478
|
+
// the block just created a new locals map, so we don't
|
|
479
|
+
// need to restore it at the end.
|
|
480
|
+
fixupLocalsMap(state);
|
|
460
481
|
const locals = state.localsStack[state.localsStack.length - 1];
|
|
461
|
-
const { map } = locals;
|
|
462
|
-
if (!map)
|
|
463
|
-
throw new Error("No local variable map!");
|
|
464
|
-
// We still need to keep track of every local name that was
|
|
465
|
-
// already in use, but we don't want to use any of its renames.
|
|
466
|
-
// We also want to know whether a local is from the function being
|
|
467
|
-
// inlined, or the calling function, so set every element to false.
|
|
468
|
-
Object.keys(map).forEach((key) => (map[key] = false));
|
|
469
482
|
const declarations = func.node.params
|
|
470
483
|
.map((param, i) => {
|
|
471
484
|
const paramName = variableDeclarationName(param);
|
|
@@ -486,6 +499,7 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
486
499
|
kind: "var",
|
|
487
500
|
};
|
|
488
501
|
node.body.unshift(insertedVariableDecls);
|
|
502
|
+
replacements.add(insertedVariableDecls);
|
|
489
503
|
}
|
|
490
504
|
return result;
|
|
491
505
|
};
|
|
@@ -501,6 +515,8 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
501
515
|
const ix = params[node.name];
|
|
502
516
|
if (ix >= 0) {
|
|
503
517
|
replacement = call.arguments[ix];
|
|
518
|
+
replacements.add(replacement);
|
|
519
|
+
return replacement;
|
|
504
520
|
}
|
|
505
521
|
break;
|
|
506
522
|
}
|
|
@@ -542,6 +558,8 @@ function inliner_unused(expression, top) {
|
|
|
542
558
|
return [];
|
|
543
559
|
case "Identifier":
|
|
544
560
|
return [];
|
|
561
|
+
case "ThisExpression":
|
|
562
|
+
return [];
|
|
545
563
|
case "BinaryExpression":
|
|
546
564
|
if (expression.operator === "as") {
|
|
547
565
|
return inliner_unused(expression.left);
|
|
@@ -644,7 +662,7 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
644
662
|
const name = variableDeclarationName(param);
|
|
645
663
|
return [name, argnum];
|
|
646
664
|
}));
|
|
647
|
-
if (!processInlineBody(state, func, call, body,
|
|
665
|
+
if (!processInlineBody(state, func, call, body, params)) {
|
|
648
666
|
return null;
|
|
649
667
|
}
|
|
650
668
|
inliner_diagnostic(state, call.loc, null);
|
|
@@ -676,7 +694,10 @@ function inliner_inlineFunction(state, func, call, context) {
|
|
|
676
694
|
}
|
|
677
695
|
const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
|
|
678
696
|
const params = Object.fromEntries(func.node.params.map((param, i) => [variableDeclarationName(param), i]));
|
|
679
|
-
|
|
697
|
+
const map = fixupLocalsMap(state);
|
|
698
|
+
const ret = processInlineBody(state, func, call, retArg, params);
|
|
699
|
+
state.localsStack[state.localsStack.length - 1].map = map;
|
|
700
|
+
return ret;
|
|
680
701
|
}
|
|
681
702
|
function applyTypeIfNeeded(node) {
|
|
682
703
|
if ("enumType" in node && node.enumType) {
|
|
@@ -729,6 +750,15 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
729
750
|
return "";
|
|
730
751
|
}))
|
|
731
752
|
.flat();
|
|
753
|
+
const member = (object, property) => ({
|
|
754
|
+
type: "MemberExpression",
|
|
755
|
+
object,
|
|
756
|
+
property,
|
|
757
|
+
computed: false,
|
|
758
|
+
start: node.start,
|
|
759
|
+
end: node.end,
|
|
760
|
+
loc: node.loc,
|
|
761
|
+
});
|
|
732
762
|
if (prefixes.length &&
|
|
733
763
|
prefixes[0].startsWith("$.") &&
|
|
734
764
|
prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
|
|
@@ -742,38 +772,32 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
742
772
|
found = true;
|
|
743
773
|
return current;
|
|
744
774
|
}
|
|
745
|
-
const object =
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
name,
|
|
749
|
-
start: node.start,
|
|
750
|
-
end: node.end,
|
|
751
|
-
loc: node.loc,
|
|
752
|
-
}
|
|
753
|
-
: name;
|
|
754
|
-
let root = null;
|
|
755
|
-
let property = current;
|
|
756
|
-
while (property.type !== "Identifier") {
|
|
757
|
-
root = property;
|
|
758
|
-
property = property.object;
|
|
759
|
-
}
|
|
760
|
-
const mb = {
|
|
761
|
-
type: "MemberExpression",
|
|
762
|
-
object,
|
|
763
|
-
property,
|
|
764
|
-
computed: false,
|
|
775
|
+
const object = {
|
|
776
|
+
type: "Identifier",
|
|
777
|
+
name,
|
|
765
778
|
start: node.start,
|
|
766
779
|
end: node.end,
|
|
767
780
|
loc: node.loc,
|
|
768
781
|
};
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
782
|
+
let root = null;
|
|
783
|
+
let property = current;
|
|
784
|
+
do {
|
|
785
|
+
root = property;
|
|
786
|
+
property = property.object;
|
|
787
|
+
} while (property.type === "MemberExpression");
|
|
788
|
+
if (property.type === "ThisExpression") {
|
|
789
|
+
root.object = object;
|
|
790
|
+
return root;
|
|
774
791
|
}
|
|
792
|
+
root.object = member(object, property);
|
|
775
793
|
return current;
|
|
776
|
-
},
|
|
794
|
+
}, member({
|
|
795
|
+
type: "ThisExpression",
|
|
796
|
+
text: "self",
|
|
797
|
+
start: node.start,
|
|
798
|
+
end: node.end,
|
|
799
|
+
loc: node.loc,
|
|
800
|
+
}, node));
|
|
777
801
|
}
|
|
778
802
|
return null;
|
|
779
803
|
}
|
|
@@ -2213,6 +2237,7 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
2213
2237
|
state.stack[0].node = node;
|
|
2214
2238
|
break;
|
|
2215
2239
|
case "TypeSpecList":
|
|
2240
|
+
case "TypeSpecPart":
|
|
2216
2241
|
state.inType = true;
|
|
2217
2242
|
break;
|
|
2218
2243
|
case "ImportModule":
|
|
@@ -2454,6 +2479,11 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
2454
2479
|
if (state.post)
|
|
2455
2480
|
ret = state.post(node, state);
|
|
2456
2481
|
switch (type) {
|
|
2482
|
+
// Don't clear inType for TypeSpecPart, since they
|
|
2483
|
+
// generally occur in TypeSpecLists. But do clear it for
|
|
2484
|
+
// SizedArrayExpression, since thats the only place they
|
|
2485
|
+
// happen on their own.
|
|
2486
|
+
case "SizedArrayExpression":
|
|
2457
2487
|
case "TypeSpecList":
|
|
2458
2488
|
case "TypedefDeclaration":
|
|
2459
2489
|
case "EnumDeclaration":
|
|
@@ -2473,7 +2503,7 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
2473
2503
|
}
|
|
2474
2504
|
}
|
|
2475
2505
|
}
|
|
2476
|
-
if (ret
|
|
2506
|
+
if (ret != null) {
|
|
2477
2507
|
state.removeNodeComments(node, ast);
|
|
2478
2508
|
}
|
|
2479
2509
|
return ret;
|
package/build/optimizer.cjs
CHANGED
|
@@ -11165,11 +11165,29 @@ function shouldInline(state, func, call, context) {
|
|
|
11165
11165
|
}
|
|
11166
11166
|
return false;
|
|
11167
11167
|
}
|
|
11168
|
-
|
|
11168
|
+
// We still need to keep track of every local name that was
|
|
11169
|
+
// already in use before we started inlining, but we don't want to
|
|
11170
|
+
// use any of its renames. We also want to know whether a local is
|
|
11171
|
+
// from the function being inlined, or the calling function, so
|
|
11172
|
+
// set every element to false.
|
|
11173
|
+
function fixupLocalsMap(state) {
|
|
11174
|
+
if (!state.localsStack)
|
|
11175
|
+
throw new Error("No local variable map!");
|
|
11176
|
+
const locals = state.localsStack[state.localsStack.length - 1];
|
|
11177
|
+
const { map } = locals;
|
|
11178
|
+
if (!map)
|
|
11179
|
+
throw new Error("No local variable map!");
|
|
11180
|
+
const original = { ...map };
|
|
11181
|
+
Object.keys(map).forEach((key) => (map[key] = false));
|
|
11182
|
+
return original;
|
|
11183
|
+
}
|
|
11184
|
+
function processInlineBody(state, func, call, root, params) {
|
|
11169
11185
|
let failed = false;
|
|
11170
11186
|
const pre = state.pre;
|
|
11171
11187
|
const post = state.post;
|
|
11172
11188
|
state.inlining = true;
|
|
11189
|
+
let insertedVariableDecls = null;
|
|
11190
|
+
const replacements = new Set();
|
|
11173
11191
|
try {
|
|
11174
11192
|
state.pre = (node) => {
|
|
11175
11193
|
if (failed)
|
|
@@ -11177,19 +11195,14 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11177
11195
|
node.start = call.start;
|
|
11178
11196
|
node.end = call.end;
|
|
11179
11197
|
node.loc = call.loc;
|
|
11180
|
-
if (node
|
|
11198
|
+
if (replacements.has(node))
|
|
11181
11199
|
return false;
|
|
11182
11200
|
const result = pre(node, state);
|
|
11183
11201
|
if (!insertedVariableDecls && node.type === "BlockStatement") {
|
|
11202
|
+
// the block just created a new locals map, so we don't
|
|
11203
|
+
// need to restore it at the end.
|
|
11204
|
+
fixupLocalsMap(state);
|
|
11184
11205
|
const locals = state.localsStack[state.localsStack.length - 1];
|
|
11185
|
-
const { map } = locals;
|
|
11186
|
-
if (!map)
|
|
11187
|
-
throw new Error("No local variable map!");
|
|
11188
|
-
// We still need to keep track of every local name that was
|
|
11189
|
-
// already in use, but we don't want to use any of its renames.
|
|
11190
|
-
// We also want to know whether a local is from the function being
|
|
11191
|
-
// inlined, or the calling function, so set every element to false.
|
|
11192
|
-
Object.keys(map).forEach((key) => (map[key] = false));
|
|
11193
11206
|
const declarations = func.node.params
|
|
11194
11207
|
.map((param, i) => {
|
|
11195
11208
|
const paramName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
|
|
@@ -11210,6 +11223,7 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11210
11223
|
kind: "var",
|
|
11211
11224
|
};
|
|
11212
11225
|
node.body.unshift(insertedVariableDecls);
|
|
11226
|
+
replacements.add(insertedVariableDecls);
|
|
11213
11227
|
}
|
|
11214
11228
|
return result;
|
|
11215
11229
|
};
|
|
@@ -11225,6 +11239,8 @@ function processInlineBody(state, func, call, root, insertedVariableDecls, param
|
|
|
11225
11239
|
const ix = params[node.name];
|
|
11226
11240
|
if (ix >= 0) {
|
|
11227
11241
|
replacement = call.arguments[ix];
|
|
11242
|
+
replacements.add(replacement);
|
|
11243
|
+
return replacement;
|
|
11228
11244
|
}
|
|
11229
11245
|
break;
|
|
11230
11246
|
}
|
|
@@ -11266,6 +11282,8 @@ function unused(expression, top) {
|
|
|
11266
11282
|
return [];
|
|
11267
11283
|
case "Identifier":
|
|
11268
11284
|
return [];
|
|
11285
|
+
case "ThisExpression":
|
|
11286
|
+
return [];
|
|
11269
11287
|
case "BinaryExpression":
|
|
11270
11288
|
if (expression.operator === "as") {
|
|
11271
11289
|
return unused(expression.left);
|
|
@@ -11368,7 +11386,7 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11368
11386
|
const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(param);
|
|
11369
11387
|
return [name, argnum];
|
|
11370
11388
|
}));
|
|
11371
|
-
if (!processInlineBody(state, func, call, body,
|
|
11389
|
+
if (!processInlineBody(state, func, call, body, params)) {
|
|
11372
11390
|
return null;
|
|
11373
11391
|
}
|
|
11374
11392
|
diagnostic(state, call.loc, null);
|
|
@@ -11400,7 +11418,10 @@ function inlineFunction(state, func, call, context) {
|
|
|
11400
11418
|
}
|
|
11401
11419
|
const retArg = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
|
|
11402
11420
|
const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
|
|
11403
|
-
|
|
11421
|
+
const map = fixupLocalsMap(state);
|
|
11422
|
+
const ret = processInlineBody(state, func, call, retArg, params);
|
|
11423
|
+
state.localsStack[state.localsStack.length - 1].map = map;
|
|
11424
|
+
return ret;
|
|
11404
11425
|
}
|
|
11405
11426
|
function applyTypeIfNeeded(node) {
|
|
11406
11427
|
if ("enumType" in node && node.enumType) {
|
|
@@ -11453,6 +11474,15 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
11453
11474
|
return "";
|
|
11454
11475
|
}))
|
|
11455
11476
|
.flat();
|
|
11477
|
+
const member = (object, property) => ({
|
|
11478
|
+
type: "MemberExpression",
|
|
11479
|
+
object,
|
|
11480
|
+
property,
|
|
11481
|
+
computed: false,
|
|
11482
|
+
start: node.start,
|
|
11483
|
+
end: node.end,
|
|
11484
|
+
loc: node.loc,
|
|
11485
|
+
});
|
|
11456
11486
|
if (prefixes.length &&
|
|
11457
11487
|
prefixes[0].startsWith("$.") &&
|
|
11458
11488
|
prefixes.every((prefix, i) => !i || prefix === prefixes[i - 1])) {
|
|
@@ -11466,38 +11496,32 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
11466
11496
|
found = true;
|
|
11467
11497
|
return current;
|
|
11468
11498
|
}
|
|
11469
|
-
const object =
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
name,
|
|
11473
|
-
start: node.start,
|
|
11474
|
-
end: node.end,
|
|
11475
|
-
loc: node.loc,
|
|
11476
|
-
}
|
|
11477
|
-
: name;
|
|
11478
|
-
let root = null;
|
|
11479
|
-
let property = current;
|
|
11480
|
-
while (property.type !== "Identifier") {
|
|
11481
|
-
root = property;
|
|
11482
|
-
property = property.object;
|
|
11483
|
-
}
|
|
11484
|
-
const mb = {
|
|
11485
|
-
type: "MemberExpression",
|
|
11486
|
-
object,
|
|
11487
|
-
property,
|
|
11488
|
-
computed: false,
|
|
11499
|
+
const object = {
|
|
11500
|
+
type: "Identifier",
|
|
11501
|
+
name,
|
|
11489
11502
|
start: node.start,
|
|
11490
11503
|
end: node.end,
|
|
11491
11504
|
loc: node.loc,
|
|
11492
11505
|
};
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11506
|
+
let root = null;
|
|
11507
|
+
let property = current;
|
|
11508
|
+
do {
|
|
11509
|
+
root = property;
|
|
11510
|
+
property = property.object;
|
|
11511
|
+
} while (property.type === "MemberExpression");
|
|
11512
|
+
if (property.type === "ThisExpression") {
|
|
11513
|
+
root.object = object;
|
|
11514
|
+
return root;
|
|
11498
11515
|
}
|
|
11516
|
+
root.object = member(object, property);
|
|
11499
11517
|
return current;
|
|
11500
|
-
},
|
|
11518
|
+
}, member({
|
|
11519
|
+
type: "ThisExpression",
|
|
11520
|
+
text: "self",
|
|
11521
|
+
start: node.start,
|
|
11522
|
+
end: node.end,
|
|
11523
|
+
loc: node.loc,
|
|
11524
|
+
}, node));
|
|
11501
11525
|
}
|
|
11502
11526
|
return null;
|
|
11503
11527
|
}
|
|
@@ -13085,7 +13109,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
13085
13109
|
// the oldest optimized file, we don't need to regenerate
|
|
13086
13110
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
13087
13111
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
13088
|
-
if (source_time < opt_time &&
|
|
13112
|
+
if (source_time < opt_time && 1655916886685 < opt_time) {
|
|
13089
13113
|
return { hasTests, diagnostics: prevDiagnostics };
|
|
13090
13114
|
}
|
|
13091
13115
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function sizeBasedPRE(state: ProgramStateAnalysis, func: FunctionStateNode): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markw65/monkeyc-optimizer",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.28",
|
|
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",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"author": "markw65",
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@markw65/prettier-plugin-monkeyc": "^1.0.
|
|
40
|
+
"@markw65/prettier-plugin-monkeyc": "^1.0.29"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/glob": "^7.2.0",
|