See https://github.com/dart-lang/sdk/issues/53000
Committing separately to the revert of pathContext.fromUri() so if in future that CL is reverted (to re-land the change), it doesn't remove these tests.
Change-Id: I922e5e770a0c8dfcfc6a1cd41f6734d88c2edf7a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315280
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
pathContext.removeUri does not handle escaped colons in drive letters (`Uri.toFilePath()` does), which VS Code currently sends.
Fixes https://github.com/dart-lang/sdk/issues/53000
Change-Id: Ic500404827a51afe3ffb14985df30fc98ba612f0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315260
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Several locations in the core SDK contain `!` or `?.` operations that
will become unnecessary once the language feature `inference-update-2`
(which provides field promotion) is enabled. For example, in this
method from the class `_IOOverridesScope`, `_previous` refers to a
private final field, so after field promotion is enabled, the test `if
(_previous != null)` will promote it, and the `!` in
`_previous!.createDirectory` will become unnecessary:
Directory createDirectory(String path) {
if (_createDirectory != null) return _createDirectory!(path);
if (_previous != null) return _previous!.createDirectory(path);
return super.createDirectory(path);
}
Since the SDK is built in a mode where warnings like this result in
build failures, we need to temporarily change the logic into a form
where the same promotion effect is achieved through local variable
type promotion:
Directory createDirectory(String path) {
if (_createDirectory != null) return _createDirectory!(path);
var previous = _previous;
if (previous != null) return previous.createDirectory(path);
return super.createDirectory(path);
}
(Note that `_createDirectory` doesn't need to change, because it is a
non-final field, so it won't undergo promotion).
After `interface-update-2` has been enabled, I will make a follow-up
CL that removes the local variables and simply takes advantage of
field promotion, e.g.:
Directory createDirectory(String path) {
if (_createDirectory != null) return _createDirectory!(path);
if (_previous != null) return _previous.createDirectory(path);
return super.createDirectory(path);
}
Note: in theory it would be possible to do all this in a single step,
by atomically enabling field promotion and changing the SDK in the
same CL. However, I prefer breaking it up into stages like this,
because the act of flipping a langauge flag on tends to have
wide-ranging consequences, so I want the CL that does the flip to be
as small as possible.
Change-Id: I421c7661348bf407093ee64ef7f9dbfc0c04a353
Bug: https://github.com/dart-lang/language/issues/2020
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314500
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
When using the "mini-ast" pseudo-language to write unit tests for the
flow analysis and type analysis logic in the `_fe_analyzer_shared`
package, it is no longer necessary to use `.switchCase` to turn a
`Pattern` (or a `GuardedPattern`) into a `SwitchHead`; this now
happens automatically. The way this works under the hood is that the
`PossiblyGuardedPattern`, and `SwitchHead` classes implement the
`ProtoSwitchHead` interface; constructs that expect switch heads are
declared with input parameters of type `ProtoSwitchHead`, and they
automatically convert to switch heads when necessary.
Change-Id: Ic16264fc52ffff08bf0e0cc72db064a6da63eda5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315180
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
When using the "mini-ast" pseudo-language to write unit tests for the
flow analysis and type analysis logic in the `_fe_analyzer_shared`
package, it is no longer necessary to use `.asCollectionElement` to
turn an expression into a collection element; this now happens
automatically. The way this works under the hood is that both the
`CollectionElement` and `Expression` classes mix in the
`ProtoCollectionElement` mixin; constructs that expect collection
elements are declared with input parameters of type
`ProtoCollectionElement`, and they automatically convert expressions
to collection elements when necessary.
Also, instead of using `.inContextElementType` to establish the
appropriate context when testing a collection element, the tests not
simply create a `listLiteral` of the appropriate type, containing the
appropriate collection elements. This makes the unit tests much more
similar to the way actual Dart code is written in the wild, and makes
the test infrastructure more closely mirror the way types are analyzed
by the analyzer and CFE.
Change-Id: Ib628ff12caa84254df069308ae3a25061377db29
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314141
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Because it can, and therefore should.
Also update the methods to use `??` more, which should be
safe now that unsound null safety is no longer a thing.
Avoid chains of override-scopes by inlining the parts of the
outer scope which is not overridden.
Fix two bugs:
* `statSync` was checking whether `_stat` was non-`null`, then
calling `_statSync`.
* `socketConncet` did not pass source port to function.
CoreLibraryReviewExempt: Affects only VM.
Change-Id: I9d4971271305c52948d334f69ae71d750587ed97
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314880
Commit-Queue: Lasse Nielsen <lrn@google.com>
Reviewed-by: Brian Quinlan <bquinlan@google.com>
New typed data implementation that optimizes the common cases.
This uses the best possible representation for the fast case with a
representation like:
class _I32List implements Int32List {
final WasmIntArray<WasmI32> _data;
int operator [](int index) {
// range check
return _data.read(index);
}
void operator []=(int index, int value) {
// range check
_data.writeSigned(index, value);
}
...
}
This gives us the best possible runtime performance in the common cases
of:
- The list is used directly.
- The list is used via a view of the same Wasm element type (e.g. a
`Uint32List` view of a `Int32List`) and with aligned byte offset.
All other classes (`ByteBuffer`, `ByteData`, and view classes)
implemented to be able to support this representation.
Summary of classes:
- One list class per Dart typed data list, with the matching Wasm array
as the buffer (as shown in the example above): `_I8List`, `_U8List`,
`_U8ClampedList`, `_I16List`, `_U16List`, ...
- One list class per Dart typed data list, with mismatching Wasm array
as the buffer. These classes are used when a view is created from a
list, and the original list has a Wasm array with different element
type than the view needs. `_SlowI8List`, `_SlowU8List`, ...
These classes use `ByteData` interface to update the buffer.
- One list class for each of the classes listed above, for immutable
views. `_UnmodifiableI32List`, `_UnmodifiableSlowU64List`, ...
These classes inherit from their modifiable list classes and override
update methods using a mixin.
- One `ByteData` class for each Wasm array type: `_I8ByteData`,
`_I16ByteData`,
...
- One immutable `ByteData` view for each `ByteData` class.
- One `ByteBuffer` class for each Wasm array type: `_I8ByteBuffer`,
`_I16ByteBuffer`, ...
- A single `ByteBuffer` class for the immutable view of a byte buffer.
We don't need one immutable `ByteBuffer` view class per Wasm array
type as `ByteBuffer` API does not provide direct access to the buffer.
Other optimizations:
- `setRange` now uses `array.copy` when possible, which causes a huge
performance win in some benchmarks.
- The new implementation is pure Dart and needs no support or special
cases from the compiler other than the Wasm array type support and
intrinsics like `array.copy`. As a result this removes a bunch of
`entry-point` pragmas and significantly reduces code size in some
cases.
Other changes:
- Patch and implementation files for typed data and SIMD types are split
into separate files. `typed_data_patch.dart` and `simd_patch.dart` now
only contains patched factories. Implementation classes are moved to
`typed_data.dart` and `simd.dart` as libraries `dart:_typed_data` and
`dart:_simd`.
Benchmark results:
This CL significantly improves common cases. New implementation is only
slower than the current implementation when a view uses a Wasm array
type with incompatible element type (for example, `Uint32List` created
from a `Uint64List`).
These cases can still be improved by overriding the relevant `ByteData`
methods. For example, in the example of `Uint32List` view of a
`Uint64List`, by overriding `_I64ByteData.getUint32` to do a single read
then requested bytes don't cross element boundaries in the Wasm array.
These optimizations are left as future work.
Some sample benchmarks:
vector_math matrix_bench before:
Binary size: 133,104 bytes.
MatrixMultiply(RunTime): 201 us.
SIMDMatrixMultiply(RunTime): 3,608 us.
VectorTransform(RunTime): 94 us.
SIMDVectorTransform(RunTime): 833 us.
setViewMatrix(RunTime): 506 us.
aabb2Transform(RunTime): 987 us.
aabb2Rotate(RunTime): 721 us.
aabb3Transform(RunTime): 1,710 us.
aabb3Rotate(RunTime): 1,156 us.
Matrix3.determinant(RunTime): 171 us.
Matrix3.transform(Vector3)(RunTime): 8,550 us.
Matrix3.transform(Vector2)(RunTime): 3924 us.
Matrix3.transposeMultiply(RunTime): 201 us.
vector_math matrix_bench after:
Binary size: 135,198 bytes.
MatrixMultiply(RunTime): 42 us.
SIMDMatrixMultiply(RunTime): 2,068 us.
VectorTransform(RunTime): 12 us.
SIMDVectorTransform(RunTime): 272 us.
setViewMatrix(RunTime): 82 us.
aabb2Transform(RunTime): 167 us.
aabb2Rotate(RunTime): 147 us.
aabb3Transform(RunTime): 194 us.
aabb3Rotate(RunTime): 199 us.
Matrix3.determinant(RunTime): 70 us.
Matrix3.transform(Vector3)(RunTime): 726 us.
Matrix3.transform(Vector2)(RunTime): 504 us.
Matrix3.transposeMultiply(RunTime): 53 us.
FluidMotion before:
Binary size: 121,130 bytes.
FluidMotion(RunTime): 270,625 us.
FluidMotion after:
Binary size: 110,674 bytes.
FluidMotion(RunTime): 71,357 us.
With bound checks omitted (not in this CL), FluidMotion becomes
competitive with `dart2js -O4`:
FluidMotion dart2js -O4:
FluidMotion(RunTime): 47,813 us.
FluidMotion this CL + boud checks omitted:
FluidMotion(RunTime): 51,289 us.
Fixes#52710.
Tested: With existing tests.
Change-Id: I33bf5585c3be5d3919a99af857659cf7d9393df0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/312907
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
This reverts commit f827eb3a78.
Reason for revert: The tests being run, and the results being compared to, are changing dramatically, causing all sorts of test results going from [status] -> Skipped and from New Test -> [status].
Something is really going wrong.
Original change's description:
> Balance tests equally across shards.
>
> The sharded test runner invocations are now passed the previous results
> which contains the test timing, which are used to simulate how long each
> shard would take to run. The shards are now balanced as evenly as
> possible on a test level, taking multiple cores into account.
>
> Sharded tests are now run starting with the slowest test first, such
> that extremely long running tests finish as early as possible. This
> behavior ensures the cores are saturated and can be padded with fast
> tests near the end, rather than waiting for a few slow tests to complete
> while the rest of the system is idle.
>
> The algorithm works very well whenever it's able to accurately predict
> the time to run shards. In a number of cases, the model doesn't quite
> reflect reality and the data, which makes it fairly imperfect but still
> reasonably good. I think a second order feedback loop might kick in once
> it reorders the tests across shards and the test timing data reflects
> the new test timings.
>
> Multitests are no longer always sent to the same shard, since the data
> isn't available at the moment, and the change as-is speeds up the test
> running considerably.
>
> The front end unit test suites currently ignore the feature as there are
> no benefits yet to improving those quick shards.
>
> Upgrade the language version to 3.0.0 so patterns can be used and fix
> a mixin not being a mixin.
>
> Fixes: b/291585137
> Change-Id: I3cc1b1d96038d5b46e836b091e299097717c226c
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314081
> Reviewed-by: William Hesse <whesse@google.com>
> Commit-Queue: Jonas Termansen <sortie@google.com>
Change-Id: I233e4bfa6d6ecf0cea4f97c1e47f1635f7b9040c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315060
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: William Hesse <whesse@google.com>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Retrieval of local names only works in JIT as it relies on availability of LocalVarDescriptors.
For example, for this
```
import 'dart:isolate';
foo() {
final x = RawReceivePort();
RawReceivePort().sendPort.send(() => print("$x"));
}
main() {
foo();
}
```
error message says
```
Unhandled exception:
Invalid argument(s): Illegal argument in isolate message: (object is a ReceivePort)
<- field x in foo.<anonymous closure> (from file:///usr/local/google/home/aam/p/d/dart-sdk1/sdk/s1.dart)
```
Bug: https://github.com/dart-lang/sdk/issues/52957
TEST=ci
Change-Id: I684014fd19ea82829e7df17a8a67d386551a5a82
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314501
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
The tests `variable_property_not_promoted_test` and
`this_property_not_promoted_test` verify that fields are _not_
promoted. To prevent them from failing when we enable the language
feature `inference-update-2` (which provides field promotion), they
need `@dart=3.0` directives. This ensures that we will continue to
have coverage of the old (non-promoting) behavior after field
promotion is switched on.
Bug: https://github.com/dart-lang/language/issues/2020
Change-Id: I376da01dfe4223f17ae4863e4460b4f1a0708dc6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314760
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This is already skipped for AOT and is unfixable after the DropTransitiveUserDefinedConstants optimizations.
This is already skipped for reload and is unfixable for issues related to 40442.
The non-reload JIT case isn't very interesting since each kernel constant will be loaded only once anyway.
TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/27003
Bug: https://github.com/dart-lang/sdk/issues/44862
Change-Id: I0676a96426142600f4ed9ec638b344a858aab7dd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314480
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Now that we no longer need to put boxes in `core.dart`, it makes sense to move them out of `core.dart` so that we can patch these classes and their helper functions. This CL moves `BoxedInt` and `BoxedDouble` out of core patch, and moves some of their intrinsics / helpers to side libraries.
Tested: Dart2Wasm internal refactor of patch files.
Change-Id: I1dac95089a8bd9e2c8ee4f467a0d6f2792f9d665
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313900
Commit-Queue: Joshua Litt <joshualitt@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Note, that resolving against implicit 'this' is not implemented yet.
The instance scope is not correct yet.
Change-Id: I71ea51f82c5fa0a19ea77593df19be29189782fd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314580
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
regress_45684_test.dart makes use of the debugger, which isn't supported
in AOT.
TEST=N/A
Change-Id: I454aa92d1ce33638380e6fd02654dc5f925c2bf1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314820
Reviewed-by: Dan Chevalier <danchevalier@google.com>
- Rename declarationOf to typeDeclarationOf.
- Add declarationOf api for general declarations.
- Tighten the type of typeDeclarationOf in the final phase to avoid unnecessary
casts in user code.
- Refactor message handling a bit to unify the error handling.
Bug: https://github.com/dart-lang/language/issues/3216
Change-Id: Ia61da19374abec77853d37e110a08f7dfe0d3b10
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314280
Commit-Queue: Jake Macdonald <jakemac@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
The sharded test runner invocations are now passed the previous results
which contains the test timing, which are used to simulate how long each
shard would take to run. The shards are now balanced as evenly as
possible on a test level, taking multiple cores into account.
Sharded tests are now run starting with the slowest test first, such
that extremely long running tests finish as early as possible. This
behavior ensures the cores are saturated and can be padded with fast
tests near the end, rather than waiting for a few slow tests to complete
while the rest of the system is idle.
The algorithm works very well whenever it's able to accurately predict
the time to run shards. In a number of cases, the model doesn't quite
reflect reality and the data, which makes it fairly imperfect but still
reasonably good. I think a second order feedback loop might kick in once
it reorders the tests across shards and the test timing data reflects
the new test timings.
Multitests are no longer always sent to the same shard, since the data
isn't available at the moment, and the change as-is speeds up the test
running considerably.
The front end unit test suites currently ignore the feature as there are
no benefits yet to improving those quick shards.
Upgrade the language version to 3.0.0 so patterns can be used and fix
a mixin not being a mixin.
Fixes: b/291585137
Change-Id: I3cc1b1d96038d5b46e836b091e299097717c226c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314081
Reviewed-by: William Hesse <whesse@google.com>
Commit-Queue: Jonas Termansen <sortie@google.com>
It is not necessary for `InferenceVisitorImpl.visitPropertyGet` to
call `FlowAnalysis.propertyGet` directly, because it already calls
`_computePropertyGet`, which calls `FlowAnalysis.propertyGet`.
Change-Id: I806337ff24bc237ef0e2a42af7357a70d6df7f4f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313901
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This change replaces the CFE logic for deciding which fields are
promotable, so that it now makes use of the shared infrastructure in
`pkg/_fe_analyzer_shared`.
Since the shared logic doesn't depend on the CFE having already
computed `noSuchMethod` forwarders, it can be placed earlier in the
compilation pipeline, before top level type inference. As a result,
field promotion during top level type inference now works properly.
Fixes https://github.com/dart-lang/sdk/issues/50522.
Change-Id: I451aa112a0af114a9c88dd64ebb8f199f6f6589e
Bug: https://github.com/dart-lang/sdk/issues/50522
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313860
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Added a new line to _writeGlossary before the contents, because otherwise it was generating in the line directly below the contents of _writeHeader, and therefore not rendering properly. I also updated the link to [Customizing static analysis] as that changed recently and I've had to manually update it in the site-www doc version a couple times now.
Change-Id: I8c5d3d9adcc0004fc8d84d11935860617e7c2bfd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314520
Commit-Queue: Marya Belanger <mbelanger@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
In the new type system, allow native types that have a "peer" on
the Dart side to use that Dart type as their reified type.
This matches the semantics of the old type system for these types.
Change-Id: I62bf6cb1654d33549a6ea2c757e7e65fa81677a4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313700
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
The purpose of the wasm_js_compatibility target is to facilitate experiments with a JS compatibility mode for Dart2Wasm. Initially, we're just going to focus on typed data, but this will give us a place to experiment with moving List and String to JS as well.
In addition, someday down the road we hope to experiment with two additional compatibility changes:
1) Exclusively using double for all Dart numbers
2) Allowing undefined to flow as null.
The two major benefits of this approach are:
1) Much faster JS interop
2) To make it easier to bring up Dart2JS applications on Dart2Wasm
The only downside will be access overhead on the Wasm side, but the JS builtins proposal could potentially bring us close to parity with Wasm builtins someday.
Tested: Wasm specific trivial refactor.
Change-Id: I2c09426b6999507c1de6e584e9bc7072a088bda9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313240
Commit-Queue: Joshua Litt <joshualitt@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: William Hesse <whesse@google.com>
The underlying storage is only intptr_t.
TEST=ci
Change-Id: Ibb687707eb4935d71080193e55ec4366c5b9c8e0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314320
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
In the following code, it's not safe for the field `C._f` to undergo
type promotion, because a variable with static type `C` might have
type `D` at runtime, in which case `C._f` will get dispatched to
`noSuchMethod`, which is not guaranteed to return a stable result.
class C {
final int? _f;
}
class D implements C {
noSuchMethod(_) => ...;
}
foo(C c) {
if (c._f != null) {
print(c._f + 1); // UNSAFE!
}
}
Therefore, in order to determine which fields are promotable, the
implementations need to analyze enough of the class hierarchy to
figure out which field accesses might get dispatched to
`noSuchMethod`.
Currently, the CFE does this by following its usual algorithm for
generating `noSuchMethod` forwarders before trying to determine which
fields are promotable. The analyzer, on the other hand, doesn't have
an algorithm for generating `noSuchMethod` forwarders (since it
doesn't implement execution semantics); so instead it has its own
logic to figure out when a `noSuchMethod` forwarder is needed for a
field, and disable promotion for that field.
But there's a chicken-and-egg problem in the CFE: the CFE needs to
determine which fields are promotable before doing top-level inference
(since the initializers of top-level fields might make use of field
promotion, affecting their inferred types--see #50522). But it doesn't
decide where `noSuchMethod` forwarders are needed until after
top-level inference (because the same phase that generates
`noSuchMethod` forwarders also generates forwarders that do runtime
covariant type-checking, and so it has to run after all top level
types have been inferred).
To fix the chicken-and-egg problem, I plan to rework the CFE so that
it uses the same algorithm as the analyzer to determine which fields
are promotable. This CL makes a first step towards that goal, by
reworking the analyzer's field promotability algorithm into a form
where it can be shared with the CFE, and moving it to
`package:_fe_analyzer_shared`. Since this required a fairly
substantial rewrite, I went ahead and fixed#52938 in the process.
Fixes#52938.
Change-Id: I9e68f51b3ea9a967f55f15bdc445cc1c0efdabdd
Bug: https://github.com/dart-lang/sdk/issues/52938
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313293
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>