Devirtualization optimization now adds metadata to kernel AST instead
of transforming nodes to Direct* ones. The direct call metadata
provides information about checking receiver for null, while
Direct* kernel nodes do not support null checking.
VM's kernel binary loader is extended to extract arbitrary metadata
from kernel binaries and keep it for flow graph builder.
Kernel flow graph builder is extended to take direct call metadata
into account and generate CheckNull/StaticCall instructions
for devirtualized PropertyGet, PropertySet and MethodInvocation nodes.
Issue: https://github.com/dart-lang/sdk/issues/30480
Change-Id: I57f56fbf4a8981d33b1571c0d93105cf8ca71d76
Reviewed-on: https://dart-review.googlesource.com/12260
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
- We no longer erase type parameters of generic non-closures in the body of closures.
- We implement support for captured type parameters in the VM.
Bug:
Change-Id: I4f2f19301df1b44108ab2073332934d5d083e219
Reviewed-on: https://dart-review.googlesource.com/10942
Reviewed-by: Régis Crelier <regis@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
1. We no longer remove type parameters on functions.
2. We no longer remove type arguments at call sites.
3. We allow non-captured function type parameters to be used outside closures.
Bug:
Change-Id: I116ec54c90b04be90e1157042c22797e57a7c51c
Reviewed-on: https://dart-review.googlesource.com/9342
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
This CL changes devirtualization to detect corner case of a method
invocation which is resolved to a getter or a field. This kind of
invocation should call getter first, and then call 'call()' method on
the result of the getter, passing the rest of the arguments.
For simplicity, devirtualization of such method invocations is avoided.
Issue: https://github.com/dart-lang/sdk/issues/30480
Change-Id: Ibe6321931cbb5527a26b139c5f1ee9773a253629
Reviewed-on: https://dart-review.googlesource.com/5902
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Summary:
Common datastructures used by both the Kernel AST definition and the object
model are factored into a shared module. A monad for partial computation is
defined to allow us to factor out termination proofs and syntactic validity
checks from the type checking and subtyping relations.
Test Plan:
Ran through coqc.
Bug:
Change-Id: I884666d7cc5b757d62541a46b868f8579a06f011
Reviewed-on: https://dart-review.googlesource.com/4700
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
This CL adds a new target for kernel front-end, vm_precompiler. This is
an experimental target for new Dart VM precompiler pipeline which
will fully exploit strong mode type system and perform whole-program
optimizations.
As an example of such whole-program optimization, this CL adds
draft implementation of devirtualization of method invocations, which
uses single target computed by closed-world class hierarchy analysis.
Corresponding null checks (required for correctness) are not generated
yet.
Issue: https://github.com/dart-lang/sdk/issues/30480
Change-Id: I704cd16843a08f036a188b1188c80ee4dfbeab3b
Reviewed-on: https://dart-review.googlesource.com/3402
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Summary:
We use a modest set of annotations in ast.dart to describe how the Kernel AST
should be converted into Coq definitions.
We define a Kernel transformation that converts the kernel tree of ast.dart into
a valid Coq file containing the corresponding definitions.
Currently generating the Coq file is not done in the build system because
compiling it requires having Coq installed, and I don't want to introduce a
depedency on Coq into the build system.
Some parts of the AST are not represented because they don't significantly
contribute to the typing semantics:
- asserts
- typedefs
- most literals/basic types (excl. bool, which is needed for "is" tests)
- switch
- for-in
- parts
- yield/await
Test Plan:
Ran the output KernelSyntax.v file through "coqc".
Change-Id: Ic573163a017eaaf3759b741b9eec5ce3ce19225c
Reviewed-on: https://dart-review.googlesource.com/2960
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Summary:
Previously, we would create a wrapper function in the flowgraph around converted
closures, which would forward all the closure's arguments and unpack the context
argument before calling the real closure function.
Now, we perform the unpacking at the top of the real function to avoid having
any wrapper function.
Previously, captured parameters would still be appear live to the GC even if
they're updated, because after they are copied into the context, all updates to
them are done there.
Now, as in regular closures, we zero-out the parameter variable after copying
it's value into the context, avoiding potential memory leaks.
Test Plan:
Ran the closure conversion test suite.
Ran benchmarks on Golem -- all statistically significant regressions are gone.
BUG=
R=dmitryas@google.com, regis@google.com
Review-Url: https://codereview.chromium.org/3008923002 .
Summary:
Previously, we use the "Vector" type in the kernel tree for the result of the
"VectorCreation" operation as as the parameter type for converted closure
functions. In the VM, we use the "Context" type instead, which the VM treats a
little differently than normal Dart-visible types, and it doesn't not handle
type checks against it correctly, breaking all closure converted code running in
checked mode.
Now, Since we are forced to use dynamic to represent the types of elements of
the context, we may as well just use dynamic for the context type itself.
Previously, we did not correct handle converted closure type checks for closures
that capture type parameters. The way we handled these type checks also had
several latent bugs that prevented type parameters being handled properly.
Now, we handle type parameters for converted closures similarly to normal
closures, and the places we treat them specially are fewer and more integrated
with the rest of the closure type checking code.
There is still a problem where assignments to captured variables are not
checked, because they are transformed to assignments into the context, whose
elements are necessarily untyped. This breaks many co19 tests, which expect type
errors on these assignments. The example below should error in checked mode, but
after closure conversion is runs with no errors.
int b;
bool c;
(() { b = c; })()
Test Plan:
- All test cases in "pkg/kernel/testcases/closures" now run in checked mode.
- Added a test "closures_types.dart" to check that captured type parameters are
handled correctly in the converted closures' signature types.
R=dmitryas@google.com
Review-Url: https://codereview.chromium.org/3007623002 .
Summary:
1. Previously, in 'BuildGraphOfConvertedClosureFunction', the VM was unable to
correctly forward parameters to converted closure functions when
they were captured in the converted function's body. This could happen when, for
example, a closure was introduced into it by async conversion.
Now, this is fixed by an approach that mirrors the technique in
'BuildGraphOfFunction'.
2. Previously, local variables declared inside loop bodies were being saved in
the loop's enclosing context, so closures within the loop would see new
values initialized to the variable in subsequent iterations.
Now, this is fixed by creating nested contexts for all loops, regardless of
whether the loop variables are captured.
3. Previously, arity checks were not being performed on converted closures, so
they could be called with too few or too many arguments. In the former case, the
missing arguments would be filled in with garbage on the stack.
Now, the assembly generation in 'CompileGraph' inserts argument count checks
for converted closures as well as regular closures.
Test Plan:
Introduced new tests in the closure conversion suite to test each bug:
1. syncstart.dart
2. loop2.dart, blocks.dart, updated for_in_closure.dart
3. arity.dart
With these changes, closure conversion passes all co19 tests in non-checked mode, except those that are not passed without it:
python tools/test.py -m release -c dartk --vm-options "--reify --reify_generic_functions" co19
BUG=
R=dmitryas@google.com
Review-Url: https://codereview.chromium.org/3000333002 .
Previously, the captured variable analysis did not provide sufficient
information for the conversion phase regarding variable uses in initalizers: in
particular, it did not differentiate the case when a variable is used in an
initializer and captured in the body vs. being captured in the body and not used
in an initializer. In addition, there were a few bugs stemming from the use
of lazy iterables and OR conjunctives with effectful operations.
Now, we separate the information about which variables are captured from flags
indicating whether variables are used in initializers. The other bugs are fixed
in obvious ways.
Finally, we reintroduce some code that ensures that redirecting factory
constructors listed in "_redirecting#" field (a hack used when writing DILL
files) remain with one-expression bodies after closure conversion.
Test Plan:
Added a test case for the initializers bug, ensured that the patched SDK builds
with closure conversion always-on.
Reviewers: dmitryas@google.com
BUG=
R=dmitryas@google.com
Review-Url: https://codereview.chromium.org/2995083002 .
Summary:
Previously, there was no support for generic methods in kernel. This prevented
us from being able to pass captured type arguments to the target top-level
function in converted closures, so these type arguments were always instantiated
to 'dynamic'.
Now, we save the type arguments to the closure creation operation in the
context, and read them out and forward them appropriately in closure wrapper
function. Since fasta doesn't currently support generic methods (their type
parameters are replaced by 'dynamic'), only top-level generic functions can
surface in kernel, as they are generated by closure conversion of closures that
capture type parameters of a class.
My focus here is enabling closure conversion to work in only these cases, and as
such, the code has some temporary "hacks" in the VM that may not work for
generic member functions or generic closures when they are enabled in fasta.
Test Plan:
I ran all the tests in closures/, and those which were previously expected to
crash due to missing VM support now pass and produce correct results.
Further testing is paused until we understand why the recent commit "[kernel]
Insert kernel bodies into VM heap" has broken all these tests.
Reviewers: regis@google.com, jensj@google.com, dmitryas@google.com
BUG=
R=dmitryas@google.com, jensj@google.com
Review-Url: https://codereview.chromium.org/2998803002 .
Summary:
Previously, when a function parameter was captured both in an initializer and in
the body of a constructor, we would create two contexts: one created in a local
initializer and used by other initializers, and another in the body of the
function. This is incorrect, as it means that changes to the parameter in the
initializer's closure won't be visible in the body.
Now, to work around this problem we re-use the context created for the
initializers in the body of the constructor by moving the body into a new
constructor, and redirecting the original constructor to that one, passing the
context as an additional argument. This dance is necessary because local
initializers aren't visible in the body of a constructor.
Test Plan:
A few of the existing closure conversion tests were changed or fixed by this
revision. We also modify the 'closure_in_initializer.dart' test to hit this case
directly.
R=dmitryas@google.com
Reviewers: dmitryas@google.com
Review-Url: https://codereview.chromium.org/2991853002 .
Summary:
Previously, we filled in all occurrences of captured type variables with either
"dynamic" or their bound, if they had one.
Now, we add extra type parameters to the top-level function corresponding to the
closure, and pass in the corresponding arguments as type arguments to the
"MakeClosure" operation.
Test Plan:
Updated [type_variables.dart] and added a new test case to it.
R=dmitryas@google.com
Review-Url: https://codereview.chromium.org/2989563002 .
The closure-conversion transformation is not enabled yet. This commit
only adds the support for it to FlowGraphBuilder and
StreamingFlowGraphBuilder. More work should be done before enabling the
transformation; most mportantly, the 'platform.dill' file that is used
in the Kernel isolate and is loaded by VM for linking with executed
programs should be separated. The former should receive a file not
touched by the transformation, and the latter should receive a
transformed one.
BUG=
R=jensj@google.com, karlklose@google.com, kustermann@google.com
Review-Url: https://codereview.chromium.org/2891053003 .
This review scraps the (currently disabled) code for converting tearoffs in the
closure conversion pass.
The closure conversion pass can only ever do a partial job with tearoffs, due to
the possibility of an unconverted library tearing off a method from any object
it likes. Partially converting [PropertyGet]s makes the closure conversion pass
slower and introduces a new method for any field or method anywhere with a name
used in any [PropertyGet], inflating code size and potentially regressing
performance. As it provides no concrete value in return we've decided to scrap
this aspect of the transformation. Anyway, creating closures for tearoffs is
much easier for a backend than converting anonymous or nested functions, since
there is only one object ("this") captured. Thus ignoring tear-offs does not
undermine the value of the transformation.
BUG=
R=dmitryas@google.com
Review-Url: https://codereview.chromium.org/2986553002 .
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 .
Summary:
Previously, we only handled `FieldInitializer` and `LocalInitializer`.
Now we handle all initializers.
Previously, we would create separate contexts for each initializers, which was
incorrect because it changes made to an argument from a closure within one
initializer would not be seen by a closure within another.
Now, we create the context in a `LocalInitializer` so all initializers will see
the same copy of the argument variables.
There is still an outstanding issue where variables introduced as local
initializers and later captured by closures in subsequent initializers are not
placed into the context. However, this will at least trigger an assert in the closure conversion pass.
Test Plan:
'closures_initializers/initializers.dart(.expect)' has been updated with very
simple test cases for super and redirecting initializers. The second bug
mentioned (captured local initializers) has not been reproduced yet.
BUG=
R=dmitryas@google.com
Review-Url: https://codereview.chromium.org/2981603002 .
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 .
Closure conversion can now be run on a part of a program. It allows
using closure conversion in kernel-isolate. It comes at a cost of
temporarily sacrificing implementation of tear-offs via closures; VM
mechanism for tear-offs is used for now.
R=ahe@google.com
Review-Url: https://codereview.chromium.org/2938773003 .