Commit Graph

31 Commits

Author SHA1 Message Date
Alexander Markov da8cb470cc [vm/bytecode] Represent classes, libraries, scripts and recursive types in bytecode
Size of a large application:
Before: 26628600
After: 21480120 (-19.3%)

Size of snapshots:

isolate_snapshot_framework.bin
Before: 9322496
After: 6782976 (-27.2%)

isolate_snapshot_product_framework.bin
Before: 9166848
After: 6602752 (-27.9%)

Regressions in tests:

1) Test language_2/type_alias_equality_test/04 fails similarly to default mode, as VM
does not implement comparison of function types according to the specification.
Previously this test was passing as function types were canonicalized in bytecode,
which was not always correct. This CL fixes the problem with canonicalization of
function types in bytecode and the test starts failing again.

2) Tests standalone_2/entrypoints_verification_test, standalone_2/io/test_extension_test,
standalone_2/io/test_extension_fail_test fail as native extensions are not supported
in bytecode yet. These tests start passing after df5e7aac17,
which switched bytecode tests to kernel service (on x64), because kernel service doesn't
drop ASTs. This CL switches from reading AST library declarations to bytecode even if
AST is not removed, so tests fail again.

Change-Id: I8b7ba44bfa49d0b1599b2509553ff7c831a4e244
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104700
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2019-06-20 18:27:21 +00:00
Alexander Markov 68de477535 [vm/bytecode] Compact encoding of bytecode instructions (part 3/3)
Corresponding VM changes:
https://dart-review.googlesource.com/c/sdk/+/101062

On a large app, size of bytecode instructions:
Before: 12115384
After: 6282376 (-48.1%)

Total size of the app:
Before: 29790240
After: 23681504 (-20.5%)

Change-Id: Idd8f97e991236c25d663d1bcf18a51a53e73a2b7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99400
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2019-05-08 17:33:15 +00:00
Alexander Markov 8924c18003 [vm/tests] Revert changes in pkg/vm unit tests after constant-update-2018 was disabled
Pkg/vm tests were adjusted after constant evaluation was enabled in the front-end.
As constant evaluation was reverted (4b7d256a06),
we also need to revert corresponding changes in pkg/vm unit tests.

Revert "[vm/bytecode] Update expectations for bytecode generator unit test"

This reverts commit 734c50cbf2.

Revert "[vm/aot/tfa] Update TFA tests after front-end starts evaluating constants"

This reverts commit 25cb45c02f.

Change-Id: I2fcc30571bec2dd904925724ddb7105567c7ecda
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99782
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2019-04-19 18:12:21 +00:00
Alexander Markov 734c50cbf2 [vm/bytecode] Update expectations for bytecode generator unit test
This update is needed after constant-update-2018 is enabled in
e9ca6a5335

Closes https://github.com/dart-lang/sdk/issues/36601

Change-Id: I25f33e504f4df09a0d936fd11c7fa9c6236e4c78
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99265
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2019-04-12 20:15:40 +00:00
Alexander Markov 61f0f5bc43 [vm/bytecode] Declare members in bytecode
This change replaces kernel AST declarations of fields and functions
with bytecode declarations.

Size of dilp files is reduced by 11-12%.

Startup latency:
Time to the first full frame: 1.945s -> 1.687s
FinalizeClass: 554ms -> 277ms
FinishClassLoading: 296ms -> 156ms

There are following regressions in bytecode mode, which will be fixed
in future:

