Add classes for instantiations

Change-Id: Iee9df3ad673012776cd1867448ff12ba692a863f
Reviewed-on: https://dart-review.googlesource.com/41564
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Stephen Adams 2018-03-03 00:50:59 +00:00 committed by commit-bot@chromium.org
parent cae6d89429
commit 8e8287f4e0
15 changed files with 274 additions and 9 deletions

View file

@ -1068,6 +1068,13 @@ class CommonElements {
FunctionEntity get hashCodeForNativeObject =>
_findHelperFunction('hashCodeForNativeObject');
ClassEntity get instantiation1Class => _findHelperClass('Instantiation1');
ClassEntity get instantiation2Class => _findHelperClass('Instantiation2');
ClassEntity get instantiation3Class => _findHelperClass('Instantiation3');
FunctionEntity get instantiate1 => _findHelperFunction('instantiate1');
FunctionEntity get instantiate2 => _findHelperFunction('instantiate2');
FunctionEntity get instantiate3 => _findHelperFunction('instantiate3');
// From dart:_internal
ClassEntity _symbolImplementationClass;

View file

@ -786,4 +786,17 @@ class BackendImpacts {
_commonElements.typeVariableClass
]);
}
BackendImpact _genericInstantiation;
BackendImpact get genericInstantiation =>
_genericInstantiation ??= new BackendImpact(staticUses: [
_commonElements.instantiate1,
_commonElements.instantiate2,
_commonElements.instantiate3,
], instantiatedClasses: [
_commonElements.instantiation1Class,
_commonElements.instantiation2Class,
_commonElements.instantiation3Class,
]);
}

View file

@ -108,6 +108,9 @@ class JavaScriptImpactTransformer extends ImpactTransformer {
new TypeUse.instantiation(_commonElements.nullType));
registerImpact(_impacts.nullLiteral);
break;
case Feature.GENERIC_INSTANTIATION:
registerImpact(_impacts.genericInstantiation);
break;
case Feature.LAZY_FIELD:
registerImpact(_impacts.lazyField);
break;

View file

@ -0,0 +1,140 @@
// Copyright (c) 2018, 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 dart2js.js_emitter.instantiation_stub_generator;
import '../elements/entities.dart';
import '../io/source_information.dart';
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
import '../js_backend/namer.dart' show Namer;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/world_builder.dart'
show CodegenWorldBuilder, SelectorConstraints;
import '../world.dart' show ClosedWorld;
import 'model.dart';
import 'code_emitter_task.dart' show CodeEmitterTask;
// Generator of stubs required for Instantiation classes.
class InstantiationStubGenerator {
// ignore: UNUSED_FIELD
final CodeEmitterTask _emitterTask;
final Namer _namer;
final CodegenWorldBuilder _codegenWorldBuilder;
final ClosedWorld _closedWorld;
// ignore: UNUSED_FIELD
final SourceInformationStrategy _sourceInformationStrategy;
InstantiationStubGenerator(
this._emitterTask,
this._namer,
this._codegenWorldBuilder,
this._closedWorld,
this._sourceInformationStrategy);
/// Generates a stub to forward a call selector with no type arguments to a
/// call selector with stored types.
///
/// [instantiationClass] is the class containing the captured type arguments.
/// [callSelector] is the selector with no type arguments. [targetSelector] is
/// the selector accepting the type arguments.
ParameterStubMethod _generateStub(
ClassEntity instantiationClass,
FieldEntity functionField,
Selector callSelector,
Selector targetSelector) {
// TODO(sra): Generate source information for stub that has no member.
//
//SourceInformationBuilder sourceInformationBuilder =
// _sourceInformationStrategy.createBuilderForContext(member);
//SourceInformation sourceInformation =
// sourceInformationBuilder.buildStub(member, callStructure);
assert(callSelector.typeArgumentCount == 0);
int typeArgumentCount = targetSelector.typeArgumentCount;
assert(typeArgumentCount > 0);
// The forwarding stub for three arguments of an instantiation with two type
// arguments looks like this:
//
// ```
// call$3: function(a0, a1, a2) {
// return this._f.call$2$3(a0, a1, a2, this.$ti[0], this.$ti[1]);
// }
// ```
List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
List<jsAst.Expression> arguments = <jsAst.Expression>[];
for (int i = 0; i < callSelector.argumentCount; i++) {
String jsName = 'a$i';
arguments.add(js('#', jsName));
parameters.add(new jsAst.Parameter(jsName));
}
for (int i = 0; i < targetSelector.typeArgumentCount; i++) {
arguments.add(js('this.#[#]', [_namer.rtiFieldJsName, js.number(i)]));
}
jsAst.Fun function = js('function(#) { return this.#.#(#); }', [
parameters,
_namer.fieldPropertyName(functionField),
_namer.invocationName(targetSelector),
arguments,
]);
// TODO(sra): .withSourceInformation(sourceInformation);
jsAst.Name name = _namer.invocationName(callSelector);
return new ParameterStubMethod(name, null, function);
}
// Returns all stubs for an instantiation class.
//
List<StubMethod> generateStubs(
ClassEntity instantiationClass, FunctionEntity member) {
// 1. Find the number of type parameters in [instantiationClass].
int typeArgumentCount = _closedWorld.dartTypes
.getThisType(instantiationClass)
.typeArguments
.length;
assert(typeArgumentCount > 0);
// 2. Find the function field access path.
FieldEntity functionField;
_codegenWorldBuilder.forEachInstanceField(instantiationClass,
(ClassEntity enclosing, FieldEntity field) {
if (field.name == '_genericClosure') functionField = field;
});
assert(functionField != null,
"Can't find Closure field of $instantiationClass");
String call = _namer.closureInvocationSelectorName;
Map<Selector, SelectorConstraints> callSelectors =
_codegenWorldBuilder.invocationsByName(call);
List<StubMethod> stubs = <StubMethod>[];
// For every call-selector generate a stub to the corresponding selector
// with filled-in type arguments.
for (Selector selector in callSelectors.keys) {
CallStructure callStructure = selector.callStructure;
if (callStructure.typeArgumentCount != 0) continue;
CallStructure genericCallStructrure =
callStructure.withTypeArgumentCount(typeArgumentCount);
Selector genericSelector =
new Selector.call(selector.memberName, genericCallStructrure);
stubs.add(_generateStub(
instantiationClass, functionField, selector, genericSelector));
}
// TODO(sra): Generate $signature() stub that forwards to
// $instantiatedSignature() method of _f.
return stubs;
}
}

View file

@ -6,6 +6,7 @@ library dart2js.js_emitter;
export 'class_stub_generator.dart';
export 'code_emitter_task.dart';
export 'instantiation_stub_generator.dart';
export 'interceptor_stub_generator.dart';
export 'main_call_stub_generator.dart';
export 'metadata_collector.dart';

View file

@ -45,6 +45,7 @@ import '../js_emitter.dart'
ClassStubGenerator,
CodeEmitterTask,
Emitter,
InstantiationStubGenerator,
InterceptorStubGenerator,
MainCallStubGenerator,
ParameterStubGenerator,
@ -733,6 +734,12 @@ class ProgramBuilder {
callStubs.add(_buildStubMethod(name, function));
}
if (cls == _commonElements.instantiation1Class ||
cls == _commonElements.instantiation2Class ||
cls == _commonElements.instantiation3Class) {
callStubs.addAll(_generateInstantiationStubs(cls));
}
// MixinApplications run through the members of their mixin. Here, we are
// only interested in direct members.
if (!onlyForRti && !_elementEnvironment.isMixinApplication(cls)) {
@ -979,6 +986,12 @@ class ProgramBuilder {
return generator.generateParameterStubs(element, canTearOff: canTearOff);
}
List<StubMethod> _generateInstantiationStubs(ClassEntity instantiationClass) {
InstantiationStubGenerator generator = new InstantiationStubGenerator(
_task, _namer, _worldBuilder, _closedWorld, _sourceInformationStrategy);
return generator.generateStubs(instantiationClass, null);
}
/// Builds a stub method.
///
/// Stub methods may have an element that can be used for code-size

View file

@ -3990,10 +3990,33 @@ class KernelSsaGraphBuilder extends ir.Visitor
_elementMap.getDartType(type), sourceElement);
arguments.add(instruction);
}
Selector selector =
new Selector.genericInstantiation(node.typeArguments.length);
_pushDynamicInvocation(node, commonMasks.functionType, selector, arguments,
const <DartType>[], null /*_sourceInformationBuilder.?*/);
int typeArgumentCount = node.typeArguments.length;
bool targetCanThrow = false; // TODO(sra): Is this true?
FunctionEntity target = _instantiator(typeArgumentCount);
if (target == null) {
reporter.internalError(
_elementMap.getSpannable(targetElement, node),
'Generic function instantiation not implemented for '
'${typeArgumentCount} type arguments');
stack.add(graph.addConstantNull(closedWorld));
return;
}
HInstruction instruction = new HInvokeStatic(
target, arguments, commonMasks.functionType, <DartType>[],
targetCanThrow: targetCanThrow);
// TODO(sra): ..sourceInformation = sourceInformation
instruction.sideEffects
..clearAllDependencies()
..clearAllSideEffects();
push(instruction);
}
FunctionEntity _instantiator(int count) {
if (count == 1) return _commonElements.instantiate1;
if (count == 2) return _commonElements.instantiate2;
if (count == 3) return _commonElements.instantiate3;
return null;
}
@override

View file

@ -538,6 +538,12 @@ class KernelImpactBuilder extends ir.Visitor {
visitNode(node.message);
}
@override
void visitInstantiation(ir.Instantiation node) {
impactBuilder.registerFeature(Feature.GENERIC_INSTANTIATION);
node.visitChildren(this);
}
@override
void visitStringConcatenation(ir.StringConcatenation node) {
impactBuilder.registerFeature(Feature.STRING_INTERPOLATION);

View file

@ -42,6 +42,9 @@ class CallStructure {
argumentCount, namedArguments, typeArgumentCount);
}
CallStructure withTypeArgumentCount(int typeArgumentCount) =>
new CallStructure(argumentCount, namedArguments, typeArgumentCount);
/// `true` if this call has named arguments.
bool get isNamed => false;

View file

@ -43,6 +43,9 @@ enum Feature {
/// A field without an initializer.
FIELD_WITHOUT_INITIALIZER,
/// A generic instantiation (application of type parameters).
GENERIC_INSTANTIATION,
/// A local variable without an initializer.
LOCAL_WITHOUT_INITIALIZER,

View file

@ -185,6 +185,7 @@ class Selector {
factory Selector.callDefaultConstructor() => new Selector(
SelectorKind.CALL, const PublicName(''), CallStructure.NO_ARGS);
// TODO(31953): Remove this if we can implement via static calls.
factory Selector.genericInstantiation(int typeArguments) => new Selector(
SelectorKind.SPECIAL,
Names.genericInstantiation,

View file

@ -103,7 +103,8 @@ class Template {
if (arguments is List) {
if (arguments.length != positionalArgumentCount) {
throw 'Wrong number of template arguments, given ${arguments.length}, '
'expected $positionalArgumentCount';
'expected $positionalArgumentCount'
', source: "$source"';
}
return instantiator(arguments);
}

View file

@ -3074,6 +3074,54 @@ class BoundClosure extends TearOffClosure {
}
}
/// Support class for generic function type instantiation (binding of types).
///
abstract class Instantiation extends Closure {
final Closure _genericClosure;
Instantiation(this._genericClosure) {
// TODO(sra): Copy some metadata used by Function.apply.
}
/// Returns a list of the bound types.
List get _types;
String toString() {
var types = "<${_types.join(', ')}>";
// TODO(sra): Refactor Closure formatting to place type arguments inside,
// e.g. "Closure 'map<String>' of Instance of 'JSArray<int>'".
return '$_genericClosure with $types';
}
}
/// Instantiation classes are subclasses of [Instantiation]. For now we have a
/// few canned subclasses. Later we might generate the classes on demand.
class Instantiation1<T1> extends Instantiation {
Instantiation1(Closure f) : super(f);
List get _types => [T1];
}
class Instantiation2<T1, T2> extends Instantiation {
Instantiation2(Closure f) : super(f);
List get _types => [T1, T2];
}
class Instantiation3<T1, T2, T3> extends Instantiation {
Instantiation3(Closure f) : super(f);
List get _types => [T1, T2, T3];
}
Instantiation instantiate1<U>(Closure f) {
return new Instantiation1<U>(f);
}
Instantiation instantiate2<U, V>(Closure f) {
return new Instantiation2<U, V>(f);
}
Instantiation instantiate3<U, V, W>(Closure f) {
return new Instantiation3<U, V, W>(f);
}
bool jsHasOwnProperty(var jsObject, String property) {
return JS('bool', r'#.hasOwnProperty(#)', jsObject, property);
}

View file

@ -218,6 +218,9 @@ const Map<String, String> DEFAULT_JS_HELPER_LIBRARY = const <String, String>{
'getTypeArgumentByIndex': 'getTypeArgumentByIndex(target, index) {}',
'GeneralConstantMap': 'class GeneralConstantMap {}',
'iae': 'iae(x) { throw x; } ioore(x) { throw x; }',
'Instantiation1': 'class Instantiation1<T1> extends Closure {}',
'Instantiation2': 'class Instantiation2<T1,T2> extends Closure {}',
'Instantiation3': 'class Instantiation3<T1,T2,T3> extends Closure {}',
'interceptedTypeCast': 'interceptedTypeCast(value, property) {}',
'interceptedTypeCheck': 'interceptedTypeCheck(value, property) {}',
'intTypeCast': 'intTypeCast(value) {}',

View file

@ -1726,7 +1726,7 @@ function_subtype_bound_closure4_test: RuntimeError
function_subtype_bound_closure5_test: RuntimeError
function_subtype_bound_closure5a_test: RuntimeError
function_subtype_bound_closure6_test: RuntimeError
function_subtype_bound_closure7_test: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
function_subtype_bound_closure7_test: RuntimeError
function_subtype_call1_test: RuntimeError
function_subtype_call2_test: RuntimeError
function_subtype_cast1_test: RuntimeError
@ -1760,7 +1760,7 @@ generic_closure_test/01: RuntimeError
generic_closure_test/none: Crash # 'file:*/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart': Failed assertion: line 208 pos 18: '!(_useKernel && _strongMode && !_disableRtiOptimization) ||
generic_field_mixin6_test/none: RuntimeError
generic_function_bounds_test: RuntimeError
generic_function_dcall_test: Crash # Unsupported operation: Unsupported type parameter type node T.
generic_function_dcall_test: RuntimeError
generic_function_type_as_type_argument_test/01: MissingCompileTimeError
generic_function_type_as_type_argument_test/02: MissingCompileTimeError
generic_function_type_as_type_argument_test/03: RuntimeError
@ -1782,7 +1782,7 @@ generic_methods_overriding_test/01: MissingCompileTimeError
generic_methods_recursive_bound_test/02: MissingCompileTimeError
generic_methods_recursive_bound_test/03: Crash # 'file:*/pkg/compiler/lib/src/js_emitter/metadata_collector.dart': Failed assertion: line 100 pos 12: 'isBound': is not true.
generic_methods_simple_as_expression_test/02: MissingRuntimeError
generic_methods_tearoff_specialization_test: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
generic_methods_tearoff_specialization_test: RuntimeError
generic_methods_test: Crash # Stack Overflow
generic_methods_type_expression_test: RuntimeError
generic_methods_unused_parameter_test: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
@ -2661,7 +2661,7 @@ generic_methods_simple_as_expression_test/02: MissingRuntimeError
generic_methods_tearoff_specialization_test: RuntimeError
generic_methods_test: Crash # Stack Overflow
generic_methods_type_expression_test: RuntimeError
generic_methods_unused_parameter_test: Crash # Interpolated value #1 is not an Expression or List of Expressions: [Instance of 'LiteralNull', null]
generic_methods_unused_parameter_test: RuntimeError
generic_no_such_method_dispatcher_simple_test: CompileTimeError
generic_no_such_method_dispatcher_test: CompileTimeError
generic_tearoff_test: CompileTimeError