Commit Graph

104 Commits

Author SHA1 Message Date
Régis Crelier 4cf2d3990b [VM runtime] Store Smi instance type in type test cache when using the interpreter.
Instances of type Smi are handled in generated code and not looked up in
type test cache. The interpreter does not implement this special handling and
relies on the cache for Smi instances as well.

Change-Id: I3a8501efcbadfcbe848871ad0f6ada444414be43
Reviewed-on: https://dart-review.googlesource.com/76305
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Régis Crelier <regis@google.com>
2018-09-25 15:47:37 +00:00
Alexander Markov 46ec629096 [vm/bytecode] Trigger JIT-compilation from interpreter
Performance on Richards benchmark (no bytecode in platform, release build):

Interpreter (--enable-interpreter --compilation-counter-threshold=-1)
Richards(RunTime): 177228.34433333334 us.

Interpreter + bytecode compilation with default threshold 10 (--enable-interpreter)
Richards(RunTime): 930.8050725919032 us.
Varies from run to run, spikes up to 4178.005912317328 (no OSR yet, only background compilation).

Bytecode compilation (--use-bytecode-compiler)
Richards(RunTime): 830.1371626556016 us

Default pipeline:
Richards(RunTime): 880.1557113946327 us.

Numbers on Richards benchmark (platform with bytecode, release build):

Interpreter (--enable-interpreter --compilation-counter-threshold=-1)
Richards(RunTime): 354553.6346666667 us.

Interpreter + compilation with default threshold 10 (--enable-interpreter)
Richards(RunTime): 934.7108855140189 us.

Bytecode compilation (--use-bytecode-compiler)
Richards(RunTime): 822.74178403949 us.


Change-Id: Ic13e9f7c7d98f2930e6de4c4f74bac4d28478249
Reviewed-on: https://dart-review.googlesource.com/75781
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-09-20 20:57:08 +00:00
Alexander Markov 3263550e86 [vm] Decouple bytecode reading from compilation
This way requests to compile won't end prematurely after reading
bytecode if interpreter is enabled.

Change-Id: Ic06cae98ea65bc4656ef491fbd306d34b0e1ef4c
Reviewed-on: https://dart-review.googlesource.com/75628
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2018-09-20 16:22:33 +00:00
Régis Crelier a2fae0125f [VM interpreter] Mark activation frames as interpreted instead of crashing.
This is a first step in supporting bytecode in the debugger.

Change-Id: Ieb06b8b534fcc7f0291457cd6912d772b8ee247a
Reviewed-on: https://dart-review.googlesource.com/74012
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Régis Crelier <regis@google.com>
2018-09-12 00:33:30 +00:00
Zach Anderson b4004f6476 [vm] Reland: Move the interpreter under a flag.
After this CL, the interpreter is included by default in the
JIT VM under the flag --enable-interpreter.

Reland with fix to NativeArgument setup in simulator_arm.cc

Change-Id: Ib9b4df6eb4d997dfbe361188b8a127828c1d9c6f
Reviewed-on: https://dart-review.googlesource.com/74003
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Zach Anderson <zra@google.com>
2018-09-07 19:25:31 +00:00
Zach Anderson 21406f576a Revert "[vm] Move the interpreter under a flag."
This reverts commit 715ab7b30b.

Reason for revert: simarm and kernel precomp builds failing

Original change's description:
> [vm] Move the interpreter under a flag.
> 
> After this CL, the interpreter is included by default in the
> JIT VM under the flag --enable-interpreter.
> 
> Change-Id: I06458f20288d67981822788ee6e867c2127ebdd3
> Reviewed-on: https://dart-review.googlesource.com/71800
> Commit-Queue: Zach Anderson <zra@google.com>
> Reviewed-by: Alexander Markov <alexmarkov@google.com>
> Reviewed-by: Siva Annamalai <asiva@google.com>
> Reviewed-by: Régis Crelier <regis@google.com>
> Reviewed-by: Ryan Macnak <rmacnak@google.com>

TBR=rmacnak@google.com,alexmarkov@google.com,zra@google.com,asiva@google.com,regis@google.com

Change-Id: I3622f4dbe53288d07fc21b34ee5ff68f2682b36d
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/74001
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Zach Anderson <zra@google.com>
2018-09-07 17:14:21 +00:00
Zach Anderson 715ab7b30b [vm] Move the interpreter under a flag.
After this CL, the interpreter is included by default in the
JIT VM under the flag --enable-interpreter.

Change-Id: I06458f20288d67981822788ee6e867c2127ebdd3
Reviewed-on: https://dart-review.googlesource.com/71800
Commit-Queue: Zach Anderson <zra@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2018-09-07 16:46:07 +00:00
Régis Crelier cf6ac73349 [VM runtime] Add transition before checking for error after interpreting call.
Change-Id: I6030f17ae9ebb937231f5766f4477cf7127dcc33
Reviewed-on: https://dart-review.googlesource.com/73289
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2018-09-06 02:20:08 +00:00
Vyacheslav Egorov 7558644bd6 [vm/compiler] Move compiler state (CHA, deopt id) from Thread to a special class
Also move deopt id computation logic into a separate class and add a comment
explaining while deopt ids are incremented by 2.

