diff --git a/pkg/dart2bytecode/lib/bytecode_generator.dart b/pkg/dart2bytecode/lib/bytecode_generator.dart index 06c6626c22a..147f5fd9c51 100644 --- a/pkg/dart2bytecode/lib/bytecode_generator.dart +++ b/pkg/dart2bytecode/lib/bytecode_generator.dart @@ -1533,25 +1533,23 @@ class BytecodeGenerator extends RecursiveVisitor { } void _genConditionAndJumpIf(Expression condition, bool value, Label dest) { + final savedSourcePosition = asm.currentSourcePosition; + _recordSourcePosition(condition.fileOffset); final bool? constantValue = _constantConditionValue(condition); if (constantValue != null) { if (constantValue == value) { - _emitLocalSourcePosition(condition.fileOffset); + _emitSourcePosition(); asm.emitJump(dest); } - return; - } - if (condition is EqualsNull) { + } else if (condition is EqualsNull) { _generateNode(condition.expression); - _emitLocalSourcePosition(condition.fileOffset); + _emitSourcePosition(); if (value) { asm.emitJumpIfNull(dest); } else { asm.emitJumpIfNotNull(dest); } - return; - } - if (condition is Not) { + } else if (condition is Not) { _genConditionAndJumpIf(condition.operand, !value, dest); } else if (condition is LogicalExpression) { final isOR = (condition.operatorEnum == LogicalExpressionOperator.OR); @@ -1573,13 +1571,14 @@ class BytecodeGenerator extends RecursiveVisitor { if (negated) { value = !value; } - _emitLocalSourcePosition(condition.fileOffset); + _emitSourcePosition(); if (value) { asm.emitJumpIfTrue(dest); } else { asm.emitJumpIfFalse(dest); } } + asm.currentSourcePosition = savedSourcePosition; } int _getDefaultParamConstIndex(VariableDeclaration param) { @@ -2637,20 +2636,25 @@ class BytecodeGenerator extends RecursiveVisitor { _genPushInstantiatorTypeArguments(); asm.emitAllocateClosure(); - final int temp = locals.tempIndexInFrame(node); - asm.emitStoreLocal(temp); + final bool storeFunctionTAV = locals.hasFunctionTypeArgsVar; + final bool setEmptyDelayedTAV = function.typeParameters.isNotEmpty; - if (locals.hasFunctionTypeArgsVar) { - asm.emitPush(temp); - _genPushFunctionTypeArguments(); - asm.emitStoreFieldTOS(cp.addInstanceField(closureFunctionTypeArguments)); - } + if (storeFunctionTAV || setEmptyDelayedTAV) { + final int temp = locals.tempIndexInFrame(node); + asm.emitStoreLocal(temp); - // Delayed type arguments are only used by generic closures. - if (function.typeParameters.isNotEmpty) { - asm.emitPush(temp); - asm.emitPushConstant(cp.addEmptyTypeArguments()); - asm.emitStoreFieldTOS(cp.addInstanceField(closureDelayedTypeArguments)); + if (storeFunctionTAV) { + asm.emitPush(temp); + _genPushFunctionTypeArguments(); + asm.emitStoreFieldTOS( + cp.addInstanceField(closureFunctionTypeArguments)); + } + + if (setEmptyDelayedTAV) { + asm.emitPush(temp); + asm.emitPushConstant(cp.addEmptyTypeArguments()); + asm.emitStoreFieldTOS(cp.addInstanceField(closureDelayedTypeArguments)); + } } } @@ -2770,27 +2774,13 @@ class BytecodeGenerator extends RecursiveVisitor { // Emits a source position entry and/or debugger stop as appropriate. void _emitSourcePosition() { - if (options.emitSourcePositions) { - asm.emitSourcePosition(); - } + asm.emitSourcePosition(); if (options.emitDebuggerStops && (asm.currentSourcePositionFlags & SourcePositions.syntheticFlag) == 0) { asm.emitDebugCheck(); } } - // Records the given file offset as the current source position and - // emits a source position entry and/or debugger stop as appropriate, - // restoring the current source position afterwards. - void _emitLocalSourcePosition(int fileOffset) { - if (fileOffset != TreeNode.noOffset) { - final savedSourcePosition = asm.currentSourcePosition; - _recordSourcePosition(fileOffset); - _emitSourcePosition(); - asm.currentSourcePosition = savedSourcePosition; - } - } - /// Generates non-local transfer from inner node [from] into the outer /// node, executing finally blocks on the way out. [to] can be null, /// in such case all enclosing finally blocks are executed. @@ -2798,7 +2788,6 @@ class BytecodeGenerator extends RecursiveVisitor { /// the last finally block. void _generateNonLocalControlTransfer( TreeNode from, TreeNode to, GenerateContinuation continuation) { - _emitLocalSourcePosition(from.fileOffset); List tryFinallyBlocks = _getEnclosingTryFinallyBlocks(from, to); _addFinallyBlocks(tryFinallyBlocks, continuation); } @@ -3737,31 +3726,44 @@ class BytecodeGenerator extends RecursiveVisitor { @override void visitVariableSet(VariableSet node) { final v = node.variable; - final bool hasResult = !isExpressionWithoutResult(node); - final bool isLateFinal = v.isLate && v.isFinal; - - if (!isLateFinal) { - _genPushContextIfCaptured(v); - } + _genPushContextIfCaptured(v); _generateNode(node.value); + // Wrap the set in an already initialized check for late final variables. + final bool isLateFinal = v.isLate && v.isFinal; + final Label error = new Label(); + if (isLateFinal) { + _genLoadVar(v); + asm.emitJumpIfInitialized(error); + } + + // _genStoreVar pops the stored value off the stack. If the result isn't + // used, this is fine. If it is used but the variable isn't captured, then + // the generator uses StoreLocal instead of calling _genStoreVar. Otherwise, + // a temporary must be used to save and restore the value (as there is no + // keep-on-stack equivalent of StoreContextVar). + final bool hasResult = !isExpressionWithoutResult(node); + final bool isCaptured = locals.isCaptured(v); + final bool storeResultInTemp = hasResult && isCaptured; + + if (storeResultInTemp) { + asm.emitStoreLocal(locals.tempIndexInFrame(node)); + } if (!v.isSynthesized) { _emitSourcePosition(); } + if (hasResult && !isCaptured) { + asm.emitStoreLocal(locals.getVarIndexInFrame(v)); + } else { + _genStoreVar(v); + } + if (storeResultInTemp) { + asm.emitPush(locals.tempIndexInFrame(node)); + } if (isLateFinal) { - final int temp = locals.tempIndexInFrame(node); - asm.emitPopLocal(temp); - - final Label error = new Label(); final Label done = new Label(); - _genLoadVar(v); - asm.emitJumpIfInitialized(error); - - _genPushContextIfCaptured(v); - asm.emitPush(temp); - _genStoreVar(v); asm.emitJump(done); asm.bind(error); @@ -3771,28 +3773,6 @@ class BytecodeGenerator extends RecursiveVisitor { asm.emitDrop1(); asm.bind(done); - - if (hasResult) { - asm.emitPush(temp); - } - } else if (locals.isCaptured(v)) { - final int temp = locals.tempIndexInFrame(node); - if (hasResult) { - asm.emitStoreLocal(temp); - } - - _genStoreVar(v); - - if (hasResult) { - asm.emitPush(temp); - } - } else { - final int localIndex = locals.getVarIndexInFrame(v); - if (hasResult) { - asm.emitStoreLocal(localIndex); - } else { - asm.emitPopLocal(localIndex); - } } } @@ -3887,6 +3867,7 @@ class BytecodeGenerator extends RecursiveVisitor { _generateNonLocalControlTransfer(node, node.target, () { _genUnwindContext(targetContextLevel); + _emitSourcePosition(); asm.emitJump(targetLabel); }); } @@ -3899,6 +3880,7 @@ class BytecodeGenerator extends RecursiveVisitor { _generateNonLocalControlTransfer(node, node.target.parent!, () { _genUnwindContext(targetContextLevel); + _emitSourcePosition(); asm.emitJump(targetLabel); }); } @@ -3991,9 +3973,9 @@ class BytecodeGenerator extends RecursiveVisitor { @override void visitFunctionDeclaration(ast.FunctionDeclaration node) { - _emitSourcePosition(); _genPushContextIfCaptured(node.variable); _genClosure(node, node.variable.name!, node.function); + _emitSourcePosition(); _genStoreVar(node.variable); } @@ -4394,8 +4376,9 @@ class BytecodeGenerator extends RecursiveVisitor { asm.currentSourcePositionFlags |= SourcePositions.syntheticFlag; } if (emitStore) { - // Record the source position at the start of the bytecode generated - // for storing the variable. + // Record the source position of the declaration at the start of + // the generated bytecode since debugger tests expect to pause + // at the declaration prior to running the initializer (if any). if (initializer != null) { _recordSourcePosition(node.fileEqualsOffset); } diff --git a/pkg/dart2bytecode/lib/local_vars.dart b/pkg/dart2bytecode/lib/local_vars.dart index 738155f458f..6d8b4678f4f 100644 --- a/pkg/dart2bytecode/lib/local_vars.dart +++ b/pkg/dart2bytecode/lib/local_vars.dart @@ -1003,19 +1003,37 @@ class _Allocator extends RecursiveVisitor { _visitFunction(node); } + // A temporary is only needed for function declarations or expressions when: + // * There are function type arguments to capture. + // * The function is generic and so the delayed type arguments field of the + // closure must be empty-initialized, not null-initialized. + bool _closureAllocationNeedsTemp(FunctionNode function) => + _currentFrame.functionTypeArgsVar != null || + function.typeParameters.isNotEmpty; + @override void visitFunctionDeclaration(FunctionDeclaration node) { _allocateVariable(node.variable); - _allocateTemp(node); + final needsTemp = _closureAllocationNeedsTemp(node.function); + if (needsTemp) { + _allocateTemp(node); + } _visitFunction(node); - _freeTemp(node); + if (needsTemp) { + _freeTemp(node); + } } @override void visitFunctionExpression(FunctionExpression node) { - _allocateTemp(node); + final needsTemp = _closureAllocationNeedsTemp(node.function); + if (needsTemp) { + _allocateTemp(node); + } _visitFunction(node); - _freeTemp(node); + if (needsTemp) { + _freeTemp(node); + } } @override @@ -1178,8 +1196,8 @@ class _Allocator extends RecursiveVisitor { @override void visitVariableSet(VariableSet node) { - final v = node.variable; - final bool needsTemp = locals.isCaptured(v) || v.isLate && v.isFinal; + final bool needsTemp = + node.parent is! ExpressionStatement && locals.isCaptured(node.variable); _visit(node, temps: needsTemp ? 1 : 0); } diff --git a/pkg/dart2bytecode/testcases/async.dart.expect b/pkg/dart2bytecode/testcases/async.dart.expect index 156e9dd5e67..fcc7274fdb9 100644 --- a/pkg/dart2bytecode/testcases/async.dart.expect +++ b/pkg/dart2bytecode/testcases/async.dart.expect @@ -9,13 +9,12 @@ Class '', script = 'DART_SDK/pkg/dart2bytecode/testcases/async.dart' Field 'asyncInFieldInitializer', type = FunctionType (dart:async::Future < dart:core::int >) -> dart:async::Future < Null >, getter = 'get:asyncInFieldInitializer', reflectable, static, is-late, has-initializer initializer Bytecode { - Entry 3 + Entry 2 CheckStack 0 PushConstant CP#0 Push r0 PushNull AllocateClosure - StoreLocal r2 ReturnTOS } ConstantPool { @@ -530,7 +529,7 @@ Function 'closure', static, reflectable, debuggable return-type dynamic Bytecode { - Entry 4 + Entry 3 CheckStack 0 AllocateContext 0, 2 PopLocal r0 @@ -544,7 +543,6 @@ Bytecode { Push r0 PushNull AllocateClosure - StoreLocal r3 PopLocal r2 Push r2 ReturnTOS diff --git a/pkg/dart2bytecode/testcases/closures.dart.expect b/pkg/dart2bytecode/testcases/closures.dart.expect index 1178a1f1aea..e78de99a3ef 100644 --- a/pkg/dart2bytecode/testcases/closures.dart.expect +++ b/pkg/dart2bytecode/testcases/closures.dart.expect @@ -23,7 +23,6 @@ Bytecode { Push r0 PushNull AllocateClosure - StoreLocal r3 PopLocal r2 Push r2 StoreLocal r3 @@ -47,7 +46,7 @@ ConstantPool { } Closure DART_SDK/pkg/dart2bytecode/testcases/closures.dart::simpleClosure::'' (dart:core::int y) -> Null ClosureCode { - Entry 3 + Entry 2 Push FP[-6] LoadFieldTOS CP#1 PopLocal r0 @@ -780,7 +779,6 @@ Bytecode { Push r0 PushNull AllocateClosure - StoreLocal r4 PopLocal r3 Push r3 StoreLocal r4 @@ -812,7 +810,6 @@ Bytecode { Push r0 PushNull AllocateClosure - StoreLocal r3 PopLocal r2 Push r2 StoreLocal r3 @@ -888,10 +885,9 @@ L1: Push r0 PushNull AllocateClosure - StoreLocal r2 - PopLocal r3 - Push r3 - Push r3 + PopLocal r2 + Push r2 + Push r2 UncheckedClosureCall CP#10, 1 Drop1 Push r0 @@ -905,7 +901,7 @@ L2: Closure DART_SDK/pkg/dart2bytecode/testcases/closures.dart::B::topLevel::Closure/0::'closure2' () -> void ClosureCode { - Entry 3 + Entry 2 Push FP[-5] LoadFieldTOS CP#1 PopLocal r0 @@ -1012,7 +1008,6 @@ L2: Push r0 PushNull AllocateClosure - StoreLocal r4 InstantiatedInterfaceCall CP#7, 2 Drop1 Push r3 @@ -1020,7 +1015,6 @@ L2: Push r0 PushNull AllocateClosure - StoreLocal r4 InstantiatedInterfaceCall CP#7, 2 Drop1 Push r0 @@ -1081,7 +1075,7 @@ ClosureCode { Closure DART_SDK/pkg/dart2bytecode/testcases/closures.dart::C::testForLoop::'' (dart:core::int ii) -> Null ClosureCode { - Entry 3 + Entry 2 Push FP[-6] LoadFieldTOS CP#4 PopLocal r0 @@ -1132,7 +1126,6 @@ L2: Push r0 PushNull AllocateClosure - StoreLocal r4 PopLocal r3 Push r3 StoreLocal r4 @@ -1168,7 +1161,7 @@ ConstantPool { } Closure DART_SDK/pkg/dart2bytecode/testcases/closures.dart::C::testForInLoop::'' () -> Null ClosureCode { - Entry 3 + Entry 2 Push FP[-5] LoadFieldTOS CP#7 PopLocal r0 @@ -1212,7 +1205,7 @@ Function 'foo', reflectable, debuggable return-type dynamic Bytecode { - Entry 3 + Entry 2 CheckStack 0 AllocateContext 0, 1 PopLocal r0 @@ -1234,7 +1227,6 @@ L1: Push FP[-6] LoadTypeArgumentsField CP#1 AllocateClosure - StoreLocal r2 ReturnTOS } Parameter flags: [2] @@ -1266,7 +1258,7 @@ Function 'bar', reflectable, debuggable return-type dynamic Bytecode { - Entry 3 + Entry 2 CheckStack 0 AllocateContext 0, 1 PopLocal r0 @@ -1278,7 +1270,6 @@ Bytecode { Push FP[-5] LoadTypeArgumentsField CP#5 AllocateClosure - StoreLocal r2 ReturnTOS } ConstantPool { @@ -1304,7 +1295,6 @@ ClosureCode { LoadContextVar 0, 0 LoadTypeArgumentsField CP#5 AllocateClosure - StoreLocal r3 PopLocal r2 Push r2 Push r2 diff --git a/pkg/dart2bytecode/testcases/try_blocks.dart.expect b/pkg/dart2bytecode/testcases/try_blocks.dart.expect index 8396252be36..09ee8162869 100644 --- a/pkg/dart2bytecode/testcases/try_blocks.dart.expect +++ b/pkg/dart2bytecode/testcases/try_blocks.dart.expect @@ -219,7 +219,6 @@ Try #0 start: Push r0 PushNull AllocateClosure - StoreLocal r5 PopLocal r4 Push r4 Push r4 @@ -270,7 +269,6 @@ Try #0 handler: Push r0 PushNull AllocateClosure - StoreLocal r5 PopLocal r6 Push r6 ReturnTOS @@ -282,7 +280,7 @@ L1: ReturnTOS } ExceptionsTable { - try-index 0, outer -1, start 20, end 58, handler 58, needs-stack-trace, types [CP#6] + try-index 0, outer -1, start 20, end 56, handler 56, needs-stack-trace, types [CP#6] } ConstantPool { [0] = ClosureFunction 0 @@ -309,7 +307,7 @@ ConstantPool { } Closure DART_SDK/pkg/dart2bytecode/testcases/try_blocks.dart::testTryCatch3::'foo' () -> void ClosureCode { - Entry 6 + Entry 5 Push FP[-5] LoadFieldTOS CP#1 PopLocal r0 @@ -323,7 +321,7 @@ Try #0 start: Jump L1 Try #0 end: Try #0 handler: - SetFrame 6 + SetFrame 5 Push r2 PopLocal r0 MoveSpecial exception, r2 @@ -594,7 +592,6 @@ Try #1 start: Push r0 PushNull AllocateClosure - StoreLocal r8 PopLocal r7 Push r7 Push r7 @@ -651,8 +648,8 @@ L3: ReturnTOS } ExceptionsTable { - try-index 0, outer -1, start 53, end 136, handler 136, needs-stack-trace, synthetic, types [CP#11] - try-index 1, outer 0, start 70, end 98, handler 98, needs-stack-trace, synthetic, types [CP#11] + try-index 0, outer -1, start 53, end 134, handler 134, needs-stack-trace, synthetic, types [CP#11] + try-index 1, outer 0, start 70, end 96, handler 96, needs-stack-trace, synthetic, types [CP#11] } ConstantPool { [0] = InterfaceCall 'dart:core::Object::==', ArgDesc num-args 2, num-type-args 0, names [] @@ -697,7 +694,7 @@ Function 'testTryFinally3', static, reflectable, debuggable return-type dynamic Bytecode { - Entry 6 + Entry 5 CheckStack 0 AllocateContext 0, 1 PopLocal r0 @@ -713,12 +710,11 @@ Try #0 start: Push r0 PushNull AllocateClosure - StoreLocal r5 PopLocal r2 Jump L1 Try #0 end: Try #0 handler: - SetFrame 6 + SetFrame 5 Push r3 PopLocal r0 MoveSpecial exception, r3 @@ -750,7 +746,7 @@ L1: ReturnTOS } ExceptionsTable { - try-index 0, outer -1, start 23, end 37, handler 37, needs-stack-trace, synthetic, types [CP#6] + try-index 0, outer -1, start 23, end 35, handler 35, needs-stack-trace, synthetic, types [CP#6] } ConstantPool { [0] = ClosureFunction 0