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

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: Created 7 years, 2 months 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 1b2e54a4301a98ea27236684b1c94b01af9cdeb8..94ad5a4d0496654aace1b516a6a7d8284fc04aeb 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
@@ -129,17 +129,13 @@ class ContainerBuilder extends CodeEmitterHelper {
jsAst.Fun function = js.fun(parametersBuffer, body);
defineStub(invocationName, 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,
DefineStubFunction defineStub) {
+ // Bound closures are generated dynamically.
+ if (member.enclosingElement.isClosure()) return;
+
// We fill the lists depending on the selector. For example,
// take method foo:
// foo(a, b, {c, d});
@@ -169,92 +165,27 @@ class ContainerBuilder extends CodeEmitterHelper {
// 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 = compiler.codegenWorld.invokedNames[member.name];
+ if (selectors == null) {
+ selectors = compiler.codegenWorld.invokedNames[
+ namer.closureInvocationSelectorName];
kasperl 2013/10/21 10:25:44 Cache namer.closureInvocationSelectorName in a loc
ahe 2013/12/06 15:57:53 The code is now so distant that I don't think it h
if (selectors == null) return;
- for (Selector selector in selectors) {
- if (!selector.applies(member, compiler)) continue;
- addParameterStub(member, selector, defineStub, generatedStubNames);
+ } else {
+ Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[
+ namer.closureInvocationSelectorName];
+ if (callSelectors != null) {
+ selectors = new Set<Selector>.from(selectors)..addAll(callSelectors);
kasperl 2013/10/21 10:25:44 Can you use Set.union here?
ahe 2013/10/22 10:52:34 Oh yeah! I didn't know about that method :-)
}
}
- }
-
- 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.slowToString());
- Constant value = compiler.constantHandler.initialVariableValues[element];
- jsAst.Expression reference = null;
- if (value == null) {
- reference = new jsAst.LiteralNull();
- } else {
- reference = task.constantReference(value);
- }
- 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,
- <SourceString>[]));
-
- // 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,
- <SourceString>[]));
+ if (!selector.applies(member, compiler)) continue;
+ // TODO(ahe): Is the last argument to [addParameterStub] needed?
+ addParameterStub(member, selector, defineStub, new Set<String>());
}
- return selectors;
}
void emitStaticFunctionGetters(CodeBuffer eagerBuffer) {
+ return;
task.addComment('Static function getters', task.mainBuffer);
for (FunctionElement element in
Elements.sortedByPosition(staticGetters.keys)) {
@@ -579,10 +510,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);
- }
}
}
@@ -608,34 +535,70 @@ 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;
kasperl 2013/10/21 10:25:44 Consider only using tearOffName (null could repres
ahe 2013/12/06 15:57:53 I forgot about this comment, but I'm weary of chan
+ String tearOffName;
+ if (member.isInstanceMember()) {
+ // Careful with operators.
+ 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.slowToString();
- builder.addProperty('*$unmangledName', defaultValues);
- }
+
+ if (!canTearOff && !needsStubs && !backend.isNeededForReflection(member)) {
+ builder.addProperty(name, code);
+ addBailout(member, builder);
+ return;
+ }
+ // This element is needed for reflection or needs additional stubs. So we
+ // need to retain additional information.
+
+ List expressions = [];
+
+ bool canBeReflected = backend.isAccessibleByReflection(member);
+ expressions
+ ..add(code)
+ ..add(member.isAccessor() ? js("null") : js.string(tearOffName))
+ // TODO(ahe): Obtain proper name.
+ ..add(js.string("call\$${parameters.requiredParameterCount}"))
+ ..add(canBeReflected ? parameters.requiredParameterCount + 1 : 0)
+ ..add(parameters.optionalParameterCount)
+ ..addAll(task.metadataEmitter.reifyDefaultArguments(member));
+
+ if (needsStubs) {
+ addParameterStubs(member, (String name, jsAst.Fun function) {
+ expressions.add(function);
+ expressions.add(js.string(name));
+ // TODO(ahe): Obtain proper call name.
+ expressions.add(js.string("call\$${function.params.length}"));
+ });
+ }
+
+ if (canBeReflected) {
+ expressions
+ ..add(js.string(member.name.slowToString()))
+ ..addAll(task.metadataEmitter.computeMetadata(member));
}
- code = backend.generatedBailoutCode[member];
+
+ builder.addProperty(name, js.toExpression(expressions));
+
+ addBailout(member, builder);
+
+ // if (canTearOff) {
+ // emitDynamicFunctionGetter(member, builder.addProperty);
+ // }
+ }
+
+ void addBailout(FunctionElement member, ClassBuilder builder) {
+ jsAst.Expression code = backend.generatedBailoutCode[member];
if (code != null) {
builder.addProperty(namer.getBailoutName(member), code);
}
- 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);
- }
- }
}
void addMemberField(VariableElement member, ClassBuilder builder) {

Powered by Google App Engine
This is Rietveld 408576698