Change-Id: Ife489be7d10c7198a8e7adf9e97e0c516d78ea55
Reviewed-on: https://dart-review.googlesource.com/72685
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2018-09-03 16:01:24 +00:00
Vyacheslav Egorov 80615aed27 [vm] Implement static type exactness tracking for method receivers.
Change-Id: I35ffcee7dfa741d2095b711d402a6caae388b2c4
Reviewed-on: https://dart-review.googlesource.com/68943
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-08-29 10:11:17 +00:00
Martin Kustermann b7790e3147 [VM] Make all of our compilation pipeline use a [FrameLayout] to generate code
This will allow us to have configurable frame layouts during
gen_snapshot/dart_bootstrap.

Issue https://github.com/dart-lang/sdk/issues/33274

Change-Id: I18945189034be1a585c1e2edcf53a4b7537204c2
Reviewed-on: https://dart-review.googlesource.com/59880
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-08-21 10:26:12 +00:00
asiva 54ae4f9172 [VM] - Fix race condition in setting kernel isolate
(was being added to the isolate list before it was marked as a kernel isolate)

Also do not send service events or debug events from the kernel isolate

Change-Id: I82a1dac3c8a845344dd26ce8a2a9077eb93f8447
Reviewed-on: https://dart-review.googlesource.com/65881
Commit-Queue: Siva Annamalai <asiva@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2018-08-16 22:01:42 +00:00
Samir Jindel 66278e3919 [vm/precomp] Change checked/unchecked terminology to monomorphic/-
Change-Id: Ib54db47d60e7b822a4c73995998aecb6780a4cce
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/69306
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-08-10 14:32:37 +00:00
Martin Kustermann 575a8f8381 [VM] Extend subtype-test mechanism with support for generic methods
Until now the subtype-test cache mechanism did not work (i.e. could
return the wrong result) for partially instantiated generic closures.

Additionally, closures which close over generic methods were always
handled in runtime.  This caused a servere performance regression for
any code hitting this (e.g. code which uses `package:stack_trace`).

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

Change-Id: Idb73e6f348c2fe0c737f42c57009f5f7a636c9a6
Reviewed-on: https://dart-review.googlesource.com/68369
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2018-08-08 13:40:58 +00:00
Régis Crelier b04def964c [VM interpreter] Save previous argdesc_ and pp_ on reentry, restore on exit.
Fix previously broken AssertAssignable bytecode failing to throw.
Do not assume interpreter is never called on generic closure.
Propagate error after failed getter invocation in GetFieldForDispatch runtime
call.

Change-Id: I548a49829cc29addbbd310f1dc19ce8073738015
Reviewed-on: https://dart-review.googlesource.com/67922
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
2018-08-02 17:56:50 +00:00
Aart Bik 8bad5c7b29 [vm/compiler] Non-speculative X64 long division/remainder.
Rationale:
Having a non-speculative implementation avoids deopting
under JIT and enables AOT.

https://github.com/dart-lang/sdk/issues/33967

Change-Id: Ib38200502f5a8f63912ff5d7a808ea6e27f9001d
Reviewed-on: https://dart-review.googlesource.com/67502
Commit-Queue: Aart Bik <ajcbik@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-08-01 00:13:55 +00:00
Régis Crelier a98feb0f01 [VM interpreter] Fix exception handling.
Convert bytecode indices to pc offsets when reading bytecode exception tables.
Print pc descriptors and exception handlers in bytecode disassembly.
Propagate unhandled exceptions after calling interpreter.

Change-Id: Idb3b5459165ab0a124877452b1d9865d27c06d56
Reviewed-on: https://dart-review.googlesource.com/67501
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Régis Crelier <regis@google.com>
2018-07-30 23:31:07 +00:00
Régis Crelier c7ed22a5d8 [VM interpreter] Support "invoke field dispatcher' and 'method extractor' functions without jitting them.
Change-Id: I78bbb34d13b643507a3eaa483ce111d20db1f5b6
Reviewed-on: https://dart-review.googlesource.com/66406
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
2018-07-25 18:58:34 +00:00
Régis Crelier 25ff988071 [VM interpeter] Allocate a SubtypeTestCache and use it in interpreted implicit setter.
Change-Id: I1c18ff79bf9b56b650a51c193fa0759d00470786
Reviewed-on: https://dart-review.googlesource.com/65483
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-07-19 15:52:17 +00:00
Samir Jindel c1df0d4c10 [vm] Very basic store barrier elimination.
If the left-hand side of the store is an allocation and no GC-triggering
instructions have been executed since, it is safe to elide the store barrier.

This gives a 1.4% code size reduction on Flutter Gallery ARM32.

Change-Id: Ib7227d3ef9d798d5e30f238f3f789f9a2e637d6a
Cq-Include-Trybots: luci.dart.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/64687
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2018-07-17 22:59:28 +00:00
Régis Crelier 9be82b92ab [VM interpreter] Support inline type check of implicit setter value.
Change-Id: I2c357a638308f15d83d284a85623b550395a6f4e
Reviewed-on: https://dart-review.googlesource.com/64825
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-07-16 20:33:41 +00:00
Ryan Macnak 937ee2e8ca [vm] Propagate unwind errors received during reload stress testing.
Disable reloading during a dynamic load.

