Skip to content

Commit 53a0aad

Browse files
committed
Switch binder to parallel stacks, temporarily partially revert emitBinary
1 parent 5d3ab2b commit 53a0aad

File tree

2 files changed

+127
-119
lines changed

2 files changed

+127
-119
lines changed

src/compiler/binder.ts

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,31 +1502,40 @@ namespace ts {
15021502
}
15031503

15041504
function createBindBinaryExpressionFlow() {
1505-
class BindBinaryExpressionState {
1506-
public skip = false;
1507-
constructor(
1508-
readonly isInStrictMode: boolean | undefined,
1509-
readonly parent: Node | undefined
1510-
) {
1511-
}
1512-
}
1513-
1514-
return createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, identity);
1505+
let stackIndex = -1;
1506+
let inStrictModeStack: (boolean | undefined)[];
1507+
let parentStack: (Node | undefined)[];
1508+
1509+
const trampoline = createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, identity);
1510+
return (node: BinaryExpression) => {
1511+
const savedStackIndex = stackIndex;
1512+
const savedInStrictModeStack = inStrictModeStack;
1513+
const savedParentStack = parentStack;
1514+
stackIndex = -1;
1515+
inStrictModeStack = [undefined];
1516+
parentStack = [undefined];
1517+
trampoline(node);
1518+
stackIndex = savedStackIndex;
1519+
inStrictModeStack = savedInStrictModeStack;
1520+
parentStack = savedParentStack;
1521+
};
15151522

