feff33b892
Instantiator type arguments are sometimes reused instead of doing instantiation at run time. VM has a bunch of assertions to verify that this optimization happened. In case of bytecode pipeline, decision to reuse instantiator type arguments is done while generating bytecode. For this optimization to correctly happen, bytecode generator should be able to construct instantiator type arguments the same way as VM does at run time. Besides flattening of type arguments of superclasses, VM shrinks them by overlapping type parameters with type arguments of a superclass (if they match). This CL implements such overlapping in bytecode generator. Also, --overlap_type_arguments VM option is removed, as disabling of type arguments overlapping would break bytecode pipeline. Change-Id: Ib276c0e688e0e86b44278d88a5c0af09dd342798 Reviewed-on: https://dart-review.googlesource.com/70060 Reviewed-by: Régis Crelier <regis@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
624 lines
16 KiB
Plaintext
624 lines
16 KiB
Plaintext
library #lib;
|
|
import self as self;
|
|
import "dart:core" as core;
|
|
import "dart:_internal" as _in;
|
|
|
|
class Base<T1 extends core::Object = dynamic, T2 extends core::Object = dynamic> extends core::Object {
|
|
generic-covariant-impl field self::Base::T1 t1 = null;
|
|
generic-covariant-impl field self::Base::T2 t2 = null;
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 1
|
|
CheckStack
|
|
Push FP[-5]
|
|
PushConstant CP#1
|
|
IndirectStaticCall 1, CP#0
|
|
Drop1
|
|
PushConstant CP#2
|
|
PushConstant CP#3
|
|
CreateArrayTOS
|
|
StoreLocal r0
|
|
Push r0
|
|
PushConstant CP#4
|
|
PushConstant CP#5
|
|
StoreIndexedTOS
|
|
Push r0
|
|
PushConstant CP#6
|
|
Push FP[-5]
|
|
LoadTypeArgumentsField CP#8
|
|
PushConstant CP#2
|
|
InstantiateType CP#7
|
|
StoreIndexedTOS
|
|
Push r0
|
|
PushConstant CP#9
|
|
PushConstant CP#10
|
|
StoreIndexedTOS
|
|
Push r0
|
|
PushConstant CP#11
|
|
Push FP[-5]
|
|
LoadTypeArgumentsField CP#8
|
|
PushConstant CP#2
|
|
InstantiateType CP#12
|
|
StoreIndexedTOS
|
|
PushConstant CP#13
|
|
IndirectStaticCall 1, CP#0
|
|
PushConstant CP#14
|
|
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
|
|
[3] = Int 4
|
|
[4] = Int 0
|
|
[5] = String 'Base: '
|
|
[6] = Int 1
|
|
[7] = Type #lib::Base::T1
|
|
[8] = TypeArgumentsField #lib::Base
|
|
[9] = Int 2
|
|
[10] = String ', '
|
|
[11] = Int 3
|
|
[12] = Type #lib::Base::T2
|
|
[13] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#0
|
|
[14] = StaticICData target 'dart.core::print', arg-desc CP#0
|
|
}
|
|
] constructor •() → void
|
|
: super core::Object::•() {
|
|
core::print("Base: ${self::Base::T1}, ${self::Base::T2}");
|
|
}
|
|
}
|
|
class A extends self::Base<core::int, core::String> {
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 0
|
|
CheckStack
|
|
Push FP[-6]
|
|
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::Base::', arg-desc CP#0
|
|
[2] = Null
|
|
}
|
|
] constructor •(core::String s) → void
|
|
: super self::Base::•()
|
|
;
|
|
}
|
|
class B<T extends core::Object = dynamic> extends self::Base<core::List<self::B::T>, core::String> {
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 1
|
|
CheckStack
|
|
Push FP[-5]
|
|
PushConstant CP#1
|
|
IndirectStaticCall 1, CP#0
|
|
Drop1
|
|
PushConstant CP#2
|
|
PushConstant CP#3
|
|
CreateArrayTOS
|
|
StoreLocal r0
|
|
Push r0
|
|
PushConstant CP#4
|
|
PushConstant CP#5
|
|
StoreIndexedTOS
|
|
Push r0
|
|
PushConstant CP#6
|
|
Push FP[-5]
|
|
LoadTypeArgumentsField CP#8
|
|
PushConstant CP#2
|
|
InstantiateType CP#7
|
|
StoreIndexedTOS
|
|
PushConstant CP#9
|
|
IndirectStaticCall 1, CP#0
|
|
PushConstant CP#10
|
|
IndirectStaticCall 1, CP#0
|
|
Drop1
|
|
PushConstant CP#2
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = ArgDesc num-args 1, num-type-args 0, names []
|
|
[1] = StaticICData target '#lib::Base::', arg-desc CP#0
|
|
[2] = Null
|
|
[3] = Int 2
|
|
[4] = Int 0
|
|
[5] = String 'B: '
|
|
[6] = Int 1
|
|
[7] = Type #lib::B::T
|
|
[8] = TypeArgumentsField #lib::B
|
|
[9] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#0
|
|
[10] = StaticICData target 'dart.core::print', arg-desc CP#0
|
|
}
|
|
] constructor •() → void
|
|
: super self::Base::•() {
|
|
core::print("B: ${self::B::T}");
|
|
}
|
|
}
|
|
class C extends core::Object {
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 1
|
|
CheckStack
|
|
Push FP[-6]
|
|
PushConstant CP#1
|
|
IndirectStaticCall 1, CP#0
|
|
Drop1
|
|
PushConstant CP#2
|
|
PushConstant CP#3
|
|
CreateArrayTOS
|
|
StoreLocal r0
|
|
Push r0
|
|
PushConstant CP#4
|
|
PushConstant CP#5
|
|
StoreIndexedTOS
|
|
Push r0
|
|
PushConstant CP#6
|
|
Push FP[-5]
|
|
StoreIndexedTOS
|
|
PushConstant CP#7
|
|
IndirectStaticCall 1, CP#0
|
|
PushConstant CP#8
|
|
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
|
|
[3] = Int 2
|
|
[4] = Int 0
|
|
[5] = String 'C: '
|
|
[6] = Int 1
|
|
[7] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#0
|
|
[8] = StaticICData target 'dart.core::print', arg-desc CP#0
|
|
}
|
|
] constructor •(core::String s) → void
|
|
: super core::Object::•() {
|
|
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]
|
|
LoadTypeArgumentsField CP#0
|
|
PushConstant CP#2
|
|
IndirectStaticCall 1, CP#1
|
|
ReturnTOS
|
|
PushConstant CP#3
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = TypeArgumentsField #lib::E
|
|
[1] = ArgDesc num-args 1, num-type-args 0, 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]
|
|
LoadTypeArgumentsField CP#0
|
|
PushConstant CP#2
|
|
IndirectStaticCall 1, CP#1
|
|
ReturnTOS
|
|
PushConstant CP#3
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = TypeArgumentsField #lib::F
|
|
[1] = ArgDesc num-args 1, num-type-args 0, 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
|
|
Push FP[-5]
|
|
PushConstant CP#1
|
|
InstantiateTypeArgumentsTOS 0, CP#2
|
|
PushConstant CP#0
|
|
AllocateT
|
|
StoreLocal r0
|
|
Push r0
|
|
PushConstant CP#4
|
|
IndirectStaticCall 1, CP#3
|
|
Drop1
|
|
ReturnTOS
|
|
PushConstant CP#1
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = Class #lib::H
|
|
[1] = Null
|
|
[2] = TypeArgumentsForInstanceAllocation #lib::H [dart.core::String, #lib::G::test_factory::K, #lib::G::test_factory::V]
|
|
[3] = ArgDesc num-args 1, num-type-args 0, names []
|
|
[4] = StaticICData target '#lib::H::', arg-desc CP#3
|
|
}
|
|
] 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::•()
|
|
;
|
|
}
|
|
class I extends core::Object {
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 0
|
|
CheckStack
|
|
Push FP[-6]
|
|
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 •(dynamic param) → void
|
|
: super core::Object::•()
|
|
;
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
EntryOptional 1, 0, 1
|
|
LoadConstant r1, CP#0
|
|
LoadConstant r1, CP#1
|
|
Frame 1
|
|
CheckStack
|
|
Allocate CP#2
|
|
StoreLocal r2
|
|
Push r2
|
|
Push r1
|
|
PushConstant CP#4
|
|
IndirectStaticCall 2, CP#3
|
|
Drop1
|
|
ReturnTOS
|
|
PushConstant CP#1
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = String 'param'
|
|
[1] = Null
|
|
[2] = Class #lib::I
|
|
[3] = ArgDesc num-args 2, num-type-args 0, names []
|
|
[4] = StaticICData target '#lib::I::', arg-desc CP#3
|
|
}
|
|
] static factory test_factory2({dynamic param = null}) → self::I
|
|
return new self::I::•(param);
|
|
}
|
|
class J extends core::Object {
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 0
|
|
CheckStack
|
|
Push FP[-5]
|
|
NativeCall CP#0
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = NativeEntry agent_J
|
|
}
|
|
] @_in::ExternalName::•("agent_J")
|
|
external static factory •() → self::J;
|
|
}
|
|
abstract class K<A extends core::Object = dynamic, B extends core::Object = dynamic> extends core::Object {
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 1
|
|
CheckStack
|
|
Push FP[-5]
|
|
PushConstant CP#0
|
|
AllocateT
|
|
StoreLocal r0
|
|
Push r0
|
|
PushConstant CP#2
|
|
IndirectStaticCall 1, CP#1
|
|
Drop1
|
|
ReturnTOS
|
|
PushConstant CP#3
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = Class #lib::TestTypeArgReuse
|
|
[1] = ArgDesc num-args 1, num-type-args 0, names []
|
|
[2] = StaticICData target '#lib::TestTypeArgReuse::', arg-desc CP#1
|
|
[3] = Null
|
|
}
|
|
] static factory •<A extends core::Object = dynamic, B extends core::Object = dynamic>() → self::K<self::K::•::A, self::K::•::B>
|
|
return new self::TestTypeArgReuse::•<self::K::•::A, self::K::•::B>();
|
|
}
|
|
class TestTypeArgReuse<P extends core::Object = dynamic, Q extends core::Object = dynamic> extends self::Base<self::TestTypeArgReuse::P, self::TestTypeArgReuse::Q> implements self::K<self::TestTypeArgReuse::P, self::TestTypeArgReuse::Q> {
|
|
[@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::Base::', arg-desc CP#0
|
|
[2] = Null
|
|
}
|
|
] synthetic constructor •() → void
|
|
: super self::Base::•()
|
|
;
|
|
}
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 1
|
|
CheckStack
|
|
Allocate CP#0
|
|
StoreLocal r0
|
|
Push r0
|
|
PushConstant CP#1
|
|
PushConstant CP#3
|
|
IndirectStaticCall 2, CP#2
|
|
Drop1
|
|
ReturnTOS
|
|
PushConstant CP#4
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = Class #lib::C
|
|
[1] = String 'hello'
|
|
[2] = ArgDesc num-args 2, num-type-args 0, names []
|
|
[3] = StaticICData target '#lib::C::', arg-desc CP#2
|
|
[4] = Null
|
|
}
|
|
]static method foo1() → dynamic
|
|
return new self::C::•("hello");
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 1
|
|
CheckStack
|
|
PushConstant CP#1
|
|
PushConstant CP#0
|
|
AllocateT
|
|
StoreLocal r0
|
|
Push r0
|
|
PushConstant CP#2
|
|
PushConstant CP#4
|
|
IndirectStaticCall 2, CP#3
|
|
Drop1
|
|
Drop1
|
|
PushConstant CP#6
|
|
PushConstant CP#5
|
|
AllocateT
|
|
StoreLocal r0
|
|
Push r0
|
|
PushConstant CP#8
|
|
IndirectStaticCall 1, CP#7
|
|
Drop1
|
|
Drop1
|
|
PushConstant CP#9
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = Class #lib::A
|
|
[1] = TypeArgumentsForInstanceAllocation #lib::A []
|
|
[2] = String 'hi'
|
|
[3] = ArgDesc num-args 2, num-type-args 0, names []
|
|
[4] = StaticICData target '#lib::A::', arg-desc CP#3
|
|
[5] = Class #lib::B
|
|
[6] = TypeArgumentsForInstanceAllocation #lib::B [dart.core::int]
|
|
[7] = ArgDesc num-args 1, num-type-args 0, names []
|
|
[8] = StaticICData target '#lib::B::', arg-desc CP#7
|
|
[9] = Null
|
|
}
|
|
]static method foo2() → void {
|
|
new self::A::•("hi");
|
|
new self::B::•<core::int>();
|
|
}
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 2
|
|
CheckStack
|
|
CheckFunctionTypeArgs 1, 0
|
|
PushConstant CP#1
|
|
Push r0
|
|
InstantiateTypeArgumentsTOS 0, CP#2
|
|
PushConstant CP#0
|
|
AllocateT
|
|
StoreLocal r1
|
|
Push r1
|
|
PushConstant CP#4
|
|
IndirectStaticCall 1, CP#3
|
|
Drop1
|
|
Drop1
|
|
PushConstant CP#1
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = Class #lib::B
|
|
[1] = Null
|
|
[2] = TypeArgumentsForInstanceAllocation #lib::B [dart.core::List<#lib::foo3::T>]
|
|
[3] = ArgDesc num-args 1, num-type-args 0, names []
|
|
[4] = StaticICData target '#lib::B::', arg-desc CP#3
|
|
}
|
|
]static method foo3<T extends core::Object = dynamic>() → void {
|
|
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] = TypeArgumentsForInstanceAllocation #lib::G [dart.core::int, dart.core::List<dart.core::String>]
|
|
[1] = ArgDesc num-args 1, num-type-args 0, 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
|
|
PushConstant CP#0
|
|
PushConstant CP#2
|
|
IndirectStaticCall 1, CP#1
|
|
Drop1
|
|
PushConstant CP#0
|
|
PushConstant CP#3
|
|
PushConstant CP#5
|
|
IndirectStaticCall 2, CP#4
|
|
Drop1
|
|
PushConstant CP#0
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = Null
|
|
[1] = ArgDesc num-args 1, num-type-args 0, names []
|
|
[2] = StaticICData target '#lib::I::test_factory2', arg-desc CP#1
|
|
[3] = Int 42
|
|
[4] = ArgDesc num-args 2, num-type-args 0, names [param]
|
|
[5] = StaticICData target '#lib::I::test_factory2', arg-desc CP#4
|
|
}
|
|
]static method foo5() → void {
|
|
self::I::test_factory2();
|
|
self::I::test_factory2(param: 42);
|
|
}
|
|
[@vm.bytecode=
|
|
Bytecode {
|
|
Entry 0
|
|
CheckStack
|
|
PushConstant CP#1
|
|
IndirectStaticCall 0, CP#0
|
|
Drop1
|
|
PushConstant CP#2
|
|
IndirectStaticCall 0, CP#0
|
|
Drop1
|
|
PushConstant CP#3
|
|
PushConstant CP#5
|
|
IndirectStaticCall 1, CP#4
|
|
Drop1
|
|
PushConstant CP#6
|
|
ReturnTOS
|
|
}
|
|
ConstantPool {
|
|
[0] = ArgDesc num-args 0, num-type-args 0, names []
|
|
[1] = StaticICData target '#lib::foo1', arg-desc CP#0
|
|
[2] = StaticICData target '#lib::foo2', arg-desc CP#0
|
|
[3] = TypeArgs [dart.core::String]
|
|
[4] = ArgDesc num-args 0, num-type-args 1, names []
|
|
[5] = StaticICData target '#lib::foo3', arg-desc CP#4
|
|
[6] = Null
|
|
}
|
|
]static method main() → dynamic {
|
|
self::foo1();
|
|
self::foo2();
|
|
self::foo3<core::String>();
|
|
}
|