Change-Id: I58f578b41495566c3df26607712dac2642ad1039
Reviewed-on: https://dart-review.googlesource.com/64761
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2018-07-12 21:02:08 +00:00
Régis Crelier afb283543f [VM interpreter] Fix bad ifdef.
Change-Id: Ib2a211578dc7b83ca836aaa7e0748b008807d078
Reviewed-on: https://dart-review.googlesource.com/64766
Reviewed-by: Régis Crelier <regis@google.com>
2018-07-12 19:21:11 +00:00
Régis Crelier f793a60790 [VM interpreter] Improve transition from jitted code to interpreted code.
Arguments are not copied anymore into an array allocated for each transition.

Change-Id: Ib9e708737de6cc0d221c53f2b003e0d4040b17fc
Reviewed-on: https://dart-review.googlesource.com/64664
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
2018-07-12 18:58:24 +00:00
Ryan Macnak 7952cf0b8d [vm] In the reload stress test, reload from the script uri instead of the root library's uri, which are different when not running from source.
Assumes the embedder has properly set the script URI hook, which is true of the standalone embedder that we run the reload stress tests on.

Bug: https://github.com/dart-lang/sdk/issues/33291
Bug: https://github.com/dart-lang/sdk/issues/32134
Change-Id: I18ec87081b584e47cde84590ebf6670bee6d5fdb
Reviewed-on: https://dart-review.googlesource.com/64181
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2018-07-11 22:35:43 +00:00
Samir Jindel d9c36e8d4d [vm/precomp] Re-land support for slow-path sharing of CheckStackOverflow with status file updates.
Patchset 1 contains the original revision.

Cq-Include-Trybots: luci.dart.try:vm-kernel-reload-linux-release-x64-try;luci.dart.try:vm-kernel-reload-rollback-linux-release-x64-try
Change-Id: Ic2601a268e1cf909183283e9418c03dc6559e809
Reviewed-on: https://dart-review.googlesource.com/62902
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-06-29 12:32:28 +00:00
Samir Jindel 0152213386 Revert "[vm/precomp] Support slow-path sharing for CheckStackOverflow."
This reverts commit dff333e1bf.

Reason for revert: Several hot-reload bots are broken.

Original change's description:
> [vm/precomp] Support slow-path sharing for CheckStackOverflow.
> 
> Test Plan:
> 
> Added new test "stack_overflow_shared_test" which uses --stacktrace_filter to
> force the stack overflow checks to go into the slow-path.
> 
> Change-Id: I92e8ab5f88b1e0855148af212e43adda40ce4d15
> Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try;luci.dart.try:vm-kernel-precomp-linux-release-x64-try;luci.dart.try:vm-kernel-precomp-linux-release-simarm-try
> Reviewed-on: https://dart-review.googlesource.com/60340
> Commit-Queue: Samir Jindel <sjindel@google.com>
> Reviewed-by: Alexander Markov <alexmarkov@google.com>

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

Change-Id: I632ac9840d360fa624de4c9d17ae679e72c1b16f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try;luci.dart.try:vm-kernel-precomp-linux-release-x64-try;luci.dart.try:vm-kernel-precomp-linux-release-simarm-try
Reviewed-on: https://dart-review.googlesource.com/62920
Reviewed-by: Samir Jindel <sjindel@google.com>
Commit-Queue: Samir Jindel <sjindel@google.com>
2018-06-28 19:08:29 +00:00
Samir Jindel dff333e1bf [vm/precomp] Support slow-path sharing for CheckStackOverflow.
Test Plan:

Added new test "stack_overflow_shared_test" which uses --stacktrace_filter to
force the stack overflow checks to go into the slow-path.

Change-Id: I92e8ab5f88b1e0855148af212e43adda40ce4d15
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try;luci.dart.try:vm-kernel-precomp-linux-release-x64-try;luci.dart.try:vm-kernel-precomp-linux-release-simarm-try
Reviewed-on: https://dart-review.googlesource.com/60340
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-06-28 17:20:07 +00:00
Régis Crelier 008aa729c5 [VM interpreter] Support implicit getters and setters without compiling them.
Change-Id: I1e61cd79f66efe55c963d970e27f81a9d4084600
Reviewed-on: https://dart-review.googlesource.com/61860
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-06-26 20:24:38 +00:00
Vyacheslav Egorov 20ca5bbb05 [vm/jit] Introduce dynamic invocation forwarders that perform type checking
This forwarders are used at dynamic call-sites and perform type checking
for all non-generic-covariant arguments. This allows to skip the same
type checks in the actual method body.

This yield on average 10% improvement in performance across the body of
benchmarks including dart2js compilation times.

Bug: https://github.com/dart-lang/sdk/issues/33257
Change-Id: If3fc94a2e0a6f496ec0633f0b379d053a54a40ca
Reviewed-on: https://dart-review.googlesource.com/61244
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2018-06-25 07:27:04 +00:00
Alexander Markov c4d6ac0cbe [vm/compiler/aot] Implement non-speculative int64 shift operation
Closes https://github.com/dart-lang/sdk/issues/33364

Change-Id: I9432d82a1ee58fbbdc1b54b810a71c2c7ddd8fce
Reviewed-on: https://dart-review.googlesource.com/59821
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-06-22 15:43:28 +00:00
Ryan Macnak 8da46d35f5 [vm] Move heap-related code to its own subdirectory (cf. compiler).
Remove some dead includes.

