OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of js_backend; | 5 part of js_backend; |
6 | 6 |
7 /** | 7 /** |
8 * A function element that represents a closure call. The signature is copied | 8 * A function element that represents a closure call. The signature is copied |
9 * from the given element. | 9 * from the given element. |
10 */ | 10 */ |
(...skipping 1741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1752 } | 1752 } |
1753 | 1753 |
1754 return (ClassElement cls) => !unneededClasses.contains(cls); | 1754 return (ClassElement cls) => !unneededClasses.contains(cls); |
1755 } | 1755 } |
1756 | 1756 |
1757 void emitClosureClassIfNeeded(CodeBuffer buffer) { | 1757 void emitClosureClassIfNeeded(CodeBuffer buffer) { |
1758 // The closure class could have become necessary because of the generation | 1758 // The closure class could have become necessary because of the generation |
1759 // of stubs. | 1759 // of stubs. |
1760 ClassElement closureClass = compiler.closureClass; | 1760 ClassElement closureClass = compiler.closureClass; |
1761 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { | 1761 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { |
1762 ClassElement objectClass = compiler.objectClass; | |
1763 if (!instantiatedClasses.contains(objectClass)) { | |
1764 generateClass(objectClass, bufferForElement(objectClass, buffer)); | |
1765 } | |
1762 generateClass(closureClass, bufferForElement(closureClass, buffer)); | 1766 generateClass(closureClass, bufferForElement(closureClass, buffer)); |
1763 } | 1767 } |
1764 } | 1768 } |
1765 | 1769 |
1766 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { | 1770 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { |
1767 if (needsDefineClass) { | 1771 if (needsDefineClass) { |
1768 buffer.write('$finishClassesName($classesCollector,' | 1772 buffer.write('$finishClassesName($classesCollector,' |
1769 '$_$isolateProperties,' | 1773 '$_$isolateProperties,' |
1770 '${_}null)$N'); | 1774 '${_}null)$N'); |
1771 | 1775 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1807 | 1811 |
1808 // Is it possible the primary function was inlined but the bailout was not? | 1812 // Is it possible the primary function was inlined but the bailout was not? |
1809 for (Element element in | 1813 for (Element element in |
1810 Elements.sortedByPosition(pendingElementsWithBailouts)) { | 1814 Elements.sortedByPosition(pendingElementsWithBailouts)) { |
1811 CodeBuffer buffer = bufferForElement(element, eagerBuffer); | 1815 CodeBuffer buffer = bufferForElement(element, eagerBuffer); |
1812 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; | 1816 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; |
1813 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 1817 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); |
1814 } | 1818 } |
1815 } | 1819 } |
1816 | 1820 |
1821 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.
| |
1822 | |
1817 void emitStaticFunctionGetters(CodeBuffer eagerBuffer) { | 1823 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
| |
1824 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.
| |
1825 CodeBuffer buffer = bufferForElement(element, eagerBuffer); | |
1826 String closureClass = namer.isolateAccess(closure); | |
1827 String name = namer.getStaticTearOffClosureName(element); | |
1828 String staticName = namer.getName(element); | |
1829 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.
| |
1830 buffer.write('new $closureClass($isolateProperties.$staticName)'); | |
1831 buffer.write('$N'); | |
1832 }); | |
1833 } | |
1834 | |
1835 void emitStaticFunctionClosures() { | |
1818 Set<FunctionElement> functionsNeedingGetter = | 1836 Set<FunctionElement> functionsNeedingGetter = |
1819 compiler.codegenWorld.staticFunctionsNeedingGetter; | 1837 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.
| |
1820 for (FunctionElement element in | 1838 for (FunctionElement element in |
1821 Elements.sortedByPosition(functionsNeedingGetter)) { | 1839 Elements.sortedByPosition(functionsNeedingGetter)) { |
1822 CodeBuffer buffer = bufferForElement(element, eagerBuffer); | 1840 String staticName = namer.getName(element); |
1841 String superName = namer.getName(compiler.closureClass); | |
1842 String name = 'TearOff_${element.name.slowToString()}'; | |
1843 needsClosureClass = true; | |
1823 | 1844 |
1824 // The static function does not have the correct name. Since | 1845 ClassElement closureClassElement = new ClosureClassElement( |
1825 // [addParameterStubs] use the name to create its stubs we simply | 1846 null, new SourceString(name), compiler, element, |
1826 // create a fake element with the correct name. | 1847 element.getCompilationUnit()); |
1848 // Now add the methods on the closure class. The instance method does not | |
1849 // have the correct name. Since [addParameterStubs] use the name to create | |
1850 // its stubs we simply create a fake element with the correct name. | |
1827 // Note: the callElement will not have any enclosingElement. | 1851 // Note: the callElement will not have any enclosingElement. |
1828 FunctionElement callElement = | 1852 FunctionElement callElement = |
1829 new ClosureInvocationElement(namer.closureInvocationSelectorName, | 1853 new ClosureInvocationElement(namer.closureInvocationSelectorName, |
1830 element); | 1854 element); |
1831 String staticName = namer.getName(element); | 1855 |
1832 String invocationName = namer.instanceMethodName(callElement); | 1856 String invocationName = namer.instanceMethodName(callElement); |
1833 String fieldAccess = '$isolateProperties.$staticName'; | 1857 String mangledName = namer.getName(closureClassElement); |
1834 buffer.write("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); | |
1835 | 1858 |
1836 addParameterStubs(callElement, (String name, jsAst.Expression value) { | 1859 // Define the constructor with a name so that Object.toString can |
1837 jsAst.Expression assignment = | 1860 // find the class name of the closure class. |
1838 js('$isolateProperties.$staticName.$name = #', value); | 1861 ClassBuilder closureBuilder = new ClassBuilder(); |
1839 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); | 1862 emitBoundClosureClassHeader( |
1840 buffer.write('$N'); | 1863 mangledName, superName, <String>[invocationName], closureBuilder); |
1841 }); | |
1842 | 1864 |
1843 // If a static function is used as a closure we need to add its name | 1865 // If a static function is used as a closure we need to add its name |
1844 // in case it is used in spawnFunction. | 1866 // in case it is used in spawnFunction. |
1845 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1867 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
1846 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); | 1868 String tearOffName = namer.getStaticTearOffClosureName(element); |
1847 getTypedefChecksOn(element.computeType(compiler)).forEach( | 1869 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.
| |
1848 (Element typedef) { | 1870 |
1849 String operator = namer.operatorIs(typedef); | 1871 addParameterStubs(callElement, closureBuilder.addProperty); |
1850 buffer.write('$fieldAccess.$operator$_=${_}true$N'); | 1872 |
1851 } | 1873 DartType type = element.computeType(compiler); |
1852 ); | 1874 getTypedefChecksOn(type).forEach((Element typedef) { |
1875 String operator = namer.operatorIs(typedef); | |
1876 closureBuilder.addProperty(operator, js('true')); | |
1877 }); | |
1878 | |
1879 boundClosures.add( | |
1880 js('$classesCollector.$mangledName = #', | |
1881 closureBuilder.toObjectInitializer())); | |
1882 | |
1883 staticGetters[element] = closureClassElement; | |
1853 } | 1884 } |
1854 } | 1885 } |
1855 | 1886 |
1856 void emitBoundClosureClassHeader(String mangledName, | 1887 void emitBoundClosureClassHeader(String mangledName, |
1857 String superName, | 1888 String superName, |
1858 List<String> fieldNames, | 1889 List<String> fieldNames, |
1859 ClassBuilder builder) { | 1890 ClassBuilder builder) { |
1860 builder.addProperty('', | 1891 builder.addProperty('', |
1861 js.string("$superName;${fieldNames.join(',')}")); | 1892 js.string("$superName;${fieldNames.join(',')}")); |
1862 } | 1893 } |
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2346 for (String jsName in addedJsNames.keys.toList()..sort()) { | 2377 for (String jsName in addedJsNames.keys.toList()..sort()) { |
2347 Selector selector = addedJsNames[jsName]; | 2378 Selector selector = addedJsNames[jsName]; |
2348 jsAst.Expression method = generateMethod(jsName, selector); | 2379 jsAst.Expression method = generateMethod(jsName, selector); |
2349 if (method != null) defineStub(jsName, method); | 2380 if (method != null) defineStub(jsName, method); |
2350 } | 2381 } |
2351 } | 2382 } |
2352 | 2383 |
2353 String buildIsolateSetup(CodeBuffer buffer, | 2384 String buildIsolateSetup(CodeBuffer buffer, |
2354 Element appMain, | 2385 Element appMain, |
2355 Element isolateMain) { | 2386 Element isolateMain) { |
2356 String mainAccess = "${namer.isolateAccess(appMain)}"; | 2387 String mainAccess = "${namer.isolateStaticTearOffClosureAccess(appMain)}"; |
2357 String currentIsolate = "${namer.CURRENT_ISOLATE}"; | 2388 String currentIsolate = "${namer.CURRENT_ISOLATE}"; |
2358 // Since we pass the closurized version of the main method to | 2389 // Since we pass the closurized version of the main method to |
2359 // the isolate method, we must make sure that it exists. | 2390 // the isolate method, we must make sure that it exists. |
2360 if (!compiler.codegenWorld.staticFunctionsNeedingGetter.contains(appMain)) { | |
2361 Selector selector = new Selector.callClosure(0); | |
2362 String invocationName = namer.invocationName(selector); | |
2363 buffer.write("$mainAccess.$invocationName = $mainAccess$N"); | |
2364 } | |
2365 return "${namer.isolateAccess(isolateMain)}($mainAccess)"; | 2391 return "${namer.isolateAccess(isolateMain)}($mainAccess)"; |
2366 } | 2392 } |
2367 | 2393 |
2368 String get nameOfDispatchPropertyInitializer => 'initializeDispatchProperty'; | 2394 String get nameOfDispatchPropertyInitializer => 'initializeDispatchProperty'; |
2369 | 2395 |
2370 jsAst.Expression generateDispatchPropertyInitialization() { | 2396 jsAst.Expression generateDispatchPropertyInitialization() { |
2371 String ref(Element element) { | 2397 String ref(Element element) { |
2372 return '${namer.CURRENT_ISOLATE}.${namer.getName(element)}'; | 2398 return '${namer.CURRENT_ISOLATE}.${namer.getName(element)}'; |
2373 } | 2399 } |
2374 | 2400 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2446 throw 'internal error'; | 2472 throw 'internal error'; |
2447 } else if (cls == backend.jsArrayClass || | 2473 } else if (cls == backend.jsArrayClass || |
2448 cls == backend.jsMutableArrayClass || | 2474 cls == backend.jsMutableArrayClass || |
2449 cls == backend.jsFixedArrayClass || | 2475 cls == backend.jsFixedArrayClass || |
2450 cls == backend.jsExtendableArrayClass) { | 2476 cls == backend.jsExtendableArrayClass) { |
2451 condition = js('receiver.constructor == Array'); | 2477 condition = js('receiver.constructor == Array'); |
2452 } else if (cls == backend.jsStringClass) { | 2478 } else if (cls == backend.jsStringClass) { |
2453 condition = js('(typeof receiver) == "string"'); | 2479 condition = js('(typeof receiver) == "string"'); |
2454 } else if (cls == backend.jsNullClass) { | 2480 } else if (cls == backend.jsNullClass) { |
2455 condition = js('receiver == null'); | 2481 condition = js('receiver == null'); |
2456 } else if (cls == backend.jsFunctionClass) { | |
2457 condition = js('(typeof receiver) == "function"'); | |
2458 } else { | 2482 } else { |
2459 throw 'internal error'; | 2483 throw 'internal error'; |
2460 } | 2484 } |
2461 return js.if_(condition, buildReturnInterceptor(cls)); | 2485 return js.if_(condition, buildReturnInterceptor(cls)); |
2462 } | 2486 } |
2463 | 2487 |
2464 bool hasArray = false; | 2488 bool hasArray = false; |
2465 bool hasBool = false; | 2489 bool hasBool = false; |
2466 bool hasDouble = false; | 2490 bool hasDouble = false; |
2467 bool hasFunction = false; | |
2468 bool hasInt = false; | 2491 bool hasInt = false; |
2469 bool hasNull = false; | 2492 bool hasNull = false; |
2470 bool hasNumber = false; | 2493 bool hasNumber = false; |
2471 bool hasString = false; | 2494 bool hasString = false; |
2472 bool hasNative = false; | 2495 bool hasNative = false; |
2473 for (ClassElement cls in classes) { | 2496 for (ClassElement cls in classes) { |
2474 if (cls == backend.jsArrayClass || | 2497 if (cls == backend.jsArrayClass || |
2475 cls == backend.jsMutableArrayClass || | 2498 cls == backend.jsMutableArrayClass || |
2476 cls == backend.jsFixedArrayClass || | 2499 cls == backend.jsFixedArrayClass || |
2477 cls == backend.jsExtendableArrayClass) hasArray = true; | 2500 cls == backend.jsExtendableArrayClass) hasArray = true; |
2478 else if (cls == backend.jsBoolClass) hasBool = true; | 2501 else if (cls == backend.jsBoolClass) hasBool = true; |
2479 else if (cls == backend.jsDoubleClass) hasDouble = true; | 2502 else if (cls == backend.jsDoubleClass) hasDouble = true; |
2480 else if (cls == backend.jsFunctionClass) hasFunction = true; | |
2481 else if (cls == backend.jsIntClass) hasInt = true; | 2503 else if (cls == backend.jsIntClass) hasInt = true; |
2482 else if (cls == backend.jsNullClass) hasNull = true; | 2504 else if (cls == backend.jsNullClass) hasNull = true; |
2483 else if (cls == backend.jsNumberClass) hasNumber = true; | 2505 else if (cls == backend.jsNumberClass) hasNumber = true; |
2484 else if (cls == backend.jsStringClass) hasString = true; | 2506 else if (cls == backend.jsStringClass) hasString = true; |
2485 else { | 2507 else { |
2486 // TODO(sra): The set of classes includes classes mixed-in to | 2508 // TODO(sra): The set of classes includes classes mixed-in to |
2487 // interceptor classes. | 2509 // interceptor classes. |
2488 // assert(cls == compiler.objectClass || cls.isNative()); | 2510 // assert(cls == compiler.objectClass || cls.isNative()); |
2489 if (cls.isNative()) hasNative = true; | 2511 if (cls.isNative()) hasNative = true; |
2490 } | 2512 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2531 } | 2553 } |
2532 if (hasNull) { | 2554 if (hasNull) { |
2533 block.statements.add(buildInterceptorCheck(backend.jsNullClass)); | 2555 block.statements.add(buildInterceptorCheck(backend.jsNullClass)); |
2534 } else { | 2556 } else { |
2535 // Returning "undefined" or "null" here will provoke a JavaScript | 2557 // Returning "undefined" or "null" here will provoke a JavaScript |
2536 // TypeError which is later identified as a null-error by | 2558 // TypeError which is later identified as a null-error by |
2537 // [unwrapException] in js_helper.dart. | 2559 // [unwrapException] in js_helper.dart. |
2538 block.statements.add(js.if_('receiver == null', | 2560 block.statements.add(js.if_('receiver == null', |
2539 js.return_(js('receiver')))); | 2561 js.return_(js('receiver')))); |
2540 } | 2562 } |
2541 if (hasFunction) { | |
2542 block.statements.add(buildInterceptorCheck(backend.jsFunctionClass)); | |
2543 } | |
2544 if (hasBool) { | 2563 if (hasBool) { |
2545 block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); | 2564 block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); |
2546 } | 2565 } |
2547 // TODO(ahe): It might be faster to check for Array before | 2566 // TODO(ahe): It might be faster to check for Array before |
2548 // function and bool. | 2567 // function and bool. |
2549 if (hasArray) { | 2568 if (hasArray) { |
2550 block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); | 2569 block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); |
2551 } | 2570 } |
2552 | 2571 |
2553 if (hasNative) { | 2572 if (hasNative) { |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2913 addComment(HOOKS_API_USAGE, mainBuffer); | 2932 addComment(HOOKS_API_USAGE, mainBuffer); |
2914 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); | 2933 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); |
2915 mainBuffer.add('init()$N$n'); | 2934 mainBuffer.add('init()$N$n'); |
2916 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. | 2935 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. |
2917 isolateProperties = namer.CURRENT_ISOLATE; | 2936 isolateProperties = namer.CURRENT_ISOLATE; |
2918 mainBuffer.add( | 2937 mainBuffer.add( |
2919 'var $isolateProperties$_=$_$isolatePropertiesName$N'); | 2938 'var $isolateProperties$_=$_$isolatePropertiesName$N'); |
2920 | 2939 |
2921 if (!regularClasses.isEmpty || | 2940 if (!regularClasses.isEmpty || |
2922 !deferredClasses.isEmpty || | 2941 !deferredClasses.isEmpty || |
2923 !nativeClasses.isEmpty) { | 2942 !nativeClasses.isEmpty || |
2943 !compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty) { | |
2924 // Shorten the code by using "$$" as temporary. | 2944 // Shorten the code by using "$$" as temporary. |
2925 classesCollector = r"$$"; | 2945 classesCollector = r"$$"; |
2926 mainBuffer.add('var $classesCollector$_=$_{}$N$n'); | 2946 mainBuffer.add('var $classesCollector$_=$_{}$N$n'); |
2927 } | 2947 } |
2928 | 2948 |
2929 // As a side-effect, emitting classes will produce "bound closures" in | 2949 // As a side-effect, emitting classes will produce "bound closures" in |
2930 // [boundClosures]. The bound closures are JS AST nodes that add | 2950 // [boundClosures]. The bound closures are JS AST nodes that add |
2931 // properties to $$ [classesCollector]. The bound closures are not | 2951 // properties to $$ [classesCollector]. The bound closures are not |
2932 // emitted until we have emitted all other classes (native or not). | 2952 // emitted until we have emitted all other classes (native or not). |
2933 | 2953 |
(...skipping 25 matching lines...) Expand all Loading... | |
2959 generateClass(element, deferredBuffer); | 2979 generateClass(element, deferredBuffer); |
2960 } | 2980 } |
2961 | 2981 |
2962 deferredBuffer.add('$finishClassesName(\$\$,' | 2982 deferredBuffer.add('$finishClassesName(\$\$,' |
2963 '$_${namer.CURRENT_ISOLATE},' | 2983 '$_${namer.CURRENT_ISOLATE},' |
2964 '$_$isolatePropertiesName)$N'); | 2984 '$_$isolatePropertiesName)$N'); |
2965 // Reset the map. | 2985 // Reset the map. |
2966 deferredBuffer.add("\$\$$_=${_}null$N$n"); | 2986 deferredBuffer.add("\$\$$_=${_}null$N$n"); |
2967 } | 2987 } |
2968 | 2988 |
2989 emitStaticFunctionClosures(); | |
2969 emitClosureClassIfNeeded(mainBuffer); | 2990 emitClosureClassIfNeeded(mainBuffer); |
2970 | 2991 |
2971 addComment('Bound closures', mainBuffer); | 2992 addComment('Bound closures', mainBuffer); |
2972 // Now that we have emitted all classes, we know all the bound | 2993 // Now that we have emitted all classes, we know all the bound |
2973 // closures that will be needed. | 2994 // closures that will be needed. |
2974 for (jsAst.Node node in boundClosures) { | 2995 for (jsAst.Node node in boundClosures) { |
2975 // TODO(ahe): Some of these can be deferred. | 2996 // TODO(ahe): Some of these can be deferred. |
2976 mainBuffer.add(jsAst.prettyPrint(node, compiler)); | 2997 mainBuffer.add(jsAst.prettyPrint(node, compiler)); |
2977 mainBuffer.add("$N$n"); | 2998 mainBuffer.add("$N$n"); |
2978 } | 2999 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3089 """; | 3110 """; |
3090 const String HOOKS_API_USAGE = """ | 3111 const String HOOKS_API_USAGE = """ |
3091 // The code supports the following hooks: | 3112 // The code supports the following hooks: |
3092 // dartPrint(message) - if this function is defined it is called | 3113 // dartPrint(message) - if this function is defined it is called |
3093 // instead of the Dart [print] method. | 3114 // instead of the Dart [print] method. |
3094 // dartMainRunner(main) - if this function is defined, the Dart [main] | 3115 // dartMainRunner(main) - if this function is defined, the Dart [main] |
3095 // method will not be invoked directly. | 3116 // method will not be invoked directly. |
3096 // Instead, a closure that will invoke [main] is | 3117 // Instead, a closure that will invoke [main] is |
3097 // passed to [dartMainRunner]. | 3118 // passed to [dartMainRunner]. |
3098 """; | 3119 """; |
OLD | NEW |