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

Unified Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 11365170: Start new design for interceptors and implement String.charCodeAt with it. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 1 month 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: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
===================================================================
--- sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart (revision 14732)
+++ sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart (working copy)
@@ -45,6 +45,7 @@
String isolateProperties;
String classesCollector;
final Map<int, String> boundClosureCache;
ahe 2012/11/12 13:24:11 Document what "bound closure" means.
ngeoffray 2012/11/13 11:45:16 Done.
+ final Map<int, String> boundClosureInterceptorCache;
Set<ClassElement> checkedClasses;
final bool generateSourceMap;
@@ -54,6 +55,7 @@
mainBuffer = new CodeBuffer(),
this.namer = namer,
boundClosureCache = new Map<int, String>(),
+ boundClosureInterceptorCache = new Map<int, String>(),
ahe 2012/11/12 13:24:11 The term bound-closure-interceptor is confusing to
ngeoffray 2012/11/13 11:45:16 Done.
constantEmitter = new ConstantEmitter(compiler, namer),
super(compiler) {
nativeEmitter = new NativeEmitter(this);
@@ -617,7 +619,7 @@
bool needsLeadingComma) {
assert(invariant(classElement, classElement.isDeclaration));
bool needsComma = needsLeadingComma;
- void defineInstanceMember(String name, CodeBuffer memberBuffer) {
+ void defineInstanceMember(String name, StringBuffer memberBuffer) {
if (needsComma) buffer.add(',');
needsComma = true;
buffer.add('\n');
@@ -625,6 +627,12 @@
buffer.add(memberBuffer);
}
+ if (classElement == compiler.objectInterceptorClass) {
+ emitInterceptorMethods(defineInstanceMember);
+ // The ObjectIntercetpr does not have any instance methods.
ahe 2012/11/12 13:24:11 ObjectIntercetpr -> ObjectInterceptor
ngeoffray 2012/11/13 11:45:16 Done.
+ return;
+ }
+
classElement.implementation.forEachMember(
(ClassElement enclosing, Element member) {
assert(invariant(classElement, member.isDeclaration));
@@ -855,6 +863,39 @@
buffer.add('\n};\n\n');
}
+ void emitInterceptorMethods(
+ void defineInstanceMember(String name, StringBuffer memberBuffer)) {
+ JavaScriptBackend backend = compiler.backend;
+ // Emit forwarders for the ObjectInterceptor class. We need to
+ // emit all possible sends on intercepted methods.
+ for (Selector selector in backend.usedInterceptors) {
+ String name;
+ String comma = '';
+ String parameters = '';
+ if (selector.isGetter()) {
+ name = backend.namer.getterName(selector.library, selector.name);
+ } else if (selector.isSetter()) {
+ name = backend.namer.setterName(selector.library, selector.name);
+ } else {
+ assert(selector.isCall());
+ name = backend.namer.instanceMethodInvocationName(
+ selector.library, selector.name, selector);
+ if (selector.argumentCount > 0) {
+ comma = ', ';
+ int i = 0;
+ for (; i < selector.argumentCount - 1; i++) {
+ parameters = '${parameters}a$i, ';
+ }
+ parameters = '${parameters}a$i';
+ }
+ }
+ StringBuffer body = new StringBuffer(
+ "function(receiver$comma$parameters) {"
+ " return receiver.$name($parameters); }");
+ defineInstanceMember(name, body);
+ }
+ }
+
/**
* Generate "is tests" for [cls]: itself, and the "is tests" for the
* classes it implements. We don't need to add the "is tests" of the
@@ -1016,13 +1057,22 @@
}
void emitBoundClosureClassHeader(String mangledName,
- String superName,
- CodeBuffer buffer) {
- buffer.add("""
+ String superName,
+ String extraArg,
ahe 2012/11/12 13:24:11 extraArg -> extraArgument
ngeoffray 2012/11/13 11:45:16 Done.
+ CodeBuffer buffer) {
+ if (extraArg.isEmpty) {
ahe 2012/11/12 13:24:11 Could be simplified with this: extraArgument = ex
ngeoffray 2012/11/13 11:45:16 Done.
+ buffer.add("""
$classesCollector.$mangledName = {'':
['self', 'target'],
'super': '$superName',
""");
+ } else {
+ buffer.add("""
+$classesCollector.$mangledName = {'':
+['self', '$extraArg', 'target'],
+'super': '$superName',
+""");
+ }
}
/**
@@ -1057,8 +1107,26 @@
bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
int parameterCount = member.parameterCount(compiler);
+ Map<int, String> cache;
+ String extraArg;
+ String extraArgWithThis;
+ String extraArgWithoutComma;
+ // Methods on foreign classes take an extra parameter, which is
+ // the actual receiver of the call.
+ if (compiler.isForeignClass(member.getEnclosingClass())) {
+ cache = boundClosureInterceptorCache;
+ extraArg = 'receiver, ';
+ extraArgWithThis = 'this.receiver, ';
+ extraArgWithoutComma = 'receiver';
+ } else {
+ cache = boundClosureCache;
+ extraArg = '';
+ extraArgWithoutComma = '';
+ extraArgWithThis = '';
+ }
+
String closureClass =
- hasOptionalParameters ? null : boundClosureCache[parameterCount];
+ hasOptionalParameters ? null : cache[parameterCount];
if (closureClass == null) {
// Either the class was not cached yet, or there are optional parameters.
// Create a new closure class.
@@ -1071,14 +1139,15 @@
// Define the constructor with a name so that Object.toString can
// find the class name of the closure class.
- emitBoundClosureClassHeader(mangledName, superName, boundClosureBuffer);
+ emitBoundClosureClassHeader(
+ mangledName, superName, extraArgWithoutComma, boundClosureBuffer);
// Now add the methods on the closure class. The instance method does not
// have the correct name. Since [addParameterStubs] use the name to create
// its stubs we simply create a fake element with the correct name.
// Note: the callElement will not have any enclosingElement.
FunctionElement callElement =
new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member);
-
+
String invocationName = namer.instanceMethodName(callElement);
List<String> arguments = new List<String>(parameterCount);
for (int i = 0; i < parameterCount; i++) {
@@ -1087,7 +1156,8 @@
String joinedArgs = Strings.join(arguments, ", ");
boundClosureBuffer.add(
"$invocationName: function($joinedArgs) {");
- boundClosureBuffer.add(" return this.self[this.target]($joinedArgs);");
+ boundClosureBuffer.add(
+ " return this.self[this.target]($extraArgWithThis$joinedArgs);");
boundClosureBuffer.add(" }");
addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) {
boundClosureBuffer.add(',\n $stubName: $memberValue');
@@ -1098,7 +1168,7 @@
// Cache it.
if (!hasOptionalParameters) {
- boundClosureCache[parameterCount] = closureClass;
+ cache[parameterCount] = closureClass;
}
}
@@ -1106,8 +1176,8 @@
String getterName = namer.getterName(member.getLibrary(), member.name);
String targetName = namer.instanceMethodName(member);
CodeBuffer getterBuffer = new CodeBuffer();
- getterBuffer.add(
- "function() { return new $closureClass(this, '$targetName'); }");
+ getterBuffer.add("function($extraArgWithoutComma) "
+ "{ return new $closureClass(this, $extraArg'$targetName'); }");
defineInstanceMember(getterName, getterBuffer);
}

Powered by Google App Engine
This is Rietveld 408576698