Change-Id: I31f3e739e5ee46dcbba5d6a2f091491b46402943
Reviewed-on: https://dart-review.googlesource.com/60146
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2018-06-20 00:39:49 +00:00
Régis Crelier 686fd133a7 [VM interpreter] Propagate unhandled exception returned from jitted code to interpreter.
Change-Id: I1d6426b6af7a0efbda1ef3a9b8c838d3b0119063
Reviewed-on: https://dart-review.googlesource.com/60520
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
2018-06-18 19:22:05 +00:00
Samir Jindel f1d1da6164 [vm/precomp] Reduce the size of slow-path code in precompiled mode.
The stub code for calling into the runtime is now responsible for saving any
live registers. Since it doesn't know which registers are live (it's shared
across many safepoints), it saves all the registers. The stackmaps and
environments for safepoints which call this stub are extended to cover the stack
slots in the stub's frame which correspond to registers which are actually live
at the safepoint.

Currently this is only supported in precompiled X64 for the `CheckNull`
slow-path. By creating a separate stub for the CheckNull slow path we are able
to eliminate the size overhead of preparing arguments for the runtime call stub,
and reduce the slow-path size on X64 to 1 instruction.

# Test Plan

The stackmap for a safepoint in the `CheckNull` slowpath is only used when
handling the exception causes a GC, which is extremely unlikely. To induce this,
we add a flag to force this behavior in debug-mode and a test which exercises
this. The rest of the changes inherit existing coverage.

Change-Id: I3d8f2a7c3560c432599344d7420d42ddbee7a89d
Reviewed-on: https://dart-review.googlesource.com/59660
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Samir Jindel <sjindel@google.com>
2018-06-15 15:59:05 +00:00
Ryan Macnak 9b5a931b06 [vm] Replace most runtime/vm uses of OS::Print with OS::PrintErr.
Leave --print-snapshot-sizes on stdout because it is parsed by Flutter benchmarks.

Replace all runtime/bin uses of OS::Print with Log::Print.

Bug: https://github.com/dart-lang/sdk/issues/32134
Change-Id: I74aacfb410cdfa9270d06e7f6ab0534520c7c7ba
Reviewed-on: https://dart-review.googlesource.com/60021
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-06-13 19:51:40 +00:00
Alexander Markov c3b5939965 [vm] Remove --limit-ints-to-64-bits option and old _Bigint class
Closes https://github.com/dart-lang/sdk/issues/33306

Change-Id: I7088d8b7143edbe24f5cefe4be037ad2006e0625
Reviewed-on: https://dart-review.googlesource.com/58101
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2018-06-04 20:10:40 +00:00
Régis Crelier 57dc25c6f6 [VM interpreter] Initial version of stack walking of interpreted frames.
Various improvements and bug fixes.

Change-Id: Ice0ce0ba8db8c9f78b9fad89f951218c90c831b7
Reviewed-on: https://dart-review.googlesource.com/57443
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-06-04 18:37:30 +00:00
Ryan Macnak 2b5de60888 [vm] Improve --verbose-gc.
- Track mark-compact as a GC type instead of a GC reason.
 - Track external allocation as a GC reason.

Change-Id: Id79bf6a582109e3ebb97954822aefeffe68959e2
Reviewed-on: https://dart-review.googlesource.com/58002
Reviewed-by: Zach Anderson <zra@google.com>
2018-06-04 17:33:03 +00:00
Martin Kustermann 35b17f3730 [VM] Consistently use ValidationPolicy in frame iteration APIs
Previously there were places in the code where an API accepted a
`bool validate_frames` and call sites passed an enum value (which
implicitly got converted to a bool).

By changing the APIs to require an enum, the compiler will tell us if a
caller doesn't pass one.

Change-Id: I29fcd0b018e6cdd7e00b5bb03e83b9636d1345d4
Reviewed-on: https://dart-review.googlesource.com/57823
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2018-06-04 14:46:26 +00:00
Vyacheslav Egorov 99a5f149ac [vm] Enable type stubs based type checks in JIT mode for some types.
Relanding 4be50d6fa1 with fixes to DBC
and location summaries: AssertAssignable must save FPU registers.

For now we are limiting this to type checks against type parameter types.


In Dart 1 mode Dart2JS compiles itself in 28s when running from source
and in 23s when running from ideal app-jit snapshot (trained on the
same workload).

Before this change in Dart 2 mode numbers were 51s and 57s respectively.

After this change in Dart 2 mode numbers are 38s and 32s. Meaning
that regression is reduced by 50%.

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

Change-Id: Ifb55f86453bfdf36a2e03bcd7f3197cfde257103
Reviewed-on: https://dart-review.googlesource.com/57980
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2018-06-01 20:58:33 +00:00
Vyacheslav Egorov 0aadba1189 Revert "[vm] Enable type stubs based type checks in JIT mode for some types."
This reverts commit 4be50d6fa1.

Reason for revert: Failures on SIMDBC64 and Analyzer bots.

