This CL includes the following fixes:
* Fix for incorrect non-nullable assumption about _Closure._hash field.
* Add error handling into BecomeMapTraits::Hash.
* Correct assertions for validating layout of Closure objects.
* Add identityHashCode to the list of VM entry points in precompiler.
Closes#30211.
Original code review:
https://codereview.chromium.org/2983823002/
Original CL description:
This performance improvement is inspired by Flutter listeners stored in
the HashSet (see ObserverList) and frequently checked using
HashSet.contains(). If there are many such listeners and they are
implicit instance closures (for example, created by
'new Listenable.merge(...)'), HashSet.contains() becomes very slow.
It spends a lot of time in Closure_equals native method due to hash
collisions between closure objects with same function
but different receivers.
This CL improves hashCode() calculation for implicit instance closures
by mixing function hashcode with identity hashcode of the receiver.
For explicit closures and static implicit closures hashCode() is
improved by using identityHashCode() of a closure object.
Also, hashcode is calculated once and cached in each closure instance.
The size of a closure instance doesn't grow up because there was unused
word-size padding both on 32-bit and 64-bit architectures.
The execution time of the following micro-benchmark is reduced from
47665ms to 135ms on my Linux/x64 box.
-------------------------------------
import "dart:collection";
class Foo {
int _a;
Foo(this._a);
void bar() {}
}
main() {
HashSet hs = new HashSet();
for (int i = 0; i < 1000; ++i) {
hs.add(new Foo(i).bar);
}
var watch = new Stopwatch()..start();
for (int i = 0; i < 1000; ++i) {
for (var c in hs) {
hs.contains(c);
}
}
int time = watch.elapsedMilliseconds;
print("Time: ${time}ms\n");
}
-------------------------------------
R=zra@google.com
Review-Url: https://codereview.chromium.org/2988493002 .
This performance improvement is inspired by Flutter listeners stored in
the HashSet (see ObserverList) and frequently checked using
HashSet.contains(). If there are many such listeners and they are
implicit instance closures (for example, created by
'new Listenable.merge(...)'), HashSet.contains() becomes very slow.
It spends a lot of time in Closure_equals native method due to hash
collisions between closure objects with same function
but different receivers.
This CL improves hashCode() calculation for implicit instance closures
by mixing function hashcode with identity hashcode of the receiver.
For explicit closures and static implicit closures hashCode() is
improved by using identityHashCode() of a closure object.
Also, hashcode is calculated once and cached in each closure instance.
The size of a closure instance doesn't grow up because there was unused
word-size padding both on 32-bit and 64-bit architectures.
The execution time of the following micro-benchmark is reduced from
47665ms to 135ms on my Linux/x64 box.
-------------------------------------
import "dart:collection";
class Foo {
int _a;
Foo(this._a);
void bar() {}
}
main() {
HashSet hs = new HashSet();
for (int i = 0; i < 1000; ++i) {
hs.add(new Foo(i).bar);
}
var watch = new Stopwatch()..start();
for (int i = 0; i < 1000; ++i) {
for (var c in hs) {
hs.contains(c);
}
}
int time = watch.elapsedMilliseconds;
print("Time: ${time}ms\n");
}
-------------------------------------
R=rmacnak@google.com, zra@google.com
Review-Url: https://codereview.chromium.org/2983823002 .
This is the 2nd attempt to land the CL
abed3c2a70
Original review: https://codereview.chromium.org/2982823002
No extra changes were made. Large literals in the Dart core library
which caused failures during the previous attempt to land this CL have
been fixed separately.
Description of the CL:
In --limit-ints-to-64-bits mode:
* Integer constructors return Integer::null if integer is out of range.
* Error is reported for integer literals which are out of range.
* Dart API is revised to return errors if integers are out of range.
Bigint::IsDisabled() method is introduced to be able to enable/disable
Bigints independently of --limit-ints-to-64-bits mode in future.
Deprecated constructor Integer::NewFromUint64 is replaced with
Integer::New in certain cases.
R=regis@google.com
Issue: https://github.com/dart-lang/sdk/issues/30103
Review-Url: https://codereview.chromium.org/2980223002 .
Proper sequencing of _asyncStackTraceHelper in Kernel
This helper function was being called before its argument was
initialized so it was passing null. Instead, it should be called
after its argument is initialized.
Because the initialization happens in Kernel code, it is simplest to
insert the call explicitly in Kernel code as well as part of the async
transformation. This has the consequence that we now call the helper
function even when the flag causal_async_stacks is false.
Fixes issue #29771.
Fixes issue #30178
Fixes issue #30058
BUG=
R=aam@google.com, asiva@google.com
Review-Url: https://codereview.chromium.org/2936793003 .
Review-Url: https://codereview.chromium.org/2982943002 .
In --limit-ints-to-64-bits mode:
* Integer constructors return Integer::null if integer is out of range.
* Error is reported for integer literals which are out of range.
* Dart API is revised to return errors if integers are out of range.
Bigint::IsDisabled() method is introduced to be able to enable/disable
Bigints independently of --limit-ints-to-64-bits mode in future.
Deprecated constructor Integer::NewFromUint64 is replaced with
Integer::New in certain cases.
R=zra@google.com
Issue: https://github.com/dart-lang/sdk/issues/30103
Review-Url: https://codereview.chromium.org/2982823002 .
This changeset revises --limit-ints-to-64-bits option to
change range of integers from unlimited to int64.
On overflow, integer arithmetic operations silently wrap around and
discard extra bits. No Bigints are allocated in case of overflow.
This changeset is the 1st part in the series of changes, it revises the implementation of integer arithmetic operations. More changes will follow.
R=regis@google.com, zra@google.com
Issue: https://github.com/dart-lang/sdk/issues/30103
Review-Url: https://codereview.chromium.org/2974633003 .
Array Bounds Check Generalization pass attempts to hoist CheckArrayBound
instructions out of loops by generalizing them: for example in the loop
like
for (var i = 0; i < L; i++) {
// a[i]
CheckArrayBound(i, a.length)
LoadIndexed(a, i)
}
we hoist CheckArrayBound(i, a.length) by turning it into
CheckArrayBound(L - 1, a.length):
CheckArrayBound(L - 1, a.length)
for (var i = 0; i < L; i++) {
// a[i]
LoadIndexed(a, i)
}
However this leads to deoptimizations if the loop never executes: e.g. if
L = 0 then L - 1 is -1 which does not pass generalized bounds check.
We prevent repeated deoptimizations by disabling this optimization if any
of the generalized bounds checks deoptimizes. However this does not work
as intended because we only check this flag on an outermost function, so
if function with a problematic bounds check get inlined into a lot of places
it ends up causing a lot of deoptimizations in different places.
This is why cec963f028 caused performance issues
in dartdoc: _GrowableList._grow is now called with length == 0 whenever we
add an element to an empty list. This causes deoptimization in a lot of different
functions in dartdoc because _GrowableList._grow ends up inlined into a lot
of different places.
Fixes https://github.com/dart-lang/sdk/issues/30090
This CL will be reverted once a better solution for the underlying problem is in place (tracked by https://github.com/dart-lang/sdk/issues/30102)
BUG=
R=askesc@google.com, erikcorry@google.com
Review-Url: https://codereview.chromium.org/2971303002 .
Inline instance object hash code into object header on 64 bit.
64 bit objects have 32 bits of free space in the header word.
This is used for the hash code in string objects. We take it
for the default hash code on all objects that don't override
the hashCode getter.
This is both faster and a memory reduction. Eg it makes the
MegaHashCode part of the Megamorphic benchmark 6 times faster.
This is a reland of https://codereview.chromium.org/2954453002/
which fixes an issue that made script snapshots generated on
64 bit platforms incompatible with 32 bit VMs.
BUG=
R=vegorov@google.com
Review-Url: https://codereview.chromium.org/2965723002 .
Previously these functions would only contain a single CheckStackOverflowInstr
in a backtracking block and that CheckStackOverflowInstr would have a zero
loop_depth - which means it would not be considered eligable for OSR.
This change:
* adds CheckStackOverflowInstr with non-zero loop_depth in two other places
(Boyer-Moore lookahead skip loop and greedy loop) where loops arise in the
generated IL;
* sets non-zero loop depth on the CheckStackOverflowInstr in the backtracking
block;
* adds a flag on CheckStackOverflowInstr that allows optimizing compiler to
optimize away those checks that were inserted solely to serve as OSR entries.
* ensures that IR generated by IRRegExpMacroAssembler is OSR compatible:
* GraphEntryInstr has correct osr_id;
* GraphEntry and normal entry have different block ids (B0 and B1 - instead of B0 and B0);
* unreachable blocks are pruned and GraphEntry is rewired to point to OSR entry;
* IRRegExpMacroAssembler::GrowStack should not assume that stack_array_cell and :stack
are always in sync, because :stack can come from OSR or deoptimization why stack_array_cell
is a constant associated with a particular Code object.
* refactors the way the RegExp stack was growing: instead of having a special instruction
just emit a call to a Dart function;
* refactors the way block pruning for OSR is done by consolidating duplicated code
in a single function.
We allow the optimizing compiler to remove preemption checks from
non-backtracking loops in the regexp code because those loops
unlike backtracking have guaranteed O(input_length) time
complexity.
Performance Implications
------------------------
This change improves performance of regexps in cases where regexp spends a lot
of time in the first invocation (either due to backtracking or due to long non
matching prefix) by allowing VM to optimize the :matcher while :matcher is
running.
For example on regex-redux[1] benchmark it improves Dart performance by 3x
(from ~18s to ~6s on my Mac Book Pro).
CL history
----------
This relands commit d87cc52c3e.
Original code review: https://codereview.chromium.org/2950783003/
[1] https://benchmarksgame.alioth.debian.org/u64q/program.php?test=regexredux&lang=dart&id=2R=erikcorry@google.com
Review-Url: https://codereview.chromium.org/2951053003 .
Inline instance object hash code into object header on 64 bit.
64 bit objects have 32 bits of free space in the header word.
This is used for the hash code in string objects. We take it
for the default hash code on all objects that don't override
the hashCode getter.
This is both faster and a memory reduction. Eg it makes the
MegaHashCode part of the Megamorphic benchmark 6 times faster.
This is a reland of https://codereview.chromium.org/2912863006/
It fixes issues with the 32 bit compare-swap instruction on
ARM64 and fixes a fragile tree shaking test that is sensitive
to which private methods are in the core libraries.
R=kustermann@google.com, vegorov@google.com
BUG=
Review-Url: https://codereview.chromium.org/2954453002 .
I collected statistics for the sizes and capacities of growable arrays which are promoted to old-space or survive an old-space gc when running dart2js and Fasta. For these applications, the vast majority of arrays stay empty. More than half of the total object size of promoted backing arrays is backing for empty growable arrays.
Furthermore, since the overhead for an array is 3 words (header, type parameters and length), and object sizes are rounded up to an even number of words, we waste one word for all even-sized arrays.
This CL changes the growth strategy so that empty growable arrays are created with a shared, zero-sized array as backing, avoiding the allocation of a backing array if no elements are added. When the array needs to grow, it starts out at 3 and grows to double size plus one each time: 7, 15, 31, ...
A few places in the VM code need to handle these shared, zero-sized arrays specially. In particular, the Array::MakeArray function needs to allocate a new, empty array if its result is to be returned to Dart code.
Benchmarks suggest that the change improves memory usage by a few percent overall and does not significantly affect run time.
BUG=
R=erikcorry@google.com
Review-Url: https://codereview.chromium.org/2949803002 .
64 bit objects have 32 bits of free space in the header word.
This is used for the hash code in string objects. We take it
for the default hash code on all objects that don't override
the hashCode getter.
This is both faster and a memory reduction. Eg it shaves about
70% off the running time of this microbenchmark:
List list = [];
class Thing {
get hashCode => 42;
}
class Thing2 {
get hashCode => 42;
}
class Thing3 { }
class Thing4 { }
main() {
int sum = 103;
for (int i = 0; i < 10000000; i++) {
list = [];
list.add("foo");
list.add(123);
list.add(1.23);
list.add(new Object());
list.add(new Thing());
list.add(new Thing2());
list.add(new Thing3());
list.add(new Thing4());
for (int j = 0; j < 2; j++) {
sum ^= biz(list);
}
}
print(sum);
}
int biz(List list) {
int sum = 103;
for (var x in list) {
sum ^= x.hashCode;
}
return sum;
}
R=rmacnak@google.com, vegorov@google.com
BUG=
Review-Url: https://codereview.chromium.org/2912863006 .
Do this in unoptimized code only, when --reify-generic-functions is specified.
This is still work in progress, and support in optimizer, in inliner, in DBC,
in kernel to ir, and other areas, will follow.
Many small fixes and added todos.
R=rmacnak@google.com, vegorov@google.com
Review-Url: https://codereview.chromium.org/2941643002 .
On a switch fall through error, Fasta currently generates
```
throw new core::FallThroughError::•();
```
which generates the error-message via the VM:
```
'null': Switch case fall-through at line null.
```
This introduces a new constructor taking a url and a linenumber,
which then can give a better error message.
BUG=
R=ahe@google.com
Review-Url: https://codereview.chromium.org/2951453002 .
The code in the patch is now inlined into the vmservice library.
This is being done because, the vmservice related libraries are
now compiled directly from source instead of from the "patched_sdk".
So, what is being compiled now does not have the vmservice_patch
applied. By removing the patch, we are removing the need to
artificially patch the vmservice library and making the
vmservice_io.dill complete.
R=rmacnak@google.com
Review-Url: https://codereview.chromium.org/2946773002 .
This helper function was being called before its argument was
initialized so it was passing null. Instead, it should be called
after its argument is initialized.
Because the initialization happens in Kernel code, it is simplest to
insert the call explicitly in Kernel code as well as part of the async
transformation. This has the consequence that we now call the helper
function even when the flag causal_async_stacks is false.
Fixes#29771.
BUG=
R=aam@google.com, asiva@google.com
Review-Url: https://codereview.chromium.org/2936793003 .
This mimics the behaviour of the source-based pipeline,
i.e. instead of "manually" calling _AssertionError._create and giving
the correct parameters (wrong parameters, actually), use the helper
method _AssertionError.ThrowNew.
BUG=
R=ahe@google.com, vegorov@google.com
Review-Url: https://codereview.chromium.org/2940283002 .
- Put pointer to kernel data into Script.
- Replace function.kernel_function pointer to AstNode with
kernel_offset():
- Replace field.kernel_field pointer to AstNode with kernel_offest().
- Stream the previously unstreamed AstNodes: FunctionDeclaration and
FunctionExpression.
- Move special handling for _buildin.getMainClosure into the streaming
flowgraph builder.
- Delete big parts of kernel_to_il.
R=kmillikin@google.com
Review-Url: https://codereview.chromium.org/2901533002 .
Only include OSR and field guards in the features descriptor for JIT code to avoid gen_snapshot and dart having different default values.
Disabled since core snapshots with code break tests with non-default flags for type checks, assertions, strict errors, OSR, or field guards.
R=zra@google.com
Review-Url: https://codereview.chromium.org/2902313004 .
The assertions which tried to assert that we only use
StackFrameIterator to walk frames of the current thread was incorrect.
We already have cases where other threads will walk the stack of the
mutator thread, see below for an example where this can happen.
Thread::VisitObjectPointers was incorrectly passing Thread::Current() to
the StackFrameIterator instead of 'this'. (Code in thread_registry.cc will
loop over a number of threads and calls VisitObjectPointers on them)
Mutator thread:
0 pthread_cond_wait@@GLIBC_2.3.2
1 dart::Monitor::WaitMicros
2 dart::Monitor::Wait
3 dart::MonitorLocker::Wait
4 dart::ThreadBarrier::Sync
5 dart::GCMarker::MarkObjects
6 dart::PageSpace::MarkSweep
7 dart::Heap::CollectOldSpaceGarbage
8 dart::Heap::CollectNewSpaceGarbage
9 dart::Heap::CollectGarbage
10 dart::DN_HelperObject_<native>
11 dart::BootstrapNatives::<native>
<dart frames>
MarkTask thread:
1 dart::EntryFrame::VisitObjectPointers
2 dart::Thread::VisitObjectPointers <---- Walks mutator thread stack
3 dart::ThreadRegistry::VisitObjectPointers <---- Iterates over a number of threads
4 dart::Isolate::VisitStackPointers
5 dart::Isolate::VisitObjectPointers
6 dart::GCMarker::IterateRoots
7 dart::MarkTask::Run
8 dart::ThreadPool::Worker::Loop
9 dart::ThreadPool::Worker::Main
10 dart::ThreadStart
R=rmacnak@google.com
Review-Url: https://codereview.chromium.org/2845053003 .
The VM has a fingerprint on the function and failed during compilation.
Revert "Fix patch errors."
This reverts commit ff1d7488d9.
Revert "Update documentation on trignometric functions."
This reverts commit 40220ec076.
BUG=
Review-Url: https://codereview.chromium.org/2851163003 .