[vm/kernel/bytecode] Optimize instantiation of types and type arguments
This CL contains 2 optimizations: * instantiator type arguments are reused if possible; * instantiator and function type arguments are not loaded if they are not needed for a particular type being instantiated. Change-Id: Id1f6e5385051044b3b9f78cef884a917e65e801d Reviewed-on: https://dart-review.googlesource.com/58680 Reviewed-by: Zach Anderson <zra@google.com> Reviewed-by: Régis Crelier <regis@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
f059df7cc5
commit
e285bc52d7
@@ -11,6 +11,8 @@ import 'package:kernel/core_types.dart' show CoreTypes;
|
||||
import 'package:kernel/library_index.dart' show LibraryIndex;
|
||||
import 'package:kernel/transformations/constants.dart'
|
||||
show ConstantEvaluator, ConstantsBackend, EvaluationEnvironment;
|
||||
import 'package:kernel/type_algebra.dart'
|
||||
show Substitution, containsTypeVariable;
|
||||
import 'package:kernel/type_environment.dart' show TypeEnvironment;
|
||||
import 'package:kernel/vm/constants_native_effects.dart'
|
||||
show VmConstantsBackend;
|
||||
@@ -57,6 +59,9 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
||||
|
||||
Class enclosingClass;
|
||||
Member enclosingMember;
|
||||
Set<TypeParameter> classTypeParameters;
|
||||
Set<TypeParameter> functionTypeParameters;
|
||||
List<DartType> instantiatorTypeArguments;
|
||||
LocalVariables locals;
|
||||
ConstantEvaluator constantEvaluator;
|
||||
Map<LabeledStatement, Label> labeledStatements;
|
||||
@@ -285,31 +290,45 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
||||
}
|
||||
|
||||
void _genTypeArguments(List<DartType> typeArgs, {Class instantiatingClass}) {
|
||||
int typeArgsCPIndex = cp.add(new ConstantTypeArguments(typeArgs));
|
||||
if (instantiatingClass != null) {
|
||||
typeArgsCPIndex = cp.add(new ConstantTypeArgumentsForInstanceAllocation(
|
||||
instantiatingClass, typeArgsCPIndex));
|
||||
int typeArgsCPIndex() {
|
||||
int cpIndex = cp.add(new ConstantTypeArguments(typeArgs));
|
||||
if (instantiatingClass != null) {
|
||||
cpIndex = cp.add(new ConstantTypeArgumentsForInstanceAllocation(
|
||||
instantiatingClass, cpIndex));
|
||||
}
|
||||
return cpIndex;
|
||||
}
|
||||
|
||||
if (typeArgs.isEmpty || !hasTypeParameters(typeArgs)) {
|
||||
asm.emitPushConstant(typeArgsCPIndex);
|
||||
asm.emitPushConstant(typeArgsCPIndex());
|
||||
} else {
|
||||
// TODO(alexmarkov): try to reuse instantiator type arguments
|
||||
_genPushInstantiatorAndFunctionTypeArguments(typeArgs);
|
||||
asm.emitInstantiateTypeArgumentsTOS(1, typeArgsCPIndex);
|
||||
if (_canReuseInstantiatorTypeArguments(typeArgs, instantiatingClass)) {
|
||||
_genPushInstantiatorTypeArguments();
|
||||
} else {
|
||||
_genPushInstantiatorAndFunctionTypeArguments(typeArgs);
|
||||
asm.emitInstantiateTypeArgumentsTOS(1, typeArgsCPIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _genPushInstantiatorAndFunctionTypeArguments(List<DartType> types) {
|
||||
// TODO(alexmarkov): do not load instantiator type arguments / function type
|
||||
// arguments if they are not needed for these particular [types].
|
||||
_genPushInstantiatorTypeArguments();
|
||||
_genPushFunctionTypeArguments();
|
||||
if (classTypeParameters != null &&
|
||||
types.any((t) => containsTypeVariable(t, classTypeParameters))) {
|
||||
assert(instantiatorTypeArguments != null);
|
||||
_genPushInstantiatorTypeArguments();
|
||||
} else {
|
||||
_genPushNull();
|
||||
}
|
||||
if (functionTypeParameters != null &&
|
||||
types.any((t) => containsTypeVariable(t, functionTypeParameters))) {
|
||||
_genPushFunctionTypeArguments();
|
||||
} else {
|
||||
_genPushNull();
|
||||
}
|
||||
}
|
||||
|
||||
void _genPushInstantiatorTypeArguments() {
|
||||
// TODO(alexmarkov): access to type arguments in factory constructors.
|
||||
if ((enclosingMember.isInstanceMember || enclosingMember is Constructor) &&
|
||||
hasInstantiatorTypeArguments(enclosingClass)) {
|
||||
if (instantiatorTypeArguments != null) {
|
||||
_genPushReceiver();
|
||||
final int cpIndex =
|
||||
cp.add(new ConstantTypeArgumentsFieldOffset(enclosingClass));
|
||||
@@ -319,6 +338,48 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
||||
}
|
||||
}
|
||||
|
||||
List<DartType> _flattenInstantiatorTypeArguments(
|
||||
Class instantiatedClass, List<DartType> typeArgs) {
|
||||
assert(typeArgs.length == instantiatedClass.typeParameters.length);
|
||||
|
||||
List<DartType> flatTypeArgs;
|
||||
final supertype = instantiatedClass.supertype;
|
||||
if (supertype == null) {
|
||||
flatTypeArgs = <DartType>[];
|
||||
} else {
|
||||
final substitution =
|
||||
Substitution.fromPairs(instantiatedClass.typeParameters, typeArgs);
|
||||
flatTypeArgs = _flattenInstantiatorTypeArguments(supertype.classNode,
|
||||
substitution.substituteSupertype(supertype).typeArguments);
|
||||
}
|
||||
flatTypeArgs.addAll(typeArgs);
|
||||
return flatTypeArgs;
|
||||
}
|
||||
|
||||
bool _canReuseInstantiatorTypeArguments(
|
||||
List<DartType> typeArgs, Class instantiatingClass) {
|
||||
if (instantiatorTypeArguments == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (instantiatingClass != null) {
|
||||
typeArgs =
|
||||
_flattenInstantiatorTypeArguments(instantiatingClass, typeArgs);
|
||||
}
|
||||
|
||||
if (typeArgs.length > instantiatorTypeArguments.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < typeArgs.length; ++i) {
|
||||
if (typeArgs[i] != instantiatorTypeArguments[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _genPushFunctionTypeArguments() {
|
||||
if (locals.hasTypeArgsVar) {
|
||||
asm.emitPush(locals.typeArgsVarIndexInFrame);
|
||||
@@ -440,6 +501,24 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
||||
void start(Member node) {
|
||||
enclosingClass = node.enclosingClass;
|
||||
enclosingMember = node;
|
||||
if (enclosingMember.isInstanceMember || enclosingMember is Constructor) {
|
||||
if (enclosingClass.typeParameters.isNotEmpty) {
|
||||
classTypeParameters =
|
||||
new Set<TypeParameter>.from(enclosingClass.typeParameters);
|
||||
}
|
||||
if (hasInstantiatorTypeArguments(enclosingClass)) {
|
||||
final typeParameters = enclosingClass.typeParameters
|
||||
.map((p) => new TypeParameterType(p))
|
||||
.toList();
|
||||
instantiatorTypeArguments =
|
||||
_flattenInstantiatorTypeArguments(enclosingClass, typeParameters);
|
||||
}
|
||||
}
|
||||
if (enclosingMember.function != null &&
|
||||
enclosingMember.function.typeParameters.isNotEmpty) {
|
||||
functionTypeParameters =
|
||||
new Set<TypeParameter>.from(enclosingMember.function.typeParameters);
|
||||
}
|
||||
locals = new LocalVariables(node);
|
||||
// TODO(alexmarkov): improve caching in ConstantEvaluator and reuse it
|
||||
constantEvaluator = new ConstantEvaluator(constantsBackend, typeEnvironment,
|
||||
@@ -496,6 +575,9 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
||||
|
||||
enclosingClass = null;
|
||||
enclosingMember = null;
|
||||
classTypeParameters = null;
|
||||
functionTypeParameters = null;
|
||||
instantiatorTypeArguments = null;
|
||||
locals = null;
|
||||
constantEvaluator = null;
|
||||
labeledStatements = null;
|
||||
@@ -610,6 +692,12 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
||||
_pushAssemblerState();
|
||||
|
||||
locals.enterScope(node);
|
||||
|
||||
if (function.typeParameters.isNotEmpty) {
|
||||
functionTypeParameters ??= new Set<TypeParameter>();
|
||||
functionTypeParameters.addAll(function.typeParameters);
|
||||
}
|
||||
|
||||
List<Label> savedYieldPoints = yieldPoints;
|
||||
yieldPoints = locals.isSyncYieldingFrame ? <Label>[] : null;
|
||||
|
||||
@@ -644,6 +732,10 @@ class BytecodeGenerator extends RecursiveVisitor<Null> {
|
||||
|
||||
cp.add(new ConstantEndClosureFunctionScope());
|
||||
|
||||
if (function.typeParameters.isNotEmpty) {
|
||||
functionTypeParameters.removeAll(function.typeParameters);
|
||||
}
|
||||
|
||||
locals.leaveScope();
|
||||
|
||||
closures.add(new ClosureBytecode(
|
||||
|
||||
@@ -228,7 +228,7 @@ Bytecode {
|
||||
Push r2
|
||||
InstanceCall1 1, CP#52
|
||||
Drop1
|
||||
PushConstant CP#36
|
||||
PushConstant CP#18
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
@@ -250,30 +250,30 @@ ConstantPool {
|
||||
[15] = Int 0
|
||||
[16] = Type #lib::A::T1
|
||||
[17] = TypeArgumentsFieldOffset #lib::A
|
||||
[18] = Int 1
|
||||
[19] = Type #lib::A::T2
|
||||
[20] = Type #lib::A::foo::T3
|
||||
[21] = Int 3
|
||||
[22] = Type #lib::A::foo::T4
|
||||
[23] = Type T5
|
||||
[24] = Int 5
|
||||
[25] = Type T6
|
||||
[26] = Type T7
|
||||
[27] = Int 7
|
||||
[28] = Type T8
|
||||
[29] = ArgDesc num-args 1, num-type-args 1, names []
|
||||
[30] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#29
|
||||
[31] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[32] = StaticICData target 'dart.core::print', arg-desc CP#31
|
||||
[33] = TypeArgs [#lib::A::T1, #lib::A::T2, #lib::A::foo::T3, #lib::A::foo::T4, T5, T6, T7, T8]
|
||||
[34] = ArgDesc num-args 0, num-type-args 8, names []
|
||||
[35] = StaticICData target '#lib::callWithArgs', arg-desc CP#34
|
||||
[36] = Null
|
||||
[18] = Null
|
||||
[19] = Int 1
|
||||
[20] = Type #lib::A::T2
|
||||
[21] = Type #lib::A::foo::T3
|
||||
[22] = Int 3
|
||||
[23] = Type #lib::A::foo::T4
|
||||
[24] = Type T5
|
||||
[25] = Int 5
|
||||
[26] = Type T6
|
||||
[27] = Type T7
|
||||
[28] = Int 7
|
||||
[29] = Type T8
|
||||
[30] = ArgDesc num-args 1, num-type-args 1, names []
|
||||
[31] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#30
|
||||
[32] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[33] = StaticICData target 'dart.core::print', arg-desc CP#32
|
||||
[34] = TypeArgs [#lib::A::T1, #lib::A::T2, #lib::A::foo::T3, #lib::A::foo::T4, T5, T6, T7, T8]
|
||||
[35] = ArgDesc num-args 0, num-type-args 8, names []
|
||||
[36] = StaticICData target '#lib::callWithArgs', arg-desc CP#35
|
||||
[37] = EndClosureFunctionScope
|
||||
[38] = Class dart.core::_Closure
|
||||
[39] = FieldOffset dart.core::_Closure::_instantiator_type_arguments
|
||||
[40] = FieldOffset dart.core::_Closure::_function
|
||||
[41] = ICData target-name 'call', arg-desc CP#31
|
||||
[41] = ICData target-name 'call', arg-desc CP#32
|
||||
[42] = EndClosureFunctionScope
|
||||
[43] = TypeArgs [#lib::C7, #lib::C8]
|
||||
[44] = ArgDesc num-args 1, num-type-args 2, names []
|
||||
@@ -306,79 +306,67 @@ Closure CP#12 {
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
Push r0
|
||||
PushConstant CP#18
|
||||
InstantiateType CP#16
|
||||
StoreIndexedTOS
|
||||
Push r3
|
||||
PushConstant CP#19
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
PushConstant CP#18
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
Push r0
|
||||
InstantiateType CP#19
|
||||
StoreIndexedTOS
|
||||
Push r3
|
||||
PushConstant CP#5
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
Push r0
|
||||
InstantiateType CP#20
|
||||
StoreIndexedTOS
|
||||
Push r3
|
||||
PushConstant CP#21
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
PushConstant CP#5
|
||||
PushConstant CP#18
|
||||
Push r0
|
||||
InstantiateType CP#22
|
||||
InstantiateType CP#21
|
||||
StoreIndexedTOS
|
||||
Push r3
|
||||
PushConstant CP#6
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
PushConstant CP#22
|
||||
PushConstant CP#18
|
||||
Push r0
|
||||
InstantiateType CP#23
|
||||
StoreIndexedTOS
|
||||
Push r3
|
||||
PushConstant CP#24
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
PushConstant CP#6
|
||||
PushConstant CP#18
|
||||
Push r0
|
||||
InstantiateType CP#25
|
||||
InstantiateType CP#24
|
||||
StoreIndexedTOS
|
||||
Push r3
|
||||
PushConstant CP#10
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
PushConstant CP#25
|
||||
PushConstant CP#18
|
||||
Push r0
|
||||
InstantiateType CP#26
|
||||
StoreIndexedTOS
|
||||
Push r3
|
||||
PushConstant CP#27
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
PushConstant CP#10
|
||||
PushConstant CP#18
|
||||
Push r0
|
||||
InstantiateType CP#28
|
||||
InstantiateType CP#27
|
||||
StoreIndexedTOS
|
||||
PushConstant CP#30
|
||||
IndirectStaticCall 2, CP#29
|
||||
PushConstant CP#32
|
||||
IndirectStaticCall 1, CP#31
|
||||
Push r3
|
||||
PushConstant CP#28
|
||||
PushConstant CP#18
|
||||
Push r0
|
||||
InstantiateType CP#29
|
||||
StoreIndexedTOS
|
||||
PushConstant CP#31
|
||||
IndirectStaticCall 2, CP#30
|
||||
PushConstant CP#33
|
||||
IndirectStaticCall 1, CP#32
|
||||
Drop1
|
||||
Push r1
|
||||
LoadFieldTOS CP#1
|
||||
LoadFieldTOS CP#17
|
||||
Push r0
|
||||
InstantiateTypeArgumentsTOS 1, CP#33
|
||||
PushConstant CP#35
|
||||
IndirectStaticCall 1, CP#34
|
||||
Drop1
|
||||
InstantiateTypeArgumentsTOS 1, CP#34
|
||||
PushConstant CP#36
|
||||
IndirectStaticCall 1, CP#35
|
||||
Drop1
|
||||
PushConstant CP#18
|
||||
ReturnTOS
|
||||
|
||||
}
|
||||
@@ -417,7 +405,7 @@ Closure CP#9 {
|
||||
Push r2
|
||||
InstanceCall1 1, CP#41
|
||||
Drop1
|
||||
PushConstant CP#36
|
||||
PushConstant CP#18
|
||||
ReturnTOS
|
||||
|
||||
}
|
||||
@@ -461,7 +449,7 @@ Closure CP#2 {
|
||||
Push r2
|
||||
InstanceCall1 1, CP#47
|
||||
Drop1
|
||||
PushConstant CP#36
|
||||
PushConstant CP#18
|
||||
ReturnTOS
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,25 @@ void foo3<T>() {
|
||||
new B<List<T>>();
|
||||
}
|
||||
|
||||
class E<K, V> {
|
||||
test_reuse1() => new Map<K, V>();
|
||||
}
|
||||
|
||||
class F<K, V> extends E<String, List<V>> {
|
||||
test_reuse2() => new Map<String, List<V>>();
|
||||
}
|
||||
|
||||
class G<K, V> {
|
||||
G();
|
||||
factory G.test_factory() => new H<String, K, V>();
|
||||
}
|
||||
|
||||
class H<P1, P2, P3> extends G<P2, P3> {}
|
||||
|
||||
void foo4() {
|
||||
new G<int, List<String>>.test_factory();
|
||||
}
|
||||
|
||||
main() {
|
||||
foo1();
|
||||
foo2();
|
||||
|
||||
@@ -185,6 +185,158 @@ ConstantPool {
|
||||
core::print("C: ${s}");
|
||||
}
|
||||
}
|
||||
class E<K extends core::Object = dynamic, V extends core::Object = dynamic> extends core::Object {
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
Push FP[-5]
|
||||
PushConstant CP#1
|
||||
IndirectStaticCall 1, CP#0
|
||||
Drop1
|
||||
PushConstant CP#2
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
|
||||
[2] = Null
|
||||
}
|
||||
] synthetic constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
Push FP[-5]
|
||||
LoadFieldTOS CP#0
|
||||
PushConstant CP#2
|
||||
IndirectStaticCall 1, CP#1
|
||||
ReturnTOS
|
||||
PushConstant CP#3
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = TypeArgumentsFieldOffset #lib::E
|
||||
[1] = ArgDesc num-args 0, num-type-args 2, names []
|
||||
[2] = StaticICData target 'dart.core::Map::', arg-desc CP#1
|
||||
[3] = Null
|
||||
}
|
||||
] method test_reuse1() → dynamic
|
||||
return core::Map::•<self::E::K, self::E::V>();
|
||||
}
|
||||
class F<K extends core::Object = dynamic, V extends core::Object = dynamic> extends self::E<core::String, core::List<self::F::V>> {
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
Push FP[-5]
|
||||
PushConstant CP#1
|
||||
IndirectStaticCall 1, CP#0
|
||||
Drop1
|
||||
PushConstant CP#2
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[1] = StaticICData target '#lib::E::', arg-desc CP#0
|
||||
[2] = Null
|
||||
}
|
||||
] synthetic constructor •() → void
|
||||
: super self::E::•()
|
||||
;
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
Push FP[-5]
|
||||
LoadFieldTOS CP#0
|
||||
PushConstant CP#2
|
||||
IndirectStaticCall 1, CP#1
|
||||
ReturnTOS
|
||||
PushConstant CP#3
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = TypeArgumentsFieldOffset #lib::F
|
||||
[1] = ArgDesc num-args 0, num-type-args 2, names []
|
||||
[2] = StaticICData target 'dart.core::Map::', arg-desc CP#1
|
||||
[3] = Null
|
||||
}
|
||||
] method test_reuse2() → dynamic
|
||||
return core::Map::•<core::String, core::List<self::F::V>>();
|
||||
}
|
||||
class G<K extends core::Object = dynamic, V extends core::Object = dynamic> extends core::Object {
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
Push FP[-5]
|
||||
PushConstant CP#1
|
||||
IndirectStaticCall 1, CP#0
|
||||
Drop1
|
||||
PushConstant CP#2
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
|
||||
[2] = Null
|
||||
}
|
||||
] constructor •() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 1
|
||||
CheckStack
|
||||
PushConstant CP#1
|
||||
Push FP[-5]
|
||||
InstantiateTypeArgumentsTOS 1, CP#3
|
||||
PushConstant CP#0
|
||||
AllocateT
|
||||
StoreLocal r0
|
||||
Push r0
|
||||
PushConstant CP#5
|
||||
IndirectStaticCall 1, CP#4
|
||||
Drop1
|
||||
ReturnTOS
|
||||
PushConstant CP#1
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = Class #lib::H
|
||||
[1] = Null
|
||||
[2] = TypeArgs [dart.core::String, #lib::G::test_factory::K, #lib::G::test_factory::V]
|
||||
[3] = TypeArgumentsForInstanceAllocation #lib::H type-args CP#2
|
||||
[4] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[5] = StaticICData target '#lib::H::', arg-desc CP#4
|
||||
}
|
||||
] static factory test_factory<K extends core::Object = dynamic, V extends core::Object = dynamic>() → self::G<self::G::test_factory::K, self::G::test_factory::V>
|
||||
return new self::H::•<core::String, self::G::test_factory::K, self::G::test_factory::V>();
|
||||
}
|
||||
class H<P1 extends core::Object = dynamic, P2 extends core::Object = dynamic, P3 extends core::Object = dynamic> extends self::G<self::H::P2, self::H::P3> {
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
Push FP[-5]
|
||||
PushConstant CP#1
|
||||
IndirectStaticCall 1, CP#0
|
||||
Drop1
|
||||
PushConstant CP#2
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[1] = StaticICData target '#lib::G::', arg-desc CP#0
|
||||
[2] = Null
|
||||
}
|
||||
] synthetic constructor •() → void
|
||||
: super self::G::•()
|
||||
;
|
||||
}
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 1
|
||||
@@ -257,9 +409,9 @@ ConstantPool {
|
||||
Bytecode {
|
||||
Entry 1
|
||||
CheckStack
|
||||
PushConstant CP#3
|
||||
PushConstant CP#1
|
||||
Push FP[-5]
|
||||
InstantiateTypeArgumentsTOS 1, CP#2
|
||||
InstantiateTypeArgumentsTOS 1, CP#3
|
||||
PushConstant CP#0
|
||||
AllocateT
|
||||
StoreLocal r0
|
||||
@@ -268,14 +420,14 @@ Bytecode {
|
||||
IndirectStaticCall 1, CP#4
|
||||
Drop1
|
||||
Drop1
|
||||
PushConstant CP#3
|
||||
PushConstant CP#1
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = Class #lib::B
|
||||
[1] = TypeArgs [dart.core::List<#lib::foo3::T>]
|
||||
[2] = TypeArgumentsForInstanceAllocation #lib::B type-args CP#1
|
||||
[3] = Null
|
||||
[1] = Null
|
||||
[2] = TypeArgs [dart.core::List<#lib::foo3::T>]
|
||||
[3] = TypeArgumentsForInstanceAllocation #lib::B type-args CP#2
|
||||
[4] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[5] = StaticICData target '#lib::B::', arg-desc CP#4
|
||||
}
|
||||
@@ -283,6 +435,26 @@ ConstantPool {
|
||||
new self::B::•<core::List<self::foo3::T>>();
|
||||
}
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
PushConstant CP#0
|
||||
PushConstant CP#2
|
||||
IndirectStaticCall 1, CP#1
|
||||
Drop1
|
||||
PushConstant CP#3
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = TypeArgs [dart.core::int, dart.core::List<dart.core::String>]
|
||||
[1] = ArgDesc num-args 0, num-type-args 2, names []
|
||||
[2] = StaticICData target '#lib::G::test_factory', arg-desc CP#1
|
||||
[3] = Null
|
||||
}
|
||||
]static method foo4() → void {
|
||||
self::G::test_factory<core::int, core::List<core::String>>();
|
||||
}
|
||||
[@vm.bytecode=
|
||||
Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
|
||||
@@ -551,16 +551,16 @@ Bytecode {
|
||||
PushConstant CP#15
|
||||
IndirectStaticCall 1, CP#9
|
||||
Drop1
|
||||
PushConstant CP#17
|
||||
PushConstant CP#16
|
||||
Push FP[-8]
|
||||
InstantiateTypeArgumentsTOS 1, CP#16
|
||||
InstantiateTypeArgumentsTOS 1, CP#17
|
||||
PushConstant CP#18
|
||||
PushConstant CP#19
|
||||
IndirectStaticCall 2, CP#7
|
||||
PushConstant CP#20
|
||||
IndirectStaticCall 1, CP#9
|
||||
Drop1
|
||||
PushConstant CP#17
|
||||
PushConstant CP#16
|
||||
Push FP[-8]
|
||||
InstantiateTypeArgumentsTOS 1, CP#21
|
||||
PushConstant CP#1
|
||||
@@ -580,7 +580,7 @@ Bytecode {
|
||||
PushConstant CP#23
|
||||
IndirectStaticCall 1, CP#9
|
||||
Drop1
|
||||
PushConstant CP#17
|
||||
PushConstant CP#16
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
@@ -600,8 +600,8 @@ ConstantPool {
|
||||
[13] = ICData target-name 'toString', arg-desc CP#9
|
||||
[14] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#7
|
||||
[15] = StaticICData target 'dart.core::print', arg-desc CP#9
|
||||
[16] = TypeArgs [dart.core::String, #lib::test_map_literal::T]
|
||||
[17] = Null
|
||||
[16] = Null
|
||||
[17] = TypeArgs [dart.core::String, #lib::test_map_literal::T]
|
||||
[18] = List type-arg dynamic, entries CP# []
|
||||
[19] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#7
|
||||
[20] = StaticICData target 'dart.core::print', arg-desc CP#9
|
||||
|
||||
@@ -159,8 +159,7 @@ Bytecode {
|
||||
Entry 0
|
||||
CheckStack
|
||||
Push FP[-5]
|
||||
Push FP[-6]
|
||||
LoadFieldTOS CP#0
|
||||
PushConstant CP#0
|
||||
Push FP[-7]
|
||||
PushConstant CP#1
|
||||
InstanceCall1 4, CP#3
|
||||
@@ -174,31 +173,31 @@ Bytecode {
|
||||
L1:
|
||||
Push FP[-5]
|
||||
Push FP[-6]
|
||||
LoadFieldTOS CP#0
|
||||
LoadFieldTOS CP#8
|
||||
Push FP[-7]
|
||||
PushConstant CP#8
|
||||
InstanceCall1 4, CP#9
|
||||
PushConstant CP#9
|
||||
InstanceCall1 4, CP#10
|
||||
PushConstant CP#4
|
||||
IfNeStrictTOS
|
||||
Jump L2
|
||||
PushConstant CP#10
|
||||
PushConstant CP#11
|
||||
PushConstant CP#12
|
||||
IndirectStaticCall 1, CP#6
|
||||
Drop1
|
||||
L2:
|
||||
Push FP[-5]
|
||||
Push FP[-6]
|
||||
LoadFieldTOS CP#0
|
||||
LoadFieldTOS CP#8
|
||||
Push FP[-7]
|
||||
PushConstant CP#12
|
||||
InstanceCall1 4, CP#13
|
||||
InstanceCall1 1, CP#14
|
||||
PushConstant CP#13
|
||||
InstanceCall1 4, CP#14
|
||||
InstanceCall1 1, CP#15
|
||||
ReturnTOS
|
||||
PushConstant CP#15
|
||||
PushConstant CP#0
|
||||
ReturnTOS
|
||||
}
|
||||
ConstantPool {
|
||||
[0] = TypeArgumentsFieldOffset #lib::D
|
||||
[0] = Null
|
||||
[1] = Type #lib::A<#lib::D::foo3::T1>
|
||||
[2] = ArgDesc num-args 4, num-type-args 0, names []
|
||||
[3] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#2
|
||||
@@ -206,14 +205,14 @@ ConstantPool {
|
||||
[5] = String '31'
|
||||
[6] = ArgDesc num-args 1, num-type-args 0, names []
|
||||
[7] = StaticICData target 'dart.core::print', arg-desc CP#6
|
||||
[8] = Type #lib::C<dart.core::Map<#lib::D::foo3::T1, #lib::D::P>, dart.core::List<#lib::D::foo3::T2>, #lib::D::Q>
|
||||
[9] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#2
|
||||
[10] = String '32'
|
||||
[11] = StaticICData target 'dart.core::print', arg-desc CP#6
|
||||
[12] = Type dart.core::Map<#lib::D::foo3::T2, #lib::D::Q>
|
||||
[13] = ICData target-name 'dart.core::_as', arg-desc CP#2
|
||||
[14] = ICData get target-name 'values', arg-desc CP#6
|
||||
[15] = Null
|
||||
[8] = TypeArgumentsFieldOffset #lib::D
|
||||
[9] = Type #lib::C<dart.core::Map<#lib::D::foo3::T1, #lib::D::P>, dart.core::List<#lib::D::foo3::T2>, #lib::D::Q>
|
||||
[10] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#2
|
||||
[11] = String '32'
|
||||
[12] = StaticICData target 'dart.core::print', arg-desc CP#6
|
||||
[13] = Type dart.core::Map<#lib::D::foo3::T2, #lib::D::Q>
|
||||
[14] = ICData target-name 'dart.core::_as', arg-desc CP#2
|
||||
[15] = ICData get target-name 'values', arg-desc CP#6
|
||||
}
|
||||
] method foo3<T1 extends core::Object = dynamic, T2 extends core::Object = dynamic>(dynamic z) → dynamic {
|
||||
if(z is self::A<self::D::foo3::T1>) {
|
||||
|
||||
Reference in New Issue
Block a user