Index: lib/compiler/implementation/js_backend/emitter.dart |
=================================================================== |
--- lib/compiler/implementation/js_backend/emitter.dart (revision 13403) |
+++ lib/compiler/implementation/js_backend/emitter.dart (working copy) |
@@ -476,20 +476,97 @@ |
// |
// We need to generate a stub for (5) because the order of the |
// stub arguments and the real method may be different. |
- Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; |
- if (selectors == null) return; |
+ |
// 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>(); |
- for (Selector selector in selectors) { |
- if (!selector.applies(member, compiler)) continue; |
- addParameterStub( |
- member, selector, defineInstanceMember, generatedStubNames); |
+ if (compiler.enabledFunctionApply |
+ && member.name == Namer.CLOSURE_INVOCATION_NAME) { |
+ // If [Function.apply] is called, we pessimistically compile all |
+ // possible stubs for this closure. |
+ // TODO(5074): This functionality only supports the new |
+ // parameter specification, and this comment should be removed |
+ // once the old specification is not supported. |
+ FunctionSignature signature = member.computeSignature(compiler); |
+ Set<Selector> selectors = signature.optionalParametersAreNamed |
+ ? computeNamedSelectors(signature, member) |
+ : computeOptionalSelectors(signature, member); |
+ for (Selector selector in selectors) { |
+ addParameterStub( |
+ member, selector, defineInstanceMember, generatedStubNames); |
+ } |
+ } else { |
+ Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; |
+ if (selectors == null) return; |
+ for (Selector selector in selectors) { |
+ if (!selector.applies(member, compiler)) continue; |
+ addParameterStub( |
+ member, selector, defineInstanceMember, generatedStubNames); |
+ } |
} |
} |
+ /** |
+ * Compute the set of possible selectors in the presence of named |
+ * parameters. |
+ */ |
+ Set<Selector> computeNamedSelectors(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 iterator over the set of |
+ // already computed selectors and create new selectors with that |
+ // parameter now being passed. |
+ signature.forEachOptionalParameter((Element element) { |
+ Set<Selector> newSet = new Set<Selector>(); |
+ selectors.forEach((Selector other) { |
+ List<SourceString> namedArguments = [element.name]; |
+ namedArguments.addAll(other.namedArguments); |
+ newSet.add(new Selector(other.kind, |
+ other.name, |
+ other.library, |
+ other.argumentCount + 1, |
+ namedArguments)); |
+ }); |
+ selectors.addAll(newSet); |
+ }); |
+ return selectors; |
+ } |
+ |
+ /** |
+ * 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>[])); |
+ } |
+ return selectors; |
+ } |
+ |
bool instanceFieldNeedsGetter(Element member) { |
assert(member.isField()); |
return compiler.codegenWorld.hasInvokedGetter(member, compiler); |