mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 10:48:25 +00:00
[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:
parent
bd179a2660
commit
3619d26f70
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue