[dart2js] Emit code for checks

Emit as-casts and type-checks.

The recipes and environments are dummy values, and there is no
propagation of type information, so the code is pretty terrible.

Change-Id: Iea8b7d7dddd4538187d88f12e9ed81439f74d0e1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106428
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
This commit is contained in:
Stephen Adams 2019-06-18 02:38:18 +00:00 committed by commit-bot@chromium.org
parent bd179a2660
commit 3619d26f70
9 changed files with 165 additions and 13 deletions

View file

@ -98,6 +98,9 @@ abstract class CommonElements {
/// The dart:_foreign_helper library.
LibraryEntity get foreignLibrary;
/// The dart:_internal library.
LibraryEntity get rtiLibrary;
/// The dart:_internal library.
LibraryEntity get internalLibrary;
@ -475,6 +478,15 @@ abstract class CommonElements {
FunctionEntity get extractFunctionTypeObjectFromInternal;
// From dart:_rti
FunctionEntity get findType;
FieldEntity get rtiAsField;
FieldEntity get rtiCheckField;
FieldEntity get rtiIsField;
FunctionEntity get rtiEvalMethod;
FunctionEntity get rtiBindMethod;
// From dart:_internal
ClassEntity get symbolImplementationClass;
@ -729,6 +741,11 @@ class CommonElementsImpl
LibraryEntity get foreignLibrary =>
_foreignLibrary ??= _env.lookupLibrary(Uris.dart__foreign_helper);
LibraryEntity _rtiLibrary;
@override
LibraryEntity get rtiLibrary =>
_rtiLibrary ??= _env.lookupLibrary(Uris.dart__rti, required: true);
/// Reference to the internal library to lookup functions to always inline.
LibraryEntity _internalLibrary;
@override
@ -1785,6 +1802,42 @@ class CommonElementsImpl
cls.name.startsWith('Instantiation');
}
// From dart:_rti
FunctionEntity _findRtiFunction(String name) =>
_findLibraryMember(rtiLibrary, name);
FunctionEntity _findType;
@override
FunctionEntity get findType => _findType ??= _findRtiFunction('findType');
ClassEntity get _rtiImplClass => _findClass(rtiLibrary, 'Rti');
FieldEntity _findRtiClassField(String name) =>
_findClassMember(_rtiImplClass, name);
FieldEntity _rtiAsField;
@override
FieldEntity get rtiAsField => _rtiAsField ??= _findRtiClassField('_as');
FieldEntity _rtiIsField;
@override
FieldEntity get rtiIsField => _rtiIsField ??= _findRtiClassField('_is');
FieldEntity _rtiCheckField;
@override
FieldEntity get rtiCheckField =>
_rtiCheckField ??= _findRtiClassField('_check');
FunctionEntity _rtiEvalMethod;
@override
FunctionEntity get rtiEvalMethod =>
_rtiEvalMethod ??= _findClassMember(_rtiImplClass, '_eval');
FunctionEntity _rtiBindMethod;
@override
FunctionEntity get rtiBindMethod =>
_rtiBindMethod ??= _findClassMember(_rtiImplClass, '_bind');
// From dart:_internal
ClassEntity _symbolImplementationClass;

View file

@ -90,8 +90,9 @@ class BackendImpact {
/// The JavaScript backend dependencies for various features.
class BackendImpacts {
final CommonElements _commonElements;
final bool _newRti;
BackendImpacts(this._commonElements);
BackendImpacts(this._commonElements, this._newRti);
BackendImpact _getRuntimeTypeArgument;
@ -110,7 +111,7 @@ class BackendImpacts {
_commonElements.setRuntimeTypeInfo,
_commonElements.getRuntimeTypeInfo,
_commonElements.computeSignature,
_commonElements.getRuntimeTypeArguments
_commonElements.getRuntimeTypeArguments,
], otherImpacts: [
listValues
]);
@ -186,8 +187,9 @@ class BackendImpacts {
BackendImpact _asCheck;
BackendImpact get asCheck {
return _asCheck ??=
new BackendImpact(staticUses: [_commonElements.throwRuntimeError]);
return _asCheck ??= new BackendImpact(staticUses: [
_commonElements.throwRuntimeError,
], otherImpacts: _newRti ? [usesNewRti] : []);
}
BackendImpact _throwNoSuchMethod;
@ -759,4 +761,16 @@ class BackendImpacts {
], instantiatedClasses: [
_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,
]);
}
}

View file

