[vm/bytecode] Replace InstanceCall instruction with InterfaceCall and DynamicCall.

Dispatch interface calls via hashtable rather than inline cache.
InterfaceCall doesn't need to take arguments descriptor into account
when doing method lookup.

Change-Id: I30eae6ea638d1d2ad2cf3ff073c653fee3377f31
Reviewed-on: https://dart-review.googlesource.com/c/86106
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Régis Crelier <regis@google.com>
This commit is contained in:
Régis Crelier 2018-12-14 16:51:51 +00:00 committed by commit-bot@chromium.org
parent e2007126eb
commit 25851db73d
25 changed files with 1103 additions and 712 deletions

View file

@ -271,9 +271,14 @@ class BytecodeAssembler {
emitWord(_encodeAD(Opcode.kIndirectStaticCall, ra, rd));
}
void emitInstanceCall(int ra, int rd) {
void emitInterfaceCall(int ra, int rd) {
emitSourcePosition();
emitWord(_encodeAD(Opcode.kInstanceCall, ra, rd));
emitWord(_encodeAD(Opcode.kInterfaceCall, ra, rd));
}
void emitDynamicCall(int ra, int rd) {
emitSourcePosition();
emitWord(_encodeAD(Opcode.kDynamicCall, ra, rd));
}
void emitNativeCall(int rd) {

View file

@ -169,6 +169,15 @@ type ConstantSymbol extends ConstantPoolEntry {
PackedObject name;
}
// Occupies 2 entries in the constant pool.
type ConstantInterfaceCall extends ConstantPoolEntry {
Byte tag = 26;
Byte flags(invocationKindBit0, invocationKindBit1);
// Where invocationKind is index into InvocationKind.
PackedObject targetName;
ConstantIndex argDesc;
}
*/
enum ConstantTag {
@ -198,6 +207,7 @@ enum ConstantTag {
kPartialTearOffInstantiation,
kEmptyTypeArguments,
kSymbol,
kInterfaceCall,
}
abstract class ConstantPoolEntry {
@ -271,6 +281,8 @@ abstract class ConstantPoolEntry {
return new ConstantEmptyTypeArguments.read(reader);
case ConstantTag.kSymbol:
return new ConstantSymbol.read(reader);
case ConstantTag.kInterfaceCall:
return new ConstantInterfaceCall.read(reader);
}
throw 'Unexpected constant tag $tag';
}
@ -1071,6 +1083,50 @@ class ConstantSymbol extends ConstantPoolEntry {
bool operator ==(other) => other is ConstantSymbol && this.name == other.name;
}
class ConstantInterfaceCall extends ConstantPoolEntry {
final InvocationKind invocationKind;
final ObjectHandle targetName;
final int argDescConstantIndex;
ConstantInterfaceCall(
this.invocationKind, this.targetName, this.argDescConstantIndex);
// Reserve 1 extra slot for arguments descriptor, following target name slot.
int get numReservedEntries => 1;
@override
ConstantTag get tag => ConstantTag.kInterfaceCall;
@override
void writeValue(BufferedWriter writer) {
writer.writeByte(invocationKind.index);
writer.writePackedObject(targetName);
writer.writePackedUInt30(argDescConstantIndex);
}
ConstantInterfaceCall.read(BufferedReader reader)
: invocationKind = InvocationKind.values[reader.readByte()],
targetName = reader.readPackedObject(),
argDescConstantIndex = reader.readPackedUInt30();
@override
String toString() => 'InterfaceCall '
'${_invocationKindToString(invocationKind)}'
'target-name \'$targetName\', arg-desc CP#$argDescConstantIndex';
@override
int get hashCode => _combineHashes(
_combineHashes(invocationKind.index, targetName.hashCode),
argDescConstantIndex);
@override
bool operator ==(other) =>
other is ConstantInterfaceCall &&
this.invocationKind == other.invocationKind &&
this.targetName == other.targetName &&
this.argDescConstantIndex == other.argDescConstantIndex;
}
/// Reserved constant pool entry.
class _ReservedConstantPoolEntry extends ConstantPoolEntry {
const _ReservedConstantPoolEntry();
@ -1131,6 +1187,23 @@ class ConstantPool {
isSetter: invocationKind == InvocationKind.setter),
argDescCpIndex));
int addInterfaceCall(
InvocationKind invocationKind, Name targetName, int argDescCpIndex) =>
_add(new ConstantInterfaceCall(
invocationKind,
objectTable.getSelectorNameHandle(targetName,
isGetter: invocationKind == InvocationKind.getter,
isSetter: invocationKind == InvocationKind.setter),
argDescCpIndex));
int addInstanceCall(
InvocationKind invocationKind, Name targetName, int argDescCpIndex,
{bool isDynamic: false}) =>
isDynamic
? addICData(invocationKind, targetName, argDescCpIndex,
isDynamic: true)
: addInterfaceCall(invocationKind, targetName, argDescCpIndex);
int addStaticField(Field field) =>
_add(new ConstantStaticField(objectTable.getHandle(field)));

View file

@ -82,7 +82,8 @@ enum Opcode {
// Calls.
kIndirectStaticCall,
kInstanceCall,
kInterfaceCall,
kDynamicCall,
kNativeCall,
kReturnTOS,
@ -235,7 +236,9 @@ const Map<Opcode, Format> BytecodeFormats = const {
Encoding.kT, const [Operand.tgt, Operand.none, Operand.none]),
Opcode.kIndirectStaticCall: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kInstanceCall: const Format(
Opcode.kInterfaceCall: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kDynamicCall: const Format(
Encoding.kAD, const [Operand.imm, Operand.lit, Operand.none]),
Opcode.kNativeCall: const Format(
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
@ -312,7 +315,8 @@ bool isThrow(Opcode opcode) => opcode == Opcode.kThrow;
bool isCall(Opcode opcode) {
switch (opcode) {
case Opcode.kIndirectStaticCall:
case Opcode.kInstanceCall:
case Opcode.kInterfaceCall:
case Opcode.kDynamicCall:
case Opcode.kNativeCall:
return true;
default:

View file

@ -772,9 +772,9 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
assert(type.classNode.typeParameters.isEmpty);
asm.emitPushConstant(cp.addType(type));
final argDescIndex = cp.addArgDesc(2);
final icdataIndex = cp.addICData(
final icdataIndex = cp.addInterfaceCall(
InvocationKind.method, objectSimpleInstanceOf.name, argDescIndex);
asm.emitInstanceCall(2, icdataIndex);
asm.emitInterfaceCall(2, icdataIndex);
return;
}
@ -786,9 +786,9 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
}
asm.emitPushConstant(cp.addType(type));
final argDescIndex = cp.addArgDesc(4);
final icdataIndex = cp.addICData(
final icdataIndex = cp.addInterfaceCall(
InvocationKind.method, objectInstanceOf.name, argDescIndex);
asm.emitInstanceCall(4, icdataIndex);
asm.emitInterfaceCall(4, icdataIndex);
}
void start(Member node) {
@ -1945,6 +1945,14 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
asm.emitBytecode0(opcode);
}
void _genInstanceCall(int totalArgCount, int icdataCpIndex, bool isDynamic) {
if (isDynamic) {
asm.emitDynamicCall(totalArgCount, icdataCpIndex);
} else {
asm.emitInterfaceCall(totalArgCount, icdataCpIndex);
}
}
@override
visitMethodInvocation(MethodInvocation node) {
final Opcode opcode = recognizedMethods.specializedBytecodeFor(node);
@ -1953,26 +1961,28 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
return;
}
final args = node.arguments;
final isDynamic = node.interfaceTarget == null;
_genArguments(node.receiver, args);
final argDescIndex = cp.addArgDescByArguments(args, hasReceiver: true);
final icdataIndex = cp.addICData(
final icdataIndex = cp.addInstanceCall(
InvocationKind.method, node.name, argDescIndex,
isDynamic: node.interfaceTarget == null);
isDynamic: isDynamic);
final totalArgCount = args.positional.length +
args.named.length +
1 /* receiver */ +
(args.types.isNotEmpty ? 1 : 0) /* type arguments */;
asm.emitInstanceCall(totalArgCount, icdataIndex);
_genInstanceCall(totalArgCount, icdataIndex, isDynamic);
}
@override
visitPropertyGet(PropertyGet node) {
_generateNode(node.receiver);
final isDynamic = node.interfaceTarget == null;
final argDescIndex = cp.addArgDesc(1);
final icdataIndex = cp.addICData(
final icdataIndex = cp.addInstanceCall(
InvocationKind.getter, node.name, argDescIndex,
isDynamic: node.interfaceTarget == null);
asm.emitInstanceCall(1, icdataIndex);
isDynamic: isDynamic);
_genInstanceCall(1, icdataIndex, isDynamic);
}
@override
@ -1987,11 +1997,12 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
asm.emitStoreLocal(temp);
}
final isDynamic = node.interfaceTarget == null;
final argDescIndex = cp.addArgDesc(2);
final icdataIndex = cp.addICData(
final icdataIndex = cp.addInstanceCall(
InvocationKind.setter, node.name, argDescIndex,
isDynamic: node.interfaceTarget == null);
asm.emitInstanceCall(2, icdataIndex);
isDynamic: isDynamic);
_genInstanceCall(2, icdataIndex, isDynamic);
asm.emitDrop1();
if (hasResult) {
@ -2402,9 +2413,11 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
const kMoveNext = 'moveNext'; // Iterator.moveNext
const kCurrent = 'current'; // Iterator.current
asm.emitInstanceCall(
// Front-end inserts implicit cast (type check) which ensures that
// result of iterable expression is Iterable<dynamic>.
asm.emitInterfaceCall(
1,
cp.addICData(
cp.addInterfaceCall(
InvocationKind.getter, new Name(kIterator), cp.addArgDesc(1)));
final iteratorTemp = locals.tempIndexInFrame(node);
@ -2436,9 +2449,9 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
asm.emitPush(iteratorTemp);
}
asm.emitInstanceCall(
asm.emitInterfaceCall(
1,
cp.addICData(
cp.addInterfaceCall(
InvocationKind.method, new Name(kMoveNext), cp.addArgDesc(1)));
_genJumpIfFalse(/* negated = */ false, done);
@ -2447,9 +2460,9 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
_genPushContextIfCaptured(node.variable);
asm.emitPush(iteratorTemp);
asm.emitInstanceCall(
asm.emitInterfaceCall(
1,
cp.addICData(
cp.addInterfaceCall(
InvocationKind.getter, new Name(kCurrent), cp.addArgDesc(1)));
_genStoreVar(node.variable);
@ -2606,9 +2619,9 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
for (var expr in switchCase.expressions) {
asm.emitPush(temp);
_genPushConstExpr(expr);
asm.emitInstanceCall(
asm.emitInterfaceCall(
2,
cp.addICData(
cp.addInterfaceCall(
InvocationKind.method, new Name('=='), equalsArgDesc));
_genJumpIfTrue(/* negated = */ false, caseLabel);
}

View file

@ -33,13 +33,13 @@ Bytecode {
CheckStack 0
JumpIfNoAsserts L1
Push FP[-6]
InstanceCall 1, CP#1
DynamicCall 1, CP#1
AssertBoolean 0
JumpIfTrue L1
PushInt 0
PushInt 0
Push FP[-5]
InstanceCall 1, CP#2
DynamicCall 1, CP#2
PushConstant CP#4
IndirectStaticCall 3, CP#3
Drop1

File diff suppressed because it is too large Load diff

View file

@ -308,7 +308,7 @@ L2:
JumpIfFalse L3
PushConstant CP#1
PushStatic CP#1
InstanceCall 1, CP#3
DynamicCall 1, CP#3
StoreStaticTOS CP#0
L3:
PushConstant CP#0
@ -402,8 +402,8 @@ Bytecode {
Entry 0
CheckStack 0
Push FP[-5]
InstanceCall 1, CP#1
PushConstant CP#2
InterfaceCall 1, CP#1
PushConstant CP#3
IndirectStaticCall 1, CP#0
Drop1
PushNull
@ -411,8 +411,9 @@ Bytecode {
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData target-name 'toString', arg-desc CP#0
[2] = StaticICData target '#lib::_printString', arg-desc CP#0
[1] = InterfaceCall target-name 'toString', arg-desc CP#0
[2] = Reserved
[3] = StaticICData target '#lib::_printString', arg-desc CP#0
}
]static method _print(dynamic arg) → void {
self::_printString(arg.{core::Object::toString}());
@ -474,13 +475,13 @@ Bytecode {
PushConstant CP#0
PushStatic CP#0
PushConstant CP#1
InstanceCall 2, CP#3
InterfaceCall 2, CP#3
AssertBoolean 0
JumpIfTrue L1
PushConstant CP#0
PushStatic CP#0
PushConstant CP#4
InstanceCall 2, CP#5
PushConstant CP#5
InterfaceCall 2, CP#3
AssertBoolean 0
PopLocal r1
Jump L2
@ -493,7 +494,7 @@ L2:
PushConstant CP#0
PushStatic CP#0
PushConstant CP#6
InstanceCall 2, CP#7
InterfaceCall 2, CP#3
AssertBoolean 0
PopLocal r0
Jump L4
@ -505,35 +506,35 @@ L4:
JumpIfFalse L5
PushConstant CP#0
PushStatic CP#0
PushConstant CP#9
IndirectStaticCall 1, CP#8
PushConstant CP#8
IndirectStaticCall 1, CP#7
ReturnTOS
L5:
PushConstant CP#11
IndirectStaticCall 0, CP#10
PushConstant CP#10
IndirectStaticCall 0, CP#9
PushNull
PushConstant CP#0
PushStatic CP#0
PushConstant CP#12
PushConstant CP#11
IndirectStaticCall 2, CP#2
InstanceCall 2, CP#13
InterfaceCall 2, CP#12
ReturnTOS
}
ConstantPool {
[0] = StaticField #lib::_rawScript (field)
[1] = String 'http:'
[2] = ArgDesc num-args 2, num-type-args 0, names []
[3] = ICData target-name 'startsWith', arg-desc CP#2
[4] = String 'https:'
[5] = ICData target-name 'startsWith', arg-desc CP#2
[3] = InterfaceCall target-name 'startsWith', arg-desc CP#2
[4] = Reserved
[5] = String 'https:'
[6] = String 'file:'
[7] = ICData target-name 'startsWith', arg-desc CP#2
[8] = ArgDesc num-args 1, num-type-args 0, names []
[9] = StaticICData target 'dart:core::Uri::parse', arg-desc CP#8
[10] = ArgDesc num-args 0, num-type-args 0, names []
[11] = StaticICData target 'dart:core::Uri::get:base', arg-desc CP#10
[12] = StaticICData target 'dart:core::_Uri::file (constructor)', arg-desc CP#2
[13] = ICData target-name 'resolveUri', arg-desc CP#2
[7] = ArgDesc num-args 1, num-type-args 0, names []
[8] = StaticICData target 'dart:core::Uri::parse', arg-desc CP#7
[9] = ArgDesc num-args 0, num-type-args 0, names []
[10] = StaticICData target 'dart:core::Uri::get:base', arg-desc CP#9
[11] = StaticICData target 'dart:core::_Uri::file (constructor)', arg-desc CP#2
[12] = InterfaceCall target-name 'resolveUri', arg-desc CP#2
[13] = Reserved
}
]static method _scriptUri() → core::Uri {
if(self::_rawScript.{core::String::startsWith}("http:") || self::_rawScript.{core::String::startsWith}("https:") || self::_rawScript.{core::String::startsWith}("file:")) {

View file

@ -213,11 +213,11 @@ Bytecode {
PopLocal r3
PushConstant CP#44
Push r3
InstanceCall 2, CP#45
DynamicCall 2, CP#45
Drop1
PushConstant CP#46
Push r3
InstanceCall 2, CP#47
DynamicCall 2, CP#47
Drop1
PushNull
ReturnTOS
@ -319,11 +319,11 @@ L2:
PopLocal r3
PushConstant CP#38
Push r3
InstanceCall 2, CP#40
DynamicCall 2, CP#40
Drop1
PushConstant CP#41
Push r3
InstanceCall 2, CP#42
DynamicCall 2, CP#42
Drop1
PushNull
ReturnTOS
@ -376,7 +376,7 @@ L2:
StoreFieldTOS CP#1
PopLocal r3
Push r3
InstanceCall 1, CP#36
DynamicCall 1, CP#36
Drop1
PushNull
ReturnTOS
@ -522,69 +522,69 @@ Bytecode {
Push r0
PushInt 3
StoreContextVar 0, 2
Allocate CP#10
Allocate CP#11
StoreLocal r4
Push r4
PushNull
StoreFieldTOS CP#11
StoreFieldTOS CP#12
Push r4
PushNull
StoreFieldTOS CP#13
StoreFieldTOS CP#14
Push r4
PushConstant CP#15
StoreFieldTOS CP#16
PushConstant CP#16
StoreFieldTOS CP#17
Push r4
PushConstant CP#0
StoreFieldTOS CP#18
StoreFieldTOS CP#19
Push r4
Push r0
StoreFieldTOS CP#1
PopLocal r3
Push r3
PushInt 10
InstanceCall 2, CP#24
DynamicCall 2, CP#25
Drop1
Push r3
PushInt 11
InstanceCall 2, CP#25
DynamicCall 2, CP#26
Drop1
Push r2
PushConstant CP#26
IndirectStaticCall 1, CP#7
Drop1
Push r0
LoadContextVar 0, 2
PushConstant CP#27
IndirectStaticCall 1, CP#7
Drop1
Push r0
LoadContextVar 0, 1
LoadContextVar 0, 2
PushConstant CP#28
IndirectStaticCall 1, CP#7
Drop1
Push r0
LoadContextVar 0, 1
PushConstant CP#29
IndirectStaticCall 1, CP#7
Drop1
Push r0
PushInt 42
StoreContextVar 0, 3
Allocate CP#10
Allocate CP#11
StoreLocal r3
Push r3
PushNull
StoreFieldTOS CP#11
StoreFieldTOS CP#12
Push r3
PushNull
StoreFieldTOS CP#13
StoreFieldTOS CP#14
Push r3
PushConstant CP#15
StoreFieldTOS CP#16
PushConstant CP#16
StoreFieldTOS CP#17
Push r3
PushConstant CP#29
StoreFieldTOS CP#18
PushConstant CP#30
StoreFieldTOS CP#19
Push r3
Push r0
StoreFieldTOS CP#1
PopLocal r2
Push r2
InstanceCall 1, CP#32
DynamicCall 1, CP#34
Drop1
PushNull
ReturnTOS
@ -598,31 +598,33 @@ ConstantPool {
[5] = SubtypeTestCache
[6] = ClosureFunction 1
[7] = ArgDesc num-args 1, num-type-args 0, names []
[8] = ICData get target-name 'get:foo', arg-desc CP#7
[9] = EndClosureFunctionScope
[10] = Class dart:core::_Closure
[11] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
[12] = Reserved
[13] = InstanceField dart:core::_Closure::_function_type_arguments (field)
[14] = Reserved
[15] = EmptyTypeArguments
[16] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
[17] = Reserved
[18] = InstanceField dart:core::_Closure::_function (field)
[19] = Reserved
[20] = ICData dynamic target-name 'call', arg-desc CP#7
[21] = StaticICData target 'dart:core::print', arg-desc CP#7
[22] = EndClosureFunctionScope
[23] = ArgDesc num-args 2, num-type-args 0, names []
[24] = ICData dynamic target-name 'call', arg-desc CP#23
[25] = ICData dynamic target-name 'call', arg-desc CP#23
[26] = StaticICData target 'dart:core::print', arg-desc CP#7
[8] = InterfaceCall get target-name 'get:foo', arg-desc CP#7
[9] = Reserved
[10] = EndClosureFunctionScope
[11] = Class dart:core::_Closure
[12] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
[13] = Reserved
[14] = InstanceField dart:core::_Closure::_function_type_arguments (field)
[15] = Reserved
[16] = EmptyTypeArguments
[17] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
[18] = Reserved
[19] = InstanceField dart:core::_Closure::_function (field)
[20] = Reserved
[21] = ICData dynamic target-name 'call', arg-desc CP#7
[22] = StaticICData target 'dart:core::print', arg-desc CP#7
[23] = EndClosureFunctionScope
[24] = 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] = StaticICData target 'dart:core::print', arg-desc CP#7
[28] = StaticICData target 'dart:core::print', arg-desc CP#7
[29] = ClosureFunction 2
[30] = ICData set target-name 'set:foo', arg-desc CP#23
[31] = EndClosureFunctionScope
[32] = ICData dynamic target-name 'call', arg-desc CP#7
[29] = StaticICData target 'dart:core::print', arg-desc CP#7
[30] = ClosureFunction 2
[31] = InterfaceCall set target-name 'set:foo', arg-desc CP#24
[32] = Reserved
[33] = EndClosureFunctionScope
[34] = ICData dynamic target-name 'call', arg-desc CP#7
}
Closure #lib::B::topLevel::<anonymous closure> (dart:core::int y) -> dart:core::Null
ClosureBytecode {
@ -663,30 +665,30 @@ ClosureBytecode {
Push r0
PushInt 4
StoreContextVar 1, 1
Allocate CP#10
Allocate CP#11
StoreLocal r2
Push r2
PushNull
StoreFieldTOS CP#11
StoreFieldTOS CP#12
Push r2
PushNull
StoreFieldTOS CP#13
StoreFieldTOS CP#14
Push r2
PushConstant CP#15
StoreFieldTOS CP#16
PushConstant CP#16
StoreFieldTOS CP#17
Push r2
PushConstant CP#6
StoreFieldTOS CP#18
StoreFieldTOS CP#19
Push r2
Push r0
StoreFieldTOS CP#1
PopLocal r3
Push r3
InstanceCall 1, CP#20
DynamicCall 1, CP#21
Drop1
Push r0
LoadContextVar 1, 1
PushConstant CP#21
PushConstant CP#22
IndirectStaticCall 1, CP#7
Drop1
L1:
@ -714,7 +716,7 @@ ClosureBytecode {
Push r0
LoadContextParent
LoadContextVar 0, 0
InstanceCall 1, CP#8
InterfaceCall 1, CP#8
Push r0
LoadContextVar 1, 0
AddInt
@ -735,7 +737,7 @@ ClosureBytecode {
LoadContextVar 0, 0
Push r0
LoadContextVar 0, 3
InstanceCall 2, CP#30
InterfaceCall 2, CP#31
Drop1
PushNull
ReturnTOS
@ -855,7 +857,7 @@ L2:
Push r3
Push r0
StoreFieldTOS CP#5
InstanceCall 2, CP#18
InterfaceCall 2, CP#18
Drop1
Push r4
Allocate CP#8
@ -870,12 +872,12 @@ L2:
PushConstant CP#13
StoreFieldTOS CP#14
Push r3
PushConstant CP#19
PushConstant CP#20
StoreFieldTOS CP#16
Push r3
Push r0
StoreFieldTOS CP#5
InstanceCall 2, CP#24
InterfaceCall 2, CP#18
Drop1
Push r0
CloneContext 1, 1
@ -919,13 +921,13 @@ ConstantPool {
[15] = Reserved
[16] = InstanceField dart:core::_Closure::_function (field)
[17] = Reserved
[18] = ICData target-name 'add', arg-desc CP#1
[19] = ClosureFunction 1
[20] = Type dart:core::int
[21] = String 'ii'
[22] = SubtypeTestCache
[23] = EndClosureFunctionScope
[24] = ICData target-name 'add', arg-desc CP#1
[18] = InterfaceCall target-name 'add', arg-desc CP#1
[19] = Reserved
[20] = ClosureFunction 1
[21] = Type dart:core::int
[22] = String 'ii'
[23] = SubtypeTestCache
[24] = EndClosureFunctionScope
}
Closure #lib::C::testForLoop::<anonymous closure> () -> dart:core::int
ClosureBytecode {
@ -952,11 +954,11 @@ ClosureBytecode {
LoadFieldTOS CP#5
PopLocal r0
Push FP[-5]
PushConstant CP#20
PushNull
PushNull
PushConstant CP#21
AssertAssignable 1, CP#22
PushNull
PushNull
PushConstant CP#22
AssertAssignable 1, CP#23
Drop1
Push r0
Push FP[-5]
@ -985,43 +987,43 @@ Bytecode {
Entry 5
CheckStack 0
Push FP[-5]
InstanceCall 1, CP#1
InterfaceCall 1, CP#1
PopLocal r2
L2:
CheckStack 1
Push r2
InstanceCall 1, CP#2
InterfaceCall 1, CP#3
JumpIfFalse L1
AllocateContext 0, 1
PopLocal r0
Push r0
Push r2
InstanceCall 1, CP#3
InterfaceCall 1, CP#5
StoreContextVar 0, 0
Allocate CP#8
Allocate CP#11
StoreLocal r4
Push r4
PushNull
StoreFieldTOS CP#9
StoreFieldTOS CP#12
Push r4
PushNull
StoreFieldTOS CP#11
Push r4
PushConstant CP#13
StoreFieldTOS CP#14
Push r4
PushConstant CP#4
StoreFieldTOS CP#16
PushConstant CP#16
StoreFieldTOS CP#17
Push r4
PushConstant CP#7
StoreFieldTOS CP#19
Push r4
Push r0
StoreFieldTOS CP#5
StoreFieldTOS CP#8
PopLocal r3
Push r3
InstanceCall 1, CP#18
DynamicCall 1, CP#21
Drop1
Push r0
LoadContextVar 0, 0
PushConstant CP#19
PushConstant CP#22
IndirectStaticCall 1, CP#0
Drop1
Push r0
@ -1034,32 +1036,35 @@ L1:
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData get target-name 'get:iterator', arg-desc CP#0
[2] = ICData target-name 'moveNext', arg-desc CP#0
[3] = ICData get target-name 'get:current', arg-desc CP#0
[4] = ClosureFunction 0
[5] = InstanceField dart:core::_Closure::_context (field)
[1] = InterfaceCall get target-name 'get:iterator', arg-desc CP#0
[2] = Reserved
[3] = InterfaceCall target-name 'moveNext', arg-desc CP#0
[4] = Reserved
[5] = InterfaceCall get target-name 'get:current', arg-desc CP#0
[6] = Reserved
[7] = EndClosureFunctionScope
[8] = Class dart:core::_Closure
[9] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
[10] = Reserved
[11] = InstanceField dart:core::_Closure::_function_type_arguments (field)
[12] = Reserved
[13] = EmptyTypeArguments
[14] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
[7] = ClosureFunction 0
[8] = InstanceField dart:core::_Closure::_context (field)
[9] = Reserved
[10] = EndClosureFunctionScope
[11] = Class dart:core::_Closure
[12] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
[13] = Reserved
[14] = InstanceField dart:core::_Closure::_function_type_arguments (field)
[15] = Reserved
[16] = InstanceField dart:core::_Closure::_function (field)
[17] = Reserved
[18] = ICData dynamic target-name 'call', arg-desc CP#0
[19] = StaticICData target 'dart:core::print', arg-desc CP#0
[16] = EmptyTypeArguments
[17] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
[18] = Reserved
[19] = InstanceField dart:core::_Closure::_function (field)
[20] = Reserved
[21] = ICData dynamic target-name 'call', arg-desc CP#0
[22] = StaticICData target 'dart:core::print', arg-desc CP#0
}
Closure #lib::C::testForInLoop::<anonymous closure> () -> dart:core::Null
ClosureBytecode {
EntryFixed 1, 3
CheckStack 0
Push FP[-5]
LoadFieldTOS CP#5
LoadFieldTOS CP#8
PopLocal r0
Push r0
Push r0
@ -1202,7 +1207,7 @@ Bytecode {
PopLocal r2
Push r2
PushInt 3
InstanceCall 2, CP#18
DynamicCall 2, CP#18
Drop1
Push r0
LoadContextVar 0, 0
@ -1359,20 +1364,20 @@ Bytecode {
PushConstant CP#4
IndirectStaticCall 1, CP#3
Drop1
InstanceCall 2, CP#6
InterfaceCall 2, CP#6
Drop1
PushConstant CP#7
PushConstant CP#8
PushConstant CP#2
PushConstant CP#1
AllocateT
StoreLocal r0
Push r0
PushConstant CP#8
PushConstant CP#9
IndirectStaticCall 1, CP#3
Drop1
InstanceCall 2, CP#9
InterfaceCall 2, CP#6
Drop1
PushConstant CP#7
PushConstant CP#8
PushConstant CP#10
PushConstant CP#1
AllocateT
@ -1381,7 +1386,7 @@ Bytecode {
PushConstant CP#11
IndirectStaticCall 1, CP#3
Drop1
InstanceCall 2, CP#12
InterfaceCall 2, CP#6
Drop1
PushNull
ReturnTOS
@ -1393,13 +1398,12 @@ ConstantPool {
[3] = ArgDesc num-args 1, num-type-args 0, names []
[4] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#3
[5] = ArgDesc num-args 1, num-type-args 2, names []
[6] = ICData target-name 'foo', arg-desc CP#5
[7] = TypeArgs [dart:core::List < #lib::C3 >, dart:core::List < #lib::C4 >]
[8] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#3
[9] = ICData target-name 'foo', arg-desc CP#5
[6] = InterfaceCall target-name 'foo', arg-desc CP#5
[7] = Reserved
[8] = TypeArgs [dart:core::List < #lib::C3 >, dart:core::List < #lib::C4 >]
[9] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#3
[10] = TypeArgumentsForInstanceAllocation #lib::A [dart:core::List < #lib::C1 >, dart:core::List < #lib::C2 >]
[11] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#3
[12] = ICData target-name 'foo', arg-desc CP#5
}
]static method callA() → void {
new self::A::•<self::C1, self::C2>().{self::A::foo}<self::C3, self::C4>();

View file

@ -483,15 +483,15 @@ Bytecode {
Push r0
PushInt 1
Push FP[-5]
InstanceCall 1, CP#7
InterfaceCall 1, CP#7
StoreIndexedTOS
Push r0
PushInt 2
PushConstant CP#8
StoreIndexedTOS
PushConstant CP#9
IndirectStaticCall 2, CP#1
StoreIndexedTOS
PushConstant CP#10
IndirectStaticCall 2, CP#1
PushConstant CP#11
IndirectStaticCall 1, CP#3
Drop1
PushNull
@ -505,10 +505,11 @@ ConstantPool {
[4] = StaticICData target 'dart:core::print', arg-desc CP#3
[5] = TypeArgs [dart:core::String]
[6] = String 'a'
[7] = ICData target-name 'toString', arg-desc CP#3
[8] = String 'b'
[9] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#1
[10] = StaticICData target 'dart:core::print', arg-desc CP#3
[7] = InterfaceCall target-name 'toString', arg-desc CP#3
[8] = Reserved
[9] = String 'b'
[10] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#1
[11] = StaticICData target 'dart:core::print', arg-desc CP#3
}
]static method test_list_literal(core::int a) → void {
core::print(<core::int>[1, a, 3]);
@ -561,29 +562,29 @@ Bytecode {
Push r1
PushInt 2
Push FP[-6]
InstanceCall 1, CP#8
InterfaceCall 1, CP#8
StoreIndexedTOS
Push r1
PushInt 3
PushInt 3
StoreIndexedTOS
PushConstant CP#9
IndirectStaticCall 2, CP#2
PushConstant CP#10
IndirectStaticCall 1, CP#4
Drop1
PushNull
Push r0
InstantiateTypeArgumentsTOS 0, CP#11
PushConstant CP#12
PushConstant CP#13
IndirectStaticCall 2, CP#2
PushConstant CP#14
PushConstant CP#11
IndirectStaticCall 1, CP#4
Drop1
PushNull
Push r0
InstantiateTypeArgumentsTOS 0, CP#15
InstantiateTypeArgumentsTOS 0, CP#12
PushConstant CP#13
PushConstant CP#14
IndirectStaticCall 2, CP#2
PushConstant CP#15
IndirectStaticCall 1, CP#4
Drop1
PushNull
Push r0
InstantiateTypeArgumentsTOS 0, CP#16
PushConstant CP#1
PushInt 2
CreateArrayTOS
@ -596,9 +597,9 @@ Bytecode {
PushInt 1
PushInt 4
StoreIndexedTOS
PushConstant CP#16
IndirectStaticCall 2, CP#2
PushConstant CP#17
IndirectStaticCall 2, CP#2
PushConstant CP#18
IndirectStaticCall 1, CP#4
Drop1
PushNull
@ -613,16 +614,17 @@ ConstantPool {
[5] = StaticICData target 'dart:core::print', arg-desc CP#4
[6] = TypeArgs [dart:core::String, dart:core::int]
[7] = String 'foo'
[8] = ICData target-name 'toString', arg-desc CP#4
[9] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
[10] = StaticICData target 'dart:core::print', arg-desc CP#4
[11] = TypeArgs [dart:core::String, #lib::test_map_literal::TypeParam/0]
[12] = List type-arg dynamic, entries CP# []
[13] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
[14] = StaticICData target 'dart:core::print', arg-desc CP#4
[15] = TypeArgs [#lib::test_map_literal::TypeParam/0, dart:core::int]
[16] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
[17] = StaticICData target 'dart:core::print', arg-desc CP#4
[8] = InterfaceCall target-name 'toString', arg-desc CP#4
[9] = Reserved
[10] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
[11] = StaticICData target 'dart:core::print', arg-desc CP#4
[12] = TypeArgs [dart:core::String, #lib::test_map_literal::TypeParam/0]
[13] = List type-arg dynamic, entries CP# []
[14] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
[15] = StaticICData target 'dart:core::print', arg-desc CP#4
[16] = TypeArgs [#lib::test_map_literal::TypeParam/0, dart:core::int]
[17] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
[18] = StaticICData target 'dart:core::print', arg-desc CP#4
}
]static method test_map_literal<T extends core::Object = dynamic>(core::int a, core::int b, self::test_map_literal::T c) → void {
core::print(<core::int, core::int>{1: a, b: 2});

View file

@ -14,13 +14,13 @@ L2:
CheckStack 1
Push r1
Push FP[-5]
InstanceCall 1, CP#1
InterfaceCall 1, CP#1
CompareIntLt
JumpIfFalse L1
Push r0
Push FP[-5]
Push r1
InstanceCall 2, CP#3
InterfaceCall 2, CP#4
AddInt
PopLocal r0
Push r1
@ -35,9 +35,11 @@ L1:
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData get target-name 'get:length', arg-desc CP#0
[2] = ArgDesc num-args 2, num-type-args 0, names []
[3] = ICData target-name '[]', arg-desc CP#2
[1] = InterfaceCall get target-name 'get:length', arg-desc CP#0
[2] = Reserved
[3] = ArgDesc num-args 2, num-type-args 0, names []
[4] = InterfaceCall target-name '[]', arg-desc CP#3
[5] = Reserved
}
]static method test_for(core::List<core::int> list) → core::int {
core::int sum = 0;
@ -62,7 +64,7 @@ L3:
JumpIfFalse L1
Push r1
Push FP[-5]
InstanceCall 1, CP#1
InterfaceCall 1, CP#1
CompareIntGe
JumpIfFalse L2
Jump L1
@ -70,7 +72,7 @@ L2:
Push r0
Push FP[-5]
Push r1
InstanceCall 2, CP#3
InterfaceCall 2, CP#4
AddInt
PopLocal r0
Push r1
@ -85,9 +87,11 @@ L1:
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData get target-name 'get:length', arg-desc CP#0
[2] = ArgDesc num-args 2, num-type-args 0, names []
[3] = ICData target-name '[]', arg-desc CP#2
[1] = InterfaceCall get target-name 'get:length', arg-desc CP#0
[2] = Reserved
[3] = ArgDesc num-args 2, num-type-args 0, names []
[4] = InterfaceCall target-name '[]', arg-desc CP#3
[5] = Reserved
}
]static method test_for_break(core::List<core::int> list) → core::int {
core::int sum = 0;
@ -113,7 +117,7 @@ L4:
CheckStack 1
Push r1
Push FP[-5]
InstanceCall 1, CP#1
InterfaceCall 1, CP#1
CompareIntLt
JumpIfFalse L1
Push r1
@ -125,7 +129,7 @@ L2:
Push r0
Push FP[-5]
Push r1
InstanceCall 2, CP#3
InterfaceCall 2, CP#4
AddInt
PopLocal r0
L3:
@ -141,9 +145,11 @@ L1:
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData get target-name 'get:length', arg-desc CP#0
[2] = ArgDesc num-args 2, num-type-args 0, names []
[3] = ICData target-name '[]', arg-desc CP#2
[1] = InterfaceCall get target-name 'get:length', arg-desc CP#0
[2] = Reserved
[3] = ArgDesc num-args 2, num-type-args 0, names []
[4] = InterfaceCall target-name '[]', arg-desc CP#3
[5] = Reserved
}
]static method test_for_continue(core::List<core::int> list) → core::int {
core::int sum = 0;
@ -169,7 +175,7 @@ L2:
CheckStack 1
Push r1
Push FP[-5]
InstanceCall 1, CP#1
InterfaceCall 1, CP#1
CompareIntLt
JumpIfFalse L1
Push r0
@ -182,7 +188,7 @@ L2:
StoreLocal r1
PopLocal r3
Push r2
InstanceCall 2, CP#3
InterfaceCall 2, CP#4
AddInt
PopLocal r0
Jump L2
@ -192,9 +198,11 @@ L1:
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData get target-name 'get:length', arg-desc CP#0
[2] = ArgDesc num-args 2, num-type-args 0, names []
[3] = ICData target-name '[]', arg-desc CP#2
[1] = InterfaceCall get target-name 'get:length', arg-desc CP#0
[2] = Reserved
[3] = ArgDesc num-args 2, num-type-args 0, names []
[4] = InterfaceCall target-name '[]', arg-desc CP#3
[5] = Reserved
}
]static method test_while(core::List<core::int> list) → core::int {
core::int sum = 0;
@ -217,7 +225,7 @@ L1:
Push r0
Push FP[-5]
Push r1
InstanceCall 2, CP#1
InterfaceCall 2, CP#1
AddInt
PopLocal r0
Push r1
@ -226,7 +234,7 @@ L1:
PopLocal r1
Push r1
Push FP[-5]
InstanceCall 1, CP#3
InterfaceCall 1, CP#4
CompareIntLt
JumpIfTrue L1
Push r0
@ -234,9 +242,11 @@ L1:
}
ConstantPool {
[0] = ArgDesc num-args 2, num-type-args 0, names []
[1] = ICData target-name '[]', arg-desc CP#0
[2] = ArgDesc num-args 1, num-type-args 0, names []
[3] = ICData get target-name 'get:length', arg-desc CP#2
[1] = InterfaceCall target-name '[]', arg-desc CP#0
[2] = Reserved
[3] = ArgDesc num-args 1, num-type-args 0, names []
[4] = InterfaceCall get target-name 'get:length', arg-desc CP#3
[5] = Reserved
}
]static method test_do_while(core::List<core::int> list) → core::int {
core::int sum = 0;
@ -255,15 +265,15 @@ Bytecode {
PushInt 0
PopLocal r0
Push FP[-5]
InstanceCall 1, CP#1
InterfaceCall 1, CP#1
PopLocal r1
L2:
CheckStack 1
Push r1
InstanceCall 1, CP#2
InterfaceCall 1, CP#3
JumpIfFalse L1
Push r1
InstanceCall 1, CP#3
InterfaceCall 1, CP#5
PopLocal r2
Push r0
Push r2
@ -276,9 +286,12 @@ L1:
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData get target-name 'get:iterator', arg-desc CP#0
[2] = ICData target-name 'moveNext', arg-desc CP#0
[3] = ICData get target-name 'get:current', arg-desc CP#0
[1] = InterfaceCall get target-name 'get:iterator', arg-desc CP#0
[2] = Reserved
[3] = InterfaceCall target-name 'moveNext', arg-desc CP#0
[4] = Reserved
[5] = InterfaceCall get target-name 'get:current', arg-desc CP#0
[6] = Reserved
}
]static method test_for_in(core::List<core::int> list) → core::int {
core::int sum = 0;
@ -296,15 +309,15 @@ Bytecode {
PushInt 42
PopLocal r1
Push FP[-5]
InstanceCall 1, CP#1
InterfaceCall 1, CP#1
PopLocal r2
L2:
CheckStack 1
Push r2
InstanceCall 1, CP#2
InterfaceCall 1, CP#3
JumpIfFalse L1
Push r2
InstanceCall 1, CP#3
InterfaceCall 1, CP#5
PopLocal r3
Push r3
PopLocal r1
@ -319,9 +332,12 @@ L1:
}
ConstantPool {
[0] = ArgDesc num-args 1, num-type-args 0, names []
[1] = ICData get target-name 'get:iterator', arg-desc CP#0
[2] = ICData target-name 'moveNext', arg-desc CP#0
[3] = ICData get target-name 'get:current', arg-desc CP#0
[1] = InterfaceCall get target-name 'get:iterator', arg-desc CP#0
[2] = Reserved
[3] = InterfaceCall target-name 'moveNext', arg-desc CP#0
[4] = Reserved
[5] = InterfaceCall get target-name 'get:current', arg-desc CP#0
[6] = Reserved
}
]static method test_for_in_with_outer_var(core::List<core::int> list) → core::int {
core::int sum = 0;

View file

@ -132,7 +132,7 @@ Bytecode {
PushConstant CP#2
IndirectStaticCall 1, CP#1
PushConstant CP#3
InstanceCall 3, CP#5
DynamicCall 3, CP#5
ReturnTOS
}
ConstantPool {
@ -347,7 +347,7 @@ Bytecode {
PushConstant CP#7
IndirectStaticCall 2, CP#6
PushConstant CP#8
InstanceCall 3, CP#10
DynamicCall 3, CP#10
ReturnTOS
}
ConstantPool {

View file

@ -12,15 +12,15 @@ Bytecode {
PopLocal r1
Push r1
PushInt 1
InstanceCall 2, CP#1
InterfaceCall 2, CP#1
JumpIfTrue L1
Push r1
PushInt 2
InstanceCall 2, CP#2
InterfaceCall 2, CP#1
JumpIfTrue L2
Push r1
PushInt 3
InstanceCall 2, CP#3
InterfaceCall 2, CP#1
JumpIfTrue L3
Jump L4
L1:
@ -41,9 +41,8 @@ L4:
}
ConstantPool {
[0] = ArgDesc num-args 2, num-type-args 0, names []
[1] = ICData target-name '==', arg-desc CP#0
[2] = ICData target-name '==', arg-desc CP#0
[3] = ICData target-name '==', arg-desc CP#0
[1] = InterfaceCall target-name '==', arg-desc CP#0
[2] = Reserved
}
]static method foo1(core::int x) → core::int {
core::int y;
@ -80,27 +79,27 @@ Bytecode {
PopLocal r1
Push r1
PushInt 1
InstanceCall 2, CP#1
InterfaceCall 2, CP#1
JumpIfTrue L1
Push r1
PushInt 2
InstanceCall 2, CP#2
InterfaceCall 2, CP#1
JumpIfTrue L1
Push r1
PushInt 3
InstanceCall 2, CP#3
InterfaceCall 2, CP#1
JumpIfTrue L1
Push r1
PushInt 4
InstanceCall 2, CP#4
InterfaceCall 2, CP#1
JumpIfTrue L2
Push r1
PushInt 5
InstanceCall 2, CP#5
InterfaceCall 2, CP#1
JumpIfTrue L2
Push r1
PushInt 6
InstanceCall 2, CP#6
InterfaceCall 2, CP#1
JumpIfTrue L2
Jump L3
L1:
@ -120,12 +119,8 @@ L4:
}
ConstantPool {
[0] = ArgDesc num-args 2, num-type-args 0, names []
[1] = ICData target-name '==', arg-desc CP#0
[2] = ICData target-name '==', arg-desc CP#0
[3] = ICData target-name '==', arg-desc CP#0
[4] = ICData target-name '==', arg-desc CP#0
[5] = ICData target-name '==', arg-desc CP#0
[6] = ICData target-name '==', arg-desc CP#0
[1] = InterfaceCall target-name '==', arg-desc CP#0
[2] = Reserved
}
]static method foo2(core::int x) → core::int {
core::int y;
@ -165,27 +160,27 @@ Bytecode {
PopLocal r1
Push r1
PushInt 1
InstanceCall 2, CP#1
InterfaceCall 2, CP#1
JumpIfTrue L1
Push r1
PushInt 2
InstanceCall 2, CP#2
InterfaceCall 2, CP#1
JumpIfTrue L1
Push r1
PushInt 3
InstanceCall 2, CP#3
InterfaceCall 2, CP#1
JumpIfTrue L1
Push r1
PushInt 4
InstanceCall 2, CP#4
InterfaceCall 2, CP#1
JumpIfTrue L2
Push r1
PushInt 5
InstanceCall 2, CP#5
InterfaceCall 2, CP#1
JumpIfTrue L2
Push r1
PushInt 6
InstanceCall 2, CP#6
InterfaceCall 2, CP#1
JumpIfTrue L2
Jump L3
L1:
@ -205,12 +200,8 @@ L3:
}
ConstantPool {
[0] = ArgDesc num-args 2, num-type-args 0, names []
[1] = ICData target-name '==', arg-desc CP#0
[2] = ICData target-name '==', arg-desc CP#0
[3] = ICData target-name '==', arg-desc CP#0
[4] = ICData target-name '==', arg-desc CP#0
[5] = ICData target-name '==', arg-desc CP#0
[6] = ICData target-name '==', arg-desc CP#0
[1] = InterfaceCall target-name '==', arg-desc CP#0
[2] = Reserved
}
]static method foo3(core::int x) → core::int {
core::int y;

View file

@ -78,17 +78,17 @@ Try #0 handler:
MoveSpecial stackTrace, r1
Push r0
PushConstant CP#3
InstanceCall 2, CP#5
InterfaceCall 2, CP#5
JumpIfFalse L2
PushConstant CP#6
PushConstant CP#7
PushConstant CP#8
IndirectStaticCall 1, CP#1
Drop1
Jump L1
L2:
Push r0
PushConstant CP#8
InstanceCall 2, CP#9
PushConstant CP#9
InterfaceCall 2, CP#5
JumpIfFalse L3
Push r0
PopLocal r2
@ -113,7 +113,7 @@ L2:
L3:
Push r0
PushConstant CP#13
InstanceCall 2, CP#14
InterfaceCall 2, CP#5
JumpIfFalse L4
Push r0
PopLocal r2
@ -125,7 +125,7 @@ L3:
StoreLocal r4
Push r4
PushInt 0
PushConstant CP#15
PushConstant CP#14
StoreIndexedTOS
Push r4
PushInt 1
@ -133,15 +133,15 @@ L3:
StoreIndexedTOS
Push r4
PushInt 2
PushConstant CP#16
PushConstant CP#15
StoreIndexedTOS
Push r4
PushInt 3
Push r3
StoreIndexedTOS
PushConstant CP#17
PushConstant CP#16
IndirectStaticCall 1, CP#1
PushConstant CP#18
PushConstant CP#17
IndirectStaticCall 1, CP#1
Drop1
Jump L1
@ -156,7 +156,7 @@ L4:
StoreLocal r4
Push r4
PushInt 0
PushConstant CP#20
PushConstant CP#19
StoreIndexedTOS
Push r4
PushInt 1
@ -164,15 +164,15 @@ L4:
StoreIndexedTOS
Push r4
PushInt 2
PushConstant CP#16
PushConstant CP#15
StoreIndexedTOS
Push r4
PushInt 3
Push r3
StoreIndexedTOS
PushConstant CP#21
PushConstant CP#20
IndirectStaticCall 1, CP#1
PushConstant CP#22
PushConstant CP#21
IndirectStaticCall 1, CP#1
Drop1
Jump L1
@ -181,7 +181,7 @@ L1:
ReturnTOS
}
ExceptionsTable {
try-index 0, outer -1, start 2, end 7, handler 7, needs-stack-trace, types [CP#3, CP#8, CP#13, CP#19]
try-index 0, outer -1, start 2, end 7, handler 7, needs-stack-trace, types [CP#3, CP#9, CP#13, CP#18]
}
ConstantPool {
[0] = String 'danger!'
@ -189,24 +189,23 @@ ConstantPool {
[2] = StaticICData target 'dart:core::print', arg-desc CP#1
[3] = Type dart:core::TypeError
[4] = ArgDesc num-args 2, num-type-args 0, names []
[5] = ICData target-name '_simpleInstanceOf', arg-desc CP#4
[6] = String 'caught type error'
[7] = StaticICData target 'dart:core::print', arg-desc CP#1
[8] = Type dart:core::AssertionError
[9] = ICData target-name '_simpleInstanceOf', arg-desc CP#4
[5] = InterfaceCall target-name '_simpleInstanceOf', arg-desc CP#4
[6] = Reserved
[7] = String 'caught type error'
[8] = StaticICData target 'dart:core::print', arg-desc CP#1
[9] = Type dart:core::AssertionError
[10] = String 'caught assertion error '
[11] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
[12] = StaticICData target 'dart:core::print', arg-desc CP#1
[13] = Type dart:core::Error
[14] = ICData target-name '_simpleInstanceOf', arg-desc CP#4
[15] = String 'caught error '
[16] = String ' '
[17] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
[18] = StaticICData target 'dart:core::print', arg-desc CP#1
[19] = Type dynamic
[20] = String 'caught something '
[21] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
[22] = StaticICData target 'dart:core::print', arg-desc CP#1
[14] = String 'caught error '
[15] = String ' '
[16] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
[17] = StaticICData target 'dart:core::print', arg-desc CP#1
[18] = Type dynamic
[19] = String 'caught something '
[20] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
[21] = StaticICData target 'dart:core::print', arg-desc CP#1
}
]static method testTryCatch2() → dynamic {
try {
@ -259,7 +258,7 @@ Try #0 start:
StoreFieldTOS CP#1
PopLocal r4
Push r4
InstanceCall 1, CP#19
DynamicCall 1, CP#19
Drop1
Push r0
LoadContextVar 0, 1
@ -366,12 +365,13 @@ ConstantPool {
[27] = StaticICData target 'dart:core::print', arg-desc CP#4
[28] = Type dart:core::Error
[29] = ArgDesc num-args 2, num-type-args 0, names []
[30] = ICData target-name '_simpleInstanceOf', arg-desc CP#29
[31] = String 'error '
[32] = String ', captured stack trace: '
[33] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#4
[34] = StaticICData target 'dart:core::print', arg-desc CP#4
[35] = EndClosureFunctionScope
[30] = InterfaceCall target-name '_simpleInstanceOf', arg-desc CP#29
[31] = Reserved
[32] = String 'error '
[33] = String ', captured stack trace: '
[34] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#4
[35] = StaticICData target 'dart:core::print', arg-desc CP#4
[36] = EndClosureFunctionScope
}
Closure #lib::testTryCatch3::foo () -> void
ClosureBytecode {
@ -436,7 +436,7 @@ Try #0 handler:
MoveSpecial stackTrace, r3
Push r2
PushConstant CP#28
InstanceCall 2, CP#30
InterfaceCall 2, CP#30
JumpIfFalse L2
Push r2
PopLocal r4
@ -446,7 +446,7 @@ Try #0 handler:
StoreLocal r5
Push r5
PushInt 0
PushConstant CP#31
PushConstant CP#32
StoreIndexedTOS
Push r5
PushInt 1
@ -454,17 +454,17 @@ Try #0 handler:
StoreIndexedTOS
Push r5
PushInt 2
PushConstant CP#32
PushConstant CP#33
StoreIndexedTOS
Push r5
PushInt 3
Push r0
LoadContextVar 0, 2
StoreIndexedTOS
PushConstant CP#33
IndirectStaticCall 1, CP#4
PushConstant CP#34
IndirectStaticCall 1, CP#4
PushConstant CP#35
IndirectStaticCall 1, CP#4
Drop1
Jump L1
L2:
@ -704,11 +704,11 @@ Bytecode {
PopLocal r2
Push r2
PushInt 1
InstanceCall 2, CP#1
InterfaceCall 2, CP#1
JumpIfTrue L1
Push r2
PushInt 2
InstanceCall 2, CP#2
InterfaceCall 2, CP#1
JumpIfTrue L2
Jump L3
L1:
@ -748,7 +748,7 @@ Try #1 start:
StoreFieldTOS CP#9
PopLocal r7
Push r7
InstanceCall 1, CP#24
DynamicCall 1, CP#24
Drop1
Jump L4
Try #1 end:
@ -811,8 +811,8 @@ ExceptionsTable {
}
ConstantPool {
[0] = ArgDesc num-args 2, num-type-args 0, names []
[1] = ICData target-name '==', arg-desc CP#0
[2] = ICData target-name '==', arg-desc CP#0
[1] = InterfaceCall target-name '==', arg-desc CP#0
[2] = Reserved
[3] = String 'before try 1'
[4] = ArgDesc num-args 1, num-type-args 0, names []
[5] = StaticICData target 'dart:core::print', arg-desc CP#4
@ -950,7 +950,7 @@ Try #0 handler:
IndirectStaticCall 1, CP#3
Drop1
Push r2
InstanceCall 1, CP#27
DynamicCall 1, CP#27
Drop1
Push r3
Push r4
@ -964,7 +964,7 @@ L1:
IndirectStaticCall 1, CP#3
Drop1
Push r2
InstanceCall 1, CP#29
DynamicCall 1, CP#29
Drop1
Push r0
LoadContextParent

View file

@ -106,23 +106,23 @@ Bytecode {
LoadTypeArgumentsField CP#0
PushNull
PushConstant CP#1
InstanceCall 4, CP#3
InterfaceCall 4, CP#3
JumpIfFalse L1
PushConstant CP#4
PushConstant CP#6
IndirectStaticCall 1, CP#5
PushConstant CP#5
PushConstant CP#7
IndirectStaticCall 1, CP#6
Drop1
L1:
Push FP[-5]
Push FP[-6]
LoadTypeArgumentsField CP#0
PushNull
PushConstant CP#7
InstanceCall 4, CP#8
PushConstant CP#8
InterfaceCall 4, CP#3
JumpIfFalse L2
PushConstant CP#9
PushConstant CP#10
IndirectStaticCall 1, CP#5
IndirectStaticCall 1, CP#6
Drop1
L2:
Push FP[-6]
@ -133,7 +133,7 @@ L2:
PushNull
PushConstant CP#12
AssertAssignable 0, CP#13
InstanceCall 2, CP#15
InterfaceCall 2, CP#15
Drop1
PushNull
ReturnTOS
@ -142,19 +142,20 @@ ConstantPool {
[0] = TypeArgumentsField #lib::D
[1] = Type #lib::A < #lib::D::TypeParam/0 >
[2] = ArgDesc num-args 4, num-type-args 0, names []
[3] = ICData target-name '_instanceOf', arg-desc CP#2
[4] = String '21'
[5] = ArgDesc num-args 1, num-type-args 0, names []
[6] = StaticICData target 'dart:core::print', arg-desc CP#5
[7] = Type #lib::C < dynamic, #lib::D::TypeParam/1, dart:core::List < #lib::D::TypeParam/0 > >
[8] = ICData target-name '_instanceOf', arg-desc CP#2
[3] = InterfaceCall target-name '_instanceOf', arg-desc CP#2
[4] = Reserved
[5] = String '21'
[6] = ArgDesc num-args 1, num-type-args 0, names []
[7] = StaticICData target 'dart:core::print', arg-desc CP#6
[8] = Type #lib::C < dynamic, #lib::D::TypeParam/1, dart:core::List < #lib::D::TypeParam/0 > >
[9] = String '22'
[10] = StaticICData target 'dart:core::print', arg-desc CP#5
[10] = StaticICData target 'dart:core::print', arg-desc CP#6
[11] = Type dart:core::Map < #lib::D::TypeParam/0, #lib::D::TypeParam/1 >
[12] = String ''
[13] = SubtypeTestCache
[14] = ArgDesc num-args 2, num-type-args 0, names []
[15] = ICData set target-name 'set:foo', arg-desc CP#14
[15] = InterfaceCall set target-name 'set:foo', arg-desc CP#14
[16] = Reserved
}
] method foo2(dynamic y) → dynamic {
if(y is self::A<self::D::P>) {
@ -174,51 +175,52 @@ Bytecode {
PushNull
Push r0
PushConstant CP#0
InstanceCall 4, CP#2
InterfaceCall 4, CP#2
JumpIfFalse L1
PushConstant CP#3
PushConstant CP#5
IndirectStaticCall 1, CP#4
PushConstant CP#4
PushConstant CP#6
IndirectStaticCall 1, CP#5
Drop1
L1:
Push FP[-5]
Push FP[-6]
LoadTypeArgumentsField CP#6
LoadTypeArgumentsField CP#7
Push r0
PushConstant CP#7
InstanceCall 4, CP#8
PushConstant CP#8
InterfaceCall 4, CP#2
JumpIfFalse L2
PushConstant CP#9
PushConstant CP#10
IndirectStaticCall 1, CP#4
IndirectStaticCall 1, CP#5
Drop1
L2:
Push FP[-5]
PushConstant CP#11
Push FP[-6]
LoadTypeArgumentsField CP#6
LoadTypeArgumentsField CP#7
Push r0
PushConstant CP#12
AssertAssignable 0, CP#13
InstanceCall 1, CP#14
InterfaceCall 1, CP#14
ReturnTOS
}
ConstantPool {
[0] = Type #lib::A < #lib::D::foo3::TypeParam/0 >
[1] = ArgDesc num-args 4, num-type-args 0, names []
[2] = ICData target-name '_instanceOf', arg-desc CP#1
[3] = String '31'
[4] = ArgDesc num-args 1, num-type-args 0, names []
[5] = StaticICData target 'dart:core::print', arg-desc CP#4
[6] = TypeArgumentsField #lib::D
[7] = Type #lib::C < dart:core::Map < #lib::D::foo3::TypeParam/0, #lib::D::TypeParam/0 >, dart:core::List < #lib::D::foo3::TypeParam/1 >, #lib::D::TypeParam/1 >
[8] = ICData target-name '_instanceOf', arg-desc CP#1
[2] = InterfaceCall target-name '_instanceOf', arg-desc CP#1
[3] = Reserved
[4] = String '31'
[5] = ArgDesc num-args 1, num-type-args 0, names []
[6] = StaticICData target 'dart:core::print', arg-desc CP#5
[7] = TypeArgumentsField #lib::D
[8] = Type #lib::C < dart:core::Map < #lib::D::foo3::TypeParam/0, #lib::D::TypeParam/0 >, dart:core::List < #lib::D::foo3::TypeParam/1 >, #lib::D::TypeParam/1 >
[9] = String '32'
[10] = StaticICData target 'dart:core::print', arg-desc CP#4
[10] = StaticICData target 'dart:core::print', arg-desc CP#5
[11] = Type dart:core::Map < #lib::D::foo3::TypeParam/1, #lib::D::TypeParam/1 >
[12] = String ' in type cast'
[13] = SubtypeTestCache
[14] = ICData get target-name 'get:values', arg-desc CP#4
[14] = InterfaceCall get target-name 'get:values', arg-desc CP#5
[15] = Reserved
}
] method foo3<T1 extends core::Object = dynamic, T2 extends core::Object = dynamic>(dynamic z) → dynamic {
if(z is self::A<self::D::foo3::T1>) {
@ -329,47 +331,49 @@ Bytecode {
CheckStack 0
Push FP[-5]
PushConstant CP#0
InstanceCall 2, CP#2
InterfaceCall 2, CP#2
JumpIfFalse L1
PushConstant CP#3
PushConstant CP#5
IndirectStaticCall 1, CP#4
PushConstant CP#4
PushConstant CP#6
IndirectStaticCall 1, CP#5
Drop1
L1:
Push FP[-5]
PushNull
PushNull
PushConstant CP#6
InstanceCall 4, CP#8
PushConstant CP#7
InterfaceCall 4, CP#9
JumpIfFalse L2
PushConstant CP#9
PushConstant CP#10
IndirectStaticCall 1, CP#4
PushConstant CP#11
PushConstant CP#12
IndirectStaticCall 1, CP#5
Drop1
L2:
Push FP[-5]
PushConstant CP#11
PushConstant CP#13
PushNull
PushNull
PushConstant CP#12
AssertAssignable 0, CP#13
PushConstant CP#14
AssertAssignable 0, CP#15
ReturnTOS
}
ConstantPool {
[0] = Type #lib::B
[1] = ArgDesc num-args 2, num-type-args 0, names []
[2] = ICData target-name '_simpleInstanceOf', arg-desc CP#1
[3] = String '11'
[4] = ArgDesc num-args 1, num-type-args 0, names []
[5] = StaticICData target 'dart:core::print', arg-desc CP#4
[6] = Type #lib::C < dart:core::int, dart:core::Object, dynamic >
[7] = ArgDesc num-args 4, num-type-args 0, names []
[8] = ICData target-name '_instanceOf', arg-desc CP#7
[9] = String '12'
[10] = StaticICData target 'dart:core::print', arg-desc CP#4
[11] = Type #lib::A < dart:core::int >
[12] = String ' in type cast'
[13] = SubtypeTestCache
[2] = InterfaceCall target-name '_simpleInstanceOf', arg-desc CP#1
[3] = Reserved
[4] = String '11'
[5] = ArgDesc num-args 1, num-type-args 0, names []
[6] = StaticICData target 'dart:core::print', arg-desc CP#5
[7] = Type #lib::C < dart:core::int, dart:core::Object, dynamic >
[8] = ArgDesc num-args 4, num-type-args 0, names []
[9] = InterfaceCall target-name '_instanceOf', arg-desc CP#8
[10] = Reserved
[11] = String '12'
[12] = StaticICData target 'dart:core::print', arg-desc CP#5
[13] = Type #lib::A < dart:core::int >
[14] = String ' in type cast'
[15] = SubtypeTestCache
}
]static method foo1(dynamic x) → dynamic {
if(x is self::B) {

View file

@ -214,7 +214,8 @@ static bool HasLoadFromPool(KBCInstr instr) {
case KernelBytecode::kLoadConstant:
case KernelBytecode::kPushConstant:
case KernelBytecode::kIndirectStaticCall:
case KernelBytecode::kInstanceCall:
case KernelBytecode::kInterfaceCall:
case KernelBytecode::kDynamicCall:
case KernelBytecode::kStoreStaticTOS:
case KernelBytecode::kPushStatic:
case KernelBytecode::kAllocate:

View file

@ -701,7 +701,47 @@ void BytecodeFlowGraphBuilder::BuildIndirectStaticCall() {
B->Push(call);
}
void BytecodeFlowGraphBuilder::BuildInstanceCall() {
void BytecodeFlowGraphBuilder::BuildInterfaceCall() {
if (is_generating_interpreter()) {
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
}
const String& name = String::Cast(ConstantAt(DecodeOperandD()).value());
ASSERT(name.IsSymbol());
const Array& arg_desc_array =
Array::Cast(ConstantAt(DecodeOperandD(), 1).value());
const ArgumentsDescriptor arg_desc(arg_desc_array);
const intptr_t argc = DecodeOperandA().value();
const Token::Kind token_kind =
MethodTokenRecognizer::RecognizeTokenKind(name);
intptr_t checked_argument_count = 1;
if ((token_kind != Token::kILLEGAL) ||
(name.raw() ==
Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()).raw())) {
intptr_t argument_count = arg_desc.Count();
ASSERT(argument_count <= 2);
checked_argument_count = argument_count;
}
const ArgumentArray arguments = GetArguments(argc);
// TODO(alexmarkov): store interface_target in bytecode and pass it here.
InstanceCallInstr* call = new (Z) InstanceCallInstr(
position_, name, token_kind, arguments, arg_desc.TypeArgsLen(),
Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), checked_argument_count,
*ic_data_array_, B->GetNextDeoptId());
// TODO(alexmarkov): add type info - call->SetResultType()
code_ <<= call;
B->Push(call);
}
void BytecodeFlowGraphBuilder::BuildDynamicCall() {
if (is_generating_interpreter()) {
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
}

View file

@ -344,6 +344,7 @@ void BytecodeMetadataHelper::ReadConstantPool(const Function& function,
kPartialTearOffInstantiation,
kEmptyTypeArguments,
kSymbol,
kInterfaceCall,
};
enum InvocationKind {
@ -618,6 +619,22 @@ void BytecodeMetadataHelper::ReadConstantPool(const Function& function,
Instance::Cast(obj).SetField(*symbol_name_field, name);
obj = H.Canonicalize(Instance::Cast(obj));
} break;
case ConstantPoolTag::kInterfaceCall: {
helper_->ReadByte(); // TODO(regis): Remove, unneeded.
name ^= ReadObject();
ASSERT(name.IsSymbol());
intptr_t arg_desc_index = helper_->ReadUInt();
ASSERT(arg_desc_index < i);
array ^= pool.ObjectAt(arg_desc_index);
// InterfaceCall constant occupies 2 entries.
// The first entry is used for selector name.
pool.SetTypeAt(i, ObjectPool::kTaggedObject, ObjectPool::kNotPatchable);
pool.SetObjectAt(i, name);
++i;
ASSERT(i < obj_count);
// The second entry is used for arguments descriptor.
obj = array.raw();
} break;
default:
UNREACHABLE();
}

View file

@ -271,7 +271,16 @@ namespace dart {
// SP[-(1+ArgC)], ..., SP[-1] and argument descriptor PP[D], which
// indicates whether the first argument is a type argument vector.
//
// - InstanceCall ArgC, D
// - InterfaceCall ArgC, D
//
// Lookup and invoke method using ICData in PP[D]
// with arguments SP[-(1+ArgC)], ..., SP[-1].
// Method has to be declared (explicitly or implicitly) in an interface
// implemented by a receiver, and passed arguments are valid for the
// interface method declaration.
// The ICData indicates whether the first argument is a type argument vector.
//
// - DynamicCall ArgC, D
//
// Lookup and invoke method using ICData in PP[D]
// with arguments SP[-(1+ArgC)], ..., SP[-1].
@ -439,7 +448,8 @@ namespace dart {
V(JumpIfNull, T, tgt, ___, ___) \
V(JumpIfNotNull, T, tgt, ___, ___) \
V(IndirectStaticCall, A_D, num, num, ___) \
V(InstanceCall, A_D, num, num, ___) \
V(InterfaceCall, A_D, num, num, ___) \
V(DynamicCall, A_D, num, num, ___) \
V(NativeCall, D, lit, ___, ___) \
V(ReturnTOS, 0, ___, ___, ___) \
V(AssertAssignable, A_D, num, lit, ___) \
@ -595,7 +605,8 @@ class KernelBytecode {
DART_FORCE_INLINE static bool IsCallOpcode(KBCInstr instr) {
switch (DecodeOpcode(instr)) {
case KernelBytecode::kIndirectStaticCall:
case KernelBytecode::kInstanceCall:
case KernelBytecode::kInterfaceCall:
case KernelBytecode::kDynamicCall:
return true;
default:

View file

@ -86,7 +86,6 @@ class ArgumentsDescriptor : public ValueObject {
enum {
kTypeArgsLenIndex,
kCountIndex,
kPositionalCountIndex,
kFirstNamedEntryIndex,
};

View file

@ -479,6 +479,15 @@ class MarkingWeakVisitor : public HandleVisitor {
void GCMarker::Prologue() {
isolate_->ReleaseStoreBuffers();
#ifndef DART_PRECOMPILED_RUNTIME
if (isolate_->IsMutatorThreadScheduled()) {
Interpreter* interpreter = isolate_->mutator_thread()->interpreter();
if (interpreter != NULL) {
interpreter->MajorGC();
}
}
#endif
}
void GCMarker::Epilogue() {

View file

@ -499,6 +499,66 @@ DART_FORCE_INLINE static RawFunction* FrameFunction(RawObject** FP) {
return function;
}
void LookupCache::Clear() {
for (intptr_t i = 0; i < kNumEntries; i++) {
entries_[i].receiver_cid = kIllegalCid;
}
}
bool LookupCache::Lookup(intptr_t receiver_cid,
RawString* function_name,
RawFunction** target) const {
ASSERT(receiver_cid != kIllegalCid); // Sentinel value.
const intptr_t hash =
receiver_cid ^ reinterpret_cast<intptr_t>(function_name);
const intptr_t probe1 = hash & kTableMask;
if (entries_[probe1].receiver_cid == receiver_cid &&
entries_[probe1].function_name == function_name) {
*target = entries_[probe1].target;
return true;
}
intptr_t probe2 = (hash >> 3) & kTableMask;
if (entries_[probe2].receiver_cid == receiver_cid &&
entries_[probe2].function_name == function_name) {
*target = entries_[probe2].target;
return true;
}
return false;
}
void LookupCache::Insert(intptr_t receiver_cid,
RawString* function_name,
RawFunction* target) {
// Otherwise we have to clear the cache or rehash on scavenges too.
ASSERT(function_name->IsOldObject());
ASSERT(target->IsOldObject());
const intptr_t hash =
receiver_cid ^ reinterpret_cast<intptr_t>(function_name);
const intptr_t probe1 = hash & kTableMask;
if (entries_[probe1].receiver_cid == kIllegalCid) {
entries_[probe1].receiver_cid = receiver_cid;
entries_[probe1].function_name = function_name;
entries_[probe1].target = target;
return;
}
const intptr_t probe2 = (hash >> 3) & kTableMask;
if (entries_[probe2].receiver_cid == kIllegalCid) {
entries_[probe2].receiver_cid = receiver_cid;
entries_[probe2].function_name = function_name;
entries_[probe2].target = target;
return;
}
entries_[probe1].receiver_cid = receiver_cid;
entries_[probe1].function_name = function_name;
entries_[probe1].target = target;
}
IntrinsicHandler Interpreter::intrinsics_[Interpreter::kIntrinsicCount];
// Synchronization primitives support.
@ -545,7 +605,7 @@ void Interpreter::InitOnce() {
}
Interpreter::Interpreter()
: stack_(NULL), fp_(NULL), pp_(NULL), argdesc_(NULL) {
: stack_(NULL), fp_(NULL), pp_(NULL), argdesc_(NULL), lookup_cache_() {
// Setup interpreter support first. Some of this information is needed to
// setup the architecture state.
// We allocate the stack here, the size is computed as the sum of
@ -584,6 +644,8 @@ Interpreter::Interpreter()
Interpreter::~Interpreter() {
delete[] stack_;
pp_ = NULL;
argdesc_ = NULL;
#if defined(DEBUG)
if (trace_file_ != NULL) {
FlushTraceBuffer();
@ -601,8 +663,10 @@ Interpreter::~Interpreter() {
// Get the active Interpreter for the current isolate.
Interpreter* Interpreter::Current() {
Interpreter* interpreter = Thread::Current()->interpreter();
Thread* thread = Thread::Current();
Interpreter* interpreter = thread->interpreter();
if (interpreter == NULL) {
TransitionGeneratedToVM transition(thread);
interpreter = new Interpreter();
Thread::Current()->set_interpreter(interpreter);
}
@ -697,19 +761,6 @@ void Interpreter::Exit(Thread* thread,
#endif
}
void Interpreter::CallRuntime(Thread* thread,
RawObject** base,
RawObject** exit_frame,
uint32_t* pc,
intptr_t argc_tag,
RawObject** args,
RawObject** result,
uword target) {
Exit(thread, base, exit_frame, pc);
NativeArguments native_args(thread, argc_tag, args, result);
reinterpret_cast<RuntimeFunction>(target)(native_args);
}
// Calling into runtime may trigger garbage collection and relocate objects,
// so all RawObject* pointers become outdated and should not be used across
// runtime calls.
@ -1171,8 +1222,48 @@ void Interpreter::InlineCacheMiss(int checked_args,
// Handler arguments: arguments to check and an ICData object.
const intptr_t miss_handler_argc = checked_args + 1;
RawObject** exit_frame = miss_handler_args + miss_handler_argc;
CallRuntime(thread, FP, exit_frame, pc, miss_handler_argc, miss_handler_args,
result, reinterpret_cast<uword>(handler));
Exit(thread, FP, exit_frame, pc);
NativeArguments native_args(thread, miss_handler_argc, miss_handler_args,
result);
handler(native_args);
}
DART_FORCE_INLINE bool Interpreter::InterfaceCall(Thread* thread,
RawString* target_name,
RawObject** call_base,
RawObject** top,
uint32_t** pc,
RawObject*** FP,
RawObject*** SP) {
const intptr_t type_args_len =
InterpreterHelpers::ArgDescTypeArgsLen(argdesc_);
const intptr_t receiver_idx = type_args_len > 0 ? 1 : 0;
intptr_t receiver_cid =
InterpreterHelpers::GetClassId(call_base[receiver_idx]);
RawFunction* target;
if (UNLIKELY(!lookup_cache_.Lookup(receiver_cid, target_name, &target))) {
// Table lookup miss.
top[1] = call_base[receiver_idx];
top[2] = target_name;
top[3] = argdesc_;
top[4] = 0; // Result slot.
Exit(thread, *FP, top + 5, *pc);
NativeArguments native_args(thread, 3, /* argv */ top + 1,
/* result */ top + 4);
DRT_InterpretedInterfaceCallMissHandler(native_args);
target = static_cast<RawFunction*>(top[4]);
target_name = static_cast<RawString*>(top[2]);
argdesc_ = static_cast<RawArray*>(top[3]);
ASSERT(target->IsFunction());
lookup_cache_.Insert(receiver_cid, target_name, target);
}
top[0] = target;
return Invoke(thread, call_base, top, pc, FP, SP);
}
DART_FORCE_INLINE bool Interpreter::InstanceCall1(Thread* thread,
@ -2111,7 +2202,36 @@ SwitchDispatch:
}
{
BYTECODE(InstanceCall, A_D);
BYTECODE(InterfaceCall, A_D);
// Check if single stepping.
if (thread->isolate()->single_step()) {
Exit(thread, FP, SP + 1, pc);
NativeArguments args(thread, 0, NULL, NULL);
INVOKE_RUNTIME(DRT_SingleStepHandler, args);
}
{
const uint16_t argc = rA;
const uint16_t kidx = rD;
RawObject** call_base = SP - argc + 1;
RawObject** call_top = SP + 1;
InterpreterHelpers::IncrementUsageCounter(FrameFunction(FP));
RawString* target_name = static_cast<RawString*>(LOAD_CONSTANT(kidx));
argdesc_ = static_cast<RawArray*>(LOAD_CONSTANT(kidx + 1));
if (!InterfaceCall(thread, target_name, call_base, call_top, &pc, &FP,
&SP)) {
HANDLE_EXCEPTION;
}
}
DISPATCH();
}
{
BYTECODE(DynamicCall, A_D);
// Check if single stepping.
if (thread->isolate()->single_step()) {

View file

@ -27,6 +27,36 @@ class RawFunction;
class RawSubtypeTestCache;
class ObjectPointerVisitor;
class LookupCache : public ValueObject {
public:
LookupCache() {
ASSERT(Utils::IsPowerOfTwo(sizeof(Entry)));
ASSERT(Utils::IsPowerOfTwo(sizeof(kNumEntries)));
Clear();
}
void Clear();
bool Lookup(intptr_t receiver_cid,
RawString* function_name,
RawFunction** target) const;
void Insert(intptr_t receiver_cid,
RawString* function_name,
RawFunction* target);
private:
struct Entry {
intptr_t receiver_cid;
RawString* function_name;
RawFunction* target;
intptr_t padding;
};
static const intptr_t kNumEntries = 1024;
static const intptr_t kTableMask = kNumEntries - 1;
Entry entries_[kNumEntries];
};
// Interpreter intrinsic handler. It is invoked on entry to the intrinsified
// function via Intrinsic bytecode before the frame is setup.
// If the handler returns true then Intrinsic bytecode works as a return
@ -97,6 +127,7 @@ class Interpreter {
}
void VisitObjectPointers(ObjectPointerVisitor* visitor);
void MajorGC() { lookup_cache_.Clear(); }
private:
uintptr_t* stack_;
@ -115,6 +146,8 @@ class Interpreter {
// call instruction and the function entry.
RawObject* special_[KernelBytecode::kSpecialIndexCount];
LookupCache lookup_cache_;
static IntrinsicHandler intrinsics_[kIntrinsicCount];
void Exit(Thread* thread,
@ -122,15 +155,6 @@ class Interpreter {
RawObject** exit_frame,
uint32_t* pc);
void CallRuntime(Thread* thread,
RawObject** base,
RawObject** exit_frame,
uint32_t* pc,
intptr_t argc_tag,
RawObject** args,
RawObject** result,
uword target);
bool Invoke(Thread* thread,
RawObject** call_base,
RawObject** call_top,
@ -164,6 +188,14 @@ class Interpreter {
RawObject** FP,
RawObject** SP);
bool InterfaceCall(Thread* thread,
RawString* target_name,
RawObject** call_base,
RawObject** call_top,
uint32_t** pc,
RawObject*** FP,
RawObject*** SP);
bool InstanceCall1(Thread* thread,
RawICData* icdata,
RawObject** call_base,

View file

@ -1618,6 +1618,37 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
#endif // !defined(TARGET_ARCH_DBC)
}
// Handles interpreted interface call cache miss.
// Arg0: receiver
// Arg1: target name
// Arg2: arguments descriptor
// Returns: target function
// Modifies the instance call table in current interpreter.
DEFINE_RUNTIME_ENTRY(InterpretedInterfaceCallMissHandler, 3) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
ASSERT(FLAG_enable_interpreter);
const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
const String& target_name = String::CheckedHandle(zone, arguments.ArgAt(1));
const Array& arg_desc = Array::CheckedHandle(zone, arguments.ArgAt(2));
ArgumentsDescriptor arguments_descriptor(arg_desc);
Function& target_function = Function::Handle(
zone,
Resolver::ResolveDynamic(receiver, target_name, arguments_descriptor));
// TODO(regis): In order to substitute 'simple_instance_of_function', the 2nd
// arg to the call, the type, is needed.
if (target_function.IsNull()) {
target_function = InlineCacheMissHelper(receiver, arg_desc, target_name);
}
ASSERT(!target_function.IsNull());
arguments.SetReturn(target_function);
#endif
}
// Invoke appropriate noSuchMethod or closure from getter.
// Arg0: receiver
// Arg1: ICData or MegamorphicCache

View file

@ -24,6 +24,7 @@ namespace dart {
V(InlineCacheMissHandlerTwoArgs) \
V(StaticCallMissHandlerOneArg) \
V(StaticCallMissHandlerTwoArgs) \
V(InterpretedInterfaceCallMissHandler) \
V(Instanceof) \
V(SubtypeCheck) \
V(TypeCheck) \

View file

@ -716,15 +716,15 @@ void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor,
// Only the mutator thread can run Dart code.
if (IsMutatorThread()) {
// The MarkTask, which calls this method, can run on a different thread. We
// therefore assume the mutator is at a safepoint and we can iterate it's
// therefore assume the mutator is at a safepoint and we can iterate its
// stack.
// TODO(vm-team): It would be beneficial to be able to ask the mutator
// thread whether it is in fact blocked at the moment (at a "safepoint") so
// we can safely iterate it's stack.
// we can safely iterate its stack.
//
// Unfortunately we cannot use `this->IsAtSafepoint()` here because that
// will return `false` even though the mutator thread is waiting for mark
// tasks (which iterate it's stack) to finish.
// tasks (which iterate its stack) to finish.
const StackFrameIterator::CrossThreadPolicy cross_thread_policy =
StackFrameIterator::kAllowCrossThreadIteration;