Files
sdk/pkg/dev_compiler/doc/JS_CODEGEN.md
T
Vijay Menon 3e15b67d32 [dartdevc] add forwarding from old docs to new info
Fixes https://github.com/dart-lang/sdk/issues/38984

Change-Id: Ic8ef8838b0a8c3233bf94706b243cdd9aedacbc1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/127963
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Kathy Walrath <kathyw@google.com>
Commit-Queue: Kathy Walrath <kathyw@google.com>
2019-12-10 22:53:26 +00:00

3.1 KiB
Raw Blame History

Strong Mode and Idiomatic JavaScript

Note: This document is out of date. Please see Sound Dart for up-to-date documentation on Dart's type system. The work below was a precursor towards Dart's current type system.

The Dart Dev Compiler (DDC) uses Strong Mode to safely generate idiomatic JavaScript. This enables better interoperability between Dart and JavaScript code.

The standard Dart type system is unsound by design. This means that static type annotations may not match the actual runtime values even when a program is running in checked mode. This allows considerable flexibility, but it also means that Dart implementations cannot easily use these annotations for optimization or code generation.

Because of this, existing Dart implementations require dynamic dispatch. Furthermore, because Darts dispatch semantics are different from JavaScripts, it effectively precludes mapping Dart calls to idiomatic JavaScript. For example, the following Dart code:

var x = a.bar;
b.foo("hello", x);

cannot easily be mapped to the identical JavaScript code. If a does not contain a bar field, Dart requires a NoSuchMethodError while JavaScript simply returns undefined. If b contains a foo method, but with the wrong number of arguments, Dart again requires a NoSuchMethodError while JavaScript either ignores extra arguments or fills in omitted ones with undefined.

To capture these differences, the Dart2JS compiler instead generates code that approximately looks like:

var x = getInterceptor(a).get$bar(a);
getInterceptor(b).foo$2(b, "hello", x);

The “interceptor” is Darts dispatch table for the objects a and b, and the mangled names (get$bar and foo$2) account for Darts different dispatch semantics.

The above highlights why Dart-JavaScript interoperability hasnt been seamless: Dart objects and methods do not look like normal JavaScript ones.

DDC relies on strong mode to map Dart calling conventions to normal JavaScript ones. If a and b have static type annotations (with a type other than dynamic), strong mode statically verifies that they have a field bar and a 2-argument method foo respectively. In this case, DDC safely generates the identical JavaScript:

var x = a.bar;
b.foo("hello", x);

Note that DDC still supports the dynamic type, but relies on runtime helper functions in this case. E.g., if a and b are type dynamic, DDC instead generates:

var x = dload(a, "bar");
dsend(b, "foo", "hello", x);

where dload and dsend are runtime helpers that implement Dart dispatch semantics. Programmers are encouraged to use static annotations to avoid this. Strong mode is able to use static checking to enforce much of what checked mode does at runtime. In the code above, strong mode statically verifies that bs type (if not dynamic) has a foo method that accepts a String as its first argument and a.bars type as its second. If the code is sufficiently typed, runtime checks are unnecessary.