mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
[vm] Report an error when illegally accessing class through API in AOT mode.
Move all pragma documentation into runtime/docs and reformat it a bit. Fixes https://github.com/dart-lang/sdk/issues/35170 Change-Id: I2ab4d6d598f115efaa3192135cb838fb85cbbb01 Reviewed-on: https://dart-review.googlesource.com/c/84435 Commit-Queue: Vyacheslav Egorov <vegorov@google.com> Auto-Submit: Vyacheslav Egorov <vegorov@google.com> Reviewed-by: Samir Jindel <sjindel@google.com>
This commit is contained in:
parent
aea0aadf41
commit
a1a38da58e
|
@ -1,15 +1,21 @@
|
|||
# Entry points @pragma annotations
|
||||
# `vm:entry-point` pragma
|
||||
|
||||
The annotation `@pragma("vm:entry-point", ...)` **must** be placed on a class or
|
||||
member to indicate that it may be resolved, allocated or invoked directly from
|
||||
native or VM code _in AOT mode_.
|
||||
|
||||
## Background
|
||||
|
||||
Dart VM precompiler (AOT compiler) performs whole-program optimizations such as
|
||||
tree shaking in order to decrease size of the resulting compiled apps and
|
||||
improve their performance. Such optimizations assume that compiler can see the
|
||||
whole Dart program, and is able to discover and analyze all Dart functions and
|
||||
members which can be potentially executed at run time. While the Dart code is
|
||||
fully available for precompiler, native code of the embedder and native methods
|
||||
are out of reach of the compiler. Such native code can call back to Dart via
|
||||
native Dart API.
|
||||
tree shaking and type flow analysis (TFA) in order to decrease size of the
|
||||
resulting compiled apps and improve their performance. Such optimizations
|
||||
assume that compiler can see the whole Dart program, and is able to discover
|
||||
and analyse all Dart functions and members which can be potentially executed at
|
||||
run time. While the Dart code is fully available for precompiler, native code
|
||||
of the embedder and native methods are out of reach of the compiler. Such
|
||||
native code can call back to Dart via native Dart API.
|
||||
|
||||
In order to aid precompiler, programmer can explicitly list entry points
|
||||
In order to guide precompiler, programmer **must** explicitly list entry points
|
||||
(roots) - Dart classes and members which are accessed from native code. Note
|
||||
that listing entry points is not optional: as long as program defines native
|
||||
methods which call into Dart, the entry points are required for the correctness
|
||||
|
@ -18,15 +24,11 @@ of compilation.
|
|||
In addition, when obfuscation is enabled, the precompiler needs to know which
|
||||
symbols need to be preserved to ensure they can be resolved from native code.
|
||||
|
||||
# Pragma annotation
|
||||
|
||||
The annotation `@pragma("vm:entry-point", ...)` can be placed on a class or
|
||||
member to indicate that it may be resolved, allocated or invoked directly from
|
||||
native or VM code.
|
||||
## Syntax
|
||||
|
||||
The allowed uses of the annotation are as follows.
|
||||
|
||||
## Classes
|
||||
### Classes
|
||||
|
||||
Any one of the following forms may be attached to a class:
|
||||
|
||||
|
@ -44,7 +46,7 @@ Note that `@pragma("vm:entry-point")` may be added to abstract classes -- in
|
|||
this case, their name will survive obfuscation, but they won't have any
|
||||
allocation stubs.
|
||||
|
||||
## Procedures
|
||||
### Procedures
|
||||
|
||||
Any one of the following forms may be attached to a procedure (including
|
||||
getters, setters and constructors):
|
||||
|
@ -61,7 +63,7 @@ available for lookup and invocation directly from native or VM code. If the
|
|||
procedure is a *generative* constructor, the enclosing class will also be marked
|
||||
for allocation from native or VM code.
|
||||
|
||||
## Fields
|
||||
### Fields
|
||||
|
||||
Any one of the following forms may be attached to a non-static field. The first
|
||||
three forms may be attached to static fields.
|
||||
|
@ -72,7 +74,7 @@ three forms may be attached to static fields.
|
|||
@pragma("vm:entry-point", true/false)
|
||||
@pragma("vm:entry-point", !const bool.formEnvironment("dart.vm.product"))
|
||||
@pragma("vm:entry-point", "get"/"set")
|
||||
void foo() { ... }
|
||||
int foo;
|
||||
```
|
||||
|
||||
If the second parameter is missing, `null` or `true, the field is marked for
|
|
@ -1,4 +1,6 @@
|
|||
# Pragma for testing multiple entrypoints
|
||||
# `vm:testing.unsafe.trace-entrypoints-fn` pragma
|
||||
|
||||
This pragma is used for testing purposes in the test suite.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -8,7 +10,7 @@ void hook(String functionName, int entryPointId) {
|
|||
}
|
||||
|
||||
class C<T> {
|
||||
@pragma("vm:testing.unsafe.trace-entrypoints-fn", hook)
|
||||
@pragma('vm:testing.unsafe.trace-entrypoints-fn', hook)
|
||||
void foo(T x) {
|
||||
// ...
|
||||
}
|
||||
|
@ -16,8 +18,9 @@ class C<T> {
|
|||
```
|
||||
|
||||
When `foo` is invoked, `hook` will be called in `foo`'s prologue if `foo` was
|
||||
compiled with multiple entrypoints. `hook` will be passed the name of the
|
||||
function it was called for and the ID of the entrypoint used for the invocation:
|
||||
compiled with multiple entry points. `hook` will be passed the name of the
|
||||
function it was called for and the ID of the entry point used for the
|
||||
invocation:
|
||||
|
||||
- 0: Normal entry.
|
||||
|
|
@ -1,14 +1,23 @@
|
|||
# Result type @pragma annotations
|
||||
# `vm:exact-result-type` pragma
|
||||
|
||||
To facilitate type-flow analysis and other optimizations, Dart methods may use the pragma `vm:exact-result-type` to declare an exact return type different than the return type in the signature of the method. There are three limitations on this pragma:
|
||||
To facilitate type-flow analysis and other optimizations, Dart methods may use
|
||||
the pragma `vm:exact-result-type` to declare an exact return type different than
|
||||
the return type in the signature of the method. There are three limitations on
|
||||
this pragma:
|
||||
|
||||
0. The Dart object returned by the method at runtime must have exactly the type specified in the annotation (not a subtype).
|
||||
0. The Dart object returned by the method at runtime must have exactly the type
|
||||
specified in the annotation (not a subtype).
|
||||
|
||||
1. The exact return type declared in the pragma must be a subtype of the return type declared in the method signature.
|
||||
1. The exact return type declared in the pragma must be a subtype of the return
|
||||
type declared in the method signature.
|
||||
Note that this restriction is not enforced automatically by the compiler.
|
||||
|
||||
2. `vm:exact-result-type` may only be attached to methods in the core library.
|
||||
This pragma can introduce unsafe behavior since it allows the compiler to make stronger assumptions during optimization than what the sound strong-mode type system allows, so it is only allowed in the core library where the Dart VM team can ensure that it is not misused.
|
||||
2. `vm:exact-result-type` may only be attached to methods in the `dart:*`
|
||||
libraries.
|
||||
This pragma can introduce unsafe behavior since it allows the compiler to
|
||||
make stronger assumptions during optimization than what the sound strong-mode
|
||||
type system allows, so it is only allowed in the core library where the Dart
|
||||
VM team can ensure that it is not misused.
|
||||
|
||||
If limitations 0 or 1 are violated, undefined behavior may result.
|
||||
Note that since `null` is an instance of the `Null` type, which is a subtype of any other, exactness of the annotated result type implies that the result must be non-null.
|
||||
|
@ -21,13 +30,13 @@ Note that since `null` is an instance of the `Null` type, which is a subtype of
|
|||
class A {}
|
||||
class B extends A {}
|
||||
|
||||
@pragma("vm:exact-result-type", B)
|
||||
A foo() native "foo_impl";
|
||||
@pragma('vm:exact-result-type', B)
|
||||
A foo() native 'foo_impl';
|
||||
```
|
||||
|
||||
### Reference to type via path
|
||||
|
||||
```dart
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi");
|
||||
int foo() native "foo_impl";
|
||||
@pragma('vm:exact-result-type', 'dart:core#_Smi');
|
||||
int foo() native 'foo_impl';
|
||||
```
|
|
@ -4,19 +4,17 @@
|
|||
|
||||
These pragmas are part of the VM's API and are safe for use in external code.
|
||||
|
||||
- **vm:entry-point**
|
||||
|
||||
[Defining entry-points into Dart code for an embedder or native methods]
|
||||
(file://../vm/compiler/aot/entry_points_pragma.md)
|
||||
| Pragma | Meaning |
|
||||
| --- | --- |
|
||||
| `vm:entry-point` | [Defining entry-points into Dart code for an embedder or native methods](compiler/aot/entry_point_pragma.md) |
|
||||
|
||||
## Pragmas for internal use
|
||||
|
||||
These pragmas can cause unsound behavior if used incorrectly and therefore are only allowed within the core SDK libraries.
|
||||
|
||||
- **vm:exact-result-type**
|
||||
|
||||
[Declaring an exact result type of a method]
|
||||
(file://../vm/compiler/result_type_pragma.md)
|
||||
| Pragma | Meaning |
|
||||
| --- | --- |
|
||||
| `vm:exact-result-type` | [Declaring an exact result type of a method](compiler/result_type_pragma.md) |
|
||||
|
||||
## Pragmas for internal testing
|
||||
|
||||
|
@ -25,7 +23,6 @@ They must be enabled with the `--enable-testing-pragmas` flag.
|
|||
The names of these pragmas are prefixed with "testing".
|
||||
Additionally, they are categorized into "safe" and "unsafe" forms: "safe" pragmas should not affect the behavior of the program and can be safely added anywhere, whereas "unsafe" pragmas may change the code's behavior or may cause the VM to crash if used improperly.
|
||||
|
||||
- **vm:testing.unsafe.trace-entrypoints-fn**
|
||||
|
||||
[Observing which flow-graph-level entry-point was used when a function was called]
|
||||
(file://../vm/compiler/frontend/entrypoints_pragma.md)
|
||||
| Pragma | Meaning |
|
||||
| --- | --- |
|
||||
| `vm:testing.unsafe.trace-entrypoints-fn` | [Observing which flow-graph-level entry-point was used when a function was called](compiler/frontend/testing_trace_entrypoints_pragma.md) |
|
||||
|
|
|
@ -5042,7 +5042,16 @@ static void CheckIsEntryPoint(const Class& klass) {
|
|||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
// This is not a completely thorough check that the class is an entry-point,
|
||||
// but it catches most missing annotations.
|
||||
RELEASE_ASSERT(klass.has_pragma());
|
||||
if (!klass.has_pragma()) {
|
||||
OS::PrintErr(
|
||||
"ERROR: It is illegal to access class %s through Dart C API "
|
||||
"because it was not annotated with @pragma('vm:entry-point').\n"
|
||||
"ERROR: See "
|
||||
"https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/"
|
||||
"aot/entry_point_pragma.md",
|
||||
String::Handle(klass.UserVisibleName()).ToCString());
|
||||
UNREACHABLE();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue