[dart2bytecode, vm/interpreter] await/yield/yield*

TEST=language tests in vm-aot-dyn-linux-debug-x64 configuration

Change-Id: I205bec19c2072fe9ac11a3211123bba43cb99d5e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381945
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov
2024-08-26 20:35:18 +00:00
committed by Commit Queue
parent 0d368ce290
commit 062b0738e3
18 changed files with 1866 additions and 1461 deletions
+5 -21
View File
@@ -460,6 +460,11 @@ class BytecodeAssembler {
_emitJumpInstruction(Opcode.kJumpIfUnchecked, label);
}
@pragma('vm:prefer-inline')
void emitSuspend(Label label) {
_emitJumpInstruction(Opcode.kSuspend, label);
}
@pragma('vm:prefer-inline')
void emitReturnTOS() {
emitSourcePosition();
@@ -467,27 +472,6 @@ class BytecodeAssembler {
isUnreachable = true;
}
@pragma('vm:prefer-inline')
void emitReturnAsync() {
emitSourcePosition();
_emitInstruction0(Opcode.kReturnAsync);
isUnreachable = true;
}
@pragma('vm:prefer-inline')
void emitReturnAsyncStar() {
emitSourcePosition();
_emitInstruction0(Opcode.kReturnAsyncStar);
isUnreachable = true;
}
@pragma('vm:prefer-inline')
void emitReturnSyncStar() {
emitSourcePosition();
_emitInstruction0(Opcode.kReturnSyncStar);
isUnreachable = true;
}
@pragma('vm:prefer-inline')
void emitPush(int rx) {
_emitInstructionX(Opcode.kPush, rx);
+134 -10
View File
@@ -957,12 +957,47 @@ class BytecodeGenerator extends RecursiveVisitor {
late Procedure initAsync =
libraryIndex.getProcedure('dart:async', '_SuspendState', '_initAsync');
late Procedure suspendStateFunctionData = libraryIndex.getProcedure(
'dart:async',
'_SuspendState',
LibraryIndex.getterPrefix + '_functionData');
late Procedure initAsyncStar = libraryIndex.getProcedure(
'dart:async', '_SuspendState', '_initAsyncStar');
late Procedure initSyncStar =
libraryIndex.getProcedure('dart:async', '_SuspendState', '_initSyncStar');
late Procedure _await =
libraryIndex.getProcedure('dart:async', '_SuspendState', '_await');
late Procedure _awaitWithTypeCheck = libraryIndex.getProcedure(
'dart:async', '_SuspendState', '_awaitWithTypeCheck');
late Procedure yieldAsyncStar = libraryIndex.getProcedure(
'dart:async', '_SuspendState', '_yieldAsyncStar');
late Procedure suspendSyncStarAtStart = libraryIndex.getProcedure(
'dart:async', '_SuspendState', '_suspendSyncStarAtStart');
late Procedure returnAsync =
libraryIndex.getProcedure('dart:async', '_SuspendState', '_returnAsync');
late Procedure returnAsyncStar = libraryIndex.getProcedure(
'dart:async', '_SuspendState', '_returnAsyncStar');
late Procedure asyncStarStreamControllerAdd = libraryIndex.getProcedure(
'dart:async', '_AsyncStarStreamController', 'add');
late Procedure asyncStarStreamControllerAddStream = libraryIndex.getProcedure(
'dart:async', '_AsyncStarStreamController', 'addStream');
late Field syncStarIteratorCurrent =
libraryIndex.getField('dart:async', '_SyncStarIterator', '_current');
late Field syncStarIteratorYieldStarIterable = libraryIndex.getField(
'dart:async', '_SyncStarIterator', '_yieldStarIterable');
late Library? dartFfiLibrary = libraryIndex.tryGetLibrary('dart:ffi');
void _recordSourcePosition(int fileOffset) {
@@ -1144,19 +1179,29 @@ class BytecodeGenerator extends RecursiveVisitor {
void _genReturnTOS() {
final enclosingFunction = this.enclosingFunction;
if (enclosingFunction != null) {
Procedure? returnMethod;
switch (enclosingFunction.dartAsyncMarker) {
case AsyncMarker.Async:
asm.emitReturnAsync();
return;
returnMethod = returnAsync;
break;
case AsyncMarker.AsyncStar:
asm.emitReturnAsyncStar();
return;
returnMethod = returnAsyncStar;
break;
case AsyncMarker.SyncStar:
asm.emitReturnSyncStar();
return;
asm.emitDrop1();
asm.emitPushFalse();
break;
case AsyncMarker.Sync:
break;
}
if (returnMethod != null) {
asm.emitPopLocal(locals.returnVarIndexInFrame);
asm.emitPush(locals.suspendStateVarIndexInFrame);
asm.emitPush(locals.returnVarIndexInFrame);
asm.emitPushNull();
asm.emitPopLocal(locals.suspendStateVarIndexInFrame);
_genDirectCall(returnMethod, objectTable.getArgDescHandle(2), 2);
}
}
asm.emitReturnTOS();
}
@@ -1625,8 +1670,20 @@ class BytecodeGenerator extends RecursiveVisitor {
asm.emitPopLocal(locals.suspendStateVarIndexInFrame);
if (function.dartAsyncMarker != AsyncMarker.Async) {
// TODO(alexmarkov): suspend at start for async* and sync*
_unimplemented(function, '${function.dartAsyncMarker}');
// Suspend async* and sync* functions after prologue is finished.
Label done = Label();
asm.emitSuspend(done);
final suspendMethod = (function.dartAsyncMarker == AsyncMarker.AsyncStar)
? yieldAsyncStar
: suspendSyncStarAtStart;
asm.emitPush(locals.suspendStateVarIndexInFrame);
asm.emitPushNull();
_genDirectCall(suspendMethod, objectTable.getArgDescHandle(2), 2);
asm.emitReturnTOS();
asm.bind(done);
asm.emitDrop1(); // Discard result of Suspend.
}
if (function.dartAsyncMarker == AsyncMarker.SyncStar &&
@@ -4210,12 +4267,79 @@ class BytecodeGenerator extends RecursiveVisitor {
@override
void visitAwaitExpression(AwaitExpression node) {
_unimplemented(node, 'AwaitExpression');
_generateNode(node.operand);
final int temp = locals.tempIndexInFrame(node);
asm.emitPopLocal(temp);
Label done = Label();
asm.emitSuspend(done);
final runtimeCheckType = node.runtimeCheckType;
if (runtimeCheckType != null) {
assert((runtimeCheckType as InterfaceType).classNode ==
coreTypes.futureClass);
_genTypeArguments((runtimeCheckType as InterfaceType).typeArguments);
asm.emitPush(locals.suspendStateVarIndexInFrame);
asm.emitPush(temp);
_genDirectCall(
_awaitWithTypeCheck, objectTable.getArgDescHandle(2, 1), 3);
} else {
asm.emitPush(locals.suspendStateVarIndexInFrame);
asm.emitPush(temp);
_genDirectCall(_await, objectTable.getArgDescHandle(2), 2);
}
asm.emitReturnTOS();
asm.bind(done);
}
@override
void visitYieldStatement(YieldStatement node) {
_unimplemented(node, 'YieldStatement');
asm.emitPush(locals.suspendStateVarIndexInFrame);
_genDirectCall(
suspendStateFunctionData, objectTable.getArgDescHandle(1), 1);
_generateNode(node.expression);
if (enclosingFunction!.dartAsyncMarker == AsyncMarker.AsyncStar) {
Procedure addMethod = node.isYieldStar
? asyncStarStreamControllerAddStream
: asyncStarStreamControllerAdd;
_genDirectCall(addMethod, objectTable.getArgDescHandle(2), 2);
Label ret = Label(allowsBackwardJumps: true);
asm.emitJumpIfTrue(ret);
Label resume = Label();
asm.emitSuspend(resume);
asm.emitPush(locals.suspendStateVarIndexInFrame);
asm.emitPushNull();
_genDirectCall(yieldAsyncStar, objectTable.getArgDescHandle(2), 2);
asm.emitDrop1();
asm.bind(ret);
asm.emitPushNull();
asm.emitReturnTOS();
asm.bind(resume);
asm.emitJumpIfTrue(ret);
} else if (enclosingFunction!.dartAsyncMarker == AsyncMarker.SyncStar) {
Field field = node.isYieldStar
? syncStarIteratorYieldStarIterable
: syncStarIteratorCurrent;
asm.emitStoreFieldTOS(cp.addInstanceField(field));
Label done = Label();
asm.emitSuspend(done);
asm.emitPushTrue();
asm.emitReturnTOS();
asm.bind(done);
asm.emitDrop1();
} else {
throw 'Unexpected ${enclosingFunction!.dartAsyncMarker}';
}
}
void _unimplemented(TreeNode node, String what) {
+7 -20
View File
@@ -125,6 +125,9 @@ enum Opcode {
kJumpIfNotNull,
kJumpIfNotNull_Wide,
kSuspend,
kSuspend_Wide,
// Calls.
kDirectCall,
kDirectCall_Wide,
@@ -143,9 +146,7 @@ enum Opcode {
kDynamicCall,
kDynamicCall_Wide,
kReturnTOS,
kReturnAsync,
kReturnAsyncStar,
kReturnSyncStar,
kUnused25,
// Types and type checks.
kAssertAssignable,
@@ -359,6 +360,8 @@ const Map<Opcode, Format> BytecodeFormats = const {
Encoding.kT, const [Operand.tgt, Operand.none, Operand.none]),
Opcode.kJumpIfUnchecked: const Format(
Encoding.kT, const [Operand.tgt, Operand.none, Operand.none]),
Opcode.kSuspend: const Format(
Encoding.kT, const [Operand.tgt, Operand.none, Operand.none]),
Opcode.kInterfaceCall: const Format(
Encoding.kDF, const [Operand.lit, Operand.imm, Operand.none]),
Opcode.kInstantiatedInterfaceCall: const Format(
@@ -367,12 +370,6 @@ const Map<Opcode, Format> BytecodeFormats = const {
Encoding.kDF, const [Operand.lit, Operand.imm, Operand.none]),
Opcode.kReturnTOS: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kReturnAsync: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kReturnAsyncStar: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kReturnSyncStar: const Format(
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
Opcode.kAssertAssignable: const Format(
Encoding.kAE, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kAssertBoolean: const Format(
@@ -550,17 +547,7 @@ bool isCall(Opcode opcode) {
}
}
bool isReturn(Opcode opcode) {
switch (opcode) {
case Opcode.kReturnTOS:
case Opcode.kReturnAsync:
case Opcode.kReturnAsyncStar:
case Opcode.kReturnSyncStar:
return true;
default:
return false;
}
}
bool isReturn(Opcode opcode) => (opcode == Opcode.kReturnTOS);
bool isControlFlow(Opcode opcode) =>
isJump(opcode) || isThrow(opcode) || isCall(opcode) || isReturn(opcode);
+11
View File
@@ -340,6 +340,12 @@ class _ScopeBuilder extends RecursiveVisitor {
final suspendStateVar = _currentFrame.suspendStateVar =
VariableDeclaration(':suspend_state');
_declareVariable(suspendStateVar);
if (function.dartAsyncMarker != AsyncMarker.SyncStar) {
final returnVar =
_currentFrame.returnVar = VariableDeclaration(':return');
_declareVariable(returnVar);
}
}
if (node is Procedure && node.isFactory) {
@@ -1192,6 +1198,11 @@ class _Allocator extends RecursiveVisitor {
void visitNullCheck(NullCheck node) {
_visit(node, temps: 1);
}
@override
void visitAwaitExpression(AwaitExpression node) {
_visit(node, temps: 1);
}
}
class LocalVariableIndexOverflowException
+272 -121
View File
@@ -15,7 +15,7 @@ Bytecode {
StoreLocal r2
Push r2
PushConstant CP#0
StoreFieldTOS CP#10
StoreFieldTOS CP#14
Push r2
Push r0
StoreFieldTOS CP#1
@@ -31,14 +31,18 @@ ConstantPool {
[6] = ObjectRef < Null >
[7] = DirectCall 'dart:async::_SuspendState::_initAsync', ArgDesc num-args 0, num-type-args 1, names []
[8] = Reserved
[9] = EndClosureFunctionScope
[10] = InstanceField dart:core::_Closure::_function (field)
[11] = Reserved
[9] = DirectCall 'dart:async::_SuspendState::_await', ArgDesc num-args 2, num-type-args 0, names []
[10] = Reserved
[11] = DirectCall 'dart:async::_SuspendState::_returnAsync', ArgDesc num-args 2, num-type-args 0, names []
[12] = Reserved
[13] = EndClosureFunctionScope
[14] = InstanceField dart:core::_Closure::_function (field)
[15] = Reserved
}
Closure DART_SDK/pkg/dart2bytecode/testcases/async.dart::asyncInFieldInitializer (field)::'<anonymous closure>' async (dart:async::Future < dart:core::int > x) -> dart:async::Future < Null >
ClosureCode {
EntrySuspendable 2, 0, 0
Frame 3
Frame 5
Push r1
LoadFieldTOS CP#1
PopLocal r3
@@ -55,10 +59,23 @@ L1:
PushConstant CP#6
DirectCall CP#7, 1
PopLocal r0
Trap
Push r2
PopLocal r6
Suspend L2
Push r0
Push r6
DirectCall CP#9, 2
ReturnTOS
L2:
Drop1
PushNull
ReturnAsync
PopLocal r5
Push r0
Push r5
PushNull
PopLocal r0
DirectCall CP#11, 2
ReturnTOS
}
@@ -68,18 +85,26 @@ Function 'foo', static, reflectable, debuggable, async
Bytecode {
EntrySuspendable 0, 0, 0
Frame 1
Frame 2
CheckStack 0
PushConstant CP#0
DirectCall CP#1, 1
PopLocal r0
PushInt 42
ReturnAsync
PopLocal r1
Push r0
Push r1
PushNull
PopLocal r0
DirectCall CP#3, 2
ReturnTOS
}
ConstantPool {
[0] = ObjectRef < dart:core::int >
[1] = DirectCall 'dart:async::_SuspendState::_initAsync', ArgDesc num-args 0, num-type-args 1, names []
[2] = Reserved
[3] = DirectCall 'dart:async::_SuspendState::_returnAsync', ArgDesc num-args 2, num-type-args 0, names []
[4] = Reserved
}
@@ -89,20 +114,44 @@ Function 'simpleAsyncAwait', static, reflectable, debuggable, async
Bytecode {
EntrySuspendable 2, 0, 0
Frame 1
Frame 3
CheckStack 0
PushConstant CP#0
DirectCall CP#1, 1
PopLocal r0
Trap
Trap
Push r1
PopLocal r4
Suspend L1
Push r0
Push r4
DirectCall CP#3, 2
ReturnTOS
L1:
Push r2
PopLocal r4
Suspend L2
Push r0
Push r4
DirectCall CP#3, 2
ReturnTOS
L2:
AddInt
ReturnAsync
PopLocal r3
Push r0
Push r3
PushNull
PopLocal r0
DirectCall CP#5, 2
ReturnTOS
}
ConstantPool {
[0] = ObjectRef < dart:core::int >
[1] = DirectCall 'dart:async::_SuspendState::_initAsync', ArgDesc num-args 0, num-type-args 1, names []
[2] = Reserved
[3] = DirectCall 'dart:async::_SuspendState::_await', ArgDesc num-args 2, num-type-args 0, names []
[4] = Reserved
[5] = DirectCall 'dart:async::_SuspendState::_returnAsync', ArgDesc num-args 2, num-type-args 0, names []
[6] = Reserved
}
@@ -112,70 +161,83 @@ Function 'loops', static, reflectable, debuggable, async
Bytecode {
EntrySuspendable 1, 0, 0
Frame 5
Frame 7
CheckStack 0
PushConstant CP#0
DirectCall CP#1, 1
PopLocal r0
PushInt 0
PopLocal r2
PushInt 0
PopLocal r3
L4:
PushInt 0
PopLocal r4
L5:
CheckStack 1
Push r3
Push r4
PushInt 10
CompareIntLt
JumpIfFalse L1
Push r1
InterfaceCall CP#3, 1
PopLocal r4
L3:
PopLocal r5
L4:
CheckStack 2
Push r4
Push r5
InterfaceCall CP#5, 1
JumpIfFalse L2
Push r4
InterfaceCall CP#7, 1
PopLocal r5
Push r2
Push r3
Push r5
AddInt
Trap
AddInt
AddInt
PopLocal r2
Jump L3
L2:
InterfaceCall CP#7, 1
PopLocal r6
Push r3
Push r4
Push r6
AddInt
DirectCall CP#9, 0
PopLocal r7
Suspend L3
Push r0
Push r7
DirectCall CP#11, 2
ReturnTOS
L3:
AddInt
AddInt
PopLocal r3
Jump L4
L2:
Push r4
PushInt 1
AddInt
StoreLocal r3
StoreLocal r4
Drop1
Jump L4
Jump L5
L1:
PushInt 0
PopLocal r3
L6:
PopLocal r4
L7:
CheckStack 1
Push r3
Push r4
PushInt 10
CompareIntLt
JumpIfFalse L5
Push r2
JumpIfFalse L6
Push r3
Push r4
AddInt
PopLocal r2
Push r3
PopLocal r3
Push r4
PushInt 1
AddInt
StoreLocal r3
StoreLocal r4
Drop1
Jump L6
L5:
Jump L7
L6:
Push r3
PopLocal r2
Push r0
Push r2
ReturnAsync
PushNull
PopLocal r0
DirectCall CP#13, 2
ReturnTOS
}
ConstantPool {
[0] = ObjectRef < dart:core::int >
@@ -187,6 +249,12 @@ ConstantPool {
[6] = Reserved
[7] = InterfaceCall 'dart:core::Iterator::get:current', ArgDesc num-args 1, num-type-args 0, names []
[8] = Reserved
[9] = DirectCall 'DART_SDK/pkg/dart2bytecode/testcases/async.dart::foo', ArgDesc num-args 0, num-type-args 0, names []
[10] = Reserved
[11] = DirectCall 'dart:async::_SuspendState::_await', ArgDesc num-args 2, num-type-args 0, names []
[12] = Reserved
[13] = DirectCall 'dart:async::_SuspendState::_returnAsync', ArgDesc num-args 2, num-type-args 0, names []
[14] = Reserved
}
@@ -196,93 +264,150 @@ Function 'tryCatchRethrow', static, reflectable, debuggable, async
Bytecode {
EntrySuspendable 3, 0, 0
Frame 7
Frame 9
CheckStack 0
PushConstant CP#0
DirectCall CP#1, 1
PopLocal r0
PushInt 1
PopLocal r4
PopLocal r5
Try #0 start:
Try #1 start:
Push r4
Trap
Push r5
Push r1
PopLocal r10
Suspend L1
Push r0
Push r10
DirectCall CP#3, 2
ReturnTOS
L1:
AddInt
PopLocal r4
Jump L1
PopLocal r5
Jump L2
Try #1 end:
Try #1 handler:
SetFrame 10
MoveSpecial exception, r7
MoveSpecial stackTrace, r8
Push r7
PopLocal r9
Push r9
PushConstant CP#4
InterfaceCall CP#5, 2
JumpIfFalse L2
Jump L3
L2:
Push r4
Trap
AddInt
PopLocal r4
Push r7
SetFrame 12
MoveSpecial exception, r8
MoveSpecial stackTrace, r9
Push r8
Throw 1
L1:
PopLocal r10
Push r10
PushConstant CP#6
InterfaceCall CP#7, 2
JumpIfFalse L3
Jump L4
L3:
Push r5
Push r2
PopLocal r11
Suspend L5
Push r0
Push r11
DirectCall CP#3, 2
ReturnTOS
L5:
AddInt
PopLocal r5
Push r8
Push r9
Throw 1
L2:
Jump L6
Try #0 end:
Try #0 handler:
SetFrame 10
MoveSpecial exception, r5
MoveSpecial stackTrace, r6
PushConstant CP#8
DirectCall CP#9, 1
SetFrame 12
MoveSpecial exception, r6
MoveSpecial stackTrace, r7
PushConstant CP#10
DirectCall CP#11, 1
Drop1
Push r4
Trap
Push r5
Push r3
PopLocal r8
Suspend L7
Push r0
Push r8
DirectCall CP#3, 2
ReturnTOS
L7:
AddInt
PopLocal r5
Push r5
PopLocal r4
Push r0
Push r4
ReturnAsync
L3:
PushConstant CP#8
DirectCall CP#9, 1
Drop1
Push r4
Trap
AddInt
PopLocal r4
Push r4
ReturnAsync
PushNull
PopLocal r0
DirectCall CP#13, 2
ReturnTOS
L4:
PushConstant CP#8
DirectCall CP#9, 1
PushConstant CP#10
DirectCall CP#11, 1
Drop1
Push r4
Trap
Push r5
Push r3
PopLocal r8
Suspend L8
Push r0
Push r8
DirectCall CP#3, 2
ReturnTOS
L8:
AddInt
PopLocal r5
Push r5
PopLocal r4
Push r0
Push r4
ReturnAsync
PushNull
PopLocal r0
DirectCall CP#13, 2
ReturnTOS
L6:
PushConstant CP#10
DirectCall CP#11, 1
Drop1
Push r5
Push r3
PopLocal r8
Suspend L9
Push r0
Push r8
DirectCall CP#3, 2
ReturnTOS
L9:
AddInt
PopLocal r5
Push r5
PopLocal r4
Push r0
Push r4
PushNull
PopLocal r0
DirectCall CP#13, 2
ReturnTOS
}
ExceptionsTable {
try-index 0, outer -1, start 19, end 72, handler 72, needs-stack-trace, synthetic, types [CP#7]
try-index 1, outer 0, start 19, end 29, handler 29, needs-stack-trace, types [CP#3]
try-index 0, outer -1, start 19, end 102, handler 102, needs-stack-trace, synthetic, types [CP#9]
try-index 1, outer 0, start 19, end 44, handler 44, needs-stack-trace, types [CP#5]
}
ConstantPool {
[0] = ObjectRef < dart:core::int >
[1] = DirectCall 'dart:async::_SuspendState::_initAsync', ArgDesc num-args 0, num-type-args 1, names []
[2] = Reserved
[3] = Type dart:core::Object
[4] = Type dart:core::Error
[5] = InterfaceCall 'dart:core::Object::_simpleInstanceOf', ArgDesc num-args 2, num-type-args 0, names []
[6] = Reserved
[7] = Type dynamic
[8] = ObjectRef 'fin'
[9] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
[10] = Reserved
[3] = DirectCall 'dart:async::_SuspendState::_await', ArgDesc num-args 2, num-type-args 0, names []
[4] = Reserved
[5] = Type dart:core::Object
[6] = Type dart:core::Error
[7] = InterfaceCall 'dart:core::Object::_simpleInstanceOf', ArgDesc num-args 2, num-type-args 0, names []
[8] = Reserved
[9] = Type dynamic
[10] = ObjectRef 'fin'
[11] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
[12] = Reserved
[13] = DirectCall 'dart:async::_SuspendState::_returnAsync', ArgDesc num-args 2, num-type-args 0, names []
[14] = Reserved
}
@@ -305,7 +430,7 @@ Bytecode {
StoreLocal r3
Push r3
PushConstant CP#0
StoreFieldTOS CP#11
StoreFieldTOS CP#15
Push r3
Push r0
StoreFieldTOS CP#1
@@ -320,13 +445,17 @@ ConstantPool {
[3] = ObjectRef < dart:core::int >
[4] = DirectCall 'dart:async::_SuspendState::_initAsync', ArgDesc num-args 0, num-type-args 1, names []
[5] = Reserved
[6] = Type dynamic
[7] = ObjectRef 'fin'
[8] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
[9] = Reserved
[10] = EndClosureFunctionScope
[11] = InstanceField dart:core::_Closure::_function (field)
[12] = Reserved
[6] = DirectCall 'dart:async::_SuspendState::_await', ArgDesc num-args 2, num-type-args 0, names []
[7] = Reserved
[8] = Type dynamic
[9] = ObjectRef 'fin'
[10] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
[11] = Reserved
[12] = DirectCall 'dart:async::_SuspendState::_returnAsync', ArgDesc num-args 2, num-type-args 0, names []
[13] = Reserved
[14] = EndClosureFunctionScope
[15] = InstanceField dart:core::_Closure::_function (field)
[16] = Reserved
}
Closure DART_SDK/pkg/dart2bytecode/testcases/async.dart::closure::'nested' async () -> dart:async::Future < dart:core::int >
ClosureCode {
@@ -347,14 +476,22 @@ Try #0 start:
Push r2
PushInt 5
StoreContextVar 0, 1
Trap
Push r2
LoadContextVar 0, 0
PopLocal r8
Suspend L1
Push r0
Push r8
DirectCall CP#6, 2
ReturnTOS
L1:
PopLocal r5
Push r2
LoadContextVar 0, 1
Push r5
AddInt
PopLocal r4
Jump L1
Jump L2
Try #0 end:
Try #0 handler:
SetFrame 9
@@ -362,20 +499,26 @@ Try #0 handler:
PopLocal r2
MoveSpecial exception, r6
MoveSpecial stackTrace, r7
PushConstant CP#7
DirectCall CP#8, 1
PushConstant CP#9
DirectCall CP#10, 1
Drop1
Push r6
Push r7
Throw 1
L1:
L2:
Push r6
PopLocal r2
PushConstant CP#7
DirectCall CP#8, 1
PushConstant CP#9
DirectCall CP#10, 1
Drop1
Push r4
ReturnAsync
PopLocal r4
Push r0
Push r4
PushNull
PopLocal r0
DirectCall CP#12, 2
ReturnTOS
}
@@ -385,18 +528,26 @@ Function 'testAssert', static, reflectable, debuggable, async
Bytecode {
EntrySuspendable 1, 0, 0
Frame 1
Frame 2
CheckStack 0
PushConstant CP#0
DirectCall CP#1, 1
PopLocal r0
PushInt 7
ReturnAsync
PopLocal r2
Push r0
Push r2
PushNull
PopLocal r0
DirectCall CP#3, 2
ReturnTOS
}
ConstantPool {
[0] = ObjectRef < dart:core::int >
[1] = DirectCall 'dart:async::_SuspendState::_initAsync', ArgDesc num-args 0, num-type-args 1, names []
[2] = Reserved
[3] = DirectCall 'dart:async::_SuspendState::_returnAsync', ArgDesc num-args 2, num-type-args 0, names []
[4] = Reserved
}
+3 -2
View File
@@ -78,8 +78,9 @@ class ExceptionHandlerList : public ZoneAllocated {
explicit ExceptionHandlerList(const Function& function)
: list_(),
has_async_handler_(function.IsAsyncFunction() ||
function.IsAsyncGenerator()) {}
has_async_handler_(
(function.IsAsyncFunction() || function.IsAsyncGenerator()) &&
!function.is_declared_in_bytecode()) {}
intptr_t Length() const { return list_.length(); }
+2
View File
@@ -620,7 +620,9 @@ void Precompiler::DoCompileAll() {
IG->object_store()->set_simple_instance_of_true_function(null_function);
IG->object_store()->set_simple_instance_of_false_function(
null_function);
#if !defined(DART_DYNAMIC_MODULES)
IG->object_store()->set_async_star_stream_controller(null_class);
#endif
IG->object_store()->set_native_assets_library(null_library);
DropMetadata();
DropLibraryEntries();
File diff suppressed because it is too large Load Diff
+23
View File
@@ -2586,6 +2586,29 @@ void StubCodeCompiler::GenerateCloneSuspendStateStub() {
__ Ret();
}
void StubCodeCompiler::GenerateResumeInterpreterStub() {
#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32)
// On X64/IA32 execution is resumed at PC + kResumePcDistance.
const intptr_t start = __ CodeSize();
for (intptr_t i = 0; i < SuspendStubABI::kResumePcDistance; ++i) {
__ nop();
}
RELEASE_ASSERT(__ CodeSize() - start == SuspendStubABI::kResumePcDistance);
#endif
#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
SPILLS_LR_TO_FRAME({}); // Simulate entering the caller (Dart) frame.
#endif
__ PushObject(NullObject()); // Make room for result.
__ PushRegister(CallingConventions::kReturnReg);
__ CallRuntime(kResumeInterpreterRuntimeEntry, /*argument_count=*/1);
__ Drop(1); // Drop argument.
__ PopRegister(CallingConventions::kReturnReg); // Get result.
__ LeaveDartFrame();
__ Ret();
}
void StubCodeCompiler::GenerateFfiAsyncCallbackSendStub() {
__ EnterStubFrame();
__ PushObject(NullObject()); // Make space on stack for the return value.
+13 -62
View File
@@ -290,6 +290,16 @@ namespace dart {
//
// Jump to the given target if SP[0] is true/false/null/not null.
//
// - Suspend target
//
// Create a snapshot of the current frame and store it in the suspend
// state object. Execution can be resumed from the suspend state
// at the given target PC.
// Target is specified as offset from the PC of the suspend instruction.
// The filled suspend state object is stored into the reserved suspend
// state local variable. Current function frame should be created with
// EntrySuspendable instruction.
//
// - IndirectStaticCall ArgC, D
//
// Invoke the function given by the ICData in SP[0] with arguments
@@ -329,21 +339,6 @@ namespace dart {
// stack because it can look at the call instruction at caller's PC and
// take argument count from it.
//
// - ReturnAsync
//
// Return to the caller from async function using a value from
// the top-of-stack as a result.
//
// - ReturnAsyncStar
//
// Return to the caller from async* function using a value from
// the top-of-stack as a result.
//
// - ReturnSyncStar
//
// Return to the caller from sync* function using a value from
// the top-of-stack as a result.
//
// - AssertAssignable A, D
//
// Assert that instance SP[-4] is assignable to variable named SP[0] of
@@ -573,6 +568,8 @@ namespace dart {
V(JumpIfNull_Wide, T, WIDE, tgt, ___, ___) \
V(JumpIfNotNull, T, ORDN, tgt, ___, ___) \
V(JumpIfNotNull_Wide, T, WIDE, tgt, ___, ___) \
V(Suspend, T, ORDN, tgt, ___, ___) \
V(Suspend_Wide, T, WIDE, tgt, ___, ___) \
V(DirectCall, D_F, ORDN, num, num, ___) \
V(DirectCall_Wide, D_F, WIDE, num, num, ___) \
V(UncheckedDirectCall, D_F, ORDN, num, num, ___) \
@@ -590,9 +587,7 @@ namespace dart {
V(DynamicCall, D_F, ORDN, num, num, ___) \
V(DynamicCall_Wide, D_F, WIDE, num, num, ___) \
V(ReturnTOS, 0, ORDN, ___, ___, ___) \
V(ReturnAsync, 0, ORDN, ___, ___, ___) \
V(ReturnAsyncStar, 0, ORDN, ___, ___, ___) \
V(ReturnSyncStar, 0, ORDN, ___, ___, ___) \
V(Unused25, 0, RESV, ___, ___, ___) \
V(AssertAssignable, A_E, ORDN, num, lit, ___) \
V(AssertAssignable_Wide, A_E, WIDE, num, lit, ___) \
V(Unused30, 0, RESV, ___, ___, ___) \
@@ -789,47 +784,6 @@ class KernelBytecode {
reinterpret_cast<const KBCInstr*>(pc))];
}
DART_FORCE_INLINE static bool IsJumpOpcode(const KBCInstr* instr) {
switch (DecodeOpcode(instr)) {
case KernelBytecode::kJump:
case KernelBytecode::kJump_Wide:
case KernelBytecode::kJumpIfNoAsserts:
case KernelBytecode::kJumpIfNoAsserts_Wide:
case KernelBytecode::kJumpIfNotZeroTypeArgs:
case KernelBytecode::kJumpIfNotZeroTypeArgs_Wide:
case KernelBytecode::kJumpIfEqStrict:
case KernelBytecode::kJumpIfEqStrict_Wide:
case KernelBytecode::kJumpIfNeStrict:
case KernelBytecode::kJumpIfNeStrict_Wide:
case KernelBytecode::kJumpIfTrue:
case KernelBytecode::kJumpIfTrue_Wide:
case KernelBytecode::kJumpIfFalse:
case KernelBytecode::kJumpIfFalse_Wide:
case KernelBytecode::kJumpIfNull:
case KernelBytecode::kJumpIfNull_Wide:
case KernelBytecode::kJumpIfNotNull:
case KernelBytecode::kJumpIfNotNull_Wide:
case KernelBytecode::kJumpIfUnchecked:
case KernelBytecode::kJumpIfUnchecked_Wide:
case KernelBytecode::kJumpIfInitialized:
case KernelBytecode::kJumpIfInitialized_Wide:
return true;
default:
return false;
}
}
DART_FORCE_INLINE static bool IsJumpIfUncheckedOpcode(const KBCInstr* instr) {
switch (DecodeOpcode(instr)) {
case KernelBytecode::kJumpIfUnchecked:
case KernelBytecode::kJumpIfUnchecked_Wide:
return true;
default:
return false;
}
}
DART_FORCE_INLINE static bool IsLoadConstantOpcode(const KBCInstr* instr) {
switch (DecodeOpcode(instr)) {
case KernelBytecode::kLoadConstant:
@@ -910,9 +864,6 @@ class KernelBytecode {
case KernelBytecode::kDynamicCall:
case KernelBytecode::kDynamicCall_Wide:
case KernelBytecode::kReturnTOS:
case KernelBytecode::kReturnAsync:
case KernelBytecode::kReturnAsyncStar:
case KernelBytecode::kReturnSyncStar:
case KernelBytecode::kEqualsNull:
case KernelBytecode::kNegateInt:
case KernelBytecode::kNegateDouble:
+203 -94
View File
@@ -361,6 +361,8 @@ Interpreter::Interpreter()
// High address.
stack_limit_ = overflow_stack_limit_ + OSThread::kStackSizeBufferMax;
fp_ = reinterpret_cast<ObjectPtr*>(stack_base_);
last_setjmp_buffer_ = nullptr;
DEBUG_ONLY(icount_ = 1); // So that tracing after 0 traces first bytecode.
@@ -1467,34 +1469,7 @@ bool Interpreter::AllocateClosure(Thread* thread,
}
}
ObjectPtr Interpreter::Call(FunctionPtr function,
ArrayPtr argdesc,
intptr_t argc,
ObjectPtr const* argv,
ArrayPtr args_array,
Thread* thread) {
// Interpreter state (see constants_kbc.h for high-level overview).
const KBCInstr* pc; // Program Counter: points to the next op to execute.
ObjectPtr* FP; // Frame Pointer.
ObjectPtr* SP; // Stack Pointer.
uint32_t op; // Currently executing op.
bool reentering = fp_ != nullptr;
if (!reentering) {
fp_ = reinterpret_cast<ObjectPtr*>(stack_base_);
}
#if defined(DEBUG)
if (IsTracingExecution()) {
THR_Print("%" Pu64 " ", icount_);
THR_Print("%s interpreter 0x%" Px " at fp_ 0x%" Px " exit 0x%" Px " %s\n",
reentering ? "Re-entering" : "Entering",
reinterpret_cast<uword>(this), reinterpret_cast<uword>(fp_),
thread->top_exit_frame_info(),
Function::Handle(function).ToFullyQualifiedCString());
}
#endif
void Interpreter::SetupEntryFrame(Thread* thread) {
// Setup entry frame:
//
// ^
@@ -1518,10 +1493,6 @@ ObjectPtr Interpreter::Call(FunctionPtr function,
// |
// v
//
// A negative argc indicates reverse memory order of arguments.
const intptr_t arg_count = argc < 0 ? -argc : argc;
FP = fp_ + kKBCEntrySavedSlots + arg_count + kKBCDartFrameFixedSize;
SP = FP - 1;
// Save outer top_exit_frame_info, current argdesc, and current pp.
fp_[kKBCExitLinkSlotFromEntryFp] =
@@ -1529,6 +1500,31 @@ ObjectPtr Interpreter::Call(FunctionPtr function,
thread->set_top_exit_frame_info(0);
fp_[kKBCSavedArgDescSlotFromEntryFp] = static_cast<ObjectPtr>(argdesc_);
fp_[kKBCSavedPpSlotFromEntryFp] = static_cast<ObjectPtr>(pp_);
}
ObjectPtr Interpreter::Call(FunctionPtr function,
ArrayPtr argdesc,
intptr_t argc,
ObjectPtr const* argv,
ArrayPtr args_array,
Thread* thread) {
#if defined(DEBUG)
if (IsTracingExecution()) {
THR_Print("%" Pu64 " ", icount_);
THR_Print("Entering interpreter 0x%" Px " at fp_ 0x%" Px " exit 0x%" Px
" %s\n",
reinterpret_cast<uword>(this), reinterpret_cast<uword>(fp_),
thread->top_exit_frame_info(),
Function::Handle(function).ToFullyQualifiedCString());
}
#endif
SetupEntryFrame(thread);
// A negative argc indicates reverse memory order of arguments.
const intptr_t arg_count = argc < 0 ? -argc : argc;
ObjectPtr* FP =
fp_ + kKBCEntrySavedSlots + arg_count + kKBCDartFrameFixedSize;
// Copy arguments and setup the Dart frame.
if (argv != nullptr) {
@@ -1554,10 +1550,87 @@ ObjectPtr Interpreter::Call(FunctionPtr function,
// Ready to start executing bytecode. Load entry point and corresponding
// object pool.
pc = reinterpret_cast<const KBCInstr*>(bytecode->untag()->instructions_);
NOT_IN_PRODUCT(pc_ = pc); // For the profiler.
NOT_IN_PRODUCT(fp_ = FP); // For the profiler.
pc_ = reinterpret_cast<const KBCInstr*>(bytecode->untag()->instructions_);
pp_ = bytecode->untag()->object_pool();
fp_ = FP;
return Run(thread, FP - 1);
}
ObjectPtr Interpreter::Resume(Thread* thread,
uword resumed_frame_fp,
uword resumed_frame_sp,
ObjectPtr value) {
const intptr_t suspend_state_index_from_fp =
runtime_frame_layout.FrameSlotForVariableIndex(
SuspendState::kSuspendStateVarIndex);
ASSERT(suspend_state_index_from_fp < 0);
// Resumed native frame wraps interpreter state.
ASSERT(resumed_frame_fp > resumed_frame_sp);
ASSERT(resumed_frame_fp - resumed_frame_sp >=
static_cast<uword>(-suspend_state_index_from_fp +
kKBCSuspendedFrameFixedSlots) *
kWordSize);
ObjectPtr* resumed_native_frame =
reinterpret_cast<ObjectPtr*>(resumed_frame_sp);
intptr_t interp_frame_size =
resumed_frame_fp - resumed_frame_sp -
(-suspend_state_index_from_fp + kKBCSuspendedFrameFixedSlots) * kWordSize;
FunctionPtr function =
Function::RawCast(resumed_native_frame[kKBCFunctionSlotInSuspendedFrame]);
const intptr_t pc_offset = Smi::Value(
Smi::RawCast(resumed_native_frame[kKBCPcOffsetSlotInSuspendedFrame]));
#if defined(DEBUG)
if (IsTracingExecution()) {
THR_Print("%" Pu64 " ", icount_);
THR_Print("Resuming interpreter 0x%" Px " at fp_ 0x%" Px " exit 0x%" Px
" %s\n",
reinterpret_cast<uword>(this), reinterpret_cast<uword>(fp_),
thread->top_exit_frame_info(),
Function::Handle(function).ToFullyQualifiedCString());
}
#endif
SetupEntryFrame(thread);
ObjectPtr* FP = fp_ + kKBCEntrySavedSlots + kKBCDartFrameFixedSize;
BytecodePtr bytecode = Function::GetBytecode(function);
FP[kKBCFunctionSlotFromFp] = function;
FP[kKBCPcMarkerSlotFromFp] = bytecode;
FP[kKBCSavedCallerPcSlotFromFp] = static_cast<ObjectPtr>(kEntryFramePcMarker);
FP[kKBCSavedCallerFpSlotFromFp] =
static_cast<ObjectPtr>(reinterpret_cast<uword>(fp_));
memmove(FP, &resumed_native_frame[kKBCSuspendedFrameFixedSlots],
interp_frame_size);
FP[kKBCSuspendStateSlotFromFp] = *reinterpret_cast<ObjectPtr*>(
resumed_frame_fp + suspend_state_index_from_fp * kWordSize);
ObjectPtr* SP = FP + (interp_frame_size >> kWordSizeLog2);
SP[0] = value;
argdesc_ = Array::null();
pc_ = reinterpret_cast<const KBCInstr*>(bytecode->untag()->instructions_ +
pc_offset);
pp_ = bytecode->untag()->object_pool();
fp_ = FP;
return Run(thread, SP);
}
ObjectPtr Interpreter::Run(Thread* thread, ObjectPtr* sp) {
// Interpreter state (see constants_kbc.h for high-level overview).
const KBCInstr* pc =
pc_; // Program Counter: points to the next op to execute.
ObjectPtr* FP = fp_; // Frame Pointer.
ObjectPtr* SP = sp; // Stack Pointer.
uint32_t op; // Currently executing op.
// Save current VM tag and mark thread as executing Dart code. For the
// profiler, do this *after* setting up the entry frame (compare the machine
@@ -1988,7 +2061,6 @@ SwitchDispatch:
{
BYTECODE(ReturnTOS, 0);
ReturnTOS:
ObjectPtr result; // result to return to the caller.
result = *SP;
// Restore caller PC.
@@ -2044,64 +2116,6 @@ SwitchDispatch:
DISPATCH();
}
{
BYTECODE(ReturnAsync, 0);
argdesc_ = ArgumentsDescriptor::NewBoxed(0, 2);
ObjectPtr return_value = *SP;
ObjectPtr suspend_state = FP[kKBCSuspendStateSlotFromFp];
FP[kKBCSuspendStateSlotFromFp] = null_value;
FunctionPtr function =
thread->isolate_group()->object_store()->suspend_state_return_async();
ASSERT(Function::HasCode(function));
SP[0] = suspend_state;
SP[1] = return_value;
ObjectPtr* call_base = SP;
ObjectPtr* call_top = SP + 2;
call_top[0] = function;
if (!InvokeCompiled(thread, function, call_base, call_top, &pc, &FP, &SP)) {
HANDLE_EXCEPTION;
} else {
HANDLE_RETURN;
}
goto ReturnTOS;
}
{
BYTECODE(ReturnAsyncStar, 0);
argdesc_ = ArgumentsDescriptor::NewBoxed(0, 2);
ObjectPtr return_value = *SP;
ObjectPtr suspend_state = FP[kKBCSuspendStateSlotFromFp];
FP[kKBCSuspendStateSlotFromFp] = null_value;
FunctionPtr function = thread->isolate_group()
->object_store()
->suspend_state_return_async_star();
ASSERT(Function::HasCode(function));
SP[0] = suspend_state;
SP[1] = return_value;
ObjectPtr* call_base = SP;
ObjectPtr* call_top = SP + 2;
call_top[0] = function;
if (!InvokeCompiled(thread, function, call_base, call_top, &pc, &FP, &SP)) {
HANDLE_EXCEPTION;
} else {
HANDLE_RETURN;
}
goto ReturnTOS;
}
{
BYTECODE(ReturnSyncStar, 0);
// Return false from sync* function to indicate the end of iteration.
*SP = false_value;
goto ReturnTOS;
}
{
BYTECODE(InitLateField, D);
FieldPtr field = Field::RawCast(LOAD_CONSTANT(rD + 1));
@@ -2551,6 +2565,91 @@ SwitchDispatch:
DISPATCH();
}
{
BYTECODE(Suspend, T);
const intptr_t suspend_state_index_from_fp =
runtime_frame_layout.FrameSlotForVariableIndex(
SuspendState::kSuspendStateVarIndex);
ASSERT(suspend_state_index_from_fp < 0);
// Saved interpreter frame is "wrapped" into a native frame in
// the suspend state:
//
// (-suspend_state_index_from_fp) words:
// header to mimic native frame with the slot for suspend state
// (SP + 1 - FP) words:
// locals and expression stack
// kKBCSuspendedFrameFixedSlots words:
// suspended function and PC offset to resume.
const intptr_t frame_size = ((-suspend_state_index_from_fp) +
(SP + 1 - FP) + kKBCSuspendedFrameFixedSlots) *
kWordSize;
SuspendStatePtr state;
ObjectPtr old_state = FP[kKBCSuspendStateSlotFromFp];
if (!old_state->IsSuspendState() ||
#if defined(DART_PRECOMPILED_RUNTIME)
(SuspendState::RawCast(old_state)->untag()->frame_size_ != frame_size)
#else
(SuspendState::RawCast(old_state)->untag()->frame_capacity_ <
frame_size)
#endif
) {
SP[1] = 0; // Space for result.
SP[2] = Smi::New(frame_size);
SP[3] = old_state;
Exit(thread, FP, SP + 4, pc);
INVOKE_RUNTIME(
DRT_AllocateSuspendState,
NativeArguments(thread, 2, /* argv */ SP + 2, /* retval */ SP + 1));
state = SuspendState::RawCast(SP[1]);
ASSERT(state->untag()->frame_size_ == frame_size);
FP[kKBCSuspendStateSlotFromFp] = state;
} else {
state = SuspendState::RawCast(old_state);
#if !defined(DART_PRECOMPILED_RUNTIME)
state->untag()->frame_size_ = frame_size;
#endif
}
// Copy interpreter frame, locals and expression stack.
uint8_t* payload = state->untag()->payload();
ObjectPtr* suspended_frame = reinterpret_cast<ObjectPtr*>(payload);
FunctionPtr function = FrameFunction(FP);
const intptr_t pc_offset =
(reinterpret_cast<uword>(rT) -
Function::GetBytecode(function)->untag()->instructions_);
suspended_frame[kKBCFunctionSlotInSuspendedFrame] = function;
suspended_frame[kKBCPcOffsetSlotInSuspendedFrame] = Smi::New(pc_offset);
memmove(&suspended_frame[kKBCSuspendedFrameFixedSlots], FP,
(SP + 1 - FP) * kWordSize);
// Fill suspend state slot.
const uword native_fp = reinterpret_cast<uword>(payload + frame_size);
*reinterpret_cast<ObjectPtr*>(native_fp + suspend_state_index_from_fp *
kWordSize) = state;
// Clear the rest of the slots.
for (intptr_t i = suspend_state_index_from_fp + 1; i < 0; ++i) {
*reinterpret_cast<ObjectPtr*>(native_fp + i * kWordSize) = 0;
}
#if !defined(DART_PRECOMPILED_RUNTIME)
*(reinterpret_cast<ObjectPtr*>(
native_fp + runtime_frame_layout.code_from_fp * kWordSize)) =
StubCode::ResumeInterpreter().ptr();
#endif
state->untag()->pc_ = StubCode::ResumeInterpreter().EntryPoint();
// Write barrier.
if (state->IsOldObject() || thread->is_marking()) {
DLRT_EnsureRememberedAndMarkingDeferred(static_cast<uword>(state),
thread);
}
DISPATCH();
}
{
BYTECODE(StoreIndexedTOS, 0);
SP -= 3;
@@ -3586,6 +3685,16 @@ void Interpreter::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
pc_ = reinterpret_cast<const KBCInstr*>(pc);
}
#if defined(DEBUG)
if (IsTracingExecution()) {
THR_Print("%" Pu64 " ", icount_);
THR_Print("JumpToFrame interpreter 0x%" Px " at fp_ 0x%" Px " pc_ 0x%" Px
"\n",
reinterpret_cast<uword>(this), reinterpret_cast<uword>(fp_),
reinterpret_cast<uword>(pc_));
}
#endif
// Set the tag.
thread->set_vm_tag(VMTag::kDartInterpretedTagId);
// Clear top exit frame.
+15
View File
@@ -97,6 +97,11 @@ class Interpreter {
ArrayPtr args_array,
Thread* thread);
ObjectPtr Resume(Thread* thread,
uword resumed_frame_fp,
uword resumed_frame_sp,
ObjectPtr value);
void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
uword get_sp() const { return reinterpret_cast<uword>(fp_); } // Yes, fp_.
@@ -114,6 +119,12 @@ class Interpreter {
#endif // !PRODUCT
private:
enum {
kKBCFunctionSlotInSuspendedFrame,
kKBCPcOffsetSlotInSuspendedFrame,
kKBCSuspendedFrameFixedSlots
};
uintptr_t* stack_;
uword stack_base_;
uword overflow_stack_limit_;
@@ -228,6 +239,10 @@ class Interpreter {
ObjectPtr* FP,
ObjectPtr* SP);
void SetupEntryFrame(Thread* thread);
ObjectPtr Run(Thread* thread, ObjectPtr* sp);
#if defined(DEBUG)
// Returns true if tracing of executed instructions is enabled.
bool IsTracingExecution() const;
+2
View File
@@ -157,6 +157,8 @@ class NativeArguments {
return *retval_;
}
uword GetCallerSP() const { return reinterpret_cast<uword>(retval_ + 1); }
static intptr_t thread_offset() {
return OFFSET_OF(NativeArguments, thread_);
}
+2
View File
@@ -3569,6 +3569,8 @@ class UntaggedSuspendState : public UntaggedInstance {
// Variable length payload follows here.
uint8_t* payload() { OPEN_ARRAY_START(uint8_t, uint8_t); }
const uint8_t* payload() const { OPEN_ARRAY_START(uint8_t, uint8_t); }
friend class Interpreter;
};
// VM type for capturing JS regular expressions.
+38
View File
@@ -4261,6 +4261,44 @@ uword RuntimeEntry::InterpretCallEntry() {
#endif // defined(DART_DYNAMIC_MODULES)
}
// Restore suspended interpreter frame and resume execution.
//
// Arg0: result of the suspension
DEFINE_RUNTIME_ENTRY(ResumeInterpreter, 1) {
#if defined(DART_DYNAMIC_MODULES)
const Instance& value = Instance::CheckedHandle(zone, arguments.ArgAt(0));
StackFrameIterator iterator(ValidationPolicy::kDontValidateFrames, thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* frame = iterator.NextFrame();
ASSERT(frame != nullptr);
while (frame->IsExitFrame() ||
(frame->IsStubFrame() &&
!StubCode::ResumeInterpreter().ContainsInstructionAt(frame->pc()))) {
frame = iterator.NextFrame();
ASSERT(frame != nullptr);
}
RELEASE_ASSERT(frame->IsStubFrame());
uword fp = frame->fp();
uword sp = arguments.GetCallerSP();
ASSERT((fp > sp) && (sp > frame->sp()));
MSAN_UNPOISON(reinterpret_cast<uint8_t*>(sp), fp - sp);
Interpreter* interpreter = Interpreter::Current();
auto& result = Object::Handle(zone);
{
TransitionVMToGenerated transition(thread);
result = interpreter->Resume(thread, fp, sp, value.ptr());
}
arguments.SetReturn(result);
#else
UNREACHABLE();
#endif // defined(DART_DYNAMIC_MODULES)
}
extern "C" void DFLRT_EnterSafepoint(NativeArguments __unusable_) {
CHECK_STACK_ALIGNMENT;
TRACE_RUNTIME_CALL("%s", "EnterSafepoint");
+2 -1
View File
@@ -78,7 +78,8 @@ namespace dart {
V(ClosureArgumentsValid) \
V(ResolveCallFunction) \
V(InterpretedInstanceCallMissHandler) \
V(InvokeNoSuchMethod)
V(InvokeNoSuchMethod) \
V(ResumeInterpreter)
// Note: Leaf runtime function have C linkage, so they cannot pass C++ struct
// values like ObjectPtr.
+1
View File
@@ -72,6 +72,7 @@ namespace dart {
V(CallToRuntime) \
V(LazyCompile) \
V(InterpretCall) \
V(ResumeInterpreter) \
V(CallBootstrapNative) \
V(CallNoScopeNative) \
V(CallAutoScopeNative) \
@@ -86,5 +86,8 @@ callable:
- library: 'dart:async'
class: '_StreamIterator'
member: '_subscription'
- library: 'dart:async'
class: '_SuspendState'
member: 'get:_functionData'
- library: 'dart:async'
member: '_asyncStarMoveNextHelper'