@ -237,7 +237,8 @@ class JsBackendStrategy implements BackendStrategy {
globalInferenceResults, codegen, oneShotInterceptorData);
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
CommonElements commonElements = closedWorld.commonElements;
BackendImpacts impacts = new BackendImpacts(commonElements);
BackendImpacts impacts =
new BackendImpacts(commonElements, _compiler.options.experimentNewRti);
_customElementsCodegenAnalysis = new CustomElementsCodegenAnalysis(
commonElements, elementEnvironment, closedWorld.nativeData);
return new CodegenEnqueuer(
@ -290,7 +291,8 @@ class JsBackendStrategy implements BackendStrategy {
emitterTask.createEmitter(_namer, codegen, closedWorld);
// TODO(johnniwinther): Share the impact object created in
// createCodegenEnqueuer.
BackendImpacts impacts = new BackendImpacts(closedWorld.commonElements);
BackendImpacts impacts = new BackendImpacts(
closedWorld.commonElements, _compiler.options.experimentNewRti);
_codegenImpactTransformer = new CodegenImpactTransformer(
_compiler.options,

View file

@ -140,7 +140,8 @@ class KernelFrontendStrategy extends FrontendStrategy {
ResolutionEnqueuer createResolutionEnqueuer(
CompilerTask task, Compiler compiler) {
RuntimeTypesNeedBuilder rtiNeedBuilder = _createRuntimeTypesNeedBuilder();
BackendImpacts impacts = new BackendImpacts(commonElements);
BackendImpacts impacts =
new BackendImpacts(commonElements, compiler.options.experimentNewRti);
_nativeResolutionEnqueuer = new NativeResolutionEnqueuer(
compiler.options,
elementEnvironment,

View file

@ -696,6 +696,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
if (instruction is HCheck) {
if (instruction is HTypeConversion ||
instruction is HPrimitiveCheck ||
instruction is HAsCheck ||
instruction is HBoolConversion) {
String inputName = variableNames.getName(instruction.checkedInput);
if (variableNames.getName(instruction) == inputName) {
@ -3333,12 +3334,32 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
@override
visitIsTest(HIsTest node) {
throw UnimplementedError('SsaCodeGenerator.visitIsTest $node');
use(node.typeInput);
js.Expression first = pop();
use(node.checkedInput);
js.Expression second = pop();
FieldEntity field = _commonElements.rtiIsField;
js.Name name = _namer.instanceFieldPropertyName(field);
push(js.js('#.#(#)', [first, name, second]).withSourceInformation(
node.sourceInformation));
}
@override
visitAsCheck(HAsCheck node) {
throw UnimplementedError('SsaCodeGenerator.visitAsCheck $node');
use(node.typeInput);
js.Expression first = pop();
use(node.checkedInput);
js.Expression second = pop();
FieldEntity field = node.isTypeError
? _commonElements.rtiCheckField
: _commonElements.rtiAsField;
js.Name name = _namer.instanceFieldPropertyName(field);
push(js.js('#.#(#)', [first, name, second]).withSourceInformation(
node.sourceInformation));
}
@override
@ -3348,16 +3369,56 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
@override
visitLoadType(HLoadType node) {
throw UnimplementedError('SsaCodeGenerator.visitLoadType $node');
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 helper = _emitter.staticFunctionAccess(helperElement);
push(js.js(r'#(#)', [helper, recipe]).withSourceInformation(
node.sourceInformation));
}
@override
visitTypeEval(HTypeEval node) {
throw UnimplementedError('SsaCodeGenerator.visitTypeEval $node');
// Call `env._eval("recipe")`.
use(node.inputs[0]);
js.Expression environment = pop();
// TODO(sra): Encode recipe.
js.Expression recipe = js.string('${node.typeExpression}');
MemberEntity method = _commonElements.rtiEvalMethod;
Selector selector = Selector.fromElement(method);
js.Name methodLiteral = _namer.invocationName(selector);
push(js.js('#.#(#)', [
environment,
methodLiteral,
recipe
]).withSourceInformation(node.sourceInformation));
_registry.registerStaticUse(
new StaticUse.directInvoke(method, selector.callStructure, null));
}
@override
visitTypeBind(HTypeBind node) {
throw UnimplementedError('SsaCodeGenerator.visitTypeBind $node');
// Call `env1._bind(env2)`.
assert(node.inputs.length == 2);
use(node.inputs[0]);
js.Expression environment = pop();
use(node.inputs[1]);
js.Expression extensions = pop();
MemberEntity method = _commonElements.rtiEvalMethod;
Selector selector = Selector.fromElement(method);
js.Name methodLiteral = _namer.invocationName(selector);
push(js.js('#.#(#)', [
environment,
methodLiteral,
extensions
]).withSourceInformation(node.sourceInformation));
_registry.registerStaticUse(
new StaticUse.directInvoke(method, selector.callStructure, null));
}
}

View file

@ -754,6 +754,20 @@ class SsaInstructionMerger extends HBaseVisitor with CodegenPhase {
visitInstruction(instruction);
}
@override
void visitAsCheck(HAsCheck instruction) {
// Type checks and cast checks compile to code that only use their input
// once, so we can safely visit them and try to merge the input.
visitInstruction(instruction);
}
@override
void visitTypeEval(HTypeEval instruction) {
// Type expressions compile to code that only use their input once, so we
// can safely visit them and try to merge the input.
visitInstruction(instruction);
}
@override
void visitPrimitiveCheck(HPrimitiveCheck instruction) {}

View file

@ -4382,6 +4382,9 @@ class HAsCheck extends HCheck {
@override
HInstruction get checkedInput => inputs[1];
@override
bool isJsStatement() => false;
@override
accept(HVisitor visitor) => visitor.visitAsCheck(this);

View file

@ -353,6 +353,10 @@ abstract class TypeBuilder {
if (type == null) return original;
type = type.unaliased;
if (type.isDynamic) return original;
if (type.isVoid) return original;
if (type == _closedWorld.commonElements.objectType) return original;
HInstruction reifiedType =
analyzeTypeArgumentNewRti(type, builder.sourceElement);
if (type is InterfaceType) {

View file

@ -223,7 +223,7 @@ Rti _rtiBind(Rti environment, Rti types) {
/// Evaluate a ground-term type.
/// Called from generated code.
Rti rtiTypeEval(String recipe) {
Rti findType(String recipe) {
_Universe.eval(_theUniverse(), recipe);
}