Instead of implicitly creating closures for FFI
asFunction/lookupFunction APIs in the VM, now they are explicitly expressed in the kernel AST. That makes it possible to analyze
them in TFA.
FFI calls from Dart code into native are now performed in the following way:
```
block {
Pointer #ffiTarget0 = target;
@pragma('vm:ffi:call-closure', _FfiCall<Int32 Function(Int32)>(isLeaf: false))
#ffiClosure0(int arg1) {
_nativeEffect(arg1);
return _ffiCall<int>(#ffiTarget0);
}
} =>#ffiClosure0;
```
_ffiCall method is recognized by the VM and its call is replaced
directly with FFI calling sequence. _ffiCall uses closure
parameters implicitly. No extra trampolines are generated for FFI calls.
TEST=existing
Fixes https://github.com/dart-lang/sdk/issues/54172
Issue https://github.com/dart-lang/sdk/issues/39692
CoreLibraryReviewExempt: Implementation change only.
Change-Id: I92b3ff7391470686151ad0807e2cdbbf1a69d256
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/339662
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
This adds the `Native.addressOf` function, which takes a constant tear-
off of a method annotated with `@Native` as a parameter and returns a
pointer to the underlying C function.
The CFE will resolve these calls in two steps: First, the existing
transformer for `@Native` methods adds a pragma describing the fully-
resolved native annotation (with the asset id inferred from the library
if not given explicitly). Then, the FFI use sites transformer rewrites
calls to `Native.addressOf` by searching for this pragma on the passed
function and passing the `Native` constants to `Native._addressOf`. The
latter method is implemented in the VM, which can re-use existing parts
already used for `@Native` calls.
An alternative implementation strategy would have been to forward
`addressOf` calls to `Native.ffi_resolver_function` directly without
any special consideration in the VM. However, the chosen approach makes
it easier to support static linking in the future, as this requires
unresolved symbols in the generated assembly.
Closes https://github.com/dart-lang/sdk/issues/50552
TEST=pkg/vm/testcases/transformations/ffi/ffinative.dart
TEST=tests/ffi/native_assets/asset_*_test.dart
TEST=tests/ffi/vmspecific_static_checks_ffinative_test.dart
TEST=pkg/analyzer/test/src/diagnostics/ffi_native_test.dart
Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-kernel-precomp-linux-release-x64-try
CoreLibraryReviewExempt: VM & dart2wasm only feature
Change-Id: Ic8e3a390146dffd44c95578f975a4472db79a0ee
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333920
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Original change in patchset 1.
The reland contains a fix for handles. The objects passed in handles
must live on the stack (or in the heap) so that that memory location
can be used as a handle.
This CL introduces a new allocation policy `RequiresRegister` which
forces constants to be spilled to the stack during register
allocation.
Note: Parameters to FfiCall instructions are currently not used in a
way that can make the parameters assigned to registers. So only
constants are treated currently. If we have a way to reproduce params
being assigned to registers, then we can force spilling for
non-consts as well in the register allocator.
Original change's description:
> [vm/ffi] Optimize `@Native` calls
>
> This CL removes static fields for storing the `@Native`'s function
> addresses. Instead, the function addresses are stored in the object
> pool for all archs except for ia32. ia32 has no AOT and no AppJit
> snapshots, so the addresses are directly embedded in the code.
>
> This CL removes the closure wrapping for `@Native`s. Instead of
> `pointer.asFunctionInternal()()` where `asFunction` returns a closure
> which contains the trampoline, the function is compiled to a body
> which contains the trampoline `Native()`. This is possible for
> `@Native`s because the dylib and symbol names are known statically.
>
> Doing the compilation in kernel_to_il instead of a CFE transform
> enables supporting static linking later. (The alternative would have
> been to transform in the cfe to a `@pragma('vm:cachable-idempotent')`
> instead of constructing the IL in kernel_to_il.
>
> To enable running resolution in ia32 in kernel_to_il.cc, the
> resolution function has been made available via
> `runtime/lib/ffi_dynamic_library.h`.
>
> Because the new calls are simply static calls, the TFA can figure
> out const arguments flowing to these calls. This leads to constant
> locations in the parameters to FfiCalls. So, this CL also introduces
> logic to move constants into `NativeLocation`s.
TEST=tests/ffi/vmspecific_ffi_native_handles_test.dart
TEST=tests/ffi/function_*_native_(leaf_)test.dart
TEST=pkg/vm/testcases/transformations/ffi/ffinative_compound_return.dart
Closes: https://github.com/dart-lang/sdk/issues/47625
CoreLibraryReviewExempt: Internal FFI implementation changes
Change-Id: Ia1401b335524dcbf50c663a8770d9a02802923df
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333841
Reviewed-by: Slava Egorov <vegorov@google.com>
This reverts commit e16bb210d2.
Reason for revert: Indication this caused engine test
failures of the kind:
```
[0;32m[ RUN ] [mEmbedderA11yTest.A11yTreeIsConsistentUsingV1Callbacks
../../flutter/shell/platform/embedder/tests/embedder_a11y_unittests.cc:639: Failure
Expected equality of these values:
std::strncmp(kTooltip, node->tooltip, sizeof(kTooltip) - 1)
Which is: 116
0
```
Original change's description:
> [vm/ffi] Optimize `@Native` calls
>
> This CL removes static fields for storing the `@Native`'s function
> addresses. Instead, the function addresses are stored in the object
> pool for all archs except for ia32. ia32 has no AOT and no AppJit
> snapshots, so the addresses are directly embedded in the code.
>
> This CL removes the closure wrapping for `@Native`s. Instead of
> `pointer.asFunctionInternal()()` where `asFunction` returns a closure
> which contains the trampoline, the function is compiled to a body
> which contains the trampoline `Native()`. This is possible for
> `@Native`s because the dylib and symbol names are known statically.
>
> Doing the compilation in kernel_to_il instead of a CFE transform
> enables supporting static linking later. (The alternative would have
> been to transform in the cfe to a `@pragma('vm:cachable-idempotent')`
> instead of constructing the IL in kernel_to_il.
>
> To enable running resolution in ia32 in kernel_to_il.cc, the
> resolution function has been made available via
> `runtime/lib/ffi_dynamic_library.h`.
>
> Because the new calls are simply static calls, the TFA can figure
> out const arguments flowing to these calls. This leads to constant
> locations in the parameters to FfiCalls. So, this CL also introduces
> logic to move constants into `NativeLocation`s.
>
> TEST=runtime/vm/compiler/backend/il_test.cc
> TEST=tests/ffi/function_*_native_(leaf_)test.dart
> TEST=pkg/vm/testcases/transformations/ffi/ffinative_compound_return.dart
>
> Closes: https://github.com/dart-lang/sdk/issues/47625
> Closes: https://github.com/dart-lang/sdk/issues/51618
> Change-Id: Ic5d017005dedcedea40c455c4d24dbe774f91603
> CoreLibraryReviewExempt: Internal FFI implementation changes
> Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284300
> Commit-Queue: Daco Harkes <dacoharkes@google.com>
> Reviewed-by: Alexander Markov <alexmarkov@google.com>
> Reviewed-by: Martin Kustermann <kustermann@google.com>
Change-Id: Icc87a6ca33bffecabb15c6b168a06ccc38c2fe5b
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333840
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This CL removes static fields for storing the `@Native`'s function
addresses. Instead, the function addresses are stored in the object
pool for all archs except for ia32. ia32 has no AOT and no AppJit
snapshots, so the addresses are directly embedded in the code.
This CL removes the closure wrapping for `@Native`s. Instead of
`pointer.asFunctionInternal()()` where `asFunction` returns a closure
which contains the trampoline, the function is compiled to a body
which contains the trampoline `Native()`. This is possible for
`@Native`s because the dylib and symbol names are known statically.
Doing the compilation in kernel_to_il instead of a CFE transform
enables supporting static linking later. (The alternative would have
been to transform in the cfe to a `@pragma('vm:cachable-idempotent')`
instead of constructing the IL in kernel_to_il.
To enable running resolution in ia32 in kernel_to_il.cc, the
resolution function has been made available via
`runtime/lib/ffi_dynamic_library.h`.
Because the new calls are simply static calls, the TFA can figure
out const arguments flowing to these calls. This leads to constant
locations in the parameters to FfiCalls. So, this CL also introduces
logic to move constants into `NativeLocation`s.
TEST=runtime/vm/compiler/backend/il_test.cc
TEST=tests/ffi/function_*_native_(leaf_)test.dart
TEST=pkg/vm/testcases/transformations/ffi/ffinative_compound_return.dart
Closes: https://github.com/dart-lang/sdk/issues/47625
Closes: https://github.com/dart-lang/sdk/issues/51618
Change-Id: Ic5d017005dedcedea40c455c4d24dbe774f91603
CoreLibraryReviewExempt: Internal FFI implementation changes
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284300
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Expressions missing offsets were:
- LogicalExpression
- ConditionalExpression
- Not
- BlockExpression
- Instantiation
- TypedefTearOff*
* I'm not sure how TypedefTearOff is actually being used, I don't see reference to it in the VM runtime. Unless the CFE lowers it before the VM gets it.
I also added a test on `binary.md` that ensures all expressions include a file offset in their serialized format. This can be expanded to statements if offsets are added to the remaining statement nodes without offsets.
TEST=Added binary_md_git_test.dart to ensure all expressions contain offset data going forward.
Change-Id: Ieaf80545f388b209f76be44db86ef07e80c8ad66
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/331540
Reviewed-by: Jens Johansen <jensj@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
Adds a `CachableIdempotentCallInstr` that can be invoked via
`@pragma('vm:cachable-idempotent')` if the call-sites is force
optimized.
The object pool is not visited by the scavenger. So, we store the
results as unboxed integers. Consequently, only dart functions that
return integers can be cached.
Cachable idempotent calls should never be inlined. After the first
call the function not be called again.
The call itself is on a slow path to avoid register spilling on the
fast path.
TEST=vm/cc/IRTest_CachableIdempotentCall
TEST=runtime/tests/vm/dart/cachable_idempotent_test.dart
Bug: https://github.com/dart-lang/sdk/issues/51618
Change-Id: I612e896f27add76f57796c060157e14cc687a0fd
Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-asan-linux-release-x64-try,vm-aot-linux-debug-simarm_x64-try,vm-aot-linux-debug-simriscv64-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-msan-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-tsan-linux-release-x64-try,vm-aot-ubsan-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-simriscv64-try,vm-linux-debug-x64-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-tsan-linux-release-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/301601
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Dart2JS uses the file offset on these nodes to create JS source maps. We want to maintain these file offsets across the serialization layer when we compile from dill files rather than directly from sources.
This last CL resolves all diffs observed in test files in pkg/compiler/test/inference/data.
TEST=Updating tests for all of these in fasta offsets tests.
Change-Id: If84c7542b61c8d8b894b202c68841ccfe91dafa5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/328080
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Dart2JS uses the file offset on these nodes to create JS source maps. We want to maintain these file offsets across the serialization layer when we compile from dill files rather than directly from sources.
Dart2JS tests were serializing via `--test-mode` flag and thus had incorrect source locations for some stack traces.
TEST=Updating tests for all of these in fasta offsets tests.
Change-Id: I33862462fbff84d88f8c51bdeb1efc5771cfb8b2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327160
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
FunctionTearOff node represents a tear-off of the 'call' method of
a Function, so it is basically a no-op:
FunctionTearOff(receiver) == receiver
So we can remove this node early, during lowering transformation on
kernel AST and clean up handling of FunctionTearOff nodes from the VM
and dart2wasm compilation pipelines.
TEST=ci
Change-Id: Ia1500a066a0261076162e018ff0ab502258f606f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325924
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
We are experiencing diffs in Dart2JS source maps in `--test-mode` which does a serialization round trip. JS that should map to default parameters is instead mapping to the surrounding `Constructor` member since the FieldInitializer's offset is getting dropped.
This is affecting any Dart2JS split action build since those all end of serialiaing and deserializing the kernel. Any other tools using this serialization would also be affected.
TEST=Existing/will add in follow up.
Bug: https://github.com/dart-lang/sdk/issues/53466
Change-Id: Ibeccf9153c78e6c358806c7ded4dbc2dea49d8e6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325020
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This change is almost trivial. The closure is stored on the callback's
RawReceivePort, not in the VM. So we can basically just remove the CFE
check and it pretty much works. The only problem is that we can't set
function.FfiCallbackTarget anymore, so most of the CL is dealing with
that.
A few places were deciding whether an FFI trampoline was a call or a
callback based on whether function.FfiCallbackTarget() was null. But
now the target will be null for async callbacks. So instead I've added
a new value to the FfiCallbackKind enum (and renamed it), and changed
those checks.
Sync callback closures will be a separate CL, because they're more
complicated.
Bug: https://github.com/dart-lang/sdk/issues/52689
Change-Id: I8e5dfb557362e679f66195b735c3c382e6792840
TEST=async_void_function_callbacks_test.dart
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/316160
Commit-Queue: Liam Appelbe <liama@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
a) Remove 2 fields in our object representation:
* PatchClass::library_data_
* Library::kernel_data_
=> This saves O(#libraries + #patch-classes) which can amount up to
10+ MB for big apps, as we save not just the slots but the
[ExternalTypedData] objects they used to reference.
Instead we'll compute the KernelLibraryData when we need it by making a
[TypedDataView] of sub parts of the component.
b) We make a kernel binary be represented by a single [ExternalTypedData].
Whenever we need a sub-part of a kernel binary (e.g. one for each
component for concatinated kernels, or one for a library inside a
component) we use proper [TypedDataView]s for that.
c) As we sometimes need to create a view of only a particular library
within a component we need to find start/end of a library based on
index.
=> We store the library index instead of the library offset on
Library/PatchClass.
=> We can easily derive the start/end of a library from it's index by
looking at the kernel component encoding.
d) We make the [Reader] object work purely based on a pointer - instead
of making it have if/else when reading bytes (either from pointer or
from a view).
e) We make the [KernelProgramInfo] store the kernel_component and
various TD views into it.
TEST=ci
Change-Id: Ibe160881ff48635e834c3d647a977a144b5d0565
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313561
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
** KernelProgramInfo
The VM can load multiple kernel files into an isolate. Each kernel file
is represented as a [KernelProgramInfo] object. Loading a kernel blob
will result in a tree of objects
Library
- TopLevelClass
+ Field
+ Function
+ Class
+ Field
+ Function
+ ... closure functions ...
The entire tree belongs to one [KernelProgramInfo] object. There are
two exceptions
* after a hot-reload we inject [PatchClass]es (as owners of
old [Field]/[Function] objects) that identify the old kernel data
* expression evaluation functions will get a special data array with
information about the expression evaluation kernel data
=> We attach the [KernelProgramInfo] to the root of the tree, namely
the [Library]
=> We introduce `{Field,Function,Class,Library}::KernelProgramInfo()`
that will get that object - by walking up the chain.
=> We introduce `UntaggedPatchClass::kernel_program_info_` field that
allows saving the old [KernelProgramInfo] (on which the old
[Field]/[Function] objects are based upon) in the [PatchClass].
=> We include the [KernelProgramInfo] in the expression evaluation
data array.
** Scripts
A [Script] object should represent a .dart source file. It contains the
source, line offsets, etc. of that dart source file. The contents of a
dart source file may be used by many classes/libraries or even many
kernel blobs (e.g. via our copying mixin application).
When we build a tree like above, we'll attach a reference to a
[Script] object to [Class] objects. But members of a class may come from
a different script, in which case we inject an intermediary [PatchClass]
that references that other script.
When the compiler frontend loads kernel, builds flow graph, etc we walk
down the kernel binary (the tree above) - all belonging to the same
[KernelProgramInfo] object, but sub-parts may belong to different
[Script]s.
=> We use the existing [ActiveClass] class that keeps track of the
current class & member inside the class we're operating on.
=> Whenever we need the script we get it from the active member
function/class.
** Misc
We make kernel related classes (e.g. [KernelReaderHelper]) independent
of [Script].
We make the [Script] objects hold on to the [KernelProgramInfo] they are
based upon (e.g. for lazy source reading). But since a given [Script]
doesn't belong to a particular kernel blob (multiple kernel blobs may
contain information about the same script) we don't expose this in the
public API.
=> In the future we could have a unique [Script] object per url (instead
of having several as we do now)
TEST=ci
Change-Id: I7bd698f497b0bd8ab8e546540bb1dad5b5a6dd48
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313381
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
The main contribution of this CL is unification of disparate
handling of various functions like `Future.timeout`,
`Future.wait`, `_SuspendState.createAsyncCallbacks` and
`_SuspendState._createAsyncStarCallback` into a single
`@pragma('vm:awaiter-link')` which allows Dart developers
to specify where awaiter unwinder should look for the next
awaiter.
For example this allows unwinding to succeed for the code like this:
Future<int> outer(Future<int> inner) {
@pragma('vm:awaiter-link')
final completer = Completer<int>();
inner.then((v) => completer.complete(v));
return completer.future;
}
This refactoring also ensures that we preserve information
(including Function & Code objects) required for awaiter
unwinding across all modes (JIT, AOT and AOT with DWARF stack
traces). This guarantees users will get the same information
no matter which mode they are running in. Previously
we have been disabling awaiter_stacks tests in some AOT
modes - which led to regressions in the quality of produced
stacks.
This CL also cleans up relationship between debugger and awaiter
stack returned by StackTrace.current - which makes stack trace
displayed by debugger (used for stepping out and determinining
whether exception is caught or not) and `StackTrace.current`
consistent.
Finally we make one user visible change to the stack trace:
awaiter stack will no always include intermediate listeners
created through `Future.then`. Previously we would sometimes
include these listeners at the tail of the stack trace,
which was inconsistent.
Ultimately this means that code like this:
Future<int> inner() async {
await null; // asynchronous gap
print(StackTrace.current); // (*)
return 0;
}
Future<int> outer() async {
int process(int v) {
return v + 1;
}
return await inner().then(process);
}
void main() async {
await outer();
}
Produces stack trace like this:
inner
<asynchronous suspension>
outer.process
<asynchronous suspension>
outer
<asynchronous suspension>
main
<asynchronous suspension>
And when stepping out of `inner` execution will stop at `outer.process`
first and the next step out will bring execution to `outer` next.
Fixes https://github.com/dart-lang/sdk/issues/52797
Fixes https://github.com/dart-lang/sdk/issues/52203
Issue https://github.com/dart-lang/sdk/issues/47985
TEST=ci
Bug: b/279929839
CoreLibraryReviewExempt: CL just adds @pragma to facilitate unwinding
Cq-Include-Trybots: luci.dart.try:vm-aot-linux-product-x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-dwarf-linux-product-x64-try
Change-Id: If377d5329d6a11c86effb9369dc603a7ae616fe7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/311680
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
The [PatchClass] no longer needs to refer to a original [Class] and a
patched [Class] objects: Since the CFE does handling of patches the VM
only has a single [Class] object, so those two fields are always the
same.
=> Change `PatchClass::{origin_class,patched_class} -> `PatchClass::wrapped_class`
We also remove the `Field::Origin()` / `Function::origin()` methods
as they return the same as the `Owner()` would return.
TEST=ci
Change-Id: Iec0849f6ffc2026760dad89a9bcf07e9469bc8b6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/311840
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This adds FileUriConstantExpression, a subclass of ConstantExpression, to support correct file offset of annotations for augmentations and patches.
The FileUriExpression is used to carry the file uri of the expression
before constant evaluation.
TEST=general/patch_annotations
Change-Id: I0dc8a0cb97dd530fd1960785d38c2d5e4883c3dd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/311660
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Previously, inliner was able to inline closure calls only when closure
was allocated in the current function (or in a function which was
inlined so far). This is not true for local functions declared in outer
functions (they are allocated at declaration site).
Now, when calling local functions, target of closure call is always
known regardless of where the function is declared, so calls to local
functions can be inlined.
TEST=runtime/tests/vm/dart/inline_local_functions_il_test.dart
Fixes https://github.com/dart-lang/sdk/issues/52695
Fixes https://github.com/dart-lang/sdk/issues/15558
Change-Id: I0e51dbaf63a6d4427bff366b40414ca5fac3d418
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/311465
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This is a reland of commit 43ce5487c1
In addition to removing type check, switch range checks are adjusted
in order to avoid call to 'int.operator<=', which can be removed by
tree shaker in AOT/product mode, causing NoSuchMethodError at runtime.
Original change's description:
> [vm/compiler] Remove unnecessary type check from optimized switches
>
> Switch optimization now relies on static type of the tested value,
> so it is safe to omit the type check (with sound null safety) or
> reduce it to a null check (without sound null safety).
>
> TEST=co19/LanguageFeatures/Patterns/Exhaustiveness/exhaustiveness_enum_A01_t01
> Fixes https://github.com/dart-lang/sdk/issues/52422
>
> Change-Id: Ic93f4f212bee9ed3bfe5035f3c8d7535274c2f63
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/304102
> Commit-Queue: Alexander Markov <alexmarkov@google.com>
> Reviewed-by: Alexander Aprelev <aam@google.com>
TEST=co19/LanguageFeatures/Patterns/Exhaustiveness/exhaustiveness_enum_A01_t01
TEST=language/async/switch_test
Change-Id: I70bf480bf376f946d66caa504120c8f85093ea8d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/304322
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Switch optimization now relies on static type of the tested value,
so it is safe to omit the type check (with sound null safety) or
reduce it to a null check (without sound null safety).
TEST=co19/LanguageFeatures/Patterns/Exhaustiveness/exhaustiveness_enum_A01_t01
Fixes https://github.com/dart-lang/sdk/issues/52422
Change-Id: Ic93f4f212bee9ed3bfe5035f3c8d7535274c2f63
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/304102
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
Some cleanups factored out of a larger CL (which refactors enter/exit of threads):
* remove unused `#include "vm/thread_registry.h"`
* remove unused/unnecessary fields from [Thread] object
* rename IsMutator() -> IsDartMutator()
* make tests using setjmp() drain the sticky error
=> to ensure there's no sticky error on isolate shutdown
TEST=ci
Change-Id: I53935e8bd0628ab3768627d6d5e01c3f0e3a57ad
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/296582
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
This is a reland of commit 135443706b
Original change's description:
> [vm] Avoid expanding/flattening type arguments vectors in Type objects
>
> Previously, vectors of type arguments were expanded to include type
> arguments corresponding to superclasses both in the instances of
> generic classes and in Type objects (after type finalization).
> As a result, Type objects after finalization could be recursive and
> need to use extra TypeRef objects to break loops. The finalization of
> types was very complex and sometimes slow.
>
> This change simplifies the representation of Type objects: now they
> always have short type argument vectors, corresponding only to
> the type parameters of their own classes (both before and after
> finalization). Vectors of type arguments in the instances of generic
> classes are still expanded/flattened.
>
> This greatly simplifies type finalization, makes Type objects
> non-recursive and removes the need to create and handle excessive
> TypeRefs for type arguments corresponding to superclasses,
> as those type arguments are no longer included into types.
> The only remaining use of TypeRefs is for bounds of type parameters.
>
> In order to expand/flatten type arguments, new methods Type::GetInstanceTypeArguments / Class::GetInstanceTypeArguments
> are introduced. They build canonical declaration type arguments
> once (for each class), and then instantiate them as needed.
>
> There are also simple helper methods to shrink type arguments (TypeArguments::FromInstanceTypeArguments) and expand type arguments without filling type arguments corresponding to superclasses (TypeArguments::ToInstantiatorTypeArguments).
>
> Time of edge case 'regress_51960_test' 15min -> 300ms.
>
> TEST=ci, runtime/tests/vm/dart/regress_51960_test.dart
>
> Fixes https://github.com/dart-lang/sdk/issues/52022
> Fixes https://github.com/dart-lang/sdk/issues/51960
>
> Change-Id: I75b466b74698a33c0bb5e1dcbd29542e413812a1
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295060
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
> Commit-Queue: Alexander Markov <alexmarkov@google.com>
TEST=runtime/tests/vm/dart/regress_b_278841863_test.dart
Fixes b/278841863.
Change-Id: Ib1e20055bfb26e1df0a077300c69f0bec7152480
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/296300
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This reverts commit 135443706b.
Reason for revert: breaks many targets in G3, see b/278841863
Original change's description:
> [vm] Avoid expanding/flattening type arguments vectors in Type objects
>
> Previously, vectors of type arguments were expanded to include type
> arguments corresponding to superclasses both in the instances of
> generic classes and in Type objects (after type finalization).
> As a result, Type objects after finalization could be recursive and
> need to use extra TypeRef objects to break loops. The finalization of
> types was very complex and sometimes slow.
>
> This change simplifies the representation of Type objects: now they
> always have short type argument vectors, corresponding only to
> the type parameters of their own classes (both before and after
> finalization). Vectors of type arguments in the instances of generic
> classes are still expanded/flattened.
>
> This greatly simplifies type finalization, makes Type objects
> non-recursive and removes the need to create and handle excessive
> TypeRefs for type arguments corresponding to superclasses,
> as those type arguments are no longer included into types.
> The only remaining use of TypeRefs is for bounds of type parameters.
>
> In order to expand/flatten type arguments, new methods Type::GetInstanceTypeArguments / Class::GetInstanceTypeArguments
> are introduced. They build canonical declaration type arguments
> once (for each class), and then instantiate them as needed.
>
> There are also simple helper methods to shrink type arguments (TypeArguments::FromInstanceTypeArguments) and expand type arguments without filling type arguments corresponding to superclasses (TypeArguments::ToInstantiatorTypeArguments).
>
> Time of edge case 'regress_51960_test' 15min -> 300ms.
>
> TEST=ci, runtime/tests/vm/dart/regress_51960_test.dart
>
> Fixes https://github.com/dart-lang/sdk/issues/52022
> Fixes https://github.com/dart-lang/sdk/issues/51960
>
> Change-Id: I75b466b74698a33c0bb5e1dcbd29542e413812a1
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295060
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
> Commit-Queue: Alexander Markov <alexmarkov@google.com>
Change-Id: If0b2077305620593b8f03ebf6c135375c4086b1a
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/296182
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Alexander Thomas <athom@google.com>
Commit-Queue: Ilya Yanok <yanok@google.com>
Previously, vectors of type arguments were expanded to include type
arguments corresponding to superclasses both in the instances of
generic classes and in Type objects (after type finalization).
As a result, Type objects after finalization could be recursive and
need to use extra TypeRef objects to break loops. The finalization of
types was very complex and sometimes slow.
This change simplifies the representation of Type objects: now they
always have short type argument vectors, corresponding only to
the type parameters of their own classes (both before and after
finalization). Vectors of type arguments in the instances of generic
classes are still expanded/flattened.
This greatly simplifies type finalization, makes Type objects
non-recursive and removes the need to create and handle excessive
TypeRefs for type arguments corresponding to superclasses,
as those type arguments are no longer included into types.
The only remaining use of TypeRefs is for bounds of type parameters.
In order to expand/flatten type arguments, new methods Type::GetInstanceTypeArguments / Class::GetInstanceTypeArguments
are introduced. They build canonical declaration type arguments
once (for each class), and then instantiate them as needed.
There are also simple helper methods to shrink type arguments (TypeArguments::FromInstanceTypeArguments) and expand type arguments without filling type arguments corresponding to superclasses (TypeArguments::ToInstantiatorTypeArguments).
Time of edge case 'regress_51960_test' 15min -> 300ms.
TEST=ci, runtime/tests/vm/dart/regress_51960_test.dart
Fixes https://github.com/dart-lang/sdk/issues/52022
Fixes https://github.com/dart-lang/sdk/issues/51960
Change-Id: I75b466b74698a33c0bb5e1dcbd29542e413812a1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295060
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This CL replaces `late Finalizable` variables with the original and
a nullable non-late variable. Every assignment is done first to the
late variable, and the immediately to the nullable non-late shadow
variable. The reachability fences are then inserted only for the
nullable non-late shadow variable.
The advantage of this is that the semantics are fully valid and none
of the further compiler pipeline has to know about late Finalizables.
(1) We remove the special casing in the VM.
(2) The TFA logic with finalizables is no longer blocked.
The downside of this approach is that we use more memory, we need
two fields at runtime, one storing a null and the other storing a
sentinel on initiazation. Moreover, we get some extra store
instructions.
TEST=pkg/vm/testcases/transformations/ffi/finalizable_late.dart
TEST=pkg/vm/testcases/transformations/ffi/finalizable_late_2.dart
TEST=tests/language/vm/regress_49005_test.dart
Closes: https://github.com/dart-lang/sdk/issues/51511
Change-Id: Ifedd3387a368233a2d01e1bcaa9f5e3eceb76856
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286782
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This is follow up to 65f4a733bb,
which switched optimized code to use fixed frame for outgoing
arguments.
Change Kernel to IL translation to handle null-checks in
invocations differently: this code used to duplicate receiver on
the stack to accomodate for PushArgument in unoptimized code, but
PushArgument has not been inserted since f4e61eacfd,
which means duplication of the receiver is no longer necessary.
TEST=ci
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-dwarf-linux-product-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-nnbd-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-release-simarm64-try
Change-Id: I6c1f1e8c354f9ea92424b6602b83b9e9ebce8b69
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284184
Commit-Queue: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
The representation of record shape in record instances and record
types is changed from a pair
int num_fields
Array field_names
to a single integer - packed bitfield
int num_fields(16)
int field_names_index(kSmiBits-16)
where field names index is an index in the array available from
ObjectStore.
With the new representation of record shapes:
1) Size of record instances is reduced.
2) Number of comparisons for a shape test reduced from 2 to 1
(shape test is used during type checks).
3) A few operations removed from Record.hashCode.
4) Type testing stubs (TTS) are now supported for record types with
named fields. Previously it was not possible to check shape of records
with named fields in TTS as TTS cannot access object pool and cannot
load field names array).
TEST=existing
Issue: https://github.com/dart-lang/sdk/issues/49719
Change-Id: I7cdcbb53938aba5d561cd24dc99530395dbbea7e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/276201
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Since Dart 2.0 we can never have FallThroughErrors.
The CFE does not synthesize breaks unterminated cases which never
reach the end of the block. For example:
* Call to something that returns never.
* Nested complete switch which returns from every branch.
In these cases we need to construct a correct control flow in the VM,
even though it is dead code. Because the CFE does not make the outer
switch a labelled statement, we cannot find a jump target in the VM.
Therefore, throw something (just not a FallThroughError). This should
never be hit at runtime, because it's dead code.
When the CFE emits synthetic breaks, we can remove this workaround.
TEST=build SDK and run default suites.
Bug: https://github.com/dart-lang/sdk/issues/50595
Change-Id: I595dd3baf7253b0ac4931445bd5b6da49e84cae4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/273740
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
Right each `Pointer.fromFunction()` invocation will lead to creation of
a new ffi trampoline function & it's following JITed code. In AOT we
have exactly one ffi trampoline per target/native-signature/exceptional-return
combination.
=> This CL ensures we have only one such function.
Furthermore each `Pointer.fromFunction()` will currently perform 2
runtime calls in JIT: One to create a `Function` object, the other to
JIT that function & register callback metadata.
=> This CL ensures we won't do a runtime call to get a function, instead
do it at compile-time (as in AOT)
Furthermore we eagerly assign a callback-id to the unique/deduped ffi
trampoline callbacks. Only when the application requests a pointer, do
we populate metadata on the `Thread` object.
This CL doesn't (yet) change the fact that in JIT mode we have
isolate-specific jit trampolines (that will call now shared ffi trampoline
functions).
We also avoid baking in C++ runtime function pointers in generated
code. As a result we can now preserve ffi trampolines across AppJIT
serialization.
As a nice side-effect, we remove 100 lines of code.
TEST=ffi{,_2}/ffi_callback_unique_test
Issue https://github.com/dart-lang/sdk/issues/50611
Change-Id: I458831a47b041a088086f28f825de2a3849f6adc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/273420
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
'is' tests against record types are split into series of 'is' tests of
record fields. This is more efficient as record instances cannot be
added to subtype test caches (because type of a record instance
depends on types of its fields).
This change also adds canonicalization and constant evaluation of
LoadFieldInstr for record fields.
Performance on a trivial micro-benchmark (on x64):
JIT (RunTime): 4519104.5 -> 20031.5
AOT (RunTime): 4352583.0 -> 26281.6
TEST=ci
Issue: https://github.com/dart-lang/sdk/issues/49719
Change-Id: I2ed464cd3b31f365b17805f4e7debe1d6d1051fa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268080
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>