[vm/bytecode] Add UncheckedClosureCall instruction

This improves performance of closure calls:
DeltaBlueClosures: +25.14%
DartMicroBenchMM.MaxLib +40.91%
DartMicroBenchMM.MinLib +42.58%

Change-Id: I13000e20b9433ce77bb2ba5209513de575656036
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/109220
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov
2019-07-17 21:05:44 +00:00
committed by commit-bot@chromium.org
parent 8dc4148516
commit f450cf399e
16 changed files with 275 additions and 149 deletions
+5
View File
@@ -379,6 +379,11 @@ class BytecodeAssembler {
_emitInstructionDF(Opcode.kInterfaceCall, rd, rf);
}
void emitUncheckedClosureCall(int rd, int rf) {
emitSourcePosition();
_emitInstructionDF(Opcode.kUncheckedClosureCall, rd, rf);
}
void emitUncheckedInterfaceCall(int rd, int rf) {
emitSourcePosition();
_emitInstructionDF(Opcode.kUncheckedInterfaceCall, rd, rf);
+6 -3
View File
@@ -10,7 +10,7 @@ library vm.bytecode.dbc;
/// Before bumping current bytecode version format, make sure that
/// all users have switched to a VM which is able to consume new
/// version of bytecode.
const int currentBytecodeFormatVersion = 14;
const int currentBytecodeFormatVersion = 15;
enum Opcode {
kUnusedOpcode000,
@@ -218,8 +218,8 @@ enum Opcode {
kUnused24, // Reserved for InterfaceCall1_Wide
kUnused25, // Reserved for InterfaceCall2
kUnused26, // Reserved for InterfaceCall2_Wide
kUnused27, // Reserved for InterfaceCall3
kUnused28, // Reserved for InterfaceCall3_Wide
kUncheckedClosureCall,
kUncheckedClosureCall_Wide,
kUncheckedInterfaceCall,
kUncheckedInterfaceCall_Wide,
kDynamicCall,
@@ -500,6 +500,8 @@ const Map<Opcode, Format> BytecodeFormats = const {
Encoding.kDF, const [Operand.lit, Operand.imm, Operand.none]),
Opcode.kAllocateClosure: const Format(
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
Opcode.kUncheckedClosureCall: const Format(
Encoding.kDF, const [Operand.lit, Operand.imm, Operand.none]),
Opcode.kUncheckedInterfaceCall: const Format(
Encoding.kDF, const [Operand.lit, Operand.imm, Operand.none]),
Opcode.kNegateDouble: const Format(
@@ -603,6 +605,7 @@ bool isCall(Opcode opcode) {
switch (opcode) {
case Opcode.kDirectCall:
case Opcode.kInterfaceCall:
case Opcode.kUncheckedClosureCall:
case Opcode.kUncheckedInterfaceCall:
case Opcode.kDynamicCall:
case Opcode.kNativeCall:
+29 -11
View File
@@ -42,7 +42,8 @@ import 'generics.dart'
getInstantiatorTypeArguments,
hasFreeTypeParameters,
hasInstantiatorTypeArguments,
isUncheckedCall;
isUncheckedCall,
isUncheckedClosureCall;
import 'local_variable_table.dart' show LocalVariableTable;
import 'local_vars.dart' show LocalVariables;
import 'nullability_detector.dart' show NullabilityDetector;
@@ -928,11 +929,15 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
initializedFields.add(field);
}
void _genArguments(Expression receiver, Arguments arguments) {
void _genArguments(Expression receiver, Arguments arguments,
{int storeReceiverToLocal}) {
if (arguments.types.isNotEmpty) {
_genTypeArguments(arguments.types);
}
_generateNode(receiver);
if (storeReceiverToLocal != null) {
asm.emitStoreLocal(storeReceiverToLocal);
}
_generateNodeList(arguments.positional);
arguments.named.forEach((NamedExpression ne) => _generateNode(ne.value));
}
@@ -1366,7 +1371,7 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
savedMaxSourcePositions = <int>[];
maxSourcePosition = node.fileOffset;
locals = new LocalVariables(node, options);
locals = new LocalVariables(node, options, typeEnvironment);
locals.enterScope(node);
assert(!locals.isSyncYieldingFrame);
@@ -2678,9 +2683,6 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
void _genInstanceCall(
int totalArgCount, int callCpIndex, bool isDynamic, bool isUnchecked,
[TreeNode context]) {
if (totalArgCount >= argumentsLimit) {
throw new TooManyArgumentsException(context.fileOffset);
}
if (isDynamic) {
assert(!isUnchecked);
asm.emitDynamicCall(callCpIndex, totalArgCount);
@@ -2699,6 +2701,27 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
return;
}
final args = node.arguments;
final totalArgCount = args.positional.length +
args.named.length +
1 /* receiver */ +
(args.types.isNotEmpty ? 1 : 0) /* type arguments */;
if (totalArgCount >= argumentsLimit) {
throw new TooManyArgumentsException(node.fileOffset);
}
// Front-end guarantees that all calls with known function type
// do not need any argument type checks.
if (isUncheckedClosureCall(node, typeEnvironment)) {
final int receiverTemp = locals.tempIndexInFrame(node);
_genArguments(node.receiver, args, storeReceiverToLocal: receiverTemp);
// Duplicate receiver (closure) for UncheckedClosureCall.
asm.emitPush(receiverTemp);
final argDescCpIndex = cp.addArgDescByArguments(args, hasReceiver: true);
asm.emitUncheckedClosureCall(argDescCpIndex, totalArgCount);
return;
}
_genArguments(node.receiver, args);
Member interfaceTarget = node.interfaceTarget;
if (interfaceTarget is Field ||
interfaceTarget is Procedure && interfaceTarget.isGetter) {
@@ -2709,15 +2732,10 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
final isDynamic = interfaceTarget == null;
final isUnchecked =
isUncheckedCall(interfaceTarget, node.receiver, typeEnvironment);
_genArguments(node.receiver, args);
final argDesc =
objectTable.getArgDescHandleByArguments(args, hasReceiver: true);
final callCpIndex = cp.addInstanceCall(
InvocationKind.method, interfaceTarget, node.name, argDesc);
final totalArgCount = args.positional.length +
args.named.length +
1 /* receiver */ +
(args.types.isNotEmpty ? 1 : 0) /* type arguments */;
_genInstanceCall(totalArgCount, callCpIndex, isDynamic, isUnchecked, node);
}
+10 -3
View File
@@ -176,9 +176,9 @@ bool isSealedType(DartType type, CoreTypes coreTypes) {
return false;
}
// Returns true if an instance call to [interfaceTarget] with given
// [receiver] can omit argument type checks needed due to generic-covariant
// parameters.
/// Returns true if an instance call to [interfaceTarget] with given
/// [receiver] can omit argument type checks needed due to generic-covariant
/// parameters.
bool isUncheckedCall(Member interfaceTarget, Expression receiver,
TypeEnvironment typeEnvironment) {
if (interfaceTarget == null) {
@@ -229,3 +229,10 @@ bool _hasGenericCovariantParameters(Member target) {
throw 'Unexpected instance call target ${target.runtimeType} $target';
}
}
/// Returns true if invocation [node] is a closure call with statically known
/// function type. Such invocations can omit argument type checks.
bool isUncheckedClosureCall(
MethodInvocation node, TypeEnvironment typeEnvironment) =>
node.name.name == 'call' &&
getStaticType(node.receiver, typeEnvironment) is FunctionType;
+13 -1
View File
@@ -9,6 +9,8 @@ import 'dart:math' show max;
import 'package:kernel/ast.dart';
import 'package:kernel/transformations/continuation.dart'
show ContinuationVariables;
import 'package:kernel/type_environment.dart';
import 'package:vm/bytecode/generics.dart';
import 'dbc.dart';
import 'options.dart' show BytecodeOptions;
@@ -27,6 +29,7 @@ class LocalVariables {
final Map<ForInStatement, VariableDeclaration> _capturedIteratorVars =
<ForInStatement, VariableDeclaration>{};
final BytecodeOptions options;
final TypeEnvironment typeEnvironment;
Scope _currentScope;
Frame _currentFrame;
@@ -185,7 +188,7 @@ class LocalVariables {
List<VariableDeclaration> get sortedNamedParameters =>
_currentFrame.sortedNamedParameters;
LocalVariables(Member node, this.options) {
LocalVariables(Member node, this.options, this.typeEnvironment) {
final scopeBuilder = new _ScopeBuilder(this);
node.accept(scopeBuilder);
@@ -1191,6 +1194,15 @@ class _Allocator extends RecursiveVisitor<Null> {
_visit(node, temps: 1);
}
@override
visitMethodInvocation(MethodInvocation node) {
int numTemps = 0;
if (isUncheckedClosureCall(node, locals.typeEnvironment)) {
numTemps = 1;
}
_visit(node, temps: numTemps);
}
@override
visitPropertySet(PropertySet node) {
_visit(node, temps: 1);
+10 -8
View File
@@ -41,18 +41,22 @@ Function 'test2', static, reflectable, debuggable
return-type void
Bytecode {
Entry 0
Entry 1
CheckStack 0
JumpIfNoAsserts L1
Push FP[-6]
DynamicCall CP#1, 1
StoreLocal r0
Push r0
UncheckedClosureCall CP#0, 1
AssertBoolean 0
JumpIfTrue L1
PushInt 0
PushInt 0
Push FP[-5]
DynamicCall CP#2, 1
DirectCall CP#3, 3
StoreLocal r0
Push r0
UncheckedClosureCall CP#0, 1
DirectCall CP#1, 3
Drop1
L1:
PushNull
@@ -60,10 +64,8 @@ L1:
}
ConstantPool {
[0] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData dynamic target-name 'call', arg-desc CP#0
[2] = ICData dynamic target-name 'call', arg-desc CP#0
[3] = DirectCall 'dart:core::_AssertionError::_throwNew', ArgDesc num-args 3, num-type-args 0, names []
[4] = Reserved
[1] = DirectCall 'dart:core::_AssertionError::_throwNew', ArgDesc num-args 3, num-type-args 0, names []
[2] = Reserved
}
+66 -54
View File
@@ -41,8 +41,10 @@ Bytecode {
StoreFieldTOS CP#1
PopLocal r2
Push r2
StoreLocal r3
PushInt 3
DynamicCall CP#17, 2
Push r3
UncheckedClosureCall CP#16, 2
Drop1
Push r0
LoadContextVar 0, 0
@@ -66,7 +68,6 @@ ConstantPool {
[14] = InstanceField dart:core::_Closure::_function (field)
[15] = Reserved
[16] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
[17] = ICData dynamic target-name 'call', arg-desc CP#16
}
Closure #lib::simpleClosure::'<anonymous closure>' (dart:core::int y) -> dart:core::Null
ClosureCode {
@@ -594,13 +595,17 @@ Bytecode {
Push r1
StoreFieldTOS CP#1
PopLocal r3
PushConstant CP#43
PushConstant CP#40
Push r3
DynamicCall CP#44, 2
StoreLocal r4
Push r4
UncheckedClosureCall CP#37, 2
Drop1
PushConstant CP#45
PushConstant CP#41
Push r3
DynamicCall CP#46, 2
StoreLocal r4
Push r4
UncheckedClosureCall CP#37, 2
Drop1
PushNull
ReturnTOS
@@ -641,18 +646,13 @@ ConstantPool {
[32] = InstanceField dart:core::_Closure::_function (field)
[33] = Reserved
[34] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
[35] = ICData dynamic target-name 'call', arg-desc CP#34
[36] = EndClosureFunctionScope
[37] = ObjectRef < #lib::C7, #lib::C8 >
[38] = ObjectRef ArgDesc num-args 1, num-type-args 2, names []
[39] = ICData dynamic target-name 'call', arg-desc CP#38
[40] = ObjectRef < dart:core::List < #lib::C7 >, dart:core::List < #lib::C8 > >
[41] = ICData dynamic target-name 'call', arg-desc CP#38
[42] = EndClosureFunctionScope
[43] = ObjectRef < #lib::C5, #lib::C6 >
[44] = ICData dynamic target-name 'call', arg-desc CP#38
[45] = ObjectRef < dart:core::List < #lib::C5 >, dart:core::List < #lib::C6 > >
[46] = ICData dynamic target-name 'call', arg-desc CP#38
[35] = EndClosureFunctionScope
[36] = ObjectRef < #lib::C7, #lib::C8 >
[37] = ObjectRef ArgDesc num-args 1, num-type-args 2, names []
[38] = ObjectRef < dart:core::List < #lib::C7 >, dart:core::List < #lib::C8 > >
[39] = EndClosureFunctionScope
[40] = ObjectRef < #lib::C5, #lib::C6 >
[41] = ObjectRef < dart:core::List < #lib::C5 >, dart:core::List < #lib::C6 > >
}
Closure #lib::A::foo::'nested1' <dart:core::Object T5, dart:core::Object T6> () -> void
ClosureCode {
@@ -698,13 +698,17 @@ L2:
Push r1
StoreFieldTOS CP#1
PopLocal r3
PushConstant CP#37
PushConstant CP#36
Push r3
DynamicCall CP#39, 2
StoreLocal r4
Push r4
UncheckedClosureCall CP#37, 2
Drop1
PushConstant CP#40
PushConstant CP#38
Push r3
DynamicCall CP#41, 2
StoreLocal r4
Push r4
UncheckedClosureCall CP#37, 2
Drop1
PushNull
ReturnTOS
@@ -755,7 +759,9 @@ L2:
StoreFieldTOS CP#1
PopLocal r3
Push r3
DynamicCall CP#35, 1
StoreLocal r4
Push r4
UncheckedClosureCall CP#34, 1
Drop1
PushNull
ReturnTOS
@@ -908,28 +914,32 @@ Bytecode {
StoreFieldTOS CP#1
PopLocal r3
Push r3
StoreLocal r4
PushInt 10
DynamicCall CP#25, 2
Push r4
UncheckedClosureCall CP#23, 2
Drop1
Push r3
StoreLocal r4
PushInt 11
DynamicCall CP#26, 2
Push r4
UncheckedClosureCall CP#23, 2
Drop1
Push r2
DirectCall CP#21, 1
DirectCall CP#20, 1
Drop1
Push r0
LoadContextVar 0, 2
DirectCall CP#21, 1
DirectCall CP#20, 1
Drop1
Push r0
LoadContextVar 0, 1
DirectCall CP#21, 1
DirectCall CP#20, 1
Drop1
Push r0
PushInt 42
StoreContextVar 0, 3
AllocateClosure CP#27
AllocateClosure CP#24
StoreLocal r3
Push r3
PushNull
@@ -941,14 +951,16 @@ Bytecode {
PushConstant CP#14
StoreFieldTOS CP#15
Push r3
PushConstant CP#27
PushConstant CP#24
StoreFieldTOS CP#17
Push r3
Push r0
StoreFieldTOS CP#1
PopLocal r2
Push r2
DynamicCall CP#31, 1
StoreLocal r3
Push r3
UncheckedClosureCall CP#19, 1
Drop1
PushNull
ReturnTOS
@@ -974,18 +986,14 @@ ConstantPool {
[17] = InstanceField dart:core::_Closure::_function (field)
[18] = Reserved
[19] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
[20] = ICData dynamic target-name 'call', arg-desc CP#19
[21] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
[22] = Reserved
[23] = EndClosureFunctionScope
[24] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
[25] = ICData dynamic target-name 'call', arg-desc CP#24
[26] = ICData dynamic target-name 'call', arg-desc CP#24
[27] = ClosureFunction 2
[28] = InterfaceCall '#lib::B::set:foo', ArgDesc num-args 2, num-type-args 0, names []
[29] = Reserved
[30] = EndClosureFunctionScope
[31] = ICData dynamic target-name 'call', arg-desc CP#19
[20] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
[21] = Reserved
[22] = EndClosureFunctionScope
[23] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
[24] = ClosureFunction 2
[25] = InterfaceCall '#lib::B::set:foo', ArgDesc num-args 2, num-type-args 0, names []
[26] = Reserved
[27] = EndClosureFunctionScope
}
Closure #lib::B::topLevel::'<anonymous closure>' (dart:core::int y) -> dart:core::Null
ClosureCode {
@@ -1045,11 +1053,13 @@ ClosureCode {
StoreFieldTOS CP#1
PopLocal r3
Push r3
DynamicCall CP#20, 1
StoreLocal r2
Push r2
UncheckedClosureCall CP#19, 1
Drop1
Push r0
LoadContextVar 1, 1
DirectCall CP#21, 1
DirectCall CP#20, 1
Drop1
L1:
PushNull
@@ -1095,7 +1105,7 @@ ClosureCode {
LoadContextVar 0, 0
Push r0
LoadContextVar 0, 3
InterfaceCall CP#28, 2
InterfaceCall CP#25, 2
Drop1
PushNull
ReturnTOS
@@ -1331,11 +1341,13 @@ L2:
StoreFieldTOS CP#7
PopLocal r3
Push r3
DynamicCall CP#20, 1
StoreLocal r4
Push r4
UncheckedClosureCall CP#19, 1
Drop1
Push r0
LoadContextVar 0, 0
DirectCall CP#21, 1
DirectCall CP#20, 1
Drop1
Push r0
LoadContextParent
@@ -1366,9 +1378,8 @@ ConstantPool {
[17] = InstanceField dart:core::_Closure::_function (field)
[18] = Reserved
[19] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
[20] = ICData dynamic target-name 'call', arg-desc CP#19
[21] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
[22] = Reserved
[20] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
[21] = Reserved
}
Closure #lib::C::testForInLoop::'<anonymous closure>' () -> dart:core::Null
ClosureCode {
@@ -1533,8 +1544,7 @@ ConstantPool {
[13] = InstanceField dart:core::_Closure::_function (field)
[14] = Reserved
[15] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
[16] = ICData dynamic target-name 'call', arg-desc CP#15
[17] = EndClosureFunctionScope
[16] = EndClosureFunctionScope
}
Closure #lib::D::bar::'<anonymous closure>' () -> dart:core::Null
ClosureCode {
@@ -1564,7 +1574,9 @@ ClosureCode {
StoreFieldTOS CP#1
PopLocal r2
Push r2
DynamicCall CP#16, 1
StoreLocal r3
Push r3
UncheckedClosureCall CP#15, 1
Drop1
PushNull
ReturnTOS
@@ -237,7 +237,9 @@ Try #0 start:
StoreFieldTOS CP#1
PopLocal r4
Push r4
DynamicCall CP#18, 1
StoreLocal r5
Push r5
UncheckedClosureCall CP#17, 1
Drop1
Push r0
LoadContextVar 0, 1
@@ -262,7 +264,7 @@ Try #0 handler:
StoreLocal r5
Push r5
PushInt 0
PushConstant CP#19
PushConstant CP#18
StoreIndexedTOS
Push r5
PushInt 1
@@ -270,17 +272,17 @@ Try #0 handler:
StoreIndexedTOS
Push r5
PushInt 2
PushConstant CP#20
PushConstant CP#19
StoreIndexedTOS
Push r5
PushInt 3
Push r0
LoadContextVar 0, 2
StoreIndexedTOS
DirectCall CP#21, 1
DirectCall CP#20, 1
DirectCall CP#4, 1
Drop1
AllocateClosure CP#23
AllocateClosure CP#22
StoreLocal r5
Push r5
PushNull
@@ -292,7 +294,7 @@ Try #0 handler:
PushConstant CP#12
StoreFieldTOS CP#13
Push r5
PushConstant CP#23
PushConstant CP#22
StoreFieldTOS CP#15
Push r5
Push r0
@@ -308,7 +310,7 @@ L1:
ReturnTOS
}
ExceptionsTable {
try-index 0, outer -1, start 20, end 80, handler 80, needs-stack-trace, types [CP#6]
try-index 0, outer -1, start 20, end 84, handler 84, needs-stack-trace, types [CP#6]
}
ConstantPool {
[0] = ClosureFunction 0
@@ -329,19 +331,18 @@ ConstantPool {
[15] = InstanceField dart:core::_Closure::_function (field)
[16] = Reserved
[17] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
[18] = ICData dynamic target-name 'call', arg-desc CP#17
[19] = ObjectRef 'caught '
[20] = ObjectRef ' '
[21] = DirectCall 'dart:core::_StringBase::_interpolate', ArgDesc num-args 1, num-type-args 0, names []
[22] = Reserved
[23] = ClosureFunction 1
[24] = ObjectRef 'danger bar'
[25] = Type dart:core::Error
[26] = InterfaceCall 'dart:core::Object::_simpleInstanceOf', ArgDesc num-args 2, num-type-args 0, names []
[27] = Reserved
[28] = ObjectRef 'error '
[29] = ObjectRef ', captured stack trace: '
[30] = EndClosureFunctionScope
[18] = ObjectRef 'caught '
[19] = ObjectRef ' '
[20] = DirectCall 'dart:core::_StringBase::_interpolate', ArgDesc num-args 1, num-type-args 0, names []
[21] = Reserved
[22] = ClosureFunction 1
[23] = ObjectRef 'danger bar'
[24] = Type dart:core::Error
[25] = InterfaceCall 'dart:core::Object::_simpleInstanceOf', ArgDesc num-args 2, num-type-args 0, names []
[26] = Reserved
[27] = ObjectRef 'error '
[28] = ObjectRef ', captured stack trace: '
[29] = EndClosureFunctionScope
}
Closure #lib::testTryCatch3::'foo' () -> void
ClosureCode {
@@ -389,7 +390,7 @@ ClosureCode {
Push r0
PopLocal r2
Try #0 start:
PushConstant CP#24
PushConstant CP#23
DirectCall CP#4, 1
Drop1
Jump L1
@@ -401,8 +402,8 @@ Try #0 handler:
MoveSpecial exception, r2
MoveSpecial stackTrace, r3
Push r2
PushConstant CP#25
InterfaceCall CP#26, 2
PushConstant CP#24
InterfaceCall CP#25, 2
JumpIfFalse L2
Push r2
PopLocal r4
@@ -412,7 +413,7 @@ Try #0 handler:
StoreLocal r5
Push r5
PushInt 0
PushConstant CP#28
PushConstant CP#27
StoreIndexedTOS
Push r5
PushInt 1
@@ -420,14 +421,14 @@ Try #0 handler:
StoreIndexedTOS
Push r5
PushInt 2
PushConstant CP#29
PushConstant CP#28
StoreIndexedTOS
Push r5
PushInt 3
Push r0
LoadContextVar 0, 2
StoreIndexedTOS
DirectCall CP#21, 1
DirectCall CP#20, 1
DirectCall CP#4, 1
Drop1
Jump L1
@@ -646,7 +647,9 @@ Try #1 start:
StoreFieldTOS CP#7
PopLocal r7
Push r7
DynamicCall CP#20, 1
StoreLocal r8
Push r8
UncheckedClosureCall CP#19, 1
Drop1
Jump L4
Try #1 end:
@@ -656,7 +659,7 @@ Try #1 handler:
PopLocal r0
MoveSpecial exception, r5
MoveSpecial stackTrace, r6
PushConstant CP#22
PushConstant CP#21
DirectCall CP#3, 1
Drop1
Push r5
@@ -665,7 +668,7 @@ Try #1 handler:
L4:
Push r5
PopLocal r0
PushConstant CP#22
PushConstant CP#21
DirectCall CP#3, 1
Drop1
Jump L5
@@ -676,7 +679,7 @@ Try #0 handler:
PopLocal r0
MoveSpecial exception, r3
MoveSpecial stackTrace, r4
PushConstant CP#24
PushConstant CP#23
DirectCall CP#3, 1
Drop1
Push r3
@@ -685,12 +688,12 @@ Try #0 handler:
L5:
Push r3
PopLocal r0
PushConstant CP#24
PushConstant CP#23
DirectCall CP#3, 1
Drop1
Jump L2
L2:
PushConstant CP#25
PushConstant CP#24
DirectCall CP#3, 1
Drop1
Jump L3
@@ -699,8 +702,8 @@ L3:
ReturnTOS
}
ExceptionsTable {
try-index 0, outer -1, start 53, end 158, handler 158, needs-stack-trace, types [CP#21]
try-index 1, outer 0, start 70, end 120, handler 120, needs-stack-trace, types [CP#21]
try-index 0, outer -1, start 53, end 162, handler 162, needs-stack-trace, types [CP#20]
try-index 1, outer 0, start 70, end 124, handler 124, needs-stack-trace, types [CP#20]
}
ConstantPool {
[0] = InterfaceCall 'dart:core::Object::==', ArgDesc num-args 2, num-type-args 0, names []
@@ -723,12 +726,11 @@ ConstantPool {
[17] = InstanceField dart:core::_Closure::_function (field)
[18] = Reserved
[19] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
[20] = ICData dynamic target-name 'call', arg-desc CP#19
[21] = Type dynamic
[22] = ObjectRef 'finally 1'
[23] = ObjectRef 'after try 1'
[24] = ObjectRef 'finally 2'
[25] = ObjectRef 'case 2'
[20] = Type dynamic
[21] = ObjectRef 'finally 1'
[22] = ObjectRef 'after try 1'
[23] = ObjectRef 'finally 2'
[24] = ObjectRef 'case 2'
}
Closure #lib::testTryFinally2::'foo' () -> void
ClosureCode {
@@ -259,6 +259,8 @@ static intptr_t GetConstantPoolIndex(const KBCInstr* instr) {
case KernelBytecode::kDirectCall_Wide:
case KernelBytecode::kInterfaceCall:
case KernelBytecode::kInterfaceCall_Wide:
case KernelBytecode::kUncheckedClosureCall:
case KernelBytecode::kUncheckedClosureCall_Wide:
case KernelBytecode::kUncheckedInterfaceCall:
case KernelBytecode::kUncheckedInterfaceCall_Wide:
case KernelBytecode::kDynamicCall:
@@ -882,6 +882,28 @@ Fragment BaseFlowGraphBuilder::DebugStepCheck(TokenPosition position) {
#endif
}
Fragment BaseFlowGraphBuilder::CheckNull(TokenPosition position,
LocalVariable* receiver,
const String& function_name,
bool clear_the_temp /* = true */) {
Fragment instructions = LoadLocal(receiver);
CheckNullInstr* check_null =
new (Z) CheckNullInstr(Pop(), function_name, GetNextDeoptId(), position);
instructions <<= check_null;
if (clear_the_temp) {
// Null out receiver to make sure it is not saved into the frame before
// doing the call.
instructions += NullConstant();
instructions += StoreLocal(TokenPosition::kNoSource, receiver);
instructions += Drop();
}
return instructions;
}
} // namespace kernel
} // namespace dart
@@ -303,6 +303,15 @@ class BaseFlowGraphBuilder {
Fragment DebugStepCheck(TokenPosition position);
// Loads 'receiver' and checks it for null. Throws NoSuchMethod if it is null.
// 'function_name' is a selector which is being called (reported in
// NoSuchMethod message).
// Sets 'receiver' to 'null' after the check if 'clear_the_temp'.
Fragment CheckNull(TokenPosition position,
LocalVariable* receiver,
const String& function_name,
bool clear_the_temp = true);
protected:
intptr_t AllocateBlockId() { return ++last_used_block_id_; }
@@ -879,6 +879,35 @@ void BytecodeFlowGraphBuilder::BuildUncheckedInterfaceCall() {
BuildInterfaceCallCommon(/*is_unchecked_call=*/true);
}
void BytecodeFlowGraphBuilder::BuildUncheckedClosureCall() {
if (is_generating_interpreter()) {
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
}
const Array& arg_desc_array =
Array::Cast(ConstantAt(DecodeOperandD()).value());
const ArgumentsDescriptor arg_desc(arg_desc_array);
const intptr_t argc = DecodeOperandF().value();
LocalVariable* receiver_temp = B->MakeTemporary();
code_ += B->CheckNull(position_, receiver_temp, Symbols::Call(),
/*clear_temp=*/false);
code_ += B->LoadNativeField(Slot::Closure_function());
Value* function = Pop();
const ArgumentArray arguments = GetArguments(argc);
ClosureCallInstr* call = new (Z) ClosureCallInstr(
function, arguments, arg_desc.TypeArgsLen(),
Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), position_,
B->GetNextDeoptId(), Code::EntryKind::kUnchecked);
code_ <<= call;
B->Push(call);
}
void BytecodeFlowGraphBuilder::BuildDynamicCall() {
if (is_generating_interpreter()) {
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
@@ -479,28 +479,6 @@ Fragment FlowGraphBuilder::Return(TokenPosition position,
return instructions;
}
Fragment FlowGraphBuilder::CheckNull(TokenPosition position,
LocalVariable* receiver,
const String& function_name,
bool clear_the_temp /* = true */) {
Fragment instructions = LoadLocal(receiver);
CheckNullInstr* check_null =
new (Z) CheckNullInstr(Pop(), function_name, GetNextDeoptId(), position);
instructions <<= check_null;
if (clear_the_temp) {
// Null out receiver to make sure it is not saved into the frame before
// doing the call.
instructions += NullConstant();
instructions += StoreLocal(TokenPosition::kNoSource, receiver);
instructions += Drop();
}
return instructions;
}
Fragment FlowGraphBuilder::StaticCall(TokenPosition position,
const Function& target,
intptr_t argument_count,
@@ -165,10 +165,6 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
Fragment InitStaticField(const Field& field);
Fragment NativeCall(const String* name, const Function* function);
Fragment Return(TokenPosition position, bool omit_result_type_check = false);
Fragment CheckNull(TokenPosition position,
LocalVariable* receiver,
const String& function_name,
bool clear_the_temp = true);
void SetResultTypeForStaticCall(StaticCallInstr* call,
const Function& target,
intptr_t argument_count,
+5 -3
View File
@@ -657,8 +657,8 @@ namespace dart {
V(Unused24, 0, RESV, ___, ___, ___) \
V(Unused25, 0, RESV, ___, ___, ___) \
V(Unused26, 0, RESV, ___, ___, ___) \
V(Unused27, 0, RESV, ___, ___, ___) \
V(Unused28, 0, RESV, ___, ___, ___) \
V(UncheckedClosureCall, D_F, ORDN, num, num, ___) \
V(UncheckedClosureCall_Wide, D_F, WIDE, num, num, ___) \
V(UncheckedInterfaceCall, D_F, ORDN, num, num, ___) \
V(UncheckedInterfaceCall_Wide, D_F, WIDE, num, num, ___) \
V(DynamicCall, D_F, ORDN, num, num, ___) \
@@ -749,7 +749,7 @@ class KernelBytecode {
// Maximum bytecode format version supported by VM.
// The range of supported versions should include version produced by bytecode
// generator (currentBytecodeFormatVersion in pkg/vm/lib/bytecode/dbc.dart).
static const intptr_t kMaxSupportedBytecodeFormatVersion = 14;
static const intptr_t kMaxSupportedBytecodeFormatVersion = 15;
enum Opcode {
#define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,
@@ -973,6 +973,8 @@ class KernelBytecode {
case KernelBytecode::kDirectCall_Wide:
case KernelBytecode::kInterfaceCall:
case KernelBytecode::kInterfaceCall_Wide:
case KernelBytecode::kUncheckedClosureCall:
case KernelBytecode::kUncheckedClosureCall_Wide:
case KernelBytecode::kUncheckedInterfaceCall:
case KernelBytecode::kUncheckedInterfaceCall_Wide:
case KernelBytecode::kDynamicCall:
+27
View File
@@ -1996,6 +1996,33 @@ SwitchDispatch:
DISPATCH();
}
{
BYTECODE(UncheckedClosureCall, D_F);
DEBUG_CHECK;
{
const uint32_t argc = rF;
const uint32_t kidx = rD;
RawClosure* receiver = Closure::RawCast(*SP--);
RawObject** call_base = SP - argc + 1;
RawObject** call_top = SP + 1;
InterpreterHelpers::IncrementUsageCounter(FrameFunction(FP));
if (UNLIKELY(receiver == null_value)) {
SP[0] = Symbols::Call().raw();
goto ThrowNullError;
}
argdesc_ = static_cast<RawArray*>(LOAD_CONSTANT(kidx));
call_top[0] = receiver->ptr()->function_;
if (!Invoke(thread, call_base, call_top, &pc, &FP, &SP)) {
HANDLE_EXCEPTION;
}
}
DISPATCH();
}
{
BYTECODE(UncheckedInterfaceCall, D_F);
DEBUG_CHECK;