[dart2js] Implement encoder for recipes
Change-Id: Ia8fd313b014730859796abaf0083fdf738034365
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106941
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 5e22b23..b367d3a 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -20,6 +20,7 @@
import 'checked_mode_helpers.dart';
import 'namer.dart';
import 'runtime_types.dart';
+import 'runtime_types_new.dart';
abstract class FunctionCompiler {
void initialize(
@@ -305,6 +306,7 @@
CheckedModeHelpers get checkedModeHelpers;
RuntimeTypesSubstitutions get rtiSubstitutions;
RuntimeTypesEncoder get rtiEncoder;
+ RecipeEncoder get rtiRecipeEncoder;
Tracer get tracer;
RuntimeTypeTags get rtiTags;
FixedNames get fixedNames;
@@ -321,6 +323,9 @@
final RuntimeTypesEncoder rtiEncoder;
@override
+ final RecipeEncoder rtiRecipeEncoder;
+
+ @override
final Tracer tracer;
@override
@@ -329,6 +334,6 @@
@override
final FixedNames fixedNames;
- CodegenInputsImpl(this.rtiSubstitutions, this.rtiEncoder, this.tracer,
- this.rtiTags, this.fixedNames);
+ CodegenInputsImpl(this.rtiSubstitutions, this.rtiEncoder,
+ this.rtiRecipeEncoder, this.tracer, this.rtiTags, this.fixedNames);
}
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 9f683b7..d80aa0a 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -101,7 +101,7 @@
_commonElements.getRuntimeTypeArgumentIntercepted,
_commonElements.getRuntimeTypeArgument,
_commonElements.getTypeArgumentByIndex,
- ]);
+ ], otherImpacts: newRtiImpacts('getRuntimeTypeArgument'));
}
BackendImpact _computeSignature;
@@ -189,7 +189,7 @@
BackendImpact get asCheck {
return _asCheck ??= new BackendImpact(staticUses: [
_commonElements.throwRuntimeError,
- ], otherImpacts: _newRti ? [usesNewRti] : []);
+ ], otherImpacts: newRtiImpacts('asCheck'));
}
BackendImpact _throwNoSuchMethod;
@@ -762,15 +762,16 @@
_commonElements.getInstantiationClass(typeArgumentCount),
]);
- BackendImpact _usesNewRti;
-
/// Backend impact for --experiment-new-rti.
- BackendImpact get usesNewRti {
- // TODO(sra): Can this be broken down into more selective impacts?
- return _usesNewRti ??= BackendImpact(staticUses: [
- _commonElements.findType,
- _commonElements.rtiEvalMethod,
- _commonElements.rtiBindMethod,
- ]);
+ List<BackendImpact> newRtiImpacts(String what) {
+ if (!_newRti) return [];
+ // TODO(sra): Split into refined impacts.
+ return [
+ BackendImpact(staticUses: [
+ _commonElements.findType,
+ _commonElements.rtiEvalMethod,
+ _commonElements.rtiBindMethod,
+ ])
+ ];
}
}
diff --git a/pkg/compiler/lib/src/js_backend/namer_names.dart b/pkg/compiler/lib/src/js_backend/namer_names.dart
index f405dc0..61d721a 100644
--- a/pkg/compiler/lib/src/js_backend/namer_names.dart
+++ b/pkg/compiler/lib/src/js_backend/namer_names.dart
@@ -140,6 +140,14 @@
CompoundName(this._parts);
+ // TODO(37302): Use
+ // CompoundName.from(List<jsAst.Name> parts) : this(<_NamerName>[...parts]);
+ CompoundName.from(List<jsAst.Name> parts) : _parts = [] {
+ for (var part in parts) {
+ _parts.add(part);
+ }
+ }
+
@override
String get name {
if (_cachedName == null) {
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
new file mode 100644
index 0000000..b75b178
--- /dev/null
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -0,0 +1,384 @@
+// Copyright (c) 2019, 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 js_backend.runtime_types_new;
+
+import 'package:js_runtime/shared/recipe_syntax.dart';
+
+import '../common_elements.dart' show JCommonElements, JElementEnvironment;
+import '../elements/entities.dart';
+import '../elements/types.dart';
+import '../js/js.dart' as jsAst;
+import '../js/js.dart' show js;
+import '../js_model/type_recipe.dart';
+import '../js_emitter/js_emitter.dart' show ModularEmitter;
+import '../universe/class_hierarchy.dart';
+import '../world.dart';
+import 'namer.dart';
+import 'native_data.dart';
+
+import 'runtime_types.dart' show RuntimeTypesNeed, RuntimeTypesSubstitutions;
+
+abstract class RecipeEncoder {
+ /// Returns a [jsAst.Expression] representing the given [recipe] to be
+ /// evaluated against a type environment with shape [structure].
+ jsAst.Expression encodeRecipe(ModularEmitter emitter,
+ TypeEnvironmentStructure environmentStructure, TypeRecipe recipe);
+
+ jsAst.Expression encodeGroundRecipe(
+ ModularEmitter emitter, TypeRecipe recipe);
+
+ // TODO(sra): Still need a $signature function when the function type is a
+ // function of closed type variables. See if the $signature method can always
+ // be generated through SSA in those cases.
+ jsAst.Expression encodeSignature(ModularNamer namer, ModularEmitter emitter,
+ DartType type, jsAst.Expression this_);
+}
+
+class RecipeEncoderImpl implements RecipeEncoder {
+ final JClosedWorld _closedWorld;
+ final RuntimeTypesSubstitutions _rtiSubstitutions;
+ final NativeBasicData _nativeData;
+ final JElementEnvironment _elementEnvironment;
+ final JCommonElements commonElements;
+ final RuntimeTypesNeed _rtiNeed;
+
+ RecipeEncoderImpl(this._closedWorld, this._rtiSubstitutions, this._nativeData,
+ this._elementEnvironment, this.commonElements, this._rtiNeed);
+
+ @override
+ jsAst.Expression encodeRecipe(ModularEmitter emitter,
+ TypeEnvironmentStructure environmentStructure, TypeRecipe recipe) {
+ return _RecipeGenerator(this, emitter, environmentStructure, recipe).run();
+ }
+
+ @override
+ jsAst.Expression encodeGroundRecipe(
+ ModularEmitter emitter, TypeRecipe recipe) {
+ return _RecipeGenerator(this, emitter, null, recipe).run();
+ }
+
+ @override
+ jsAst.Expression encodeSignature(ModularNamer namer, ModularEmitter emitter,
+ DartType type, jsAst.Expression this_) {
+ // TODO(sra): These inputs (referenced to quell lints) are used by the old
+ // rti signature generator. Do we need them?
+ _rtiNeed;
+ commonElements;
+ _elementEnvironment;
+ throw UnimplementedError('RecipeEncoderImpl.getSignatureEncoding');
+ }
+}
+
+class _RecipeGenerator implements DartTypeVisitor<void, void> {
+ final RecipeEncoderImpl _encoder;
+ final ModularEmitter _emitter;
+ final TypeEnvironmentStructure _environment;
+ final TypeRecipe _recipe;
+
+ final List<FunctionTypeVariable> functionTypeVariables = [];
+
+ // Accumulated recipe.
+ final List<jsAst.Literal> _fragments = [];
+ final List<int> _codes = [];
+
+ _RecipeGenerator(
+ this._encoder, this._emitter, this._environment, this._recipe);
+
+ JClosedWorld get _closedWorld => _encoder._closedWorld;
+ NativeBasicData get _nativeData => _encoder._nativeData;
+ RuntimeTypesSubstitutions get _rtiSubstitutions => _encoder._rtiSubstitutions;
+
+ jsAst.Expression run() {
+ _start(_recipe);
+ assert(functionTypeVariables.isEmpty);
+ if (_fragments.isEmpty) {
+ return js.string(String.fromCharCodes(_codes));
+ }
+ _flushCodes();
+ jsAst.LiteralString quote = jsAst.LiteralString('"');
+ // TODO(37302): Use [quote, ..._fragments, quote].
+ return jsAst.StringConcatenation(<jsAst.Literal>[quote]
+ ..addAll(_fragments)
+ ..add(quote));
+ }
+
+ void _start(TypeRecipe recipe) {
+ if (recipe is TypeExpressionRecipe) {
+ visit(recipe.type, null);
+ } else if (recipe is SingletonTypeEnvironmentRecipe) {
+ visit(recipe.type, null);
+ } else if (recipe is FullTypeEnvironmentRecipe) {
+ _startFullTypeEnvironmentRecipe(recipe, null);
+ }
+ }
+
+ void _startFullTypeEnvironmentRecipe(FullTypeEnvironmentRecipe recipe, _) {
+ if (recipe.classType == null) {
+ _emitCode(Recipe.pushDynamic);
+ assert(recipe.types.isNotEmpty);
+ } else {
+ visit(recipe.classType, null);
+ // TODO(sra): The separator can be omitted when the parser will have
+ // reduced to the top of stack to an Rti value.
+ _emitCode(Recipe.toType);
+ }
+
+ if (recipe.types.isNotEmpty) {
+ _emitCode(Recipe.startTypeArguments);
+ bool first = true;
+ for (DartType type in recipe.types) {
+ if (!first) {
+ _emitCode(Recipe.separator);
+ }
+ visit(type, _);
+ first = false;
+ }
+ _emitCode(Recipe.endTypeArguments);
+ }
+ }
+
+ void _emitCode(int code) {
+ // TODO(sra): We should permit codes with short escapes (like '\n') for
+ // infrequent operators.
+ assert(code >= 0x20 && code <= 0x7E && code != 0x22);
+ _codes.add(code);
+ }
+
+ void _flushCodes() {
+ if (_codes.isEmpty) return;
+ // TODO(sra): codes need some escaping.
+ _fragments.add(StringBackedName(String.fromCharCodes(_codes)));
+ _codes.clear();
+ }
+
+ void _emitInteger(int value) {
+ if (_codes.isEmpty ? _fragments.isNotEmpty : Recipe.isDigit(_codes.last)) {
+ _emitCode(Recipe.separator);
+ }
+ _emitStringUnescaped('$value');
+ }
+
+ void _emitStringUnescaped(String string) {
+ for (int code in string.codeUnits) {
+ _emitCode(code);
+ }
+ }
+
+ void _emitName(jsAst.Name name) {
+ if (_fragments.isNotEmpty && _codes.isEmpty) {
+ _emitCode(Recipe.separator);
+ }
+ _flushCodes();
+ _fragments.add(name);
+ }
+
+ void _emitExtensionOp(int value) {
+ _emitInteger(value);
+ _emitCode(Recipe.extensionOp);
+ }
+
+ @override
+ void visit(DartType type, _) => type.accept(this, _);
+
+ @override
+ void visitTypeVariableType(TypeVariableType type, _) {
+ TypeEnvironmentStructure environment = _environment;
+ if (environment is SingletonTypeEnvironmentStructure) {
+ if (type == environment.variable) {
+ _emitInteger(0);
+ return;
+ }
+ }
+ if (environment is FullTypeEnvironmentStructure) {
+ int i = environment.bindings.indexOf(type);
+ if (i >= 0) {
+ // Indexes are 1-based since '0' encodes using the entire type for the
+ // singleton structure.
+ _emitInteger(i + 1);
+ return;
+ }
+
+ int index = _indexIntoClassTypeVariables(type);
+ if (index != null) {
+ // Indexed class type variables come after the bound function type
+ // variables.
+ _emitInteger(1 + environment.bindings.length + index);
+ return;
+ }
+ // TODO(sra): Encode type variables names via namer.
+ }
+ // TODO(sra): Handle missing cases. This just emits some readable junk. The
+ // backticks ensure it won't parse at runtime.
+ '`$type`'.codeUnits.forEach(_emitCode);
+ }
+
+ int /*?*/ _indexIntoClassTypeVariables(TypeVariableType variable) {
+ TypeVariableEntity element = variable.element;
+ ClassEntity cls = element.typeDeclaration;
+
+ // TODO(sra): We might be in a context where the class type variable has an
+ // index, even though in the general case it is not at a specific index.
+
+ if (_closedWorld.isUsedAsMixin(cls)) return null;
+
+ ClassHierarchy classHierarchy = _closedWorld.classHierarchy;
+ if (classHierarchy.anyStrictSubclassOf(cls, (ClassEntity subclass) {
+ return !_rtiSubstitutions.isTrivialSubstitution(subclass, cls);
+ })) {
+ return null;
+ }
+ return element.index;
+ }
+
+ @override
+ void visitFunctionTypeVariable(FunctionTypeVariable type, _) {
+ int position = functionTypeVariables.indexOf(type);
+ assert(position >= 0);
+ // See [visitFunctionType] for explanation.
+ _emitInteger(functionTypeVariables.length - position - 1);
+ _emitCode(Recipe.genericFunctionTypeParameterIndex);
+ }
+
+ @override
+ void visitDynamicType(DynamicType type, _) {
+ _emitCode(Recipe.pushDynamic);
+ }
+
+ @override
+ void visitInterfaceType(InterfaceType type, _) {
+ jsAst.Name name = _emitter.typeAccessNewRti(type.element);
+ if (type.typeArguments.isEmpty) {
+ // Push the name, which is later converted by an implicit toType
+ // operation.
+ _emitName(name);
+ } else {
+ _emitName(name);
+ _emitCode(Recipe.startTypeArguments);
+ bool first = true;
+ for (DartType argumentType in type.typeArguments) {
+ if (!first) {
+ _emitCode(Recipe.separator);
+ }
+ if (_nativeData.isJsInteropClass(type.element)) {
+ // Emit 'any' type.
+ _emitExtensionOp(Recipe.pushAnyExtension);
+ } else {
+ visit(argumentType, _);
+ }
+ first = false;
+ }
+ _emitCode(Recipe.endTypeArguments);
+ }
+ }
+
+ @override
+ void visitFunctionType(FunctionType type, _) {
+ if (type.typeVariables.isNotEmpty) {
+ // Enter generic function scope.
+ //
+ // Function type variables are encoded as a modified de Bruin index. We
+ // count variables from the current scope outwards, counting the variables
+ // in the same scope left-to-right.
+ //
+ // If we push the current scope's variables in reverse, then the index is
+ // the position measured from the end.
+ //
+ // foo<AA,BB>() => ...
+ // //^0 ^1
+ // functionTypeVariables: [BB,AA]
+ //
+ // foo<AA,BB>() => <UU,VV,WW>() => ...
+ // ^3 ^4 ^0 ^1 ^2
+ // functionTypeVariables: [BB,AA,WW,VV,UU]
+ //
+ for (FunctionTypeVariable variable in type.typeVariables.reversed) {
+ functionTypeVariables.add(variable);
+ }
+ }
+
+ visit(type.returnType, _);
+ _emitCode(Recipe.startFunctionArguments);
+
+ bool first = true;
+ for (DartType parameterType in type.parameterTypes) {
+ if (!first) {
+ _emitCode(Recipe.separator);
+ }
+ visit(parameterType, _);
+ first = false;
+ }
+
+ if (type.optionalParameterTypes.isNotEmpty) {
+ first = true;
+ _emitCode(Recipe.startOptionalGroup);
+ for (DartType parameterType in type.optionalParameterTypes) {
+ if (!first) {
+ _emitCode(Recipe.separator);
+ }
+ visit(parameterType, _);
+ first = false;
+ }
+ _emitCode(Recipe.endOptionalGroup);
+ }
+
+ void emitNamedGroup(List<String> names, List<DartType> types) {
+ assert(names.length == types.length);
+ first = true;
+ _emitCode(Recipe.startNamedGroup);
+ for (int i = 0; i < names.length; i++) {
+ if (!first) {
+ _emitCode(Recipe.separator);
+ }
+ _emitStringUnescaped(names[i]);
+ _emitCode(Recipe.nameSeparator);
+ visit(types[i], _);
+ first = false;
+ }
+ _emitCode(Recipe.endNamedGroup);
+ }
+
+ // TODO(sra): These are optional named parameters. Handle required named
+ // parameters the same way when they are implemented.
+ if (type.namedParameterTypes.isNotEmpty) {
+ emitNamedGroup(type.namedParameters, type.namedParameterTypes);
+ }
+
+ _emitCode(Recipe.endFunctionArguments);
+
+ // Emit generic type bounds.
+ if (type.typeVariables.isNotEmpty) {
+ bool first = true;
+ _emitCode(Recipe.startTypeArguments);
+ for (FunctionTypeVariable typeVariable in type.typeVariables) {
+ if (!first) {
+ _emitCode(Recipe.separator);
+ }
+ visit(typeVariable.bound, _);
+ }
+ _emitCode(Recipe.endTypeArguments);
+ }
+
+ if (type.typeVariables.isNotEmpty) {
+ // Exit generic function scope. Remove the type variables pushed at entry.
+ functionTypeVariables.length -= type.typeVariables.length;
+ }
+ }
+
+ @override
+ void visitVoidType(VoidType type, _) {
+ _emitCode(Recipe.pushVoid);
+ }
+
+ @override
+ void visitTypedefType(TypedefType type, _) {
+ visit(type.unaliased, _);
+ }
+
+ @override
+ void visitFutureOrType(FutureOrType type, _) {
+ visit(type.typeArgument, _);
+ _emitCode(Recipe.wrapFutureOr);
+ }
+}
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index c9b0ec1..5d3408b 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -179,6 +179,9 @@
/// Returns the JS expression representing the type [e].
jsAst.Expression typeAccess(Entity e);
+ /// Returns the JS name representing the type [e].
+ jsAst.Name typeAccessNewRti(Entity e);
+
/// Returns the JS code for accessing the embedded [global].
jsAst.Expression generateEmbeddedGlobalAccess(String global);
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index c664a0f..d5ad70d 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -86,6 +86,11 @@
}
@override
+ js.Name typeAccessNewRti(Entity element) {
+ return _namer.globalPropertyNameForType(element);
+ }
+
+ @override
js.Expression staticClosureAccess(FunctionEntity element) {
return new js.Call(
new js.PropertyAccess(_namer.readGlobalObjectForMember(element),
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 2c0c686..f794857 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -34,6 +34,8 @@
import '../js_backend/interceptor_data.dart';
import '../js_backend/namer.dart';
import '../js_backend/runtime_types.dart';
+import '../js_backend/runtime_types_new.dart'
+ show RecipeEncoder, RecipeEncoderImpl;
import '../js_emitter/code_emitter_task.dart' show ModularEmitter;
import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
import '../js/js.dart' as js;
@@ -202,6 +204,7 @@
closedWorld.elementEnvironment,
closedWorld.commonElements,
closedWorld.rtiNeed);
+
RuntimeTypesSubstitutions rtiSubstitutions;
if (_compiler.options.disableRtiOptimization) {
rtiSubstitutions = new TrivialRuntimeTypesSubstitutions(closedWorld);
@@ -213,8 +216,18 @@
rtiSubstitutions = runtimeTypesImpl;
}
- CodegenInputs codegen = new CodegenInputsImpl(
- rtiSubstitutions, rtiEncoder, tracer, rtiTags, fixedNames);
+ RecipeEncoder rtiRecipeEncoder = _compiler.options.experimentNewRti
+ ? new RecipeEncoderImpl(
+ closedWorld,
+ rtiSubstitutions,
+ closedWorld.nativeData,
+ closedWorld.elementEnvironment,
+ closedWorld.commonElements,
+ closedWorld.rtiNeed)
+ : null;
+
+ CodegenInputs codegen = new CodegenInputsImpl(rtiSubstitutions, rtiEncoder,
+ rtiRecipeEncoder, tracer, rtiTags, fixedNames);
functionCompiler.initialize(globalTypeInferenceResults, codegen);
return codegen;
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index a80a7a6..6e81b1c 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -26,8 +26,10 @@
import '../js_backend/native_data.dart';
import '../js_backend/namer.dart' show ModularNamer;
import '../js_backend/runtime_types.dart';
+import '../js_backend/runtime_types_new.dart' show RecipeEncoder;
import '../js_emitter/code_emitter_task.dart' show ModularEmitter;
import '../js_model/elements.dart' show JGeneratorBody;
+import '../js_model/type_recipe.dart' show TypeExpressionRecipe;
import '../native/behavior.dart';
import '../options.dart';
import '../tracer.dart';
@@ -114,6 +116,7 @@
codegen.checkedModeHelpers,
codegen.rtiSubstitutions,
codegen.rtiEncoder,
+ codegen.rtiRecipeEncoder,
namer,
codegen.tracer,
closedWorld,
@@ -143,6 +146,7 @@
codegen.checkedModeHelpers,
codegen.rtiSubstitutions,
codegen.rtiEncoder,
+ codegen.rtiRecipeEncoder,
namer,
codegen.tracer,
closedWorld,
@@ -180,6 +184,7 @@
final CheckedModeHelpers _checkedModeHelpers;
final RuntimeTypesSubstitutions _rtiSubstitutions;
final RuntimeTypesEncoder _rtiEncoder;
+ final RecipeEncoder _rtiRecipeEncoder;
final ModularNamer _namer;
final Tracer _tracer;
final JClosedWorld _closedWorld;
@@ -234,6 +239,7 @@
this._checkedModeHelpers,
this._rtiSubstitutions,
this._rtiEncoder,
+ this._rtiRecipeEncoder,
this._namer,
this._tracer,
this._closedWorld,
@@ -3372,8 +3378,8 @@
FunctionEntity helperElement = _commonElements.findType;
_registry.registerStaticUse(
new StaticUse.staticInvoke(helperElement, CallStructure.ONE_ARG));
- // TODO(sra): Encode recipe.
- js.Expression recipe = js.string('${node.typeExpression}');
+ js.Expression recipe = _rtiRecipeEncoder.encodeGroundRecipe(
+ _emitter, TypeExpressionRecipe(node.typeExpression));
js.Expression helper = _emitter.staticFunctionAccess(helperElement);
push(js.js(r'#(#)', [helper, recipe]).withSourceInformation(
node.sourceInformation));
@@ -3384,8 +3390,8 @@
// Call `env._eval("recipe")`.
use(node.inputs[0]);
js.Expression environment = pop();
- // TODO(sra): Encode recipe.
- js.Expression recipe = js.string('${node.typeExpression}');
+ js.Expression recipe = _rtiRecipeEncoder.encodeRecipe(
+ _emitter, node.envStructure, node.typeExpression);
MemberEntity method = _commonElements.rtiEvalMethod;
Selector selector = Selector.fromElement(method);
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index 906f4a6..5396d8a 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -741,7 +741,7 @@
} else {
i++;
switch (ch) {
- case Recipe.noOp:
+ case Recipe.separator:
break;
case Recipe.toType:
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart b/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
index 78d0975..361652d 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
@@ -12,18 +12,33 @@
// Operators.
- static const int noOp = _comma;
+ static const int separator = _comma;
static const int toType = _semicolon;
static const int pushDynamic = _at;
static const int pushVoid = _tilde;
- static const int wrapFutureOr = _formfeed;
+
+ static const int wrapStar = _asterisk;
+ static const int wrapQuestion = _question;
+ static const int wrapFutureOr = _slash;
static const int startTypeArguments = _lessThan;
static const int endTypeArguments = _greaterThan;
+ static const int startFunctionArguments = _leftParen;
+ static const int endFunctionArguments = _rightParen;
+ static const int startOptionalGroup = _leftBracket;
+ static const int endOptionalGroup = _rightBracket;
+ static const int startNamedGroup = _leftBrace;
+ static const int endNamedGroup = _rightBrace;
+ static const int nameSeparator = _colon;
+
+ static const int genericFunctionTypeParameterIndex = _circumflex;
+
static const int extensionOp = _ampersand;
+ static const int pushNeverExtension = 0;
+ static const int pushAnyExtension = 1;
// Number and name components.
@@ -41,27 +56,48 @@
static const int _formfeed = 0x0C; // '\f' in string literal.
+ static const int _space = 0x20;
+ static const int _exclamation = 0x21;
+ static const int _hash = 0x23;
static const int _dollar = 0x24;
+ static const int _percent = 0x25;
static const int _ampersand = 0x26;
- static const int _plus = 0x2B;
- static const int _comma = 0x2C;
- static const int _period = 0x2E;
- static const int _digit0 = 0x30;
- static const int _digit9 = 0x39;
- static const int _semicolon = 0x3B;
- static const int _lessThan = 0x3C;
- static const int _greaterThan = 0x3E;
- static const int _question = 0x3f;
- static const int _at = 0x40;
-
- static const int _underscore = 0x5F;
- static const int _lowercaseA = 0x61;
- static const int _tilde = 0x7E;
-
+ static const int _apostrophe = 0x27;
static const int _leftParen = 0x28;
static const int _rightParen = 0x29;
+ static const int _asterisk = 0x2A;
+ static const int _plus = 0x2B;
+ static const int _comma = 0x2C;
+ static const int _minus = 0x2D;
+ static const int _period = 0x2E;
+ static const int _slash = 0x2F;
+
+ static const int _digit0 = 0x30;
+ static const int _digit9 = 0x39;
+
+ static const int _colon = 0x3A;
+ static const int _semicolon = 0x3B;
+ static const int _lessThan = 0x3C;
+ static const int _equals = 0x3D;
+ static const int _greaterThan = 0x3E;
+ static const int _question = 0x3F;
+ static const int _at = 0x40;
+
+ static const int _uppercaseA = 0x41;
+ static const int _uppercaseZ = 0x5A;
+
static const int _leftBracket = 0x5B;
+ static const int _backslash = 0x5C;
static const int _rightBracket = 0x5D;
+ static const int _circumflex = 0x5E;
+ static const int _underscore = 0x5F;
+ static const int _backtick = 0x60;
+
+ static const int _lowercaseA = 0x61;
+ static const int _lowercaseZ = 0x7A;
+
static const int _leftBrace = 0x7B;
+ static const int _vertical = 0x7C;
static const int _rightBrace = 0x7D;
+ static const int _tilde = 0x7E;
}