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) { |