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

Unified Diff: pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart

Issue 889693003: dart2js: Use stub instances when generating ParameterStubs (adapterStubMethods). (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove unused field. Created 5 years, 11 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: pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart
index b221f8889a045c6766dbdb998b9e8aeed9c0c450..94bd8901ea907fd113f3f9388d70db6645b3deee 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart
@@ -9,32 +9,42 @@ part of dart2js.js_emitter;
/// Initially, it is just a placeholder for code that is moved from
/// [CodeEmitterTask].
class ContainerBuilder extends CodeEmitterHelper {
+ final Set<Selector> emptySelectorSet = new Set<Selector>();
+
bool needsSuperGetter(FunctionElement element) =>
compiler.codegenWorld.methodsNeedingSuperGetter.contains(element);
/**
- * Generate stubs to handle invocation of methods with optional
+ * Generates stubs to handle invocation of methods with optional
* arguments.
*
- * A method like [: foo([x]) :] may be invoked by the following
- * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this
- * function for detailed examples.
+ * A method like `foo([x])` may be invoked by the following
+ * calls: `foo(), foo(1), foo(x: 1)`. This method generates the stub for the
+ * given [selector] and returns the generated [AdapterStubMethod].
+ *
+ * Returns null if no stub is needed.
+ *
+ * Members may be invoked in two ways: directly, or through a closure. In the
+ * latter case the caller invokes the closure's `call` method. This method
+ * accepts two selectors. The returned stub method has the corresponding
+ * name [AdapterStubMethod.name] and/or [AdapterStubMethod.callName] set if
+ * the input selector is non-null (and the member needs an adapter).
*/
- void addParameterStub(FunctionElement member,
- Selector selector,
- AddStubFunction addStub) {
+ AdapterStubMethod generateParameterStub(FunctionElement member,
+ Selector selector,
+ Selector callSelector) {
FunctionSignature parameters = member.functionSignature;
int positionalArgumentCount = selector.positionalArgumentCount;
if (positionalArgumentCount == parameters.parameterCount) {
assert(selector.namedArgumentCount == 0);
- return;
+ return null;
}
if (parameters.optionalParametersAreNamed
&& selector.namedArgumentCount == parameters.optionalParameterCount) {
// If the selector has the same number of named arguments as the element,
// we don't need to add a stub. The call site will hit the method
// directly.
- return;
+ return null;
}
JavaScriptConstantCompiler handler = backend.constants;
List<String> names = selector.getOrderedNamedArguments();
@@ -62,7 +72,6 @@ class ContainerBuilder extends CodeEmitterHelper {
count++;
parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
argumentsBuffer[0] = js('#', receiverArgumentName);
- emitter.interceptorEmitter.interceptorInvocationNames.add(invocationName);
}
int optionalParameterStart = positionalArgumentCount + extraArgumentCount;
@@ -136,11 +145,45 @@ class ContainerBuilder extends CodeEmitterHelper {
jsAst.Fun function = js('function(#) { #; }', [parametersBuffer, body]);
- addStub(selector, function);
+ String name = namer.invocationName(selector);
+ String callName =
+ (callSelector != null) ? namer.invocationName(callSelector) : null;
+ return new AdapterStubMethod(name, callName, function);
}
- void addParameterStubs(FunctionElement member, AddStubFunction defineStub,
- [bool canTearOff = false]) {
+ // We fill the lists depending on possible/invoked selectors. For example,
+ // take method foo:
+ // foo(a, b, {c, d});
+ //
+ // We may have multiple ways of calling foo:
+ // (1) foo(1, 2);
+ // (2) foo(1, 2, c: 3);
+ // (3) foo(1, 2, d: 4);
+ // (4) foo(1, 2, c: 3, d: 4);
+ // (5) foo(1, 2, d: 4, c: 3);
+ //
+ // What we generate at the call sites are:
+ // (1) foo$2(1, 2);
+ // (2) foo$3$c(1, 2, 3);
+ // (3) foo$3$d(1, 2, 4);
+ // (4) foo$4$c$d(1, 2, 3, 4);
+ // (5) foo$4$c$d(1, 2, 3, 4);
+ //
+ // The stubs we generate are (expressed in Dart):
+ // (1) foo$2(a, b) => foo$4$c$d(a, b, null, null)
+ // (2) foo$3$c(a, b, c) => foo$4$c$d(a, b, c, null);
+ // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d);
+ // (4) No stub generated, call is direct.
+ // (5) No stub generated, call is direct.
+ //
+ // We need to pay attention if this stub is for a function that has been
+ // invoked from a subclass. Then we cannot just redirect, since that
+ // would invoke the methods of the subclass. We have to compile to:
+ // (1) foo$2(a, b) => MyClass.foo$4$c$d.call(this, a, b, null, null)
+ // (2) foo$3$c(a, b, c) => MyClass.foo$4$c$d(this, a, b, c, null);
+ // (3) foo$3$d(a, b, d) => MyClass.foo$4$c$d(this, a, b, null, d);
+ List<AdapterStubMethod> generateParameterStubs(FunctionElement member,
floitsch 2015/01/30 00:00:14 I'm sorry, but I couldn't resist rewriting this fu
+ {bool canTearOff: true}) {
if (member.enclosingElement.isClosure) {
ClosureClassElement cls = member.enclosingElement;
if (cls.supertype.element == backend.boundClosureClass) {
@@ -151,87 +194,84 @@ class ContainerBuilder extends CodeEmitterHelper {
}
}
- // We fill the lists depending on the selector. For example,
- // take method foo:
- // foo(a, b, {c, d});
- //
- // We may have multiple ways of calling foo:
- // (1) foo(1, 2);
- // (2) foo(1, 2, c: 3);
- // (3) foo(1, 2, d: 4);
- // (4) foo(1, 2, c: 3, d: 4);
- // (5) foo(1, 2, d: 4, c: 3);
- //
- // What we generate at the call sites are:
- // (1) foo$2(1, 2);
- // (2) foo$3$c(1, 2, 3);
- // (3) foo$3$d(1, 2, 4);
- // (4) foo$4$c$d(1, 2, 3, 4);
- // (5) foo$4$c$d(1, 2, 3, 4);
- //
- // The stubs we generate are (expressed in Dart):
- // (1) foo$2(a, b) => foo$4$c$d(a, b, null, null)
- // (2) foo$3$c(a, b, c) => foo$4$c$d(a, b, c, null);
- // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d);
- // (4) No stub generated, call is direct.
- // (5) No stub generated, call is direct.
- //
- // We need to pay attention if this stub is for a function that has been
- // invoked from a subclass. Then we cannot just redirect, since that
- // would invoke the methods of the subclass. We have to compile to:
- // (1) foo$2(a, b) => MyClass.foo$4$c$d.call(this, a, b, null, null)
- // (2) foo$3$c(a, b, c) => MyClass.foo$4$c$d(this, a, b, c, null);
- // (3) foo$3$d(a, b, d) => MyClass.foo$4$c$d(this, a, b, null, d);
-
- Set<Selector> selectors = member.isInstanceMember
- ? 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.library,
- callSelector.argumentCount, callSelector.namedArguments);
- }).toSet();
+ // The set of selectors that apply to `member`. For example, for
+ // a member `foo(x, [y])` the following selectors may apply:
+ // `foo(x)`, and `foo(x, y)`.
+ Set<Selector> selectors;
+ // The set of selectors that apply to `member` if it's name was `call`.
+ // This happens when a member is torn-off. In that case calls to the
+ // function use the name `call`, and we must be able to handle every
+ // `call` invocation that matches the signature. For example, for
+ // a member `foo(x, [y])` the following selectors would be possible
+ // call-selectors: `call(x)`, and `call(x, y)`.
+ Set<Selector> callSelectors;
+
+ // Only instance members (not static methods) need stubs.
+ if (member.isInstanceMember) {
+ selectors = compiler.codegenWorld.invokedNames[member.name];
}
- if (selectors == null) {
- selectors = callSelectorsAsNamed();
- if (selectors == null) return;
- } else {
- Set<Selector> callSelectors = callSelectorsAsNamed();
- if (callSelectors != null) {
- selectors = selectors.union(callSelectors);
- }
+
+ if (canTearOff) {
+ String call = namer.closureInvocationSelectorName;
+ callSelectors = compiler.codegenWorld.invokedNames[call];
+ }
+
+ assert(emptySelectorSet.isEmpty);
+ if (selectors == null) selectors = emptySelectorSet;
+ if (callSelectors == null) callSelectors = emptySelectorSet;
+
+ List<AdapterStubMethod> adapters = <AdapterStubMethod>[];
+
+ if (selectors.isEmpty && callSelectors.isEmpty) {
+ return adapters;
}
+
+ // For every call-selector the corresponding selector with the name of the
+ // member.
+ //
+ // For example, for the call-selector `call(x, y)` the renamed selector
+ // for member `foo` would be `foo(x, y)`.
+ Set<Selector> renamedCallSelectors =
+ callSelectors.isEmpty ? emptySelectorSet : new Set<Selector>();
+
Set<Selector> untypedSelectors = new Set<Selector>();
- if (selectors != null) {
- for (Selector selector in selectors) {
- if (!selector.appliesUnnamed(member, compiler.world)) continue;
- if (untypedSelectors.add(selector.asUntyped)) {
- addParameterStub(member, selector, defineStub);
+
+ // Start with the callSelectors since they imply the generation of the
+ // non-call version.
+ for (Selector selector in callSelectors) {
+ Selector renamedSelector = new Selector.call(
+ member.name, member.library,
+ selector.argumentCount, selector.namedArguments);
+ renamedCallSelectors.add(renamedSelector);
+
+ if (!renamedSelector.appliesUnnamed(member, compiler.world)) continue;
+
+ if (untypedSelectors.add(renamedSelector.asUntyped)) {
+ AdapterStubMethod adapter =
+ generateParameterStub(member, renamedSelector, selector);
+ if (adapter != null) {
+ adapters.add(adapter);
}
}
}
- if (canTearOff) {
- selectors = compiler.codegenWorld.invokedNames[
- namer.closureInvocationSelectorName];
- if (selectors != null) {
- for (Selector selector in selectors) {
- selector = new Selector.call(
- member.name, member.library,
- selector.argumentCount, selector.namedArguments);
- if (!selector.appliesUnnamed(member, compiler.world)) continue;
- if (untypedSelectors.add(selector)) {
- addParameterStub(member, selector, defineStub);
- }
+
+ // Now run through the actual member selectors (eg. `foo$2(x, y)` and not
+ // `call$2(x, y)`. Some of them have already been generated because of the
+ // call-selectors (and they are in the renamedCallSelectors set.
+ for (Selector selector in selectors) {
+ if (renamedCallSelectors.contains(selector)) continue;
+ if (!selector.appliesUnnamed(member, compiler.world)) continue;
+
+ if (untypedSelectors.add(selector.asUntyped)) {
+ AdapterStubMethod adapter =
+ generateParameterStub(member, selector, null);
+ if (adapter != null) {
+ adapters.add(adapter);
}
}
}
+
+ return adapters;
}
void addMemberMethod(DartMethod method, ClassBuilder builder) {
@@ -256,13 +296,15 @@ class ContainerBuilder extends CodeEmitterHelper {
compiler.dumpInfoTask.registerElementAst(member,
builder.addProperty(name, code));
if (needsStubs) {
- addParameterStubs(
- member,
- (Selector selector, jsAst.Fun function) {
- compiler.dumpInfoTask.registerElementAst(member,
- builder.addProperty(namer.invocationName(selector),
- function));
- });
+ for (AdapterStubMethod adapter in
+ generateParameterStubs(member, canTearOff: false)) {
+ assert(adapter.callName == null);
+ String invocationName = adapter.name;
+ emitter.interceptorEmitter
+ .recordMangledNameOfMemberMethod(member, invocationName);
+ compiler.dumpInfoTask.registerElementAst(
+ member, builder.addProperty(invocationName, adapter.code));
+ }
}
return;
}
@@ -335,29 +377,25 @@ class ContainerBuilder extends CodeEmitterHelper {
List tearOffInfo = [new jsAst.LiteralString(callSelectorString)];
if (needsStubs || canTearOff) {
- addParameterStubs(member, (Selector selector, jsAst.Fun function) {
- expressions.add(function);
+ for (AdapterStubMethod adapter in
+ generateParameterStubs(member, canTearOff: canTearOff)) {
+ String invocationName = adapter.name;
+ emitter.interceptorEmitter
+ .recordMangledNameOfMemberMethod(member, invocationName);
+
+ expressions.add(adapter.code);
if (member.isInstanceMember) {
- Set invokedSelectors =
- compiler.codegenWorld.invokedNames[member.name];
- expressions.add(js.string(namer.invocationName(selector)));
+ expressions.add(js.string(invocationName));
} else {
+ // TOOD(floitsch): Since we know when reading static data versus
+ // instance data, we can eliminate this element.
expressions.add(js('null'));
- // TOOD(ahe): Since we know when reading static data versus instance
- // data, we can eliminate this element.
- }
- 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)}"';
}
+ String callName = adapter.callName;
+ String callSelectorString = (callName == null) ? 'null' : '"$callName"';
tearOffInfo.add(new jsAst.LiteralString(callSelectorString));
- }, canTearOff);
+ }
}
-
jsAst.Expression memberTypeExpression;
if (canTearOff || canBeReflected) {
DartType memberType;
« no previous file with comments | « pkg/compiler/lib/src/js_emitter/model.dart ('k') | pkg/compiler/lib/src/js_emitter/old_emitter/declarations.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698