[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:
Vyacheslav Egorov 2018-11-15 12:00:57 +00:00 committed by commit-bot@chromium.org
parent aea0aadf41
commit a1a38da58e
5 changed files with 65 additions and 45 deletions

View file

@ -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

View file

@ -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.

View file

@ -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';
```

View file

@ -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) |

View file

@ -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
}