dart-sdk/runtime/docs/compiler/pragmas_recognized_by_compiler.md
Aske Simon Christensen 1ab705f60c [vm] Require all recognized methods to be marked with pragma.
Adds a @pragma("vm:recognized", <kind>) to all recognized methods, where
<kind> is one of "intrinsic", "graph" or "other", corresponding to the
kind of recognized method.

When running in debug mode, it is checked that all recognized methods
are marked with the correct kind of pragma, and that all methods marked
with the pragma are in fact recognized.

This enables kernel-level analyses and optimizations to query whether
a method is recognized by the VM.

TEST=Asserts that check the correspondence both ways, covered by test
suite, in particular the various CompileAll tests that compile all code.
Change-Id: I12f3305c72a93ecb1aefae2d66e3d9a7dae23b44
Cq-Do-Not-Cancel-Tryjobs: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/168951
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2020-11-16 13:49:50 +00:00

4.3 KiB

Pragma annotations recognized by the compiler

Annotations for functions and methods

Changing whether a function or method is inlined

The user can change whether the VM attempts to inline a given function or method with the following pragmas.

Requesting a function be inlined

@pragma("vm:prefer-inline")

Here, the VM will inline the annotated function when possible. However, other factors can prevent inlining and thus this pragma may not always be respected.

Requesting a function never be inlined

@pragma("vm:never-inline")

Here, the VM will not inline the annotated function. In this case, the pragma is always respected.

Annotations for return types and field types

The VM is not able to see across method calls (apart from inlining) and therefore does not know anything about the return'ed values of calls, except for the interface type of the signature.

To improve this we have two types of additional information sources the VM utilizes to gain knowledge about return types:

  • inferred types (stored in kernel metadata): these are computed by global transformations (e.g. TFA) and are only available in AOT mode

  • @pragma annotations: these are recognized in JIT and AOT mode

This return type information is mainly used in the VM's type propagator.

Since those annotations side-step the normal type system, they are unsafe and we therefore restrict those annotations to only have an affect inside dart: libraries.

See also https://github.com/dart-lang/sdk/issues/35244.

Providing an exact result type

@pragma("vm:exact-result-type", <type>)

Tells the VM about the exact result type (i.e. the exact class-id) of a function or a field load.

There are two limitations on this pragma:

  • The Dart object returned by the method at runtime must have exactly the type specified in the annotation (not a subtype).

  • The exact return type declared in the pragma must be a subtype of the interface type declared in the method signature.

    Note: This limitation is not enforced automatically by the compiler.

If those limitations 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.

It is also possible to specify the type arguments of the result type if they are the same as the type arguments passed to the method itself. This is primarily useful for factory constructors:

@pragma("vm:exact-result-type", [<type>, "result-type-uses-passed-type-arguments"])

Examples for exact result types

class A {}
class B extends A {}

// Reference to type via type literal
@pragma("vm:exact-result-type", B)
A foo() native "foo_impl";

// Reference to type via path
@pragma("vm:exact-result-type", "dart:core#_Smi");
int foo() native "foo_impl";

class C {
  // Reference to type via type literal
  @pragma('vm:exact-result-type', B)
  final B bValue;

  // Reference to type via path
  @pragma('vm:exact-result-type', "dart:core#_Smi")
  final int intValue;
}

class D<T> {
  @pragma("vm:exact-result-type",
          [D, "result-type-uses-passed-type-arguments"])
  factory D();  // returns an instance of D<T>
}

Declaring a result type non-nullable

@pragma("vm:non-nullable-result-type")

Tells the VM that the method/field cannot return null.

There is one limitation on this pragma:

  • The Dart object returned by the method at runtime must not return null.

If this limitation is violated, undefined behavior may result.

Examples for non-nullable result types

@pragma("vm:non-nullable-result-type")
A foo() native "foo_impl";

class C {
  @pragma('vm:non-nullable-result-type");
  final int value;
}

Marking recognized methods

@pragma("vm:recognized", <kind>)

Marks the method as one of the methods specially recognized by the VM. Here, is one of "asm-intrinsic", "graph-intrinsic" or "other", corresponding to the category the recognized method belongs to, as defined in recognized_methods_list.h.

The pragmas must match exactly the set of recognized methods. This enables kernel-level analyses and optimizations to query whether a method is recognized by the VM. The correspondence is checked when running in debug mode.