Index: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
=================================================================== |
--- sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart (revision 22664) |
+++ sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart (working copy) |
@@ -158,6 +158,8 @@ |
checkedTypedefs.add(t.element); |
} |
}); |
+ print(compiler.resolverWorld.isChecks); |
+ print(compiler.codegenWorld.isChecks); |
} |
ClassElement computeMixinClass(MixinApplicationElement mixinApplication) { |
@@ -1759,6 +1761,10 @@ |
// of stubs. |
ClassElement closureClass = compiler.closureClass; |
if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { |
+ ClassElement objectClass = compiler.objectClass; |
+ if (!instantiatedClasses.contains(objectClass)) { |
+ generateClass(objectClass, bufferForElement(objectClass, buffer)); |
+ } |
generateClass(closureClass, bufferForElement(closureClass, buffer)); |
} |
} |
@@ -1814,42 +1820,74 @@ |
} |
} |
+ final Map<Element, Element> staticGetters = new Map<Element, Element>(); |
+ |
void emitStaticFunctionGetters(CodeBuffer eagerBuffer) { |
+ for (FunctionElement element in |
+ Elements.sortedByPosition(staticGetters.keys)) { |
+ Element closure = staticGetters[element]; |
+ CodeBuffer buffer = bufferForElement(element, eagerBuffer); |
+ String closureClass = namer.isolateAccess(closure); |
+ String name = namer.getStaticClosureName(element); |
+ String staticName = namer.getName(element); |
+ |
+ String closureName = namer.getStaticClosureName(element); |
+ jsAst.Node assignment = js('$isolateProperties.$name = ' |
+ 'new $closureClass($isolateProperties.$staticName, "$closureName")'); |
ahe
2013/05/16 20:07:56
This broke deferred loading (and try.dartlang.org)
sra1
2013/05/16 20:28:33
This would 'just work' if static function closures
ahe
2013/05/16 20:30:44
I was thinking the same thing. Well, up to the se
|
+ buffer.write(jsAst.prettyPrint(assignment, compiler)); |
+ buffer.write('$N'); |
+ } |
+ } |
+ |
+ void emitStaticFunctionClosures() { |
Set<FunctionElement> functionsNeedingGetter = |
compiler.codegenWorld.staticFunctionsNeedingGetter; |
for (FunctionElement element in |
Elements.sortedByPosition(functionsNeedingGetter)) { |
- CodeBuffer buffer = bufferForElement(element, eagerBuffer); |
+ String staticName = namer.getName(element); |
+ String superName = namer.getName(compiler.closureClass); |
+ String name = 'Closure\$${element.name.slowToString()}'; |
+ needsClosureClass = true; |
- // The static function 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. |
+ ClassElement closureClassElement = new ClosureClassElement( |
+ null, new SourceString(name), compiler, element, |
+ element.getCompilationUnit()); |
+ // 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.closureInvocationSelectorName, |
element); |
- String staticName = namer.getName(element); |
+ |
String invocationName = namer.instanceMethodName(callElement); |
- String fieldAccess = '$isolateProperties.$staticName'; |
- buffer.write("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); |
+ String mangledName = namer.getName(closureClassElement); |
- addParameterStubs(callElement, (String name, jsAst.Expression value) { |
- jsAst.Expression assignment = |
- js('$isolateProperties.$staticName.$name = #', value); |
- buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); |
- buffer.write('$N'); |
+ // Define the constructor with a name so that Object.toString can |
+ // find the class name of the closure class. |
+ ClassBuilder closureBuilder = new ClassBuilder(); |
+ // If a static function is used as a closure we need to add its name |
+ // in case it is used in spawnFunction. |
+ String methodName = namer.STATIC_CLOSURE_NAME_NAME; |
+ emitBoundClosureClassHeader( |
+ mangledName, superName, <String>[invocationName, methodName], |
+ closureBuilder); |
+ |
+ addParameterStubs(callElement, closureBuilder.addProperty); |
+ |
+ DartType type = element.computeType(compiler); |
+ getTypedefChecksOn(type).forEach((Element typedef) { |
+ String operator = namer.operatorIs(typedef); |
+ closureBuilder.addProperty(operator, js('true')); |
}); |
- // If a static function is used as a closure we need to add its name |
- // in case it is used in spawnFunction. |
- String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
- buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); |
- getTypedefChecksOn(element.computeType(compiler)).forEach( |
- (Element typedef) { |
- String operator = namer.operatorIs(typedef); |
- buffer.write('$fieldAccess.$operator$_=${_}true$N'); |
- } |
- ); |
+ // TODO(ngeoffray): Cache common base classes for clsures, bound |
+ // closures, and static closures that have common type checks. |
+ boundClosures.add( |
+ js('$classesCollector.$mangledName = #', |
+ closureBuilder.toObjectInitializer())); |
+ |
+ staticGetters[element] = closureClassElement; |
} |
} |
@@ -2353,15 +2391,10 @@ |
String buildIsolateSetup(CodeBuffer buffer, |
Element appMain, |
Element isolateMain) { |
- String mainAccess = "${namer.isolateAccess(appMain)}"; |
+ String mainAccess = "${namer.isolateStaticClosureAccess(appMain)}"; |
String currentIsolate = "${namer.CURRENT_ISOLATE}"; |
// Since we pass the closurized version of the main method to |
// the isolate method, we must make sure that it exists. |
- if (!compiler.codegenWorld.staticFunctionsNeedingGetter.contains(appMain)) { |
- Selector selector = new Selector.callClosure(0); |
- String invocationName = namer.invocationName(selector); |
- buffer.write("$mainAccess.$invocationName = $mainAccess$N"); |
- } |
return "${namer.isolateAccess(isolateMain)}($mainAccess)"; |
} |
@@ -2453,8 +2486,6 @@ |
condition = js('(typeof receiver) == "string"'); |
} else if (cls == backend.jsNullClass) { |
condition = js('receiver == null'); |
- } else if (cls == backend.jsFunctionClass) { |
- condition = js('(typeof receiver) == "function"'); |
} else { |
throw 'internal error'; |
} |
@@ -2464,7 +2495,6 @@ |
bool hasArray = false; |
bool hasBool = false; |
bool hasDouble = false; |
- bool hasFunction = false; |
bool hasInt = false; |
bool hasNull = false; |
bool hasNumber = false; |
@@ -2477,7 +2507,6 @@ |
cls == backend.jsExtendableArrayClass) hasArray = true; |
else if (cls == backend.jsBoolClass) hasBool = true; |
else if (cls == backend.jsDoubleClass) hasDouble = true; |
- else if (cls == backend.jsFunctionClass) hasFunction = true; |
else if (cls == backend.jsIntClass) hasInt = true; |
else if (cls == backend.jsNullClass) hasNull = true; |
else if (cls == backend.jsNumberClass) hasNumber = true; |
@@ -2538,9 +2567,6 @@ |
block.statements.add(js.if_('receiver == null', |
js.return_(js('receiver')))); |
} |
- if (hasFunction) { |
- block.statements.add(buildInterceptorCheck(backend.jsFunctionClass)); |
- } |
if (hasBool) { |
block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); |
} |
@@ -2920,7 +2946,8 @@ |
if (!regularClasses.isEmpty || |
!deferredClasses.isEmpty || |
- !nativeClasses.isEmpty) { |
+ !nativeClasses.isEmpty || |
+ !compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty) { |
// Shorten the code by using "$$" as temporary. |
classesCollector = r"$$"; |
mainBuffer.add('var $classesCollector$_=$_{}$N$n'); |
@@ -2966,6 +2993,7 @@ |
deferredBuffer.add("\$\$$_=${_}null$N$n"); |
} |
+ emitStaticFunctionClosures(); |
emitClosureClassIfNeeded(mainBuffer); |
addComment('Bound closures', mainBuffer); |