Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(365)

Unified Diff: dart/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart

Issue 27524003: Generate tear-off closures dynamically. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Merged with r30954 Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: dart/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
diff --git a/dart/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart b/dart/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
index b8e8210ab1136caf110312b00277963789a796ed..1ebb578d2635a53beb60969f7b8d5d76255c2bab 100644
--- a/dart/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
+++ b/dart/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
@@ -25,7 +25,7 @@ class ContainerBuilder extends CodeEmitterHelper {
*/
void addParameterStub(FunctionElement member,
Selector selector,
- DefineStubFunction defineStub,
+ AddStubFunction addStub,
Set<String> alreadyGenerated) {
FunctionSignature parameters = member.computeSignature(compiler);
int positionalArgumentCount = selector.positionalArgumentCount;
@@ -81,10 +81,7 @@ class ContainerBuilder extends CodeEmitterHelper {
int parameterIndex = 0;
parameters.orderedForEachParameter((Element element) {
- // Use generic names for closures to facilitate code sharing.
- String jsName = member is ClosureInvocationElement
- ? 'p${parameterIndex++}'
- : backend.namer.safeName(element.name);
+ String jsName = backend.namer.safeName(element.name);
assert(jsName != receiverArgumentName);
if (count < optionalParameterStart) {
parametersBuffer[count] = new jsAst.Parameter(jsName);
@@ -121,25 +118,30 @@ class ContainerBuilder extends CodeEmitterHelper {
member, isInterceptedMethod, invocationName,
parametersBuffer, argumentsBuffer,
indexOfLastOptionalArgumentInParameters);
- } else {
+ } else if (member.isInstanceMember()) {
body = [js.return_(
js('this')[namer.getNameOfInstanceMember(member)](argumentsBuffer))];
+ } else {
+ body = [js.return_(namer.elementAccess(member)(argumentsBuffer))];
}
jsAst.Fun function = js.fun(parametersBuffer, body);
- defineStub(invocationName, function);
+ addStub(selector, function);
+ }
- String reflectionName = task.getReflectionName(selector, invocationName);
- if (reflectionName != null) {
- var reflectable =
- js(backend.isAccessibleByReflection(member) ? '1' : '0');
- defineStub('+$reflectionName', reflectable);
+ void addParameterStubs(FunctionElement member, AddStubFunction defineStub,
+ [bool canTearOff = false]) {
+ if (member.enclosingElement.isClosure()) {
+ ClosureClassElement cls = member.enclosingElement;
+ if (cls.supertype.element == compiler.boundClosureClass) {
+ compiler.internalErrorOnElement(cls.methodElement, 'Bound closure1.');
ngeoffray 2013/12/09 11:15:58 Maybe add a better error message.
ahe 2013/12/09 17:06:47 Johnni said the same, so I'm going to repeat my an
ngeoffray 2013/12/09 17:14:55 BoundClosure1 may be enough for you, but besides t
+ }
+ if (cls.methodElement.isInstanceMember()) {
+ compiler.internalErrorOnElement(cls.methodElement, 'Bound closure2.');
ngeoffray 2013/12/09 11:15:58 Ditto.
ahe 2013/12/09 17:06:47 Ditto :-)
+ }
}
- }
- void addParameterStubs(FunctionElement member,
- DefineStubFunction defineStub) {
// We fill the lists depending on the selector. For example,
// take method foo:
// foo(a, b, {c, d});
@@ -165,331 +167,59 @@ class ContainerBuilder extends CodeEmitterHelper {
// (4) No stub generated, call is direct.
// (5) No stub generated, call is direct.
- // Keep a cache of which stubs have already been generated, to
- // avoid duplicates. Note that even if selectors are
- // canonicalized, we would still need this cache: a typed selector
- // on A and a typed selector on B could yield the same stub.
- Set<String> generatedStubNames = new Set<String>();
- bool isClosureInvocation =
- member.name == namer.closureInvocationSelectorName;
- if (backend.isNeededForReflection(member) ||
- (compiler.enabledFunctionApply && isClosureInvocation)) {
- // If [Function.apply] is called, we pessimistically compile all
- // possible stubs for this closure.
- FunctionSignature signature = member.computeSignature(compiler);
- Set<Selector> selectors = signature.optionalParametersAreNamed
- ? computeSeenNamedSelectors(member)
- : computeOptionalSelectors(signature, member);
- for (Selector selector in selectors) {
- addParameterStub(member, selector, defineStub, generatedStubNames);
- }
- if (signature.optionalParametersAreNamed && isClosureInvocation) {
- addCatchAllParameterStub(member, signature, defineStub);
- }
- } else {
- Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name];
+ Set<Selector> selectors = member.isInstanceMember()
ngeoffray 2013/12/09 11:15:58 For readability, I would not initialize this set h
ahe 2013/12/09 17:06:47 Done.
+ ? compiler.codegenWorld.invokedNames[member.name]
+ : null; // No stubs needed for static methods.
+
+ /// Returns all closure call selectors renamed to match this member.
+ Set<Selector> callSelectorsAsNamed() {
+ if (!canTearOff) return null;
+ Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[
+ namer.closureInvocationSelectorName];
+ if (callSelectors == null) return null;
+ return callSelectors.map((Selector callSelector) {
+ return new Selector.call(
+ member.name, member.getLibrary(),
+ callSelector.argumentCount, callSelector.namedArguments);
+ }).toSet();
+ }
+ if (selectors == null) {
+ selectors = callSelectorsAsNamed();
if (selectors == null) return;
- for (Selector selector in selectors) {
- if (!selector.applies(member, compiler)) continue;
- addParameterStub(member, selector, defineStub, generatedStubNames);
+ } else {
+ Set<Selector> callSelectors = callSelectorsAsNamed();
+ if (callSelectors != null) {
+ selectors = selectors.union(callSelectors);
}
}
- }
-
- Set<Selector> computeSeenNamedSelectors(FunctionElement element) {
- Set<Selector> selectors = compiler.codegenWorld.invokedNames[element.name];
- Set<Selector> result = new Set<Selector>();
- if (selectors == null) return result;
- for (Selector selector in selectors) {
- if (!selector.applies(element, compiler)) continue;
- result.add(selector);
- }
- return result;
- }
-
- void addCatchAllParameterStub(FunctionElement member,
- FunctionSignature signature,
- DefineStubFunction defineStub) {
- // See Primities.applyFunction in js_helper.dart for details.
- List<jsAst.Property> properties = <jsAst.Property>[];
- for (Element element in signature.orderedOptionalParameters) {
- String jsName = backend.namer.safeName(element.name);
- Constant value = compiler.constantHandler.initialVariableValues[element];
- jsAst.Expression reference = null;
- if (value == null) {
- reference = new jsAst.LiteralNull();
- } else {
- reference = task.constantReference(value);
+ Set<Selector> untypedSelectors = new Set<Selector>();
+ if (selectors != null) {
+ for (Selector selector in selectors) {
+ if (!selector.appliesUnnamed(member, compiler)) continue;
+ if (untypedSelectors.add(selector.asUntyped)) {
+ // TODO(ahe): Is the last argument to [addParameterStub] needed?
+ addParameterStub(member, selector, defineStub, new Set<String>());
+ }
}
- properties.add(new jsAst.Property(js.string(jsName), reference));
- }
- defineStub(
- backend.namer.callCatchAllName,
- js.fun([], js.return_(new jsAst.ObjectInitializer(properties))));
- }
-
- /**
- * Compute the set of possible selectors in the presence of optional
- * non-named parameters.
- */
- Set<Selector> computeOptionalSelectors(FunctionSignature signature,
- FunctionElement element) {
- Set<Selector> selectors = new Set<Selector>();
- // Add the selector that does not have any optional argument.
- selectors.add(new Selector(SelectorKind.CALL,
- element.name,
- element.getLibrary(),
- signature.requiredParameterCount,
- <String>[]));
-
- // For each optional parameter, we increment the number of passed
- // argument.
- for (int i = 1; i <= signature.optionalParameterCount; i++) {
- selectors.add(new Selector(SelectorKind.CALL,
- element.name,
- element.getLibrary(),
- signature.requiredParameterCount + i,
- <String>[]));
}
- return selectors;
- }
-
- void emitStaticFunctionGetters(CodeBuffer eagerBuffer) {
- task.addComment('Static function getters', task.mainBuffer);
- for (FunctionElement element in
- Elements.sortedByPosition(staticGetters.keys)) {
- Element closure = staticGetters[element];
- CodeBuffer buffer =
- task.isDeferred(element) ? task.deferredConstants : eagerBuffer;
- String closureClass = namer.isolateAccess(closure);
- String name = namer.getStaticClosureName(element);
-
- String closureName = namer.getStaticClosureName(element);
- jsAst.Node assignment = js(
- 'init.globalFunctions["$closureName"] ='
- ' ${namer.globalObjectFor(element)}.$name ='
- ' new $closureClass(#, "$closureName")',
- namer.elementAccess(element));
- buffer.write(jsAst.prettyPrint(assignment, compiler));
- buffer.write('$N');
- }
- }
-
- void emitStaticFunctionClosures() {
- Set<FunctionElement> functionsNeedingGetter =
- compiler.codegenWorld.staticFunctionsNeedingGetter;
- for (FunctionElement element in
- Elements.sortedByPosition(functionsNeedingGetter)) {
- String superName = namer.getNameOfClass(compiler.closureClass);
- int parameterCount = element.functionSignature.parameterCount;
- String name = 'Closure\$$parameterCount';
- assert(task.instantiatedClasses.contains(compiler.closureClass));
-
- ClassElement closureClassElement = new ClosureClassElement(
- null, name, compiler, element,
- element.getCompilationUnit());
- // Now add the methods on the closure class. The instance method does not
- // have the correct name. Since [addParameterStubs] use the name to create
- // its stubs we simply create a fake element with the correct name.
- // Note: the callElement will not have any enclosingElement.
- FunctionElement callElement =
- new ClosureInvocationElement(namer.closureInvocationSelectorName,
- element);
-
- String invocationName = namer.instanceMethodName(callElement);
- String mangledName = namer.getNameOfClass(closureClassElement);
-
- // Define the constructor with a name so that Object.toString can
- // find the class name of the closure class.
- ClassBuilder closureBuilder = new ClassBuilder();
- // If a static function is used as a closure we need to add its name
- // in case it is used in spawnFunction.
- String methodName = namer.STATIC_CLOSURE_NAME_NAME;
- List<String> fieldNames = <String>[invocationName, methodName];
- closureBuilder.addProperty('',
- js.string("$superName;${fieldNames.join(',')}"));
-
- addParameterStubs(callElement, closureBuilder.addProperty);
-
- void emitFunctionTypeSignature(Element method, FunctionType methodType) {
- RuntimeTypes rti = backend.rti;
- // [:() => null:] is dummy encoding of [this] which is never needed for
- // the encoding of the type of the static [method].
- jsAst.Expression encoding =
- rti.getSignatureEncoding(methodType, js('null'));
- String operatorSignature = namer.operatorSignature();
- // TODO(johnniwinther): Make MiniJsParser support function expressions.
- closureBuilder.addProperty(operatorSignature, encoding);
+ if (canTearOff) {
+ selectors = compiler.codegenWorld.invokedNames[
+ namer.closureInvocationSelectorName];
+ if (selectors != null) {
+ for (Selector selector in selectors) {
+ selector = new Selector.call(
+ member.name, member.getLibrary(),
+ selector.argumentCount, selector.namedArguments);
+ if (!selector.appliesUnnamed(member, compiler)) continue;
+ if (untypedSelectors.add(selector)) {
+ // TODO(ahe): Is the last argument to [addParameterStub] needed?
+ addParameterStub(member, selector, defineStub, new Set<String>());
+ }
+ }
}
-
- FunctionType methodType = element.computeType(compiler);
- Map<FunctionType, bool> functionTypeChecks =
- task.typeTestEmitter.getFunctionTypeChecksOn(methodType);
- task.typeTestEmitter.generateFunctionTypeTests(
- element, methodType, functionTypeChecks,
- emitFunctionTypeSignature);
-
- closureClassElement =
- addClosureIfNew(closureBuilder, closureClassElement, fieldNames);
- staticGetters[element] = closureClassElement;
-
}
}
- ClassElement addClosureIfNew(ClassBuilder builder,
- ClassElement closure,
- List<String> fieldNames) {
- String key =
- jsAst.prettyPrint(builder.toObjectInitializer(), compiler).getText();
- return methodClosures.putIfAbsent(key, () {
- String mangledName = namer.getNameOfClass(closure);
- emitClosureInPrecompiledFunction(mangledName, fieldNames);
- return closure;
- });
- }
-
- void emitClosureInPrecompiledFunction(String mangledName,
- List<String> fieldNames) {
- List<String> fields = fieldNames;
- String constructorName = mangledName;
- task.precompiledFunction.add(new jsAst.FunctionDeclaration(
- new jsAst.VariableDeclaration(constructorName),
- js.fun(fields, fields.map(
- (name) => js('this.$name = $name')).toList())));
- task.precompiledFunction.addAll([
- js('$constructorName.builtin\$cls = "$constructorName"'),
- js('\$desc=\$collectedClasses.$constructorName'),
- js.if_('\$desc instanceof Array', js('\$desc = \$desc[1]')),
- js('$constructorName.prototype = \$desc'),
- ]);
-
- task.precompiledConstructorNames.add(js(constructorName));
- }
-
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: [member] must be a declaration element.
- */
- void emitDynamicFunctionGetter(FunctionElement member,
- DefineStubFunction defineStub) {
- assert(invariant(member, member.isDeclaration));
- assert(task.instantiatedClasses.contains(compiler.boundClosureClass));
- // For every method that has the same name as a property-get we create a
- // getter that returns a bound closure. Say we have a class 'A' with method
- // 'foo' and somewhere in the code there is a dynamic property get of
- // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript):
- //
- // class A {
- // foo(x, y, z) { ... } // Original function.
- // get foo { return new BoundClosure499(this, "foo"); }
- // }
- // class BoundClosure499 extends BoundClosure {
- // BoundClosure499(this.self, this.name);
- // $call3(x, y, z) { return self[name](x, y, z); }
- // }
-
- bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
- int parameterCount = member.parameterCount(compiler);
-
- // Intercepted methods take an extra parameter, which is the
- // receiver of the call.
- bool inInterceptor = backend.isInterceptedMethod(member);
- List<String> fieldNames = <String>[];
- compiler.boundClosureClass.forEachInstanceField((_, Element field) {
- fieldNames.add(namer.instanceFieldPropertyName(field));
- });
-
- ClassElement classElement = member.getEnclosingClass();
- String name = inInterceptor
- ? 'BoundClosure\$i${parameterCount}'
- : 'BoundClosure\$${parameterCount}';
-
- ClassElement closureClassElement = new ClosureClassElement(
- null, name, compiler, member,
- member.getCompilationUnit());
- String superName = namer.getNameOfClass(closureClassElement.superclass);
-
- // Define the constructor with a name so that Object.toString can
- // find the class name of the closure class.
- ClassBuilder boundClosureBuilder = new ClassBuilder();
- boundClosureBuilder.addProperty('',
- js.string("$superName;${fieldNames.join(',')}"));
- // Now add the methods on the closure class. The instance method does not
- // have the correct name. Since [addParameterStubs] use the name to create
- // its stubs we simply create a fake element with the correct name.
- // Note: the callElement will not have any enclosingElement.
- FunctionElement callElement = new ClosureInvocationElement(
- namer.closureInvocationSelectorName, member);
-
- String invocationName = namer.instanceMethodName(callElement);
-
- List<String> parameters = <String>[];
- List<jsAst.Expression> arguments =
- <jsAst.Expression>[js('this')[fieldNames[0]]];
- if (inInterceptor) {
- arguments.add(js('this')[fieldNames[2]]);
- }
- for (int i = 0; i < parameterCount; i++) {
- String name = 'p$i';
- parameters.add(name);
- arguments.add(js(name));
- }
-
- jsAst.Expression fun = js.fun(
- parameters,
- js.return_(
- js('this')[fieldNames[1]]['call'](arguments)));
- boundClosureBuilder.addProperty(invocationName, fun);
-
- addParameterStubs(callElement, boundClosureBuilder.addProperty);
-
- void emitFunctionTypeSignature(Element method, FunctionType methodType) {
- jsAst.Expression encoding = backend.rti.getSignatureEncoding(
- methodType, js('this')[fieldNames[0]]);
- String operatorSignature = namer.operatorSignature();
- boundClosureBuilder.addProperty(operatorSignature, encoding);
- }
-
- DartType memberType = member.computeType(compiler);
- Map<FunctionType, bool> functionTypeChecks =
- task.typeTestEmitter.getFunctionTypeChecksOn(memberType);
-
- task.typeTestEmitter.generateFunctionTypeTests(
- member, memberType, functionTypeChecks,
- emitFunctionTypeSignature);
-
- closureClassElement =
- addClosureIfNew(boundClosureBuilder, closureClassElement, fieldNames);
-
- String closureClass = namer.isolateAccess(closureClassElement);
-
- // And finally the getter.
- String getterName = namer.getterName(member);
- String targetName = namer.instanceMethodName(member);
-
- parameters = <String>[];
- jsAst.PropertyAccess method =
- backend.namer.elementAccess(classElement)['prototype'][targetName];
- arguments = <jsAst.Expression>[js('this'), method];
-
- if (inInterceptor) {
- String receiverArg = fieldNames[2];
- parameters.add(receiverArg);
- arguments.add(js(receiverArg));
- } else {
- // Put null in the intercepted receiver field.
- arguments.add(new jsAst.LiteralNull());
- }
-
- arguments.add(js.string(targetName));
-
- jsAst.Expression getterFunction = js.fun(
- parameters, js.return_(js(closureClass).newWith(arguments)));
-
- defineStub(getterName, getterFunction);
- }
-
/**
* Documentation wanted -- johnniwinther
*
@@ -497,7 +227,7 @@ class ContainerBuilder extends CodeEmitterHelper {
*/
void emitCallStubForGetter(Element member,
Set<Selector> selectors,
- DefineStubFunction defineStub) {
+ AddPropertyFunction addProperty) {
assert(invariant(member, member.isDeclaration));
LibraryElement memberLibrary = member.getLibrary();
// If the method is intercepted, the stub gets the
@@ -549,7 +279,7 @@ class ContainerBuilder extends CodeEmitterHelper {
parameters,
js.return_(buildGetter()[closureCallName](arguments)));
- defineStub(invocationName, function);
+ addProperty(invocationName, function);
}
}
}
@@ -566,10 +296,6 @@ class ContainerBuilder extends CodeEmitterHelper {
if (selectors != null && !selectors.isEmpty) {
emitCallStubForGetter(member, selectors, builder.addProperty);
}
- } else if (member.isFunction()) {
- if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) {
- emitDynamicFunctionGetter(member, builder.addProperty);
- }
}
}
@@ -595,30 +321,182 @@ class ContainerBuilder extends CodeEmitterHelper {
jsAst.Expression code = backend.generatedCode[member];
if (code == null) return;
String name = namer.getNameOfMember(member);
- if (backend.isInterceptedMethod(member)) {
- task.interceptorEmitter.interceptorInvocationNames.add(name);
+ task.interceptorEmitter.recordMangledNameOfMemberMethod(member, name);
+ FunctionSignature parameters = member.computeSignature(compiler);
+ bool needsStubs = !parameters.optionalParameters.isEmpty;
+ bool canTearOff = false;
+ bool isClosure = false;
+ String tearOffName;
+ if (!member.isFunction() || member.isConstructor() || member.isAccessor()) {
+ canTearOff = false;
+ } else if (member.isInstanceMember()) {
+ if (member.getEnclosingClass().isClosure()) {
+ canTearOff = false;
+ isClosure = true;
+ } else {
+ // Careful with operators.
ngeoffray 2013/12/09 11:15:58 I don't understand this comment.
ahe 2013/12/09 17:06:47 Changed it to: // TODO(ahe): What happens
+ canTearOff = compiler.codegenWorld.hasInvokedGetter(member, compiler);
+ tearOffName = namer.getterName(member);
+ }
+ } else {
+ canTearOff =
+ compiler.codegenWorld.staticFunctionsNeedingGetter.contains(member);
+ tearOffName = namer.getStaticClosureName(member);
}
- code = task.metadataEmitter.extendWithMetadata(member, code);
- builder.addProperty(name, code);
- String reflectionName = task.getReflectionName(member, name);
- if (reflectionName != null) {
- var reflectable =
- js(backend.isAccessibleByReflection(member) ? '1' : '0');
- builder.addProperty('+$reflectionName', reflectable);
- jsAst.Node defaultValues =
- task.metadataEmitter.reifyDefaultArguments(member);
- if (defaultValues != null) {
- String unmangledName = member.name;
- builder.addProperty('*$unmangledName', defaultValues);
+
+ bool canBeReflected = backend.isAccessibleByReflection(member);
+ bool needStructuredInfo =
+ canTearOff || canBeReflected || compiler.enabledFunctionApply;
+ if (!needStructuredInfo) {
+ builder.addProperty(name, code);
+ if (needsStubs) {
+ addParameterStubs(
+ member,
+ (Selector selector, jsAst.Fun function) {
+ builder.addProperty(namer.invocationName(selector), function);
+ });
}
+ return;
}
- if (member.isInstanceMember()) {
- // TODO(ahe): Where is this done for static/top-level methods?
- FunctionSignature parameters = member.computeSignature(compiler);
- if (!parameters.optionalParameters.isEmpty) {
- addParameterStubs(member, builder.addProperty);
+
+ if (canTearOff) {
+ assert(invariant(member, !member.isGenerativeConstructor()));
+ assert(invariant(member, !member.isGenerativeConstructorBody()));
+ assert(invariant(member, !member.isConstructor()));
+ }
+
+ // This element is needed for reflection or needs additional stubs. So we
+ // need to retain additional information.
+
+ // The information is stored in an array with this format:
+ //
+ // 1. The JS function for this member.
+ // 2. First stub.
+ // 3. Name of first stub.
+ // ...
+ // M. Call name of this member.
+ // M+1. Call name of first stub.
+ // ...
+ // N. Getter name for tearOff.
+ // N+1. (Required parameter count << 1) + (member.isAccessor() ? 1 : 0).
+ // N+2. (Optional parameter count << 1) +
+ // (parameters.optionalParametersAreNamed ? 1 : 0).
+ // N+3. Index to function type in constant pool.
+ // N+4. First default argument.
+ // ...
+ // O. First parameter name (if needed for reflection or Function.apply).
+ // ...
+ // P. Unmangled name (if reflectable).
+ // P+1. First metadata (if reflectable).
+ // ...
+
+ List expressions = [];
+
+ String callSelectorString = 'null';
+ if (member.isFunction()) {
+ Selector callSelector =
+ new Selector.fromElement(member, compiler).toCallSelector();
+ callSelectorString = '"${namer.invocationName(callSelector)}"';
+ }
+
+ // On [requiredParameterCount], the lower bit is set if this method can be
+ // called reflectively.
+ int requiredParameterCount = parameters.requiredParameterCount << 1;
+ if (member.isAccessor()) requiredParameterCount++;
+
+ int optionalParameterCount = parameters.optionalParameterCount << 1;
+ if (parameters.optionalParametersAreNamed) optionalParameterCount++;
+
+ expressions.add(code);
+
+ // TODO(ahe): Remove comments from output.
+ List tearOffInfo =
+ [new jsAst.LiteralString('$callSelectorString /* tearOffInfo */')];
+
+ if (needsStubs || canTearOff) {
+ addParameterStubs(member, (Selector selector, jsAst.Fun function) {
+ expressions.add(function);
+ if (member.isInstanceMember()) {
+ Set invokedSelectors =
+ compiler.codegenWorld.invokedNames[member.name];
+ if (invokedSelectors != null && invokedSelectors.contains(selector)) {
+ expressions.add(js.string(namer.invocationName(selector)));
+ } else {
+ // Don't add a stub for calling this as a regular instance method,
+ // we only need the "call" stub for implicit closures of this
+ // method.
+ expressions.add("null");
+ }
+ } else {
+ // Static methods don't need "named" stubs as the default arguments
+ // are inlined at call sites. But static methods might need "call"
+ // stubs for implicit closures.
+ expressions.add("null");
+ // TOOD(ahe): Since we know when reading static data versus instance
+ // data, we can eliminate this element.
ngeoffray 2013/12/09 11:15:58 What does eliminate mean here?
ahe 2013/12/09 17:06:47 That it doesn't need to be added to the reflective
+ }
+ Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[
+ namer.closureInvocationSelectorName];
+ Selector callSelector = selector.toCallSelector();
+ String callSelectorString = 'null';
+ if (canTearOff && callSelectors != null &&
+ callSelectors.contains(callSelector)) {
+ callSelectorString = '"${namer.invocationName(callSelector)}"';
+ }
+ tearOffInfo.add(
+ new jsAst.LiteralString('$callSelectorString /* tearOffInfo */'));
+ }, canTearOff);
+ }
+
+ jsAst.Expression memberTypeExpression;
+ if ((canTearOff || canBeReflected) &&
+ !member.isGenerativeConstructorBody()) {
ngeoffray 2013/12/09 11:15:58 A generative constructor body can be reflected?
ahe 2013/12/09 17:06:47 Yeah. It is kind of a hack, but these end up being
+ DartType memberType = member.computeType(compiler);
+ if (memberType.containsTypeVariables) {
+ jsAst.Expression thisAccess = js(r'this.$receiver');
+ memberTypeExpression =
+ backend.rti.getSignatureEncoding(memberType, thisAccess);
+ } else {
+ memberTypeExpression =
+ js.toExpression(task.metadataEmitter.reifyType(memberType));
}
+ } else {
+ memberTypeExpression = js('null');
}
+
+ expressions
+ ..addAll(tearOffInfo)
+ ..add((tearOffName == null || member.isAccessor())
+ ? js("null") : js.string(tearOffName))
+ ..add(requiredParameterCount)
+ ..add(optionalParameterCount)
+ ..add(memberTypeExpression)
+ ..addAll(task.metadataEmitter.reifyDefaultArguments(member));
+
+ if (canBeReflected || compiler.enabledFunctionApply) {
+ parameters.orderedForEachParameter((Element parameter) {
+ expressions.add(task.metadataEmitter.reifyName(parameter.name));
+ });
+ }
+ if (canBeReflected) {
+ jsAst.LiteralString reflectionName;
+ if (member.isConstructor()) {
+ String reflectionNameString = task.getReflectionName(member, name);
+ reflectionName =
+ new jsAst.LiteralString(
+ '"new ${Elements.reconstructConstructorName(member)}"'
+ ' /* $reflectionNameString */');
+ } else {
+ reflectionName = js.string(member.name);
+ }
+ expressions
+ ..add(reflectionName)
+ ..addAll(task.metadataEmitter.computeMetadata(member));
+ } else if (isClosure && compiler.enabledFunctionApply) {
+ expressions.add(js.string(member.name));
+ }
+
+ builder.addProperty(name, js.toExpression(expressions));
}
void addMemberField(VariableElement member, ClassBuilder builder) {

Powered by Google App Engine
This is Rietveld 408576698