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

Unified Diff: lib/compiler/implementation/emitter.dart

Issue 10832109: Refactor the way we emit no such method handlers so it's easier to optimize it later. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Improve NSM handling. Created 8 years, 5 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
« no previous file with comments | « no previous file | lib/compiler/implementation/namer.dart » ('j') | lib/compiler/implementation/world.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/emitter.dart
diff --git a/lib/compiler/implementation/emitter.dart b/lib/compiler/implementation/emitter.dart
index 3ebf5bb43fad45c317835d39ded6ec56cd17f712..e468a329682567e9acbd24c4d3cca5e4e7cb1086 100644
--- a/lib/compiler/implementation/emitter.dart
+++ b/lib/compiler/implementation/emitter.dart
@@ -535,11 +535,11 @@ function(collectedClasses) {
});
if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) {
- // Emit the noSuchMethods on the Object prototype now, so that
- // the code in the dynamicMethod can find them. Note that the
- // code in dynamicMethod is invoked before analyzing the full JS
- // script.
- emitNoSuchMethodCalls(defineInstanceMember);
+ // Emit the noSuchMethod handlers on the Object prototype now,
+ // so that the code in the dynamicFunction helper can find
+ // them. Note that this helper is invoked before analyzing the
+ // full JS script.
+ emitNoSuchMethodHandlers(defineInstanceMember);
}
}
@@ -865,8 +865,8 @@ $classesCollector.$mangledName = {'':
}
}
- void emitNoSuchMethodCalls(DefineMemberFunction defineInstanceMember) {
- // Do not generate no such method calls if there is no class.
+ void emitNoSuchMethodHandlers(DefineMemberFunction defineInstanceMember) {
+ // Do not generate no such method handlers if there is no class.
if (compiler.codegenWorld.instantiatedClasses.isEmpty()) return;
ClassElement objectClass =
@@ -875,86 +875,92 @@ $classesCollector.$mangledName = {'':
'${namer.isolateAccess(objectClass)}.prototype';
String noSuchMethodName =
namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2);
- Collection<LibraryElement> libraries = compiler.libraries.getValues();
+
+ // Keep track of the JavaScript names we've already added so we
+ // do not introduce duplicates (bad for code size).
+ Set<String> addedJsNames = new Set<String>();
CodeBuffer generateMethod(String methodName, Selector selector) {
- CodeBuffer buffer = new CodeBuffer();
- buffer.add('function');
CodeBuffer args = new CodeBuffer();
for (int i = 0; i < selector.argumentCount; i++) {
if (i != 0) args.add(', ');
- args.add('arg$i');
+ args.add('\$$i');
}
// We need to check if the object has a noSuchMethod. If not, it
// means the object is a native object, and we can just call our
// generic noSuchMethod. Note that when calling this method, the
// 'this' object is not a Dart object.
- buffer.add(' ($args) {\n');
+ CodeBuffer buffer = new CodeBuffer();
+ buffer.add('function($args) {\n');
buffer.add(' return this.$noSuchMethodName\n');
buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n");
buffer.add(" : $runtimeObjectPrototype.$noSuchMethodName.call(");
buffer.add("this, '$methodName', [$args])\n");
- buffer.add('}');
+ buffer.add(' }');
return buffer;
}
- compiler.codegenWorld.invokedNames.forEach((SourceString methodName,
- Set<Selector> selectors) {
- if (objectClass.lookupLocalMember(methodName) === null
- && methodName != Elements.OPERATOR_EQUALS) {
- for (Selector selector in selectors) {
- if (methodName.isPrivate()) {
- for (LibraryElement lib in libraries) {
- String jsName =
- namer.instanceMethodInvocationName(lib, methodName, selector);
- CodeBuffer method =
- generateMethod(methodName.slowToString(), selector);
- defineInstanceMember(jsName, method);
- }
- } else {
- String jsName =
- namer.instanceMethodInvocationName(null, methodName, selector);
- CodeBuffer method = generateMethod(methodName.slowToString(),
- selector);
- defineInstanceMember(jsName, method);
+ void addNoSuchMethodHandlers(SourceString name, Set<Selector> selectors) {
+ // TODO(kasperl): It seems wrong to avoid generating no such
+ // method handlers for methods that exist in the Object class
+ // without taking the selector (arity) into account. Needs more
+ // investigation.
+ if (objectClass.lookupLocalMember(name) !== null &&
+ name != Elements.OPERATOR_EQUALS) return;
+
+ // TODO(kasperl): We should really teach private selectors about
+ // which libraries they are used from. That way, we wouldn't
+ // have to conservatively generate versions for all libraries
+ // the name is used from.
+ String nameString = name.slowToString();
+ Collection<LibraryElement> libraries = name.isPrivate()
+ ? namer.usedPrivateNames[nameString]
+ : const [ null ];
+
+ for (Selector selector in selectors) {
+ // If the selector is typed, we check to see if that type may
+ // have a user-defined noSuchMethod implementation. If not, we
+ // skip the selector altogether.
+ if (selector is TypedSelector) {
+ Type receiverType = (selector as TypedSelector).receiverType;
+ // For now, we check the entire world to see if an object of
+ // the receiver type may have a user-defined noSuchMethod
+ // implementation. We could do better by only looking at
+ // instantiated classes.
+ if (!compiler.world.mayHaveUserDefinedNoSuchMethod(receiverType)) {
+ continue;
}
}
- }
- });
- compiler.codegenWorld.invokedGetters.forEach((SourceString getterName,
- Set<Selector> selectors) {
- if (getterName.isPrivate()) {
for (LibraryElement lib in libraries) {
- String jsName = namer.getterName(lib, getterName);
- CodeBuffer method = generateMethod('get ${getterName.slowToString()}',
- Selector.GETTER);
- defineInstanceMember(jsName, method);
+ String jsName = null;
+ String methodName = null;
+ if (selector.kind === SelectorKind.GETTER) {
+ jsName = namer.getterName(lib, name);
+ methodName = 'get $nameString';
+ } else if (selector.kind === SelectorKind.SETTER) {
+ jsName = namer.setterName(lib, name);
+ methodName = 'set $nameString';
+ } else if (selector.kind === SelectorKind.INVOCATION) {
+ jsName = namer.instanceMethodInvocationName(lib, name, selector);
+ methodName = nameString;
+ } else {
+ // We simply ignore selectors that do not need no such
+ // method handlers.
+ continue;
+ }
+ if (!addedJsNames.contains(jsName)) {
+ CodeBuffer jsCode = generateMethod(methodName, selector);
+ defineInstanceMember(jsName, jsCode);
+ addedJsNames.add(jsName);
+ }
}
- } else {
- String jsName = namer.getterName(null, getterName);
- CodeBuffer method = generateMethod('get ${getterName.slowToString()}',
- Selector.GETTER);
- defineInstanceMember(jsName, method);
}
- });
+ }
- compiler.codegenWorld.invokedSetters.forEach((SourceString setterName,
- Set<Selector> selectors) {
- if (setterName.isPrivate()) {
- for (LibraryElement lib in libraries) {
- String jsName = namer.setterName(lib, setterName);
- CodeBuffer method = generateMethod('set ${setterName.slowToString()}',
- Selector.SETTER);
- defineInstanceMember(jsName, method);
- }
- } else {
- String jsName = namer.setterName(null, setterName);
- CodeBuffer method = generateMethod('set ${setterName.slowToString()}',
- Selector.SETTER);
- defineInstanceMember(jsName, method);
- }
- });
+ compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers);
+ compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers);
+ compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers);
}
String buildIsolateSetup(CodeBuffer buffer,
« no previous file with comments | « no previous file | lib/compiler/implementation/namer.dart » ('j') | lib/compiler/implementation/world.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698