1516-
function onEnter(node: BinaryExpression, prev: BindBinaryExpressionState | undefined) {
1517-
let state: BindBinaryExpressionState;
1518-
if (prev) {
1519-
// `prev` is only defined when recuring. We can use this to emulate the work that `bind` does before
1520-
// reaching `bindChildren`. A normal call to `bindBinaryExpressionFlow` will already have done this work.
1523+
function onEnter(node: BinaryExpression, _: boolean | undefined) {
1524+
stackIndex++;
1525+
if (stackIndex > 0) {
1526+
// Emulate the work that `bind` does before reaching `bindChildren`. A normal call to
1527+
// `bindBinaryExpressionFlow` will already have done this work.
15211528
setParent(node, parent);
15221529
const saveInStrictMode = inStrictMode;
15231530
bindWorker(node);
15241531
const saveParent = parent;
15251532
parent = node;
1526-
state = new BindBinaryExpressionState(saveInStrictMode, saveParent);
1533+
inStrictModeStack[stackIndex] = saveInStrictMode;
1534+
parentStack[stackIndex] = saveParent;
15271535
}
15281536
else {
1529-
state = new BindBinaryExpressionState(/*isInStrictMode*/ undefined, /*parent*/ undefined);
1537+
inStrictModeStack[stackIndex] = undefined;
1538+
parentStack[stackIndex] = undefined;
15301539
}
15311540

15321541
// TODO: bindLogicalExpression is recursive - if we want to handle deeply nested `&&` expressions
@@ -1545,34 +1554,34 @@ namespace ts {
15451554
else {
15461555
bindLogicalLikeExpression(node, currentTrueTarget!, currentFalseTarget!);
15471556
}
1548-
state.skip = true;
1557+
return true;
15491558
}
1550-
return state;
1559+
return false;
15511560
}
15521561

1553-
function onLeft(left: Expression, state: BindBinaryExpressionState, _node: BinaryExpression) {
1554-
if (!state.skip) {
1562+
function onLeft(left: Expression, skip: boolean, _node: BinaryExpression) {
1563+
if (!skip) {
15551564
return maybeBind(left);
15561565
}
15571566
}
15581567

1559-
function onOperator(operatorToken: BinaryOperatorToken, state: BindBinaryExpressionState, node: BinaryExpression) {
1560-
if (!state.skip) {
1568+
function onOperator(operatorToken: BinaryOperatorToken, skip: boolean, node: BinaryExpression) {
1569+
if (!skip) {
15611570
if (operatorToken.kind === SyntaxKind.CommaToken) {
15621571
maybeBindExpressionFlowIfCall(node.left);
15631572
}
15641573
bind(operatorToken);
15651574
}
15661575
}
15671576

1568-
function onRight(right: Expression, state: BindBinaryExpressionState, _node: BinaryExpression) {
1569-
if (!state.skip) {
1577+
function onRight(right: Expression, skip: boolean, _node: BinaryExpression) {
1578+
if (!skip) {
15701579
return maybeBind(right);
15711580
}
15721581
}
15731582

1574-
function onExit(node: BinaryExpression, state: BindBinaryExpressionState) {
1575-
if (!state.skip) {
1583+
function onExit(node: BinaryExpression, skip: boolean) {
1584+
if (!skip) {
15761585
const operator = node.operatorToken.kind;
15771586
if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) {
15781587
bindAssignmentTargetFlow(node.left);
@@ -1584,16 +1593,15 @@ namespace ts {
15841593
}
15851594
}
15861595
}
1587-
completeNode(state);
1588-
}
1589-
1590-
function completeNode(state: BindBinaryExpressionState) {
1591-
if (state.isInStrictMode !== undefined) {
1592-
inStrictMode = state.isInStrictMode;
1596+
const savedInStrictMode = inStrictModeStack[stackIndex];
1597+
const savedParent = parentStack[stackIndex];
1598+
if (savedInStrictMode !== undefined) {
1599+
inStrictMode = savedInStrictMode;
15931600
}
1594-
if (state.parent !== undefined) {
1595-
parent = state.parent;
1601+
if (savedParent !== undefined) {
1602+
parent = savedParent;
15961603
}
1604+
stackIndex--;
15971605
}
15981606

15991607
function maybeBind(node: Node) {

src/compiler/emitter.ts

Lines changed: 84 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -2520,64 +2520,64 @@ namespace ts {
25202520
}
25212521

25222522
function createEmitBinaryExpression() {
2523-
class EmitBinaryExpressionState {
2524-
nested = false;
2525-
preserveSourceNewlines: boolean | undefined = undefined;
2526-
containerPos = -1;
2527-
containerEnd = -1;
2528-
declarationListContainerEnd = -1;
2529-
emitFlags = EmitFlags.None;
2530-
commentRange: TextRange | undefined = undefined;
2531-
sourceMapRange: SourceMapRange | undefined = undefined;
2532-
}
2533-
2534-
return createBinaryExpressionTrampoline(onEnter, maybeEmitExpression, onOperator, maybeEmitExpression, onExit, identity);
2535-
2536-
function onEnter(node: BinaryExpression, prev: EmitBinaryExpressionState | undefined) {
2537-
const state = new EmitBinaryExpressionState();
2538-
if (prev) {
2539-
// `prev` is only defined when recuring. We can use this fact to indicate
2540-
// we are entering into a nested binary expression and can replicate the
2541-
// leading comment and sourcemap emit performed by `emitWithContext`.
2542-
state.nested = true;
2543-
onBeforeEmitNode?.(node);
2544-
2545-
state.emitFlags = getEmitFlags(node);
2546-
state.preserveSourceNewlines = preserveSourceNewlines;
2547-
if (preserveSourceNewlines && (state.emitFlags & EmitFlags.IgnoreSourceNewlines)) {
2548-
preserveSourceNewlines = false;
2549-
}
2550-
2551-
state.containerPos = containerPos;
2552-
state.containerEnd = containerEnd;
2553-
state.declarationListContainerEnd = declarationListContainerEnd;
2554-
state.commentRange = shouldEmitComments(node) ? getCommentRange(node) : undefined;
2555-
state.sourceMapRange = shouldEmitSourceMaps(node) ? getSourceMapRange(node) : undefined;
2556-
2557-
// Emit leading comments
2558-
if (state.commentRange) {
2559-
emitLeadingCommentsOfNode(node, state.emitFlags, state.commentRange.pos, state.commentRange.end);
2560-
if (state.emitFlags & EmitFlags.NoNestedComments) {
2561-
commentsDisabled = true;
2562-
}
2563-
}
2564-
2565-
// Emit leading sourcemap
2566-
if (state.sourceMapRange) {
2567-
const source = state.sourceMapRange.source || sourceMapSource;
2568-
if ((state.emitFlags & EmitFlags.NoLeadingSourceMap) === 0
2569-
&& state.sourceMapRange.pos >= 0) {
2570-
emitSourcePos(state.sourceMapRange.source || sourceMapSource, skipSourceTrivia(source, state.sourceMapRange.pos));
2571-
}
2572-
if (state.emitFlags & EmitFlags.NoNestedSourceMaps) {
2573-
sourceMapsDisabled = true;
2574-
}
2575-
}
2576-
}
2577-
return state;
2578-
}
2579-
2580-
function onOperator(operatorToken: BinaryOperatorToken, _: unknown, node: BinaryExpression) {
2523+
// class EmitBinaryExpressionState {
2524+
// nested = false;
2525+
// preserveSourceNewlines: boolean | undefined = undefined;
2526+
// containerPos = -1;
2527+
// containerEnd = -1;
2528+
// declarationListContainerEnd = -1;
2529+
// emitFlags = EmitFlags.None;
2530+
// commentRange: TextRange | undefined = undefined;
2531+
// sourceMapRange: SourceMapRange | undefined = undefined;
2532+
// }
2533+
2534+
return createBinaryExpressionTrampoline(noop, maybeEmitExpression, onOperator, maybeEmitExpression, onExit, identity);
2535+
2536+
// function onEnter(_node: BinaryExpression, _prev: EmitBinaryExpressionState | undefined) {
2537+
// const state = new EmitBinaryExpressionState();
2538+
// if (prev) {
2539+
// // `prev` is only defined when recuring. We can use this fact to indicate
2540+
// // we are entering into a nested binary expression and can replicate the
2541+
// // leading comment and sourcemap emit performed by `emitWithContext`.
2542+
// state.nested = true;
2543+
// onBeforeEmitNode?.(node);
2544+
2545+
// state.emitFlags = getEmitFlags(node);
2546+
// state.preserveSourceNewlines = preserveSourceNewlines;
2547+
// if (preserveSourceNewlines && (state.emitFlags & EmitFlags.IgnoreSourceNewlines)) {
2548+
// preserveSourceNewlines = false;
2549+
// }
2550+
2551+
// state.containerPos = containerPos;
2552+
// state.containerEnd = containerEnd;
2553+
// state.declarationListContainerEnd = declarationListContainerEnd;
2554+
// state.commentRange = shouldEmitComments(node) ? getCommentRange(node) : undefined;
2555+
// state.sourceMapRange = shouldEmitSourceMaps(node) ? getSourceMapRange(node) : undefined;
2556+
2557+
// // Emit leading comments
2558+
// if (state.commentRange) {
2559+
// emitLeadingCommentsOfNode(node, state.emitFlags, state.commentRange.pos, state.commentRange.end);
2560+
// if (state.emitFlags & EmitFlags.NoNestedComments) {
2561+
// commentsDisabled = true;
2562+
// }
2563+
// }
2564+
2565+
// // Emit leading sourcemap
2566+
// if (state.sourceMapRange) {
2567+
// const source = state.sourceMapRange.source || sourceMapSource;
2568+
// if ((state.emitFlags & EmitFlags.NoLeadingSourceMap) === 0
2569+
// && state.sourceMapRange.pos >= 0) {
2570+
// emitSourcePos(state.sourceMapRange.source || sourceMapSource, skipSourceTrivia(source, state.sourceMapRange.pos));
2571+
// }
2572+
// if (state.emitFlags & EmitFlags.NoNestedSourceMaps) {
2573+
// sourceMapsDisabled = true;
2574+
// }
2575+
// }
2576+
// }
2577+
// return state;
2578+
// }
2579+
2580+
function onOperator(operatorToken: BinaryOperatorToken, _state: unknown, node: BinaryExpression) {
25812581
const isCommaOperator = operatorToken.kind !== SyntaxKind.CommaToken;
25822582
const linesBeforeOperator = getLinesBetweenNodes(node, node.left, operatorToken);
25832583
const linesAfterOperator = getLinesBetweenNodes(node, operatorToken, node.right);
@@ -2588,44 +2588,44 @@ namespace ts {
25882588
writeLinesAndIndent(linesAfterOperator, /*writeSpaceIfNotIndenting*/ true);
25892589
}
25902590

2591-
function onExit(node: BinaryExpression, state: EmitBinaryExpressionState) {
2591+
function onExit(node: BinaryExpression, _state: unknown) {
25922592
const linesBeforeOperator = getLinesBetweenNodes(node, node.left, node.operatorToken);
25932593
const linesAfterOperator = getLinesBetweenNodes(node, node.operatorToken, node.right);
25942594
decreaseIndentIf(linesBeforeOperator, linesAfterOperator);
25952595

2596-
if (state.nested) {
2597-
// If we are marked as nested, we are recurring. We can use this fact to indicate
2598-
// we are exiting from a nested binary expression and can replicate the trailing
2599-
// comment and sourcemap emit performed by `emitWithContext`.
2596+
// if (state.nested) {
2597+
// // If we are marked as nested, we are recurring. We can use this fact to indicate
2598+
// // we are exiting from a nested binary expression and can replicate the trailing
2599+
// // comment and sourcemap emit performed by `emitWithContext`.
26002600

2601-
// Emit trailing sourcemap
2602-
if (state.sourceMapRange) {
2603-
if (state.emitFlags & EmitFlags.NoNestedSourceMaps) {
2604-
sourceMapsDisabled = false;
2605-
}
2606-
if ((state.emitFlags & EmitFlags.NoTrailingSourceMap) === 0
2607-
&& state.sourceMapRange.end >= 0) {
2608-
emitSourcePos(state.sourceMapRange.source || sourceMapSource, state.sourceMapRange.end);
2609-
}
2610-
}
2601+
// // Emit trailing sourcemap
2602+
// if (state.sourceMapRange) {
2603+
// if (state.emitFlags & EmitFlags.NoNestedSourceMaps) {
2604+
// sourceMapsDisabled = false;
2605+
// }
2606+
// if ((state.emitFlags & EmitFlags.NoTrailingSourceMap) === 0
2607+
// && state.sourceMapRange.end >= 0) {
2608+
// emitSourcePos(state.sourceMapRange.source || sourceMapSource, state.sourceMapRange.end);
2609+
// }
2610+
// }
26112611

2612-
// Emit trailing comments
2613-
if (state.commentRange) {
2614-
if (state.emitFlags & EmitFlags.NoNestedComments) {
2615-
commentsDisabled = false;
2616-
}
2617-
emitTrailingCommentsOfNode(node, state.emitFlags, state.commentRange.pos, state.commentRange.end, state.containerPos, state.containerEnd, state.declarationListContainerEnd);
2618-
}
2612+
// // Emit trailing comments
2613+
// if (state.commentRange) {
2614+
// if (state.emitFlags & EmitFlags.NoNestedComments) {
2615+
// commentsDisabled = false;
2616+
// }
2617+
// emitTrailingCommentsOfNode(node, state.emitFlags, state.commentRange.pos, state.commentRange.end, state.containerPos, state.containerEnd, state.declarationListContainerEnd);
2618+
// }
26192619

2620-
onAfterEmitNode?.(node);
2620+
// onAfterEmitNode?.(node);
26212621

2622-
preserveSourceNewlines = state.preserveSourceNewlines;
2623-
}
2622+
// preserveSourceNewlines = state.preserveSourceNewlines;
2623+
// }
26242624
}
26252625

26262626
function maybeEmitExpression(next: Expression) {
26272627
// Push a new frame for binary expressions, otherwise emit all other expressions.
2628-
if (isBinaryExpression(next)) {
2628+
if (isBinaryExpression(next) && !shouldEmitComments(next) && !shouldEmitSourceMaps(next)) {
26292629
return next;
26302630
}
26312631

0 commit comments

Comments
 (0)