Original change's description:
> [vm] Enable type stubs based type checks in JIT mode for some types.
> 
> For now we are limiting this to type checks against type parameter types.
> 
> # Performance improvements
> 
> In Dart 1 mode Dart2JS compiles itself in 28s when running from source
> and in 23s when running from ideal app-jit snapshot (trained on the
> same workload).
> 
> Before this change in Dart 2 mode numbers were 51s and 57s respectively.
> 
> After this change in Dart 2 mode numbers are 38s and 32s. Meaning
> that regression is reduced by 50%.
> 
> Issue https://github.com/dart-lang/sdk/issues/31798
> Issue https://github.com/dart-lang/sdk/issues/33257
> 
> Change-Id: I34bf5385a5cc3c7702dc281c6dfa89da85d3dde1
> Reviewed-on: https://dart-review.googlesource.com/57601
> Reviewed-by: Régis Crelier <regis@google.com>
> Commit-Queue: Vyacheslav Egorov <vegorov@google.com>

TBR=vegorov@google.com,kustermann@google.com,regis@google.com

Change-Id: I85a30c962b0cd556310e19193f5993ab76ecf2e7
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/57840
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
2018-06-01 11:23:08 +00:00
Vyacheslav Egorov 4be50d6fa1 [vm] Enable type stubs based type checks in JIT mode for some types.
For now we are limiting this to type checks against type parameter types.

# Performance improvements

In Dart 1 mode Dart2JS compiles itself in 28s when running from source
and in 23s when running from ideal app-jit snapshot (trained on the
same workload).

Before this change in Dart 2 mode numbers were 51s and 57s respectively.

After this change in Dart 2 mode numbers are 38s and 32s. Meaning
that regression is reduced by 50%.

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

Change-Id: I34bf5385a5cc3c7702dc281c6dfa89da85d3dde1
Reviewed-on: https://dart-review.googlesource.com/57601
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
2018-06-01 10:50:09 +00:00
Martin Kustermann 45c524e106 [VM] Mark functions on BG compiler bailouts specially, allow them to be re-optimized on main thread
In some cases, bailouts in the bg compiler, e.g. caused by class
finalization, mark functions as unoptimizable, which can significantly
slow down an application.

Instead of doing this, we mark these functions as non-optimizable on the
BG compiler and trigger re-compilations on the main thread.

Change-Id: Ifbb6aa7972818be8fa1313427e38d8b5576053e3
Reviewed-on: https://dart-review.googlesource.com/54886
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-05-15 09:34:22 +00:00
Régis Crelier 41fcbd097c [VM runtime] Initial version of Kernel Bytecode interpreter in VM runtime.
Not fully working yet, only x64, no gc, no frame walking, etc...

Change-Id: I4d8357f6d46371bf21c3d54266cfe26163e3c8dc
Reviewed-on: https://dart-review.googlesource.com/50021
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2018-05-09 20:29:27 +00:00
Alexander Markov 2786b9ff43 [vm/aot] Add detailed error messages and stack traces for null checks
This CL fixes error message in NoSuchMethodError thrown by null checks
and line numbers in corresponding stack traces (in AOT).

Name of the called function is placed into object pool, and metadata
for null check site is generated in CodeSourceMap.

Size of flutter gallery in release mode:
	  Before	 After
RW	  2165286	 2201642	(+1.68%)
RO	  2122192	 2168224	(+2.17%)
RX	  6871072	 6871072	(+0.00%)
Total	 11163079	11245467	(+0.74%)

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

Change-Id: I5ad1190f2ec9452a669863f7dd114ea5f9092d52
Reviewed-on: https://dart-review.googlesource.com/52703
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-04-26 20:33:15 +00:00
Martin Kustermann 3b414a277c Reland "[VM] Introduction of type testing stubs - Part 1-4"
Relands 165c583d57

    [VM] Introduction of type testing stubs - Part 1

    This CL:

      * Adds a field to [RawAbstractType] which will always hold a pointer
        to the entrypoint of a type testing stub

      * Makes this new field be initialized to a default stub whenever a
        instances are created (e.g. via Type::New(), snapshot reader, ...)

      * Makes the clustered snapshotter write a reference to the
        corresponding [RawInstructions] object when writing the field and do
        the reverse when reading it.

      * Makes us call the type testing stub for performing assert-assignable
        checks.

    To reduce unnecessary loads on callsites, we store the entrypoint of the
    type testing stubs directly in the type objects.  This means that the
    caller of type testing stubs can simply branch there without populating
    a code object first.  This also means that the type testing stubs
    themselves have no access to a pool and we therefore also don't hold on
    to the [Code] object, only the [Instruction] object is necessary.

    The type testing stubs do not setup a frame themselves and also have no
    safepoint.  In the case when the type testing stubs could not determine
    a positive answer they will tail-call a general-purpose stub.

    The general-purpose stub sets up a stub frame, tries to consult a
    [SubtypeTestCache] and bails out to runtime if this was unsuccessful.

    This CL is just the the first, for ease of reviewing.  The actual
    type-specialized type testing stubs will be generated in later CLs.

    Reviewed-on: https://dart-review.googlesource.com/44787

