[vm] Specialize 'new List()' on kernel AST
In VM, 'new List' is equivalent to either 'new _GrowableList' or
'new _List' depending on the number of arguments.
This change does the transformation early (on kernel AST), in order
to have specialized representation in TFA and in bytecode.
Change-Id: I46f0db8cc19efb3a53fdbe971ac26bdd2736fbda
Reviewed-on: https://dart-review.googlesource.com/76283
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/front_end/testcases/expressions.dart.direct.transformed.expect b/pkg/front_end/testcases/expressions.dart.direct.transformed.expect
index 7fece02..04022a3 100644
--- a/pkg/front_end/testcases/expressions.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/expressions.dart.direct.transformed.expect
@@ -42,7 +42,7 @@
core::print(let final dynamic #t3 = i in let final dynamic #t4 = i = #t3.+(1) in #t3);
core::print(new core::Object::•());
core::print(const core::Object::•());
- core::print(core::List::•<core::String>(2).runtimeType);
+ core::print(core::_List::•<core::String>(2).runtimeType);
self::foo(fisk: "Blorp gulp");
function f() → dynamic {
core::print("f was called");
diff --git a/pkg/front_end/testcases/expressions.dart.strong.transformed.expect b/pkg/front_end/testcases/expressions.dart.strong.transformed.expect
index c38365b..aa3ea16 100644
--- a/pkg/front_end/testcases/expressions.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/expressions.dart.strong.transformed.expect
@@ -48,7 +48,7 @@
core::print(let final core::int #t3 = i in let final core::int #t4 = i = #t3.{core::num::+}(1) in #t3);
core::print(new core::Object::•());
core::print(const core::Object::•());
- core::print(core::List::•<core::String>(2).{core::Object::runtimeType});
+ core::print(core::_List::•<core::String>(2).{core::Object::runtimeType});
self::foo(fisk: "Blorp gulp");
function f() → core::Null {
core::print("f was called");
diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.direct.transformed.expect b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.direct.transformed.expect
index 5b85710..3c303a7 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.direct.transformed.expect
@@ -64,7 +64,7 @@
[yield] true;
}
{
- :iterator.{core::_SyncIterator::_current} = core::List::•<dynamic>();
+ :iterator.{core::_SyncIterator::_current} = core::_GrowableList::•<dynamic>(0);
[yield] true;
}
{
@@ -72,7 +72,7 @@
[yield] true;
}
{
- :iterator.{core::_SyncIterator::_yieldEachIterable} = core::List::•<dynamic>();
+ :iterator.{core::_SyncIterator::_yieldEachIterable} = core::_GrowableList::•<dynamic>(0);
[yield] true;
}
}
diff --git a/pkg/front_end/testcases/rasta/issue_000070.dart.direct.transformed.expect b/pkg/front_end/testcases/rasta/issue_000070.dart.direct.transformed.expect
index 3ea2923b..935af28 100644
--- a/pkg/front_end/testcases/rasta/issue_000070.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/rasta/issue_000070.dart.direct.transformed.expect
@@ -6,7 +6,7 @@
class A<N extends core::Object = dynamic, S extends core::Object = dynamic, U extends core::Object = dynamic> extends core::Object {
final field core::List<self::A::U> field;
constructor •(self::A::N n, self::A::S s) → void
- : self::A::field = core::List::•<self::A::U>(), super core::Object::•() {
+ : self::A::field = core::_GrowableList::•<self::A::U>(0), super core::Object::•() {
exp::Expect::isTrue(n is self::A::N);
exp::Expect::isTrue(s is self::A::S);
}
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 251be65..6dd942a 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -15,6 +15,8 @@
show transformLibraries, transformProcedure;
import '../transformations/call_site_annotator.dart' as callSiteAnnotator;
+import '../transformations/list_factory_specializer.dart'
+ as listFactorySpecializer;
/// Specializes the kernel IR to the Dart VM.
class VmTarget extends Target {
@@ -77,6 +79,8 @@
transformAsync.transformLibraries(coreTypes, libraries, flags.syncAsync);
logger?.call("Transformed async methods");
+ listFactorySpecializer.transformLibraries(libraries, coreTypes);
+
callSiteAnnotator.transformLibraries(
component, libraries, coreTypes, hierarchy);
logger?.call("Annotated call sites");
diff --git a/pkg/vm/lib/transformations/list_factory_specializer.dart b/pkg/vm/lib/transformations/list_factory_specializer.dart
new file mode 100644
index 0000000..ca9df25
--- /dev/null
+++ b/pkg/vm/lib/transformations/list_factory_specializer.dart
@@ -0,0 +1,52 @@
+// 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.
+
+library vm.transformations.list_factory_specializer;
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/core_types.dart' show CoreTypes;
+
+/// Replaces new List() and new List(n) with VM-specific
+/// new _GrowableList(0) and new _List(n).
+void transformLibraries(List<Library> libraries, CoreTypes coreTypes) {
+ final transformer = new _ListFactorySpecializer(coreTypes);
+ libraries.forEach(transformer.visitLibrary);
+}
+
+class _ListFactorySpecializer extends Transformer {
+ final Procedure _listFactory;
+ final Procedure _growableListFactory;
+ final Procedure _fixedListFactory;
+
+ _ListFactorySpecializer(CoreTypes coreTypes)
+ : _listFactory = coreTypes.index.getMember('dart:core', 'List', ''),
+ _growableListFactory =
+ coreTypes.index.getMember('dart:core', '_GrowableList', ''),
+ _fixedListFactory =
+ coreTypes.index.getMember('dart:core', '_List', '') {
+ assert(_listFactory.isFactory);
+ assert(_growableListFactory.isFactory);
+ assert(_fixedListFactory.isFactory);
+ }
+
+ @override
+ visitStaticInvocation(StaticInvocation node) {
+ super.visitStaticInvocation(node);
+
+ if (node.target == _listFactory) {
+ if (node.arguments.positional.isEmpty) {
+ return new StaticInvocation(_growableListFactory,
+ new Arguments([new IntLiteral(0)], types: node.arguments.types))
+ ..parent = node.parent
+ ..fileOffset = node.fileOffset;
+ } else {
+ return new StaticInvocation(_fixedListFactory, node.arguments)
+ ..parent = node.parent
+ ..fileOffset = node.fileOffset;
+ }
+ }
+
+ return node;
+ }
+}
diff --git a/pkg/vm/testcases/bytecode/instance_creation.dart b/pkg/vm/testcases/bytecode/instance_creation.dart
index 05a745b..8bfa5d7 100644
--- a/pkg/vm/testcases/bytecode/instance_creation.dart
+++ b/pkg/vm/testcases/bytecode/instance_creation.dart
@@ -79,6 +79,10 @@
class TestTypeArgReuse<P, Q> extends Base<P, Q> implements K<P, Q> {}
+foo6() => new List<String>();
+
+foo7(int n) => new List<int>(n);
+
main() {
foo1();
foo2();
diff --git a/pkg/vm/testcases/bytecode/instance_creation.dart.expect b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
index e0b0287..e0d510a 100644
--- a/pkg/vm/testcases/bytecode/instance_creation.dart.expect
+++ b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
@@ -564,6 +564,44 @@
Bytecode {
Entry 0
CheckStack
+ PushConstant CP#0
+ PushInt 0
+ PushConstant CP#2
+ IndirectStaticCall 2, CP#1
+ ReturnTOS
+ PushNull
+ ReturnTOS
+}
+ConstantPool {
+ [0] = TypeArgumentsForInstanceAllocation dart.core::_GrowableList [dart.core::String]
+ [1] = ArgDesc num-args 2, num-type-args 0, names []
+ [2] = StaticICData target 'dart.core::_GrowableList::', arg-desc CP#1
+}
+]static method foo6() → dynamic
+ return core::_GrowableList::•<core::String>(0);
+[@vm.bytecode=
+Bytecode {
+ Entry 0
+ CheckStack
+ PushConstant CP#0
+ Push FP[-5]
+ PushConstant CP#2
+ IndirectStaticCall 2, CP#1
+ ReturnTOS
+ PushNull
+ ReturnTOS
+}
+ConstantPool {
+ [0] = TypeArgumentsForInstanceAllocation dart.core::_List [dart.core::int]
+ [1] = ArgDesc num-args 2, num-type-args 0, names []
+ [2] = StaticICData target 'dart.core::_List::', arg-desc CP#1
+}
+]static method foo7(core::int n) → dynamic
+ return core::_List::•<core::int>(n);
+[@vm.bytecode=
+Bytecode {
+ Entry 0
+ CheckStack
PushConstant CP#1
IndirectStaticCall 0, CP#0
Drop1
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index f69e319..881cc0d 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -1006,8 +1006,6 @@
EXPECT(walker.Down());
EXPECT_STREQ("new _List", walker.CurrentName());
EXPECT(walker.Down());
- EXPECT_STREQ("new List", walker.CurrentName());
- EXPECT(walker.Down());
EXPECT_STREQ("foo", walker.CurrentName());
EXPECT(!walker.Down());
}