[vm/kernel/bytecode] Bytecode generation for rarely used operations
Change-Id: Ie5154207b4763d950707b267803a688d4b3e0487
Reviewed-on: https://dart-review.googlesource.com/62002
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/bin/frontend_server_starter.dart b/pkg/vm/bin/frontend_server_starter.dart
index 5ae6bfd..dcbf63f 100644
--- a/pkg/vm/bin/frontend_server_starter.dart
+++ b/pkg/vm/bin/frontend_server_starter.dart
@@ -1,7 +1,6 @@
library frontend_server;
import 'dart:async';
-import 'dart:io';
import '../lib/frontend_server.dart';
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 599d4c1..986874d 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -169,9 +169,7 @@
asm.emitNativeCall(nativeEntryCpIndex);
}
- LibraryIndex _libraryIndex;
- LibraryIndex get libraryIndex =>
- _libraryIndex ??= new LibraryIndex.coreLibraries(component);
+ LibraryIndex get libraryIndex => coreTypes.index;
Procedure _listFromLiteral;
Procedure get listFromLiteral => _listFromLiteral ??=
@@ -211,6 +209,11 @@
_closureFunctionTypeArguments ??= libraryIndex.getMember(
'dart:core', '_Closure', '_function_type_arguments');
+ Field _closureDelayedTypeArguments;
+ Field get closureDelayedTypeArguments =>
+ _closureDelayedTypeArguments ??= libraryIndex.getMember(
+ 'dart:core', '_Closure', '_delayed_type_arguments');
+
Field _closureFunction;
Field get closureFunction => _closureFunction ??=
libraryIndex.getMember('dart:core', '_Closure', '_function');
@@ -223,6 +226,10 @@
Procedure get prependTypeArguments => _prependTypeArguments ??=
libraryIndex.getTopLevelMember('dart:_internal', '_prependTypeArguments');
+ Procedure _futureValue;
+ Procedure get futureValue =>
+ _futureValue ??= libraryIndex.getMember('dart:async', 'Future', 'value');
+
void _genConstructorInitializers(Constructor node) {
bool isRedirecting =
node.initializers.any((init) => init is RedirectingInitializer);
@@ -1109,9 +1116,18 @@
asm.emitDrop1();
}
-// @override
-// visitDirectMethodInvocation(DirectMethodInvocation node) {
-// }
+ @override
+ visitDirectMethodInvocation(DirectMethodInvocation node) {
+ final args = node.arguments;
+ _genArguments(node.receiver, args);
+ final target = node.target;
+ if (target is Procedure && !target.isGetter && !target.isSetter) {
+ _genStaticCallWithArgs(target, args, hasReceiver: true);
+ } else {
+ throw new UnsupportedOperationError(
+ 'Unsupported DirectMethodInvocation with target ${target.runtimeType} $target');
+ }
+ }
@override
visitDirectPropertyGet(DirectPropertyGet node) {
@@ -1125,22 +1141,58 @@
}
}
-// @override
-// visitDirectPropertySet(DirectPropertySet node) {
-// }
+ @override
+ visitDirectPropertySet(DirectPropertySet node) {
+ node.receiver.accept(this);
+ node.value.accept(this);
+ final target = node.target;
+ if (target is Field || (target is Procedure && target.isSetter)) {
+ _genStaticCall(target, new ConstantArgDesc(2), 2, isSet: true);
+ } else {
+ throw new UnsupportedOperationError(
+ 'Unsupported DirectPropertySet with target ${target.runtimeType} $target');
+ }
+ }
@override
visitFunctionExpression(FunctionExpression node) {
_genClosure(node, '<anonymous closure>', node.function);
}
-// @override
-// visitInstantiation(Instantiation node) {
-// }
-//
-// @override
-// visitInvalidExpression(InvalidExpression node) {
-// }
+ @override
+ visitInstantiation(Instantiation node) {
+ final int oldClosure = locals.tempIndexInFrame(node, tempIndex: 0);
+ final int newClosure = locals.tempIndexInFrame(node, tempIndex: 1);
+
+ node.expression.accept(this);
+ asm.emitPopLocal(oldClosure);
+
+ assert(closureClass.typeParameters.isEmpty);
+ asm.emitAllocate(cp.add(new ConstantClass(closureClass)));
+ asm.emitStoreLocal(newClosure);
+
+ _genTypeArguments(node.typeArguments);
+ asm.emitStoreFieldTOS(
+ cp.add(new ConstantFieldOffset(closureDelayedTypeArguments)));
+
+ // Copy the rest of the fields from old closure to a new closure.
+ final fieldsToCopy = <Field>[
+ closureInstantiatorTypeArguments,
+ closureFunctionTypeArguments,
+ closureFunction,
+ closureContext,
+ ];
+
+ for (Field field in fieldsToCopy) {
+ final fieldOffsetCpIndex = cp.add(new ConstantFieldOffset(field));
+ asm.emitPush(newClosure);
+ asm.emitPush(oldClosure);
+ asm.emitLoadFieldTOS(fieldOffsetCpIndex);
+ asm.emitStoreFieldTOS(fieldOffsetCpIndex);
+ }
+
+ asm.emitPush(newClosure);
+ }
@override
visitIsExpression(IsExpression node) {
@@ -1322,7 +1374,7 @@
@override
visitSuperPropertyGet(SuperPropertyGet node) {
_genPushReceiver();
- Member target =
+ final Member target =
hierarchy.getDispatchTarget(enclosingClass.superclass, node.name);
if (target == null) {
throw new UnsupportedOperationError(
@@ -1336,9 +1388,23 @@
}
}
-// @override
-// visitSuperPropertySet(SuperPropertySet node) {
-// }
+ @override
+ visitSuperPropertySet(SuperPropertySet node) {
+ _genPushReceiver();
+ node.value.accept(this);
+ final Member target = hierarchy
+ .getDispatchTarget(enclosingClass.superclass, node.name, setter: true);
+ if (target == null) {
+ throw new UnsupportedOperationError(
+ 'Unsupported SuperPropertySet without target');
+ }
+ if (target is Field || (target is Procedure && target.isSetter)) {
+ _genStaticCall(target, new ConstantArgDesc(2), 2, isSet: true);
+ } else {
+ throw new UnsupportedOperationError(
+ 'Unsupported SuperPropertySet with target ${target.runtimeType} $target');
+ }
+ }
@override
visitNot(Not node) {
@@ -1528,33 +1594,20 @@
}
}
-// @override
-// visitLoadLibrary(LoadLibrary node) {
-// }
-//
-// @override
-// visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
-// }
-//
-// @override
-// visitVectorCreation(VectorCreation node) {
-// }
-//
-// @override
-// visitVectorGet(VectorGet node) {
-// }
-//
-// @override
-// visitVectorSet(VectorSet node) {
-// }
-//
-// @override
-// visitVectorCopy(VectorCopy node) {
-// }
-//
-// @override
-// visitClosureCreation(ClosureCreation node) {
-// }
+ void _genFutureNull() {
+ _genPushNull();
+ _genStaticCall(futureValue, new ConstantArgDesc(1), 1);
+ }
+
+ @override
+ visitLoadLibrary(LoadLibrary node) {
+ _genFutureNull();
+ }
+
+ @override
+ visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
+ _genFutureNull();
+ }
@override
visitAssertStatement(AssertStatement node) {
@@ -2163,16 +2216,15 @@
asm.emitDrop1();
}
-// @override
-// visitLocalInitializer(LocalInitializer node) {
-// }
-//
-// @override
-// visitAssertInitializer(AssertInitializer node) {
-// }
-//
-// @override
-// visitInvalidInitializer(InvalidInitializer node) {}
+ @override
+ visitLocalInitializer(LocalInitializer node) {
+ node.variable.accept(this);
+ }
+
+ @override
+ visitAssertInitializer(AssertInitializer node) {
+ node.statement.accept(this);
+ }
@override
visitConstantExpression(ConstantExpression node) {
@@ -2226,8 +2278,9 @@
int visitTearOffConstant(TearOffConstant node) =>
cp.add(new ConstantTearOff(node.procedure));
-// @override
-// int visitTypeLiteralConstant(TypeLiteralConstant node) => defaultConstant(node);
+ @override
+ int visitTypeLiteralConstant(TypeLiteralConstant node) =>
+ cp.add(new ConstantType(node.type));
}
class UnsupportedOperationError {
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index 5bea5f6..1c4edcd 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -994,4 +994,9 @@
visitTryFinally(TryFinally node) {
_visit(node, temps: 2);
}
+
+ @override
+ visitInstantiation(Instantiation node) {
+ _visit(node, temps: 2);
+ }
}
diff --git a/pkg/vm/testcases/bytecode/closures.dart b/pkg/vm/testcases/bytecode/closures.dart
index 102cb0f..ff1c650 100644
--- a/pkg/vm/testcases/bytecode/closures.dart
+++ b/pkg/vm/testcases/bytecode/closures.dart
@@ -131,4 +131,12 @@
}
}
+typedef IntFunc(int arg);
+
+IntFunc testPartialInstantiation() {
+ void foo<T>(T t) {}
+ IntFunc intFunc = foo;
+ return intFunc;
+}
+
main() {}
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 2080a18..2bece87 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -2,6 +2,7 @@
import self as self;
import "dart:core" as core;
+typedef IntFunc = (core::int) → dynamic;
class C1 extends core::Object {
[@vm.bytecode=
Bytecode {
@@ -1409,6 +1410,103 @@
}
[@vm.bytecode=
Bytecode {
+ Entry 6
+ CheckStack
+ Allocate CP#12
+ StoreLocal r3
+ Push r3
+ PushConstant CP#7
+ StoreFieldTOS CP#13
+ Push r3
+ PushConstant CP#7
+ StoreFieldTOS CP#2
+ Push r3
+ PushConstant CP#0
+ StoreFieldTOS CP#14
+ Push r3
+ Push r0
+ StoreFieldTOS CP#1
+ PopLocal r2
+ Push r2
+ PopLocal r3
+ Allocate CP#12
+ StoreLocal r5
+ PushConstant CP#15
+ StoreFieldTOS CP#16
+ Push r5
+ Push r3
+ LoadFieldTOS CP#13
+ StoreFieldTOS CP#13
+ Push r5
+ Push r3
+ LoadFieldTOS CP#2
+ StoreFieldTOS CP#2
+ Push r5
+ Push r3
+ LoadFieldTOS CP#14
+ StoreFieldTOS CP#14
+ Push r5
+ Push r3
+ LoadFieldTOS CP#1
+ StoreFieldTOS CP#1
+ Push r5
+ PopLocal r4
+ Push r4
+ ReturnTOS
+ PushConstant CP#7
+ ReturnTOS
+}
+ConstantPool {
+ [0] = ClosureFunction foo <T extends dart.core::Object = dynamic>(T t) → void;
+ [1] = FieldOffset dart.core::_Closure::_context
+ [2] = FieldOffset dart.core::_Closure::_function_type_arguments
+ [3] = Int 0
+ [4] = Int 1
+ [5] = ArgDesc num-args 4, num-type-args 0, names []
+ [6] = StaticICData target 'dart._internal::_prependTypeArguments', arg-desc CP#5
+ [7] = Null
+ [8] = Type T
+ [9] = String 't'
+ [10] = SubtypeTestCache
+ [11] = EndClosureFunctionScope
+ [12] = Class dart.core::_Closure
+ [13] = FieldOffset dart.core::_Closure::_instantiator_type_arguments
+ [14] = FieldOffset dart.core::_Closure::_function
+ [15] = TypeArgs [dart.core::int]
+ [16] = FieldOffset dart.core::_Closure::_delayed_type_arguments
+}
+Closure CP#0 {
+ Entry 2
+ CheckStack
+ Push FP[-6]
+ LoadFieldTOS CP#1
+ PopLocal r0
+ Push FP[-7]
+ Push FP[-6]
+ LoadFieldTOS CP#2
+ PushConstant CP#3
+ PushConstant CP#4
+ PushConstant CP#6
+ IndirectStaticCall 4, CP#5
+ PopLocal FP[-7]
+ Push FP[-5]
+ PushConstant CP#7
+ Push FP[-7]
+ PushConstant CP#8
+ PushConstant CP#9
+ AssertAssignable 0, CP#10
+ Drop1
+ PushConstant CP#7
+ ReturnTOS
+
+}
+]static method testPartialInstantiation() → (core::int) → dynamic {
+ function foo<T extends core::Object = dynamic>(T t) → void {}
+ (core::int) → dynamic intFunc = foo<core::int>;
+ return intFunc;
+}
+[@vm.bytecode=
+Bytecode {
Entry 0
CheckStack
PushConstant CP#0
diff --git a/pkg/vm/testcases/bytecode/deferred_lib.dart b/pkg/vm/testcases/bytecode/deferred_lib.dart
new file mode 100644
index 0000000..b93cc06
--- /dev/null
+++ b/pkg/vm/testcases/bytecode/deferred_lib.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "hello.dart" deferred as lib;
+
+callDeferred() => lib.main();
+
+testLoadLibrary() => lib.loadLibrary();
+
+main() {}
diff --git a/pkg/vm/testcases/bytecode/deferred_lib.dart.expect b/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
new file mode 100644
index 0000000..8d4cb94
--- /dev/null
+++ b/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
@@ -0,0 +1,56 @@
+library #lib;
+import self as self;
+import "./hello.dart" as hel;
+
+[@vm.bytecode=
+Bytecode {
+ Entry 1
+ CheckStack
+ PushConstant CP#0
+ PushConstant CP#2
+ IndirectStaticCall 1, CP#1
+ PopLocal r0
+ PushConstant CP#4
+ IndirectStaticCall 0, CP#3
+ ReturnTOS
+ PushConstant CP#0
+ ReturnTOS
+}
+ConstantPool {
+ [0] = Null
+ [1] = ArgDesc num-args 1, num-type-args 0, names []
+ [2] = StaticICData target 'dart.async::Future::value', arg-desc CP#1
+ [3] = ArgDesc num-args 0, num-type-args 0, names []
+ [4] = StaticICData target '#lib1::main', arg-desc CP#3
+}
+]static method callDeferred() → dynamic
+ return let final dynamic #t1 = CheckLibraryIsLoaded(lib) in hel::main();
+[@vm.bytecode=
+Bytecode {
+ Entry 0
+ CheckStack
+ PushConstant CP#0
+ PushConstant CP#2
+ IndirectStaticCall 1, CP#1
+ ReturnTOS
+ PushConstant CP#0
+ ReturnTOS
+}
+ConstantPool {
+ [0] = Null
+ [1] = ArgDesc num-args 1, num-type-args 0, names []
+ [2] = StaticICData target 'dart.async::Future::value', arg-desc CP#1
+}
+]static method testLoadLibrary() → dynamic
+ return LoadLibrary(lib);
+[@vm.bytecode=
+Bytecode {
+ Entry 0
+ CheckStack
+ PushConstant CP#0
+ ReturnTOS
+}
+ConstantPool {
+ [0] = Null
+}
+]static method main() → dynamic {}
diff --git a/pkg/vm/testcases/bytecode/literals.dart b/pkg/vm/testcases/bytecode/literals.dart
index 69a0e85..0acd65b 100644
--- a/pkg/vm/testcases/bytecode/literals.dart
+++ b/pkg/vm/testcases/bytecode/literals.dart
@@ -45,7 +45,7 @@
print(42);
print('foo');
print(A.elem2);
- print(const [42, 'foo']);
+ print(const [42, 'foo', int]);
print(const <String, A>{'E2': A.elem2, 'E4': A.elem4});
print(
const D(const C(4, 5, 6), const {'foo': 42, 'bar': const B(c2.length)}));
diff --git a/pkg/vm/testcases/bytecode/literals.dart.expect b/pkg/vm/testcases/bytecode/literals.dart.expect
index a3c9ec2..7d6702f 100644
--- a/pkg/vm/testcases/bytecode/literals.dart.expect
+++ b/pkg/vm/testcases/bytecode/literals.dart.expect
@@ -360,19 +360,19 @@
PushConstant CP#9
IndirectStaticCall 1, CP#1
Drop1
- PushConstant CP#10
PushConstant CP#11
+ PushConstant CP#12
IndirectStaticCall 1, CP#1
Drop1
- PushConstant CP#19
PushConstant CP#20
+ PushConstant CP#21
IndirectStaticCall 1, CP#1
Drop1
- PushConstant CP#30
PushConstant CP#31
+ PushConstant CP#32
IndirectStaticCall 1, CP#1
Drop1
- PushConstant CP#32
+ PushConstant CP#33
ReturnTOS
}
ConstantPool {
@@ -386,35 +386,36 @@
[7] = String 'A.elem2'
[8] = Instance #lib::A type-args CP#5 {index: 6, _name: 7}
[9] = StaticICData target 'dart.core::print', arg-desc CP#1
- [10] = List type-arg dart.core::Object, entries CP# [0, 3]
- [11] = StaticICData target 'dart.core::print', arg-desc CP#1
- [12] = TypeArgs [dart.core::String, #lib::A]
- [13] = String 'E2'
- [14] = String 'E4'
- [15] = Int 3
- [16] = String 'A.elem4'
- [17] = Instance #lib::A type-args CP#5 {index: 15, _name: 16}
- [18] = List type-arg dynamic, entries CP# [13, 8, 14, 17]
- [19] = Instance dart.core::_ImmutableMap type-args CP#12 {_kvPairs: 18}
- [20] = StaticICData target 'dart.core::print', arg-desc CP#1
- [21] = Int 9
- [22] = Int 30
- [23] = Instance #lib::C type-args CP#5 {j: 21, i: 22}
- [24] = TypeArgs [dart.core::String, dart.core::Object]
- [25] = String 'bar'
- [26] = Int 6
- [27] = Instance #lib::B type-args CP#5 {i: 26}
- [28] = List type-arg dynamic, entries CP# [3, 0, 25, 27]
- [29] = Instance dart.core::_ImmutableMap type-args CP#24 {_kvPairs: 28}
- [30] = Instance #lib::D type-args CP#5 {x: 23, y: 29}
- [31] = StaticICData target 'dart.core::print', arg-desc CP#1
- [32] = Null
+ [10] = Type dart.core::int
+ [11] = List type-arg dart.core::Object, entries CP# [0, 3, 10]
+ [12] = StaticICData target 'dart.core::print', arg-desc CP#1
+ [13] = TypeArgs [dart.core::String, #lib::A]
+ [14] = String 'E2'
+ [15] = String 'E4'
+ [16] = Int 3
+ [17] = String 'A.elem4'
+ [18] = Instance #lib::A type-args CP#5 {index: 16, _name: 17}
+ [19] = List type-arg dynamic, entries CP# [14, 8, 15, 18]
+ [20] = Instance dart.core::_ImmutableMap type-args CP#13 {_kvPairs: 19}
+ [21] = StaticICData target 'dart.core::print', arg-desc CP#1
+ [22] = Int 9
+ [23] = Int 30
+ [24] = Instance #lib::C type-args CP#5 {j: 22, i: 23}
+ [25] = TypeArgs [dart.core::String, dart.core::Object]
+ [26] = String 'bar'
+ [27] = Int 6
+ [28] = Instance #lib::B type-args CP#5 {i: 27}
+ [29] = List type-arg dynamic, entries CP# [3, 0, 26, 28]
+ [30] = Instance dart.core::_ImmutableMap type-args CP#25 {_kvPairs: 29}
+ [31] = Instance #lib::D type-args CP#5 {x: 24, y: 30}
+ [32] = StaticICData target 'dart.core::print', arg-desc CP#1
+ [33] = Null
}
]static method test_constants2() → void {
core::print(42);
core::print("foo");
core::print(self::A::elem2);
- core::print(const <core::Object>[42, "foo"]);
+ core::print(const <core::Object>[42, "foo", core::int]);
core::print(const <core::String, self::A>{"E2": self::A::elem2, "E4": self::A::elem4});
core::print(const self::D::•(const self::C::•(4, 5, 6), const <core::String, core::Object>{"foo": 42, "bar": const self::B::•(self::c2.{core::String::length})}));
}