Relands f226c22424

    [VM] Introduction of type testing stubs - Part 2

    This CL starts building type testing stubs specialzed for [Type] objects
    we test against.

    More specifically, it adds support for:

      * Handling obvious fast cases on the call sites (while still having a
        call to stub for negative case)

      * Handling type tests against type parameters, by loading the value
        of the type parameter on the call sites and invoking it's type testing stub.

      * Specialzed type testing stubs for instantiated types where we can
        do [CidRange]-based subtype-checks.

        ==> e.g. String/List<dynamic>

      * Specialzed type testing stubs for instantiated types where we can
        do [CidRange]-based subclass-checks for the class and
        [CidRange]-based subtype-checks for the type arguments.

        ==> e.g. Widget<State>, where we know [Widget] is only extended and not
                 implemented.

      * Specialzed type testing stubs for certain non-instantiated types where we
        can do [CidRange]-based subclass-checks for the class and
        [CidRange]-based subtype-checks for the instantiated type arguments and
        cid based comparisons for type parameters.  (Note that this fast-case migth
        result in some false-negatives!)

        ==> e.g. _HashMapEntry<K, V>, where we know [_HashMapEntry] is only
                 extended and not implemented.

       This optimizes cases where the caller uses `new HashMap<A, B>()` and only
       uses `A` and `B` as key/values (and not subclasses of it).  The false-negative
       can occur when subtypes of A or B are used.  In such cases we fall back to the
       [SubtypeTestCache]-based imlementation.

    Reviewed-on: https://dart-review.googlesource.com/44788

Relands 25f98bcc75

    [VM] Introduction of type testing stubs - Part 3

    The changes include:

      * Make AssertAssignableInstr no longer have a call-summary, which
        helps methods with several parameter checks by not having to
        re-load/re-initialize type arguments registers

      * Lazily create SubtypeTestCaches: We already go to runtime to warm up
        the caches, so we now also create the caches on the first runtime
        call and patch the pool entries.

      * No longer load the destination name into a register: We only need
        the name when we throw an exception, so it is not on the hot path.
        Instead we let the runtime look at the call site, decoding a pool
        index from the instructions stream.  The destination name will be
        available in the pool, at a consecutive index to the subtype cache.

      * Remove the fall-through to N=1 case for probing subtypeing tests,
        since those will always be handled by the optimized stubs.

      * Do not generate optimized stubs for FutureOr<T> (so far it just
        falled-through to TTS).  We can make optimzed version of that later,
        but it requires special subtyping rules.

      * Local code quality improvement in the type-testing-stubs: Avoid
        extra jump at last case of cid-class-range checks.

    There are still a number of optimization opportunities we can do in
    future changes.

    Reviewed-on: https://dart-review.googlesource.com/46984

Relands 2c52480ec8

    [VM] Introduction of type testing stubs - Part 4

    In order to avoid generating type testing stubs for too many types in
    the system - and thereby potentially cause an increase in code size -
    this change introduces a smarter way to decide for which types we should
    generate optimized type testing stubs.

    The precompiler creates a [TypeUsageInfo] which we use to collect
    information.  More specifically:

       a) We collect the destination types for all type checks we emit
          (we do this inside AssertAssignableInstr::EmitNativeCode).

          -> These are types we might want to generate optimized type testing
             stubs for.

       b) We collect type argument vectors used in instance creations (we do
          this inside AllocateObjectInstr::EmitNativeCode) and keep a set of
          of used type argument vectors for each class.

    After the precompiler has finished compiling normal code we scan the set
    of destination types collected in a) for uninstantiated types (or more
    specifically, type parameter types).

    We then propagate the type argument vectors used on object allocation sites,
    which were collected in b), in order to find out what kind of types are flowing
    into those type parameters.

    This allows us to extend the set of types which we test against, by
    adding the types that flow into type parameters.

    We use this final augmented set of destination types as a "filter" when
    making the decision whether to generate an optimized type testing stub
    for a given type.

    Reviewed-on: https://dart-review.googlesource.com/48640

Issue https://github.com/dart-lang/sdk/issues/32603

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

Change-Id: Ib79fbe7f043aa88f32bddad62d7656c638914b44
Reviewed-on: https://dart-review.googlesource.com/50944
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2018-04-13 09:06:56 +00:00
Ryan Macnak b3c94b5d52 Revert "Reland "[VM] Introduction of type testing stubs - Part 1-4""
This reverts commit 34763bc4c9.

Bug: https://github.com/dart-lang/sdk/issues/32852
Change-Id: I2131907d7036644707d5109a951969fc48dd74e1
Reviewed-on: https://dart-review.googlesource.com/50842
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2018-04-11 22:42:59 +00:00
Martin Kustermann 34763bc4c9 Reland "[VM] Introduction of type testing stubs - Part 1-4"
Relands 165c583d57

    [VM] Introduction of type testing stubs - Part 1

    This CL:

      * Adds a field to [RawAbstractType] which will always hold a pointer
        to the entrypoint of a type testing stub

      * Makes this new field be initialized to a default stub whenever a
        instances are created (e.g. via Type::New(), snapshot reader, ...)

      * Makes the clustered snapshotter write a reference to the
        corresponding [RawInstructions] object when writing the field and do
        the reverse when reading it.

      * Makes us call the type testing stub for performing assert-assignable
        checks.

    To reduce unnecessary loads on callsites, we store the entrypoint of the
    type testing stubs directly in the type objects.  This means that the
    caller of type testing stubs can simply branch there without populating
    a code object first.  This also means that the type testing stubs
    themselves have no access to a pool and we therefore also don't hold on
    to the [Code] object, only the [Instruction] object is necessary.

    The type testing stubs do not setup a frame themselves and also have no
    safepoint.  In the case when the type testing stubs could not determine
    a positive answer they will tail-call a general-purpose stub.

    The general-purpose stub sets up a stub frame, tries to consult a
    [SubtypeTestCache] and bails out to runtime if this was unsuccessful.

    This CL is just the the first, for ease of reviewing.  The actual
    type-specialized type testing stubs will be generated in later CLs.

    Reviewed-on: https://dart-review.googlesource.com/44787

