mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
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:
parent
cae6d89429
commit
8e8287f4e0
15 changed files with 274 additions and 9 deletions
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {}',
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue