Skip to content

Commit 16737cb

Browse files
authored
Merge pull request #5 from btc-vision/closures
Refactor closure capture analysis and minor cleanups
2 parents d534476 + bc725a4 commit 16737cb

File tree

1 file changed

+30
-43
lines changed

1 file changed

+30
-43
lines changed

src/compiler.ts

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,7 +1526,7 @@ export class Compiler extends DiagnosticEmitter {
15261526

15271527
private ensureEnumToString(enumElement: Enum, reportNode: Node): string | null {
15281528
if (enumElement.toStringFunctionName) return enumElement.toStringFunctionName;
1529-
1529+
15301530
if (!this.compileEnum(enumElement)) return null;
15311531
if (enumElement.is(CommonFlags.Const)) {
15321532
this.errorRelated(
@@ -1782,8 +1782,7 @@ export class Compiler extends DiagnosticEmitter {
17821782
let preCapturedNames = instance.preCapturedNames;
17831783
if (preCapturedNames && preCapturedNames.size > 0) {
17841784
// Check if any parameters are captured
1785-
let parameterTypes = instance.signature.parameterTypes;
1786-
for (let i = 0, k = parameterTypes.length; i < k; i++) {
1785+
for (let i = 0, k = instance.signature.parameterTypes.length; i < k; i++) {
17871786
let paramName = instance.getParameterName(i);
17881787
if (preCapturedNames.has(paramName)) {
17891788
let local = flow.lookupLocal(paramName);
@@ -1798,24 +1797,21 @@ export class Compiler extends DiagnosticEmitter {
17981797
if (!capturedLocals.has(local)) {
17991798
// Calculate proper byte offset with alignment
18001799
// Reserve slot 0 for parent environment pointer (4 or 8 bytes depending on wasm32/64)
1801-
let ptrSize = this.options.usizeType.byteSize;
1802-
let currentOffset = ptrSize; // Start after parent pointer slot
1800+
let currentOffset = this.options.usizeType.byteSize; // Start after parent pointer slot
18031801
for (let _keys = Map_keys(capturedLocals), j = 0, m = _keys.length; j < m; ++j) {
18041802
let existingLocal = _keys[j];
18051803
let endOfSlot = existingLocal.envSlotIndex + existingLocal.type.byteSize;
18061804
if (endOfSlot > currentOffset) currentOffset = endOfSlot;
18071805
}
18081806
// Align to the type's natural alignment
1809-
let typeSize = local.type.byteSize;
1810-
let align = typeSize;
1807+
let align = local.type.byteSize;
18111808
currentOffset = (currentOffset + align - 1) & ~(align - 1);
18121809
local.envSlotIndex = currentOffset;
18131810
local.envOwner = instance; // Track which function owns this capture
18141811
capturedLocals.set(local, local.envSlotIndex);
18151812
}
18161813
if (!instance.envLocal) {
1817-
let envLocal = flow.addScopedLocal("$env", this.options.usizeType);
1818-
instance.envLocal = envLocal;
1814+
instance.envLocal = flow.addScopedLocal("$env", this.options.usizeType);
18191815
}
18201816
}
18211817
}
@@ -1832,23 +1828,20 @@ export class Compiler extends DiagnosticEmitter {
18321828
instance.capturedLocals = capturedLocals;
18331829
}
18341830
if (!capturedLocals.has(thisLocal)) {
1835-
let ptrSize = this.options.usizeType.byteSize;
1836-
let currentOffset = ptrSize;
1831+
let currentOffset = this.options.usizeType.byteSize;
18371832
for (let _keys = Map_keys(capturedLocals), j = 0, m = _keys.length; j < m; ++j) {
18381833
let existingLocal = _keys[j];
18391834
let endOfSlot = existingLocal.envSlotIndex + existingLocal.type.byteSize;
18401835
if (endOfSlot > currentOffset) currentOffset = endOfSlot;
18411836
}
1842-
let typeSize = thisLocal.type.byteSize;
1843-
let align = typeSize;
1837+
let align = thisLocal.type.byteSize;
18441838
currentOffset = (currentOffset + align - 1) & ~(align - 1);
18451839
thisLocal.envSlotIndex = currentOffset;
18461840
thisLocal.envOwner = instance;
18471841
capturedLocals.set(thisLocal, thisLocal.envSlotIndex);
18481842
}
18491843
if (!instance.envLocal) {
1850-
let envLocal = flow.addScopedLocal("$env", this.options.usizeType);
1851-
instance.envLocal = envLocal;
1844+
instance.envLocal = flow.addScopedLocal("$env", this.options.usizeType);
18521845
}
18531846
}
18541847
}
@@ -1858,8 +1851,7 @@ export class Compiler extends DiagnosticEmitter {
18581851
// the environment pointer. This is needed because indirect calls to other closures
18591852
// can overwrite the global $~lib/__closure_env.
18601853
if (instance.outerFunction && !instance.closureEnvLocal) {
1861-
let closureEnvLocal = flow.addScopedLocal("$closureEnv", this.options.usizeType);
1862-
instance.closureEnvLocal = closureEnvLocal;
1854+
instance.closureEnvLocal = flow.addScopedLocal("$closureEnv", this.options.usizeType);
18631855
}
18641856

18651857
// compile statements
@@ -2005,8 +1997,7 @@ export class Compiler extends DiagnosticEmitter {
20051997
valueTypeRef, property.memoryOffset
20061998
);
20071999
let flowBefore = this.currentFlow;
2008-
let flow = getterInstance.flow;
2009-
this.currentFlow = flow;
2000+
this.currentFlow = getterInstance.flow;
20102001
if (property.is(CommonFlags.DefinitelyAssigned) && valueType.isReference && !valueType.isNullableReference) {
20112002
body = this.makeRuntimeNonNullCheck(body, valueType, getterInstance.identifierNode);
20122003
}
@@ -2704,7 +2695,7 @@ export class Compiler extends DiagnosticEmitter {
27042695
// (then │ │ (body) │
27052696
// (?block $continue │ │ if loops: (incrementor) ─────┘
27062697
// (body) │ │ recompile body?
2707-
// ) ├◄┘
2698+
// ) ├◄┘
27082699
// (incrementor) ┌◄┘
27092700
// (br $loop)
27102701
// )
@@ -2993,17 +2984,17 @@ export class Compiler extends DiagnosticEmitter {
29932984
// Compile the condition (always executes)
29942985
let condExpr = this.compileExpression(statement.condition, Type.auto);
29952986
let condType = this.currentType;
2996-
2987+
29972988
// Shortcut if there are no cases
29982989
if (!numCases) return module.drop(condExpr);
2999-
2990+
30002991
// Assign the condition to a temporary local as we compare it multiple times
30012992
let outerFlow = this.currentFlow;
30022993
let tempLocal = outerFlow.getTempLocal(condType);
30032994
let tempLocalIndex = tempLocal.index;
30042995
let breaks = new Array<ExpressionRef>(1 + numCases);
30052996
breaks[0] = module.local_set(tempLocalIndex, condExpr, condType.isManaged);
3006-
2997+
30072998
// Make one br_if per labeled case and leave it to Binaryen to optimize the
30082999
// sequence of br_ifs to a br_table according to optimization levels
30093000
let breakIndex = 1;
@@ -3015,7 +3006,7 @@ export class Compiler extends DiagnosticEmitter {
30153006
defaultIndex = i;
30163007
continue;
30173008
}
3018-
3009+
30193010
// Compile the equality expression for this case
30203011
const left = statement.condition;
30213012
const leftExpr = module.local_get(tempLocalIndex, condType.toRef());
@@ -3030,7 +3021,7 @@ export class Compiler extends DiagnosticEmitter {
30303021
condType,
30313022
statement
30323023
);
3033-
3024+
30343025
// Add it to the list of breaks
30353026
breaks[breakIndex++] = module.br(`case${i}|${label}`, equalityExpr);
30363027
}
@@ -4021,7 +4012,7 @@ export class Compiler extends DiagnosticEmitter {
40214012
expression: BinaryExpression,
40224013
contextualType: Type,
40234014
): ExpressionRef {
4024-
4015+
40254016
const left = expression.left;
40264017
const leftExpr = this.compileExpression(left, contextualType);
40274018
const leftType = this.currentType;
@@ -4039,9 +4030,9 @@ export class Compiler extends DiagnosticEmitter {
40394030
);
40404031
}
40414032

4042-
/**
4033+
/**
40434034
* compile `==` `===` `!=` `!==` BinaryExpression, from previously compiled left and right expressions.
4044-
*
4035+
*
40454036
* This is split from `compileCommutativeCompareBinaryExpression` so that the logic can be reused
40464037
* for switch cases in `compileSwitchStatement`, where the left expression only should be compiled once.
40474038
*/
@@ -4059,15 +4050,15 @@ export class Compiler extends DiagnosticEmitter {
40594050

40604051
let module = this.module;
40614052
let operatorString = operatorTokenToString(operator);
4062-
4053+
40634054
// check operator overload
40644055
const operatorKind = OperatorKind.fromBinaryToken(operator);
40654056
const leftOverload = leftType.lookupOverload(operatorKind, this.program);
40664057
const rightOverload = rightType.lookupOverload(operatorKind, this.program);
40674058
if (leftOverload && rightOverload && leftOverload != rightOverload) {
40684059
this.error(
40694060
DiagnosticCode.Ambiguous_operator_overload_0_conflicting_overloads_1_and_2,
4070-
reportNode.range,
4061+
reportNode.range,
40714062
operatorString,
40724063
leftOverload.internalName,
40734064
rightOverload.internalName
@@ -4157,7 +4148,7 @@ export class Compiler extends DiagnosticEmitter {
41574148

41584149
leftExpr = this.compileExpression(left, contextualType);
41594150
leftType = this.currentType;
4160-
4151+
41614152
// check operator overload
41624153
const operatorKind = OperatorKind.fromBinaryToken(operator);
41634154
const leftOverload = leftType.lookupOverload(operatorKind, this.program);
@@ -4228,7 +4219,7 @@ export class Compiler extends DiagnosticEmitter {
42284219
return this.compileNonCommutativeCompareBinaryExpression(expression, contextualType);
42294220
}
42304221
case Token.Equals_Equals_Equals:
4231-
case Token.Equals_Equals:
4222+
case Token.Equals_Equals:
42324223
case Token.Exclamation_Equals_Equals:
42334224
case Token.Exclamation_Equals: {
42344225
return this.compileCommutativeCompareBinaryExpression(expression, contextualType);
@@ -6546,13 +6537,13 @@ export class Compiler extends DiagnosticEmitter {
65466537
if (numArguments < numParams) {
65476538
return argumentExpressions;
65486539
}
6549-
6540+
65506541
// make an array literal expression from the rest args
65516542
let elements = argumentExpressions.slice(numParams - 1);
65526543
let range = new Range(elements[0].range.start, elements[elements.length - 1].range.end);
65536544
range.source = reportNode.range.source;
65546545
let arrExpr = new ArrayLiteralExpression(elements, range);
6555-
6546+
65566547
// return the original args, but replace the rest args with the array
65576548
const exprs = argumentExpressions.slice(0, numParams - 1);
65586549
exprs.push(arrExpr);
@@ -8342,8 +8333,7 @@ export class Compiler extends DiagnosticEmitter {
83428333
case NodeKind.Function: {
83438334
// Found a function expression - analyze its captures
83448335
let funcExpr = <FunctionExpression>current;
8345-
let declaration = funcExpr.declaration;
8346-
let capturedNames = this.analyzeCapturedVariablesWithDeclared(declaration, flow, instance, declaredVars);
8336+
let capturedNames = this.analyzeCapturedVariablesWithDeclared(funcExpr.declaration, flow, declaredVars);
83478337
if (capturedNames.size > 0) {
83488338
// Check if closures feature is enabled
83498339
if (!this.options.hasFeature(Feature.Closures)) {
@@ -8593,7 +8583,6 @@ export class Compiler extends DiagnosticEmitter {
85938583
private analyzeCapturedVariablesWithDeclared(
85948584
declaration: FunctionDeclaration,
85958585
outerFlow: Flow,
8596-
outerFunc: Function,
85978586
declaredVars: Map<string, Type | null>
85988587
): Set<string> {
85998588
// For prescan, we just collect variable NAMES that are captured
@@ -8639,8 +8628,7 @@ export class Compiler extends DiagnosticEmitter {
86398628
if (endOfSlot > maxEnd) maxEnd = endOfSlot;
86408629
}
86418630
// Ensure total size is aligned to pointer size
8642-
let size = (maxEnd + usizeSize - 1) & ~(usizeSize - 1);
8643-
return size;
8631+
return (maxEnd + usizeSize - 1) & ~(usizeSize - 1);
86448632
}
86458633

86468634
/** Ensures a closure environment is set up for the outer function. */
@@ -8657,7 +8645,7 @@ export class Compiler extends DiagnosticEmitter {
86578645
for (let _keys = Map_keys(captures), i = 0, k = _keys.length; i < k; i++) {
86588646
let local = _keys[i];
86598647
if (!existingCaptures.has(local)) {
8660-
existingCaptures.set(local, captures.get(local)!);
8648+
existingCaptures.set(local, captures.get(local) as i32);
86618649
}
86628650
}
86638651
}
@@ -8666,8 +8654,7 @@ export class Compiler extends DiagnosticEmitter {
86668654

86678655
// Create a new environment local for the outer function
86688656
let usizeType = this.options.usizeType;
8669-
let envLocal = flow.addScopedLocal("$env", usizeType);
8670-
outerFunc.envLocal = envLocal;
8657+
outerFunc.envLocal = flow.addScopedLocal("$env", usizeType);;
86718658
outerFunc.capturedLocals = captures;
86728659

86738660
// Compute the environment size
@@ -9504,7 +9491,7 @@ export class Compiler extends DiagnosticEmitter {
95049491
stmts.length = 1;
95059492
stmts.push(
95069493
module.i32(1)
9507-
);
9494+
);
95089495
module.removeFunction(name);
95099496
module.addFunction(name, sizeType, TypeRef.I32, [ TypeRef.I32 ], module.block(null, stmts, TypeRef.I32));
95109497
}

0 commit comments

Comments
 (0)