Relands f226c22424

    [VM] Introduction of type testing stubs - Part 2

    This CL starts building type testing stubs specialzed for [Type] objects
    we test against.

    More specifically, it adds support for:

      * Handling obvious fast cases on the call sites (while still having a
        call to stub for negative case)

      * Handling type tests against type parameters, by loading the value
        of the type parameter on the call sites and invoking it's type testing stub.

      * Specialzed type testing stubs for instantiated types where we can
        do [CidRange]-based subtype-checks.

        ==> e.g. String/List<dynamic>

      * Specialzed type testing stubs for instantiated types where we can
        do [CidRange]-based subclass-checks for the class and
        [CidRange]-based subtype-checks for the type arguments.

        ==> e.g. Widget<State>, where we know [Widget] is only extended and not
                 implemented.

      * Specialzed type testing stubs for certain non-instantiated types where we
        can do [CidRange]-based subclass-checks for the class and
        [CidRange]-based subtype-checks for the instantiated type arguments and
        cid based comparisons for type parameters.  (Note that this fast-case migth
        result in some false-negatives!)

        ==> e.g. _HashMapEntry<K, V>, where we know [_HashMapEntry] is only
                 extended and not implemented.

       This optimizes cases where the caller uses `new HashMap<A, B>()` and only
       uses `A` and `B` as key/values (and not subclasses of it).  The false-negative
       can occur when subtypes of A or B are used.  In such cases we fall back to the
       [SubtypeTestCache]-based imlementation.

    Reviewed-on: https://dart-review.googlesource.com/44788

Relands 25f98bcc75

    [VM] Introduction of type testing stubs - Part 3

    The changes include:

      * Make AssertAssignableInstr no longer have a call-summary, which
        helps methods with several parameter checks by not having to
        re-load/re-initialize type arguments registers

      * Lazily create SubtypeTestCaches: We already go to runtime to warm up
        the caches, so we now also create the caches on the first runtime
        call and patch the pool entries.

      * No longer load the destination name into a register: We only need
        the name when we throw an exception, so it is not on the hot path.
        Instead we let the runtime look at the call site, decoding a pool
        index from the instructions stream.  The destination name will be
        available in the pool, at a consecutive index to the subtype cache.

      * Remove the fall-through to N=1 case for probing subtypeing tests,
        since those will always be handled by the optimized stubs.

      * Do not generate optimized stubs for FutureOr<T> (so far it just
        falled-through to TTS).  We can make optimzed version of that later,
        but it requires special subtyping rules.

      * Local code quality improvement in the type-testing-stubs: Avoid
        extra jump at last case of cid-class-range checks.

    There are still a number of optimization opportunities we can do in
    future changes.

    Reviewed-on: https://dart-review.googlesource.com/46984

Relands 2c52480ec8

    [VM] Introduction of type testing stubs - Part 4

    In order to avoid generating type testing stubs for too many types in
    the system - and thereby potentially cause an increase in code size -
    this change introduces a smarter way to decide for which types we should
    generate optimized type testing stubs.

    The precompiler creates a [TypeUsageInfo] which we use to collect
    information.  More specifically:

       a) We collect the destination types for all type checks we emit
          (we do this inside AssertAssignableInstr::EmitNativeCode).

          -> These are types we might want to generate optimized type testing
             stubs for.

       b) We collect type argument vectors used in instance creations (we do
          this inside AllocateObjectInstr::EmitNativeCode) and keep a set of
          of used type argument vectors for each class.

    After the precompiler has finished compiling normal code we scan the set
    of destination types collected in a) for uninstantiated types (or more
    specifically, type parameter types).

    We then propagate the type argument vectors used on object allocation sites,
    which were collected in b), in order to find out what kind of types are flowing
    into those type parameters.

    This allows us to extend the set of types which we test against, by
    adding the types that flow into type parameters.

    We use this final augmented set of destination types as a "filter" when
    making the decision whether to generate an optimized type testing stub
    for a given type.

    Reviewed-on: https://dart-review.googlesource.com/48640

Issue https://github.com/dart-lang/sdk/issues/32603

Change-Id: I6d33d4ca3d5187a1eb1664078c003061855f0160
Reviewed-on: https://dart-review.googlesource.com/50482
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2018-04-10 12:20:10 +00:00
Martin Kustermann 1e997ee6b7 Revert "Reland "[VM] Introduction of type testing stubs - Part 1-4""
This reverts commit 8054409a02.

Reason for revert: Potential cause of flakes, not entirely clear yet if it was caused by this CL.