* dart:mirrors are not supported yet (implementation of mirrors relies
  on reading kernel AST in certain cases).

  As the result, lib_2/mirrors/* tests fail.

* native extensions are not supported yet (annotations on libraries
  and classes in AST are cleaned up as they could reference members
  which are now removed from AST).

  As the result, standalone_2/entrypoints_verification_test test fails.

* language_2/spread_collections/const_error_test/* tests fail
  due to https://github.com/dart-lang/sdk/issues/36286.

Change-Id: I5130f401fd7b84038b136136e7ccc1a6e51b6cea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97561
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2019-03-26 21:40:10 +00:00
Alexander Markov 336969538c [vm/bytecode] Revise representation of types, constants and calls in bytecode
* Type arguments are moved to global object table (and de-duplicated).
* Finalize non-recursive generic types at bytecode generation time.
* Constants are moved to global object table (and de-duplicated).
* ICData creation is avoided for direct calls.
* Interface calls reference target member instead of selector name.

Size of a dilp files: 17868K => 15896K (-11%).

Change-Id: I0c9bf338137a0fae6ed90ab6b125ed2b24a1a8ad
Reviewed-on: https://dart-review.googlesource.com/c/91108
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2019-02-05 20:13:45 +00:00
Régis Crelier 25851db73d [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>
2018-12-14 16:51:51 +00:00
Alexander Markov 9f49b47823 [vm/bytecode] Revise representation of objects and strings in bytecode
This is a major revamp of bytecode metadata format. Now bytecode has
its own serialization mechanisms.

This CL adds 'bytecode component' metadata, which contains bytecode
object table and string table. All references from bytecode (constant
pools) to libraries, classes, members, types and strings now have a new
format. References to frequently used objects are represented as indices
in object table, while rarely used objects are written inline.
This allows VM to cache frequently used objects while reading bytecode.

Representation of strings is aligned with VM - string characters are
stored in separate pools of one-byte and two-byte strings. This allows
VM to avoid UTF-8 decoding and extra copying.

Closure declarations are now explicit. Type parameters no longer require
enslosing scopes when reading/writing them.

Benchmarks:
GenKernelKernelReadAllBytecode (Intel Core i5) +29.84%
GenKernelKernelReadAllBytecode (Intel Xeon) +28.74%
Change-Id: I4b80009733a8f8c038264af74f97c4e094b9e311
Reviewed-on: https://dart-review.googlesource.com/c/85469
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
2018-12-03 19:08:42 +00:00
Alexander Markov 7fafcec013 [vm/bytecode] Eliminate AssertBoolean instructions if condition is non-nullable
Number of AssertBoolean instructions in the 100Mb dynamic trace of
Richards benchmark in pure interpreted mode (platform with bytecode):

Before: 1812005
After:   251451
Change-Id: I9fe9d37499d73ffa7636c9ca5fb9c2c18dbc1397
Reviewed-on: https://dart-review.googlesource.com/c/84643
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Zach Anderson <zra@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
2018-11-16 19:18:27 +00:00
Alexander Markov c04461c16d [vm/bytecode] Fix allocation of temporary locals for StaticSet
Change-Id: I47fc4f5d462be30351f4828bf4354404c0ad7088
Reviewed-on: https://dart-review.googlesource.com/c/84300
Commit-Queue: Régis Crelier <regis@google.com>
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2018-11-13 20:19:16 +00:00
Alexander Markov 3c32b32d56 [vm/bytecode] Enable OSR for unoptimized code compiled from bytecode
In order to enable OSR, CheckStackOverflow IL instructions are attributed
with a non-zero loop depth. The original loop depth is passed as operand
of CheckStack bytecode instruction.

Change-Id: I771f59ba9f8d071680a3b7156be380e0f606b7b2
Reviewed-on: https://dart-review.googlesource.com/c/84081
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-11-12 19:04:54 +00:00
Alexander Markov 1d10e037ef [vm/bytecode] Remove unreachable bytecode
Change-Id: I29393604547038cf359b8e19ea48078dd0eea3b1
Reviewed-on: https://dart-review.googlesource.com/c/81201
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Auto-Submit: Alexander Markov <alexmarkov@google.com>
2018-10-23 23:26:13 +00:00
Alexander Markov 9406b7b44e [vm/bytecode] Add versioning to bytecode format
Change-Id: I35d86aec17aa0f6894a6380e4bb5ac7ca3092fac
Reviewed-on: https://dart-review.googlesource.com/c/80522
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-10-22 18:03:20 +00:00
Alexander Markov 6d0601a72b [vm/bytecode] Add bytecodes for int operations and '== null'
DeltaBlue performance in pure interpreted mode
(--enable-interpreter --compilation-counter-threshold=-1):
Before: DeltaBlue(RunTime): 269198.732 us.
After:  DeltaBlue(RunTime): 158216.34376923076 us. (-41.23%)

Change-Id: I9dea8d7949421986ee6fbdeae046fe4ef6d3227f
Reviewed-on: https://dart-review.googlesource.com/c/77231
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-10-03 15:45:36 +00:00
Alexander Markov 2aac05fe10 [vm/bytecode] Add specialized JumpIf* instructions
This change adds JumpIfEqStrict, JumpIfNeStrict, JumpIfTrue, JumpIfFalse,
JumpIfNull, JumpIfNotNull bytecode instructions. These instructions
supercede If*/Jump instruction patterns.

Change-Id: Icf9dc624001ce64d4b21409864591d693ead51d3
Reviewed-on: https://dart-review.googlesource.com/77011
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-09-28 16:29:23 +00:00
Daniel Hillerström 98a9adf696 Make constructor function types conform with the specification.
Prior to this CL the return type of any constructor function was
always void. According to the specification §9.3 the return type of a
constructor function ought to be its enclosing class.

Change-Id: I70d76cc354b7f118ce96bf4954daf7fe535eb7be
Reviewed-on: https://dart-review.googlesource.com/76160
Commit-Queue: Daniel Hillerström <hillerstrom@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
2018-09-26 09:39:11 +00:00
Alexander Markov 76091c13db [vm/bytecode] Add PushNull, PushTrue, PushFalse and PushInt bytecodes
These bytecode instructions are added in order to shrink constant pools
and reduce time spent for reading constant pool entries.

Change-Id: I8522f73dc7a6236969ac0422c6cb89b945559b2d
Reviewed-on: https://dart-review.googlesource.com/75125
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-09-15 17:55:46 +00:00
Alexander Markov cdd18e6811 [vm/bytecode] Support dynamic invocation forwarders and omit checks in bytecode
This CL adds support for _dynamic_ calls (which are routed through
dynamic invocation forwarders) to bytecode pipeline.

This allows to skip argument type checks for non-covariant and
non-generic-convarint-impl parameters in bytecode when calling instance
members through known interface targets. In case of dynamic call, dynamic
invocation forwarders perform type checks which are otherwise skipped.

This CL also corrects argument type checks in forwarding stubs.
Forwarding stubs are synthetic methods, introduced by front-end to ensure
type safety if some of the argument type checks are skipped.
The specifics of forwarding stubs is that they should use parameter types
of a *target* of a stub for the argument type checks.

This change unifies how argument type checks are performed in bytecode
and in the VM in JIT mode. This allows to mix bytecode methods with
methods JIT-compiled from kernel AST in more cases.

Change-Id: I3a2720a488c8bbb91de1b189eb36ee8c51684a78
Reviewed-on: https://dart-review.googlesource.com/72543
Reviewed-by: Samir Jindel <sjindel@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-09-06 17:23:12 +00:00
Samir Jindel 2beb05b829 [vm] Re-land use of multiple entrypoints for closure calls.
Original patchset is in revision 1.

Change-Id: I29ab0dbc3711f99895fd4f04a49d4185463a1602
Cq-Include-Trybots: luci.dart.try:vm-kernel-win-release-x64-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-reload-linux-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/71241
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-08-23 17:54:19 +00:00
Samir Jindel 569290dbf5 Revert "[vm] Use multiple entrypoints to remove unnecessary checks on statically-typed closure calls."
This reverts commit 19126e861e.

Reason for revert: Breaks several bots.

Original change's description:
> [vm] Use multiple entrypoints to remove unnecessary checks on statically-typed closure calls.
> 
> Test Plan:
> 
> Behavioral correctness should be ensured by existing tests. Tests in vm/dart/entrypoints
> ensure that the unchecked entrypoint is used in cases where the optimization should trigger.
> 
> Bug: https://github.com/dart-lang/sdk/issues/31798
> 
> Change-Id: Id25ecba86e20c22f0678c12986ad620db312ddaa
> Cq-Include-Trybots: luci.dart.try:vm-kernel-win-release-x64-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-win-release-x64-try
> Reviewed-on: https://dart-review.googlesource.com/69743
> Commit-Queue: Samir Jindel <sjindel@google.com>
> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>

TBR=vegorov@google.com,sjindel@google.com

Change-Id: Ia33e9d141827d3c990c65d839333443c224dc85d
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: https://github.com/dart-lang/sdk/issues/31798
Cq-Include-Trybots: luci.dart.try:vm-kernel-win-release-x64-try, vm-kernel-optcounter-threshold-linux-release-x64-try, vm-kernel-precomp-linux-debug-x64-try, vm-kernel-precomp-linux-release-simarm-try, vm-kernel-precomp-linux-release-simarm64-try, vm-kernel-precomp-linux-release-x64-try, vm-kernel-precomp-win-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/70920
Reviewed-by: Samir Jindel <sjindel@google.com>
Commit-Queue: Samir Jindel <sjindel@google.com>
2018-08-21 17:10:56 +00:00
Samir Jindel 19126e861e [vm] Use multiple entrypoints to remove unnecessary checks on statically-typed closure calls.
Test Plan:

Behavioral correctness should be ensured by existing tests. Tests in vm/dart/entrypoints
ensure that the unchecked entrypoint is used in cases where the optimization should trigger.

Bug: https://github.com/dart-lang/sdk/issues/31798

Change-Id: Id25ecba86e20c22f0678c12986ad620db312ddaa
Cq-Include-Trybots: luci.dart.try:vm-kernel-win-release-x64-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-win-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/69743
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-08-21 16:00:57 +00:00
Alexander Markov 741f662a60 [vm/kernel/bytecode] Fix number of checked arguments in bytecode calls
Number of checked arguments is corrected in ICData objects created when
reading bytecode, both for instance and static calls.

InstanceCall1 and InstanceCall2 bytecode instructions are replaced with
InstanceCall which works for any number of checked arguments. This makes
decision on number of checked arguments internal to VM and it is no longer
exposed to bytecode.

Change-Id: I0bba01eca6347336f3832de863b2ce4715fda04a
Reviewed-on: https://dart-review.googlesource.com/69421
Reviewed-by: Régis Crelier <regis@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-08-13 17:50:21 +00:00
Alexander Markov 85d85246ad [vm/kernel/bytecode] Revise access to instance fields in bytecode
Constant pool:

* Field constant pool entry is renamed to StaticField
* FieldOffset constant pool entry is replaced with InstanceField.
  InstanceField occupies 2 slots for field offset and field object.
* ContextOffset constant pool entry is removed.
* TypeArgumentsFieldOffset is renamed to TypeArgumentsField

Bytecodes:

* LoadFieldTOS and StoreFieldTOS require InstanceField entry.
* New bytecodes added: LoadContextParent, StoreContextParent,
  LoadContextVar, StoreContextVar, LoadTypeArgumentsField.

This CL is a preparation for compilation of bytecodes related
to instance field accesses.

Change-Id: I1d6274e94bd7cd764e4fc83d9847daf4f21e5a25
Reviewed-on: https://dart-review.googlesource.com/68843
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2018-08-08 16:35:25 +00:00
Alexander Markov ae001707b7 [vm/kernel/bytecode] Do not call getter for a static field initialized with double literal
Values of static fields with trivial initializers are pre-initialized
at load time, so such static fields do not have implicit getters.
Bytecode generator is fixed to treat double literal initializers as trivial
and avoid calling getters for such fields.

Also, this CL disables bytecode generation for static fields with trivial
initializers as their bytecode is not used.

Change-Id: I44b9d26ab2007e33d0d5b9f716e30848f0c38e8a
Reviewed-on: https://dart-review.googlesource.com/68005
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-08-02 16:10:02 +00:00
Alexander Markov 1b66c0a78c [vm/kernel/bytecode] Remove extra pushes/drops for Set expressions with unused result
Also, bytecode generation of DirectPropertySet and SuperPropertySet is
corrected in case result is used.

Change-Id: I680645f961d9c471579dcbdc9a5b7544cbc9e188
Reviewed-on: https://dart-review.googlesource.com/63343
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-07-02 18:27:23 +00:00
Alexander Markov c53952a46d [vm/kernel/bytecode] Generate bytecode for assertions, bool checks
In addition:

* Use InstanceCall1 instead of InstanceCall2 for now as InstanceCall2
  requires ICData objects with 2 checked arguments.

* Remove try-catch around bytecode generation as all operations are
  supported and silent fallback is no longer needed.

Change-Id: Iead5a4997450cc47ef3bb3221647e733b7a72b62
Reviewed-on: https://dart-review.googlesource.com/62443
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-06-26 23:07:18 +00:00
Alexander Markov 828a168622 [vm/kernel/bytecode] Generate bytecode for native methods
Change-Id: If47ef9ef4ff5ac3cb3f4f6737590370b647fc9ff
Reviewed-on: https://dart-review.googlesource.com/59180
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2018-06-13 01:16:03 +00:00
Alexander Markov d52d060950 [vm/kernel/bytecode] Count type arguments argument for factory calls
Implicit argument for type arguments vector is not counted
in the number of arguments in ArgumentsDescriptor when calling
generic functions, but VM requires it to be counted
when calling factory constructors.

Bytecode generator is adjusted to cope with this discrepancy.

Change-Id: Id041563dfc68491b87593bcb6dff5cae64bfedc6
Reviewed-on: https://dart-review.googlesource.com/58961
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
2018-06-07 17:24:08 +00:00
Kevin Millikin 6ac6baae8e Record interfaceTargets for calls on dynamic receivers
When calling Object methods on dynamic receivers, record the
interfaceTarget it Kernel.  Back ends will use this to treat the call
as a statically typed one.  This is half of the problem in
https://github.com/dart-lang/sdk/issues/33293

Bug: https://github.com/dart-lang/sdk/issues/33293
Change-Id: I8d05903e5b85370a4e697ad3afc494cbc14bcc6a
Reviewed-on: https://dart-review.googlesource.com/57820
Commit-Queue: Kevin Millikin <kmillikin@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
2018-06-04 09:47:21 +00:00
Alexander Markov d319d3eda4 [vm/kernel/bytecode] Do not generate bytecode for external (native) members
Change-Id: I5887893528b8b0d4c93ef5e1088e229e0338ecef
Reviewed-on: https://dart-review.googlesource.com/58040
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-06-01 22:13:19 +00:00
Kevin Millikin b62b438e8a Infer Object members for dynamic receivers
For method, getter, and setter invocations with names of methods on
Object on expressions with static type `dynamic`, if the invocation
cannot possibly be an invocation of noSuchMethod, infer the type of
the invocation using the type of the member of Object.

This implements the feature spec
https://github.com/dart-lang/sdk/commit/472ec7780f1bb38f049d0fcc903a69bfb8ef9133

Fixes https://github.com/dart-lang/sdk/issues/32414

Change-Id: I135156346fe1468561d56a01cf3c5f0efde30739
Reviewed-on: https://dart-review.googlesource.com/56942
Commit-Queue: Kevin Millikin <kmillikin@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
2018-05-31 12:43:22 +00:00