Index: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
=================================================================== |
--- sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart (revision 22409) |
+++ sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart (working copy) |
@@ -1759,6 +1759,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 +1818,69 @@ |
} |
} |
+ final Map<Element, Element> staticGetters = new Map<Element, Element>(); |
sra1
2013/05/07 00:26:14
Is the key a FunctionElement?
ngeoffray
2013/05/13 10:24:48
Yes.
|
+ |
void emitStaticFunctionGetters(CodeBuffer eagerBuffer) { |
sra1
2013/05/07 00:26:14
Can we make constant functions be emitted instead
ngeoffray
2013/05/13 10:24:48
Not sure I understand what you mean here.
sra1
2013/05/14 03:19:46
What I mean is that the whole life-cycle of a stat
ngeoffray
2013/05/14 08:28:45
I see. So there is already a FunctionConstant to r
|
+ staticGetters.forEach((Element element, Element closure) { |
sra1
2013/05/07 00:26:14
Please emit in source order, otherwise output orde
ngeoffray
2013/05/13 10:24:48
Done.
|
+ CodeBuffer buffer = bufferForElement(element, eagerBuffer); |
+ String closureClass = namer.isolateAccess(closure); |
+ String name = namer.getStaticTearOffClosureName(element); |
+ String staticName = namer.getName(element); |
+ buffer.write('$isolateProperties.$name = '); |
sra1
2013/05/07 00:26:14
Please construct an AST and prettyPrint that to ge
ngeoffray
2013/05/13 10:24:48
Done.
|
+ buffer.write('new $closureClass($isolateProperties.$staticName)'); |
+ buffer.write('$N'); |
+ }); |
+ } |
+ |
+ void emitStaticFunctionClosures() { |
Set<FunctionElement> functionsNeedingGetter = |
compiler.codegenWorld.staticFunctionsNeedingGetter; |
sra1
2013/05/07 00:26:14
We have
staticGetters.keys
and
compiler.codege
ngeoffray
2013/05/13 10:24:48
None.
|
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 = 'TearOff_${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(); |
+ emitBoundClosureClassHeader( |
+ mangledName, superName, <String>[invocationName], closureBuilder); |
// 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'); |
- } |
- ); |
+ String tearOffName = namer.getStaticTearOffClosureName(element); |
+ closureBuilder.addProperty(fieldName, js('"$tearOffName"')); |
sra1
2013/05/07 00:26:14
Make $name a field of the closure, initialized by
ngeoffray
2013/05/13 10:24:48
Done.
|
+ |
+ addParameterStubs(callElement, closureBuilder.addProperty); |
+ |
+ DartType type = element.computeType(compiler); |
+ getTypedefChecksOn(type).forEach((Element typedef) { |
+ String operator = namer.operatorIs(typedef); |
+ closureBuilder.addProperty(operator, js('true')); |
+ }); |
+ |
+ boundClosures.add( |
+ js('$classesCollector.$mangledName = #', |
+ closureBuilder.toObjectInitializer())); |
+ |
+ staticGetters[element] = closureClassElement; |
} |
} |
@@ -2353,15 +2384,10 @@ |
String buildIsolateSetup(CodeBuffer buffer, |
Element appMain, |
Element isolateMain) { |
- String mainAccess = "${namer.isolateAccess(appMain)}"; |
+ String mainAccess = "${namer.isolateStaticTearOffClosureAccess(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 +2479,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 +2488,6 @@ |
bool hasArray = false; |
bool hasBool = false; |
bool hasDouble = false; |
- bool hasFunction = false; |
bool hasInt = false; |
bool hasNull = false; |
bool hasNumber = false; |
@@ -2477,7 +2500,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 +2560,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 +2939,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 +2986,7 @@ |
deferredBuffer.add("\$\$$_=${_}null$N$n"); |
} |
+ emitStaticFunctionClosures(); |
emitClosureClassIfNeeded(mainBuffer); |
addComment('Bound closures', mainBuffer); |