Change-Id: Icb119a107f22245ba2f303c7f2ae11f061f605f5
Reviewed-on: https://dart-review.googlesource.com/50261
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2018-04-09 14:29:07 +00:00
Martin Kustermann 8054409a02 Reland "[VM] Introduction of type testing stubs - Part 1-4"
Relands 165c583d57

    [VM] Introduction of type testing stubs - Part 1

    This CL:

      * Adds a field to [RawAbstractType] which will always hold a pointer
        to the entrypoint of a type testing stub

      * Makes this new field be initialized to a default stub whenever a
        instances are created (e.g. via Type::New(), snapshot reader, ...)

      * Makes the clustered snapshotter write a reference to the
        corresponding [RawInstructions] object when writing the field and do
        the reverse when reading it.

      * Makes us call the type testing stub for performing assert-assignable
        checks.

    To reduce unnecessary loads on callsites, we store the entrypoint of the
    type testing stubs directly in the type objects.  This means that the
    caller of type testing stubs can simply branch there without populating
    a code object first.  This also means that the type testing stubs
    themselves have no access to a pool and we therefore also don't hold on
    to the [Code] object, only the [Instruction] object is necessary.

    The type testing stubs do not setup a frame themselves and also have no
    safepoint.  In the case when the type testing stubs could not determine
    a positive answer they will tail-call a general-purpose stub.

    The general-purpose stub sets up a stub frame, tries to consult a
    [SubtypeTestCache] and bails out to runtime if this was unsuccessful.

    This CL is just the the first, for ease of reviewing.  The actual
    type-specialized type testing stubs will be generated in later CLs.

    Reviewed-on: https://dart-review.googlesource.com/44787

Relands f226c22424

    [VM] Introduction of type testing stubs - Part 2

    This CL starts building type testing stubs specialzed for [Type] objects
    we test against.

    More specifically, it adds support for:

      * Handling obvious fast cases on the call sites (while still having a
        call to stub for negative case)

      * Handling type tests against type parameters, by loading the value
        of the type parameter on the call sites and invoking it's type testing stub.

      * Specialzed type testing stubs for instantiated types where we can
        do [CidRange]-based subtype-checks.

        ==> e.g. String/List<dynamic>

      * Specialzed type testing stubs for instantiated types where we can
        do [CidRange]-based subclass-checks for the class and
        [CidRange]-based subtype-checks for the type arguments.

        ==> e.g. Widget<State>, where we know [Widget] is only extended and not
                 implemented.

      * Specialzed type testing stubs for certain non-instantiated types where we
        can do [CidRange]-based subclass-checks for the class and
        [CidRange]-based subtype-checks for the instantiated type arguments and
        cid based comparisons for type parameters.  (Note that this fast-case migth
        result in some false-negatives!)

        ==> e.g. _HashMapEntry<K, V>, where we know [_HashMapEntry] is only
                 extended and not implemented.

       This optimizes cases where the caller uses `new HashMap<A, B>()` and only
       uses `A` and `B` as key/values (and not subclasses of it).  The false-negative
       can occur when subtypes of A or B are used.  In such cases we fall back to the
       [SubtypeTestCache]-based imlementation.

    Reviewed-on: https://dart-review.googlesource.com/44788

Relands 25f98bcc75

    [VM] Introduction of type testing stubs - Part 3

    The changes include:

      * Make AssertAssignableInstr no longer have a call-summary, which
        helps methods with several parameter checks by not having to
        re-load/re-initialize type arguments registers

      * Lazily create SubtypeTestCaches: We already go to runtime to warm up
        the caches, so we now also create the caches on the first runtime
        call and patch the pool entries.

      * No longer load the destination name into a register: We only need
        the name when we throw an exception, so it is not on the hot path.
        Instead we let the runtime look at the call site, decoding a pool
        index from the instructions stream.  The destination name will be
        available in the pool, at a consecutive index to the subtype cache.

      * Remove the fall-through to N=1 case for probing subtypeing tests,
        since those will always be handled by the optimized stubs.

      * Do not generate optimized stubs for FutureOr<T> (so far it just
        falled-through to TTS).  We can make optimzed version of that later,
        but it requires special subtyping rules.

      * Local code quality improvement in the type-testing-stubs: Avoid
        extra jump at last case of cid-class-range checks.

    There are still a number of optimization opportunities we can do in
    future changes.

    Reviewed-on: https://dart-review.googlesource.com/46984

Relands 2c52480ec8

    [VM] Introduction of type testing stubs - Part 4

    In order to avoid generating type testing stubs for too many types in
    the system - and thereby potentially cause an increase in code size -
    this change introduces a smarter way to decide for which types we should
    generate optimized type testing stubs.

    The precompiler creates a [TypeUsageInfo] which we use to collect
    information.  More specifically:

       a) We collect the destination types for all type checks we emit
          (we do this inside AssertAssignableInstr::EmitNativeCode).

          -> These are types we might want to generate optimized type testing
             stubs for.

       b) We collect type argument vectors used in instance creations (we do
          this inside AllocateObjectInstr::EmitNativeCode) and keep a set of
          of used type argument vectors for each class.

    After the precompiler has finished compiling normal code we scan the set
    of destination types collected in a) for uninstantiated types (or more
    specifically, type parameter types).

    We then propagate the type argument vectors used on object allocation sites,
    which were collected in b), in order to find out what kind of types are flowing
    into those type parameters.

    This allows us to extend the set of types which we test against, by
    adding the types that flow into type parameters.

    We use this final augmented set of destination types as a "filter" when
    making the decision whether to generate an optimized type testing stub
    for a given type.

    Reviewed-on: https://dart-review.googlesource.com/48640

Issue https://github.com/dart-lang/sdk/issues/32603

Change-Id: I44a1d5d4b27454ae026aef2a301aada3dd399ea0
Reviewed-on: https://dart-review.googlesource.com/49861
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
2018-04-09 11:25:36 +00:00