[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:
committed by
Commit Queue
parent
0d368ce290
commit
062b0738e3
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user