[ddc] Include shared library for new runtime types

When compiling the Dart SDK with the `--canary` flag DDC will include
the new shared runtime type library in the compiled SDK.

Change-Id: I7a418033fb7397939aa6f4b7fb84820ead99c3be
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241690
Commit-Queue: Nicholas Shahan <nshahan@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Anna Gringauze <annagrin@google.com>
This commit is contained in:
Nicholas Shahan
2022-05-25 18:23:29 +00:00
committed by Commit Bot
parent 33b6483ad1
commit 4d9b28dc08
14 changed files with 294 additions and 12 deletions
@@ -9,6 +9,22 @@ import '../js_ast/js_ast.dart';
/// The ES6 name for the Dart SDK. All dart:* libraries are in this module.
const String dartSdkModule = 'dart_sdk';
/// Names expected to be used without renaming.
///
/// These are fixed by the dart:_rti library and are accessed through the
/// `JsGetName` enum.
abstract class FixedNames {
static const operatorIsPrefix = r'$is';
static const operatorSignature = r'$signature';
static const rtiName = r'$ti';
// TODO(48585) Fix this name.
static const futureClassName = 'TODO';
// TODO(48585) Fix this name.
static const listClassName = 'TODO';
static const rtiAsField = '_as';
static const rtiIsField = '_is';
}
/// Unique instance for temporary variables. Will be renamed consistently
/// across the entire file. Different instances will be named differently
/// even if they have the same name, this makes it safe to use in code
@@ -2,6 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:js_shared/synced/embedded_names.dart'
show RtiUniverseFieldNames;
import '../js_ast/js_ast.dart';
/// Simplify `(args) => (() => { ... })()` to `(args) => { ... }`.
@@ -51,3 +54,21 @@ class SourceInformationClearer extends BaseVisitorVoid {
node.sourceInformation = null;
}
}
/// Returns an expression that creates the initial Rti Universe.
///
/// This needs to be kept in sync with `_Universe.create` in `dart:_rti`.
Expression createRtiUniverse() {
Property initField(String name, String value) =>
Property(js.string(name), js(value));
var universeFields = [
initField(RtiUniverseFieldNames.evalCache, 'new Map()'),
initField(RtiUniverseFieldNames.typeRules, '{}'),
initField(RtiUniverseFieldNames.erasedTypes, '{}'),
initField(RtiUniverseFieldNames.typeParameterVariances, '{}'),
initField(RtiUniverseFieldNames.sharedEmptyArray, '[]'),
];
return ObjectInitializer(universeFields);
}
@@ -178,6 +178,10 @@ abstract class SharedCompiler<Library, Class, InterfaceType, FunctionNode> {
@protected
String libraryToModule(Library library);
/// Returns true if [library] is identified by [name].
@protected
bool isDartLibrary(Library library, String name);
/// Returns true if the library [l] is "dart:_runtime".
@protected
bool isSdkInternalRuntime(Library l);
+119 -5
View File
@@ -9,6 +9,7 @@ import 'dart:convert';
import 'dart:math' show max, min;
import 'package:front_end/src/api_unstable/ddc.dart';
import 'package:js_shared/synced/embedded_names.dart' show JsGetName, JsBuiltin;
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
@@ -368,6 +369,17 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
// Initialize library variables.
isBuildingSdk = libraries.any(isSdkInternalRuntime);
// TODO(48585) Remove after new type system has landed.
if (isBuildingSdk && !_options.newRuntimeTypes) {
libraries.removeWhere((library) {
var path = library.importUri.path;
return path == '_js_shared_embedded_names' ||
path == '_js_names' ||
path == '_recipe_syntax' ||
path == '_rti';
});
}
// For runtime performance reasons, we only containerize SDK symbols in web
// libraries. Otherwise, we use a 600-member cutoff before a module is
// containerized. This is somewhat arbitrary but works promisingly for the
@@ -475,6 +487,8 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
if (!isBuildingSdk) {
items.add(
runtimeStatement('_checkModuleNullSafetyMode(#)', [soundNullSafety]));
items.add(runtimeStatement('_checkModuleRuntimeTypes(#)',
[js_ast.LiteralBool(_options.newRuntimeTypes)]));
}
// Emit the hoisted type table cache variables
@@ -519,9 +533,16 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
library.parts.map((part) => part.partUri);
/// True when [library] is the sdk internal library 'dart:_internal'.
bool _isDartInternal(Library library) {
bool _isDartInternal(Library library) => isDartLibrary(library, '_internal');
/// True when [library] is the sdk internal library 'dart:_internal'.
bool _isDartForeignHelper(Library library) =>
isDartLibrary(library, '_foreign_helper');
@override
bool isDartLibrary(Library library, String name) {
var importUri = library.importUri;
return importUri.isScheme('dart') && importUri.path == '_internal';
return importUri.isScheme('dart') && importUri.path == name;
}
@override
@@ -559,6 +580,12 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
}
if (isSdkInternalRuntime(library)) {
if (_options.newRuntimeTypes) {
// Add embedded globals.
moduleItems.add(
runtimeCall('typeUniverse = #', [js_ast.createRtiUniverse()])
.toStatement());
}
// `dart:_runtime` uses a different order for bootstrapping.
//
// Functions are first because we use them to associate type info
@@ -5535,17 +5562,45 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
if (isInlineJS(target)) return _emitInlineJSCode(node) as js_ast.Expression;
if (target.isFactory) return _emitFactoryInvocation(node);
// Optimize some internal SDK calls.
if (_isDartInternal(target.enclosingLibrary)) {
var enclosingLibrary = target.enclosingLibrary;
if (_isDartInternal(enclosingLibrary)) {
var args = node.arguments;
if (args.positional.length == 1 &&
args.types.length == 1 &&
args.named.isEmpty &&
target.name.text == 'unsafeCast') {
// Optimize some internal SDK calls by avoiding the insertion of a
// runtime cast.
return args.positional.single.accept(this);
}
}
if (isSdkInternalRuntime(target.enclosingLibrary)) {
if (_isDartForeignHelper(enclosingLibrary)) {
var args = node.arguments.positional;
var name = target.name.text;
if (args.length == 1) {
if (name == 'JS_GET_NAME') {
var staticGet = args.single as StaticGet;
var enumField = staticGet.target as Field;
return _emitNameForJsGetName(asJsGetName(enumField));
}
} else if (args.length == 2) {
if (name == 'JS_EMBEDDED_GLOBAL') return _emitEmbeddedGlobal(node);
if (name == 'JS_STRING_CONCAT') {
var left = _visitExpression(args.first);
var right = _visitExpression(args.last);
return js.call('# + #', [left, right]);
}
}
if (name == 'JS_BUILTIN') {
var staticGet = args[1] as StaticGet;
var enumField = staticGet.target as Field;
return _emitOperationForJsBuiltIn(asJsBuiltin(enumField));
}
}
if (isSdkInternalRuntime(enclosingLibrary)) {
var name = target.name.text;
if (node.arguments.positional.isEmpty &&
node.arguments.types.length == 1) {
@@ -5577,6 +5632,9 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
if (flagName == 'soundNullSafety') {
return js.boolean(_options.soundNullSafety);
}
if (flagName == 'newRuntimeTypes') {
return js.boolean(_options.newRuntimeTypes);
}
throw UnsupportedError('Invalid flag in call to $name: $flagName');
}
} else if (node.arguments.positional.length == 2) {
@@ -5762,6 +5820,62 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
return result.withSourceInformation(_nodeStart(node));
}
js_ast.Expression _emitEmbeddedGlobal(StaticInvocation node) {
var constantExpression = node.arguments.positional[1] as ConstantExpression;
var name = constantExpression.constant as StringConstant;
return runtimeCall('#', [name.value]);
}
/// Returns the string literal that is to be used as the result of a call to
/// [JS_GET_NAME] for [name].
js_ast.LiteralString _emitNameForJsGetName(JsGetName name) {
switch (name) {
case JsGetName.OPERATOR_IS_PREFIX:
return js.string(js_ast.FixedNames.operatorIsPrefix);
case JsGetName.SIGNATURE_NAME:
return js.string(js_ast.FixedNames.operatorSignature);
case JsGetName.RTI_NAME:
return js.string(js_ast.FixedNames.rtiName);
case JsGetName.FUTURE_CLASS_TYPE_NAME:
return js.string(js_ast.FixedNames.futureClassName);
case JsGetName.LIST_CLASS_TYPE_NAME:
return js.string(js_ast.FixedNames.listClassName);
case JsGetName.RTI_FIELD_AS:
return js.string(js_ast.FixedNames.rtiAsField);
case JsGetName.RTI_FIELD_IS:
return js.string(js_ast.FixedNames.rtiIsField);
default:
throw UnsupportedError('JsGetName has no name for "$name".');
}
}
/// Returns the expression that is to be used as the result of a call to
/// [JS_BUILTIN] for [builtin].
js_ast.Expression _emitOperationForJsBuiltIn(JsBuiltin builtin) {
switch (builtin) {
case JsBuiltin.dartClosureConstructor:
// TODO(48585) How to get constructor for a Dart Function?
return js.call('TODO');
case JsBuiltin.dartObjectConstructor:
// TODO(48585) How to get constructor for a Dart Object?
return js.call('TODO');
default:
throw UnsupportedError('JsBuiltin has no operation for "$builtin".');
}
}
String _enumValueName(Field field) {
var enumName = field.enclosingClass.name;
var valueName = field.name.text;
return '$enumName.$valueName';
}
JsGetName asJsGetName(Field field) => JsGetName.values
.firstWhere((val) => val.toString() == _enumValueName(field));
JsBuiltin asJsBuiltin(Field field) => JsBuiltin.values
.firstWhere((val) => val.toString() == _enumValueName(field));
bool _isWebLibrary(Uri importUri) =>
importUri != null &&
importUri.isScheme('dart') &&
@@ -203,9 +203,13 @@ Expression? getInvocationReceiver(InvocationExpression node) {
}
bool isInlineJS(Member e) =>
e is Procedure &&
e.name.text == 'JS' &&
e.enclosingLibrary.importUri.toString() == 'dart:_foreign_helper';
e is Procedure && _isProcedureFromForeignHelper('JS', e);
/// Returns `true` if [p] is the procedure named [name] from the
/// 'dart:_foreign_helper' library.
bool _isProcedureFromForeignHelper(String name, Procedure p) =>
p.name.text == name &&
p.enclosingLibrary.importUri.toString() == 'dart:_foreign_helper';
/// Whether the parameter [p] is covariant (either explicitly `covariant` or
/// implicitly due to generics) and needs a check for soundness.
@@ -57,6 +57,9 @@ class DevCompilerTarget extends Target {
@override
List<String> get extraRequiredLibraries => const [
'dart:_runtime',
'dart:_js_shared_embedded_names',
'dart:_recipe_syntax',
'dart:_rti',
'dart:_dart2js_runtime_metrics',
'dart:_debugger',
'dart:_foreign_helper',
@@ -64,6 +67,7 @@ class DevCompilerTarget extends Target {
'dart:_internal',
'dart:_isolate_helper',
'dart:_js_helper',
'dart:_js_names',
'dart:_js_primitives',
'dart:_metadata',
'dart:_native_typed_data',
@@ -103,6 +107,7 @@ class DevCompilerTarget extends Target {
'dart:_js_helper',
'dart:_native_typed_data',
'dart:_runtime',
'dart:_rti',
];
@override
+1
View File
@@ -14,6 +14,7 @@ dependencies:
build_integration: any
collection: any
front_end: any
js_shared: any
kernel: any
meta: any
path: any
@@ -44,6 +44,21 @@ void _checkModuleNullSafetyMode(@notNull bool isModuleSound) {
}
}
/// Throws if [useNewTypes] does not match the version of the type
/// representation of this SDK.
///
/// The call to this method is inserted into every module at compile time.
void _checkModuleRuntimeTypes(@notNull bool useNewTypes) {
if (useNewTypes != compileTimeFlag('newRuntimeTypes')) {
var sdkTypes = compileTimeFlag('newRuntimeTypes') ? 'new' : 'old';
var moduleTypes = useNewTypes ? 'new' : 'old';
throw AssertionError('The Dart SDK module is using the $sdkTypes runtime '
'type representation and is incompatible with the $moduleTypes '
'representation used in this module.');
}
}
final _nullFailedSet = JS('!', 'new Set()');
String _nullFailedMessage(variableName) =>
@@ -4,6 +4,9 @@
library dart._foreign_helper;
import 'dart:_js_shared_embedded_names' show JsBuiltin, JsGetName;
import 'dart:_rti' show Rti;
/**
* Emits a JavaScript code fragment parameterized by arguments.
*
@@ -221,7 +224,7 @@ external String JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG();
external String JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG();
/// Returns the JS name for [name] from the Namer.
external String JS_GET_NAME(String name);
external String JS_GET_NAME(JsGetName name);
/// Returns the state of a flag that is determined by the state of the compiler
/// when the program has been analyzed.
@@ -274,3 +277,52 @@ dynamic spread(args) {
throw StateError('The spread function cannot be called, '
'it should be compiled away.');
}
/// Reads an embedded global.
///
/// The [name] should be a constant defined in the `_js_shared_embedded_names`
/// library.
external JS_EMBEDDED_GLOBAL(String typeDescription, String name);
/// Instructs the compiler to execute the [builtinName] action at the call-site.
///
/// The [builtin] should be a constant defined in the
/// `_js_shared_embedded_names` library.
// Add additional optional arguments if needed. The method is treated internally
// as a variable argument method.
external JS_BUILTIN(String typeDescription, JsBuiltin builtin,
[arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11]);
/// Returns the interceptor for [object].
///
// TODO(nshahan) Replace calls at compile time?
external getInterceptor(object);
/// Returns the Rti object for the type for JavaScript arrays via JS-interop.
///
// TODO(nshahan) Replace calls at compile time?
external Object getJSArrayInteropRti();
/// Returns a raw reference to the JavaScript function which implements
/// [function].
///
/// Warning: this is dangerous, you should probably use
/// [DART_CLOSURE_TO_JS] instead. The returned object is not a valid
/// Dart closure, does not store the isolate context or arity.
///
/// A valid example of where this can be used is as the second argument
/// to V8's Error.captureStackTrace. See
/// https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.
// TODO(nshahan) Replace calls at compile time?
external RAW_DART_FUNCTION_REF(Function function);
/// Returns a TypeReference to [T].
// TODO(nshahan) Replace calls at compile time?
external Rti TYPE_REF<T>();
/// Returns a TypeReference to [T]*.
// TODO(nshahan) Replace calls at compile time?
external Rti LEGACY_TYPE_REF<T>();
/// JavaScript string concatenation. Inputs must be Strings.
external String JS_STRING_CONCAT(String a, String b);
@@ -23,9 +23,6 @@ abstract class Interceptor {
String toString() => JS<String>('!', '#.toString()', this);
}
// TODO(jmesserly): remove
getInterceptor(obj) => obj;
/**
* The interceptor class for [bool].
*/
@@ -296,3 +293,6 @@ setDispatchProperty(object, value) {}
// TODO(sigmund): revisit whether this method is still needed after reoganizing
// all web tests.
findInterceptorForType(Type? type) {}
// TODO(nshahan) Find a correct representation for JS functions.
typedef JavaScriptFunction = dart.FunctionType;
@@ -0,0 +1,9 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart._js_names;
String? unmangleGlobalNameIfPreservedAnyways(String name) {
throw ('Unimplemented');
}
+12
View File
@@ -424,9 +424,15 @@
"_js_annotations": {
"uri": "js/_js_annotations.dart"
},
"_js_shared_embedded_names": {
"uri": "_internal/js_shared/lib/synced/embedded_names.dart"
},
"_js_helper": {
"uri": "_internal/js_dev_runtime/private/js_helper.dart"
},
"_js_names": {
"uri": "_internal/js_dev_runtime/private/js_names.dart"
},
"_js_primitives": {
"uri": "_internal/js_dev_runtime/private/js_primitives.dart"
},
@@ -439,6 +445,12 @@
"_dart2js_runtime_metrics": {
"uri": "_internal/js_dev_runtime/private/runtime_metrics.dart"
},
"_rti": {
"uri": "_internal/js_shared/lib/rti.dart"
},
"_recipe_syntax": {
"uri": "_internal/js_shared/lib/synced/recipe_syntax.dart"
},
"async": {
"uri": "async/async.dart",
"patches": "_internal/js_dev_runtime/patch/async_patch.dart"
+12
View File
@@ -390,9 +390,15 @@ dartdevc:
_js_annotations:
uri: "js/_js_annotations.dart"
_js_shared_embedded_names:
uri: "_internal/js_shared/lib/synced/embedded_names.dart"
_js_helper:
uri: "_internal/js_dev_runtime/private/js_helper.dart"
_js_names:
uri: "_internal/js_dev_runtime/private/js_names.dart"
_js_primitives:
uri: "_internal/js_dev_runtime/private/js_primitives.dart"
@@ -405,6 +411,12 @@ dartdevc:
_dart2js_runtime_metrics:
uri: "_internal/js_dev_runtime/private/runtime_metrics.dart"
_rti:
uri: "_internal/js_shared/lib/rti.dart"
_recipe_syntax:
uri: "_internal/js_shared/lib/synced/recipe_syntax.dart"
async:
uri: "async/async.dart"
patches: "_internal/js_dev_runtime/patch/async_patch.dart"
+17
View File
@@ -8,6 +8,11 @@ import("../../utils/compile_platform.gni")
import("../application_snapshot.gni")
import("../create_timestamp.gni")
declare_args() {
# Enables DDC canary features during compilation to Javascript.
ddc_canary = false
}
patched_sdk_dir = "$target_gen_dir/patched_sdk"
sdk_summary = "$target_gen_dir/ddc_sdk.sum"
@@ -30,6 +35,10 @@ application_snapshot("dartdevc") {
rebase_path("../../pkg/dev_compiler/bin/dartdevc.dart"),
]
if (ddc_canary) {
training_args += [ "--canary" ]
}
deps = [
":dartdevc_kernel_sdk",
":dartdevc_platform",
@@ -186,6 +195,10 @@ template("dartdevc_kernel_compile") {
"package:$module/$module.dart",
]
if (ddc_canary) {
args += [ "--canary" ]
}
if (defined(invoker.extra_libraries)) {
foreach(lib, invoker.extra_libraries) {
args += [ "package:$module/$lib.dart" ]
@@ -356,6 +369,10 @@ template("dartdevc_sdk_js") {
if (invoker.sound_null_safety) {
args += [ "--sound-null-safety" ]
}
if (ddc_canary) {
args += [ "--canary" ]
}
}
}