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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 class CodeEmitterTask extends CompilerTask { | 52 class CodeEmitterTask extends CompilerTask { |
53 bool needsInheritFunction = false; | 53 bool needsInheritFunction = false; |
54 bool needsDefineClass = false; | 54 bool needsDefineClass = false; |
55 bool needsClosureClass = false; | 55 bool needsClosureClass = false; |
56 bool needsLazyInitializer = false; | 56 bool needsLazyInitializer = false; |
57 final Namer namer; | 57 final Namer namer; |
58 ConstantEmitter constantEmitter; | 58 ConstantEmitter constantEmitter; |
59 NativeEmitter nativeEmitter; | 59 NativeEmitter nativeEmitter; |
60 CodeBuffer boundClosureBuffer; | 60 CodeBuffer boundClosureBuffer; |
61 CodeBuffer mainBuffer; | 61 CodeBuffer mainBuffer; |
| 62 final CodeBuffer deferredBuffer = new CodeBuffer(); |
62 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | 63 /** Shorter access to [isolatePropertiesName]. Both here in the code, as |
63 well as in the generated code. */ | 64 well as in the generated code. */ |
64 String isolateProperties; | 65 String isolateProperties; |
65 String classesCollector; | 66 String classesCollector; |
66 Set<ClassElement> neededClasses; | 67 Set<ClassElement> neededClasses; |
67 // TODO(ngeoffray): remove this field. | 68 // TODO(ngeoffray): remove this field. |
68 Set<ClassElement> instantiatedClasses; | 69 Set<ClassElement> instantiatedClasses; |
69 | 70 |
70 String get _ => compiler.enableMinification ? "" : " "; | 71 String get _ => compiler.enableMinification ? "" : " "; |
71 String get n => compiler.enableMinification ? "" : "\n"; | 72 String get n => compiler.enableMinification ? "" : "\n"; |
(...skipping 1289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1361 Element member = element.lookupLocalMember(noSuchMethodName); | 1362 Element member = element.lookupLocalMember(noSuchMethodName); |
1362 if (member == null) continue; | 1363 if (member == null) continue; |
1363 if (noSuchMethodSelector.applies(member, compiler)) { | 1364 if (noSuchMethodSelector.applies(member, compiler)) { |
1364 nativeEmitter.handleNoSuchMethod = true; | 1365 nativeEmitter.handleNoSuchMethod = true; |
1365 break; | 1366 break; |
1366 } | 1367 } |
1367 } | 1368 } |
1368 } | 1369 } |
1369 | 1370 |
1370 for (ClassElement element in sortedClasses) { | 1371 for (ClassElement element in sortedClasses) { |
| 1372 if (isDeferred(element)) continue; |
1371 generateClass(element, buffer); | 1373 generateClass(element, buffer); |
1372 } | 1374 } |
1373 | 1375 |
1374 // The closure class could have become necessary because of the generation | 1376 // The closure class could have become necessary because of the generation |
1375 // of stubs. | 1377 // of stubs. |
1376 ClassElement closureClass = compiler.closureClass; | 1378 ClassElement closureClass = compiler.closureClass; |
1377 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { | 1379 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { |
1378 generateClass(closureClass, buffer); | 1380 generateClass(closureClass, buffer); |
1379 } | 1381 } |
1380 } | 1382 } |
1381 | 1383 |
1382 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { | 1384 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { |
1383 if (needsDefineClass) { | 1385 if (needsDefineClass) { |
1384 buffer.add("$finishClassesName($classesCollector)$N"); | 1386 buffer.add("$finishClassesName($classesCollector)$N"); |
1385 // Reset the map. | 1387 // Reset the map. |
1386 buffer.add("$classesCollector$_=$_{}$N"); | 1388 buffer.add("$classesCollector$_=$_{}$N"); |
1387 } | 1389 } |
1388 } | 1390 } |
1389 | 1391 |
1390 void emitStaticFunction(CodeBuffer buffer, | 1392 void emitStaticFunction(CodeBuffer buffer, |
1391 String name, | 1393 String name, |
1392 js.Expression functionExpression) { | 1394 js.Expression functionExpression) { |
1393 js.Expression assignment = | 1395 js.Expression assignment = |
1394 js.assign(js.use(isolateProperties).dot(name), functionExpression); | 1396 js.assign(js.use(isolateProperties).dot(name), functionExpression); |
1395 buffer.add(js.prettyPrint(assignment, compiler)); | 1397 buffer.add(js.prettyPrint(assignment, compiler)); |
1396 buffer.add('$N$n'); | 1398 buffer.add('$N$n'); |
1397 } | 1399 } |
1398 | 1400 |
1399 void emitStaticFunctions(CodeBuffer buffer) { | 1401 void emitStaticFunctions(CodeBuffer eagerBuffer) { |
1400 bool isStaticFunction(Element element) => | 1402 bool isStaticFunction(Element element) => |
1401 !element.isInstanceMember() && !element.isField(); | 1403 !element.isInstanceMember() && !element.isField(); |
1402 | 1404 |
1403 Iterable<Element> elements = | 1405 Iterable<Element> elements = |
1404 compiler.codegenWorld.generatedCode.keys.where(isStaticFunction); | 1406 compiler.codegenWorld.generatedCode.keys.where(isStaticFunction); |
1405 Set<Element> pendingElementsWithBailouts = | 1407 Set<Element> pendingElementsWithBailouts = |
1406 compiler.codegenWorld.generatedBailoutCode.keys | 1408 compiler.codegenWorld.generatedBailoutCode.keys |
1407 .where(isStaticFunction) | 1409 .where(isStaticFunction) |
1408 .toSet(); | 1410 .toSet(); |
1409 | 1411 |
1410 for (Element element in Elements.sortedByPosition(elements)) { | 1412 for (Element element in Elements.sortedByPosition(elements)) { |
| 1413 CodeBuffer buffer = isDeferred(element) ? deferredBuffer : eagerBuffer; |
1411 js.Expression code = compiler.codegenWorld.generatedCode[element]; | 1414 js.Expression code = compiler.codegenWorld.generatedCode[element]; |
1412 emitStaticFunction(buffer, namer.getName(element), code); | 1415 emitStaticFunction(buffer, namer.getName(element), code); |
1413 js.Expression bailoutCode = | 1416 js.Expression bailoutCode = |
1414 compiler.codegenWorld.generatedBailoutCode[element]; | 1417 compiler.codegenWorld.generatedBailoutCode[element]; |
1415 if (bailoutCode != null) { | 1418 if (bailoutCode != null) { |
1416 pendingElementsWithBailouts.remove(element); | 1419 pendingElementsWithBailouts.remove(element); |
1417 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 1420 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); |
1418 } | 1421 } |
1419 } | 1422 } |
1420 | 1423 |
1421 // Is it possible the primary function was inlined but the bailout was not? | 1424 // Is it possible the primary function was inlined but the bailout was not? |
1422 for (Element element in | 1425 for (Element element in |
1423 Elements.sortedByPosition(pendingElementsWithBailouts)) { | 1426 Elements.sortedByPosition(pendingElementsWithBailouts)) { |
| 1427 CodeBuffer buffer = isDeferred(element) ? deferredBuffer : eagerBuffer; |
1424 js.Expression bailoutCode = | 1428 js.Expression bailoutCode = |
1425 compiler.codegenWorld.generatedBailoutCode[element]; | 1429 compiler.codegenWorld.generatedBailoutCode[element]; |
1426 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 1430 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); |
1427 } | 1431 } |
1428 } | 1432 } |
1429 | 1433 |
1430 void emitStaticFunctionGetters(CodeBuffer buffer) { | 1434 void emitStaticFunctionGetters(CodeBuffer buffer) { |
1431 Set<FunctionElement> functionsNeedingGetter = | 1435 Set<FunctionElement> functionsNeedingGetter = |
1432 compiler.codegenWorld.staticFunctionsNeedingGetter; | 1436 compiler.codegenWorld.staticFunctionsNeedingGetter; |
1433 for (FunctionElement element in | 1437 for (FunctionElement element in |
1434 Elements.sortedByPosition(functionsNeedingGetter)) { | 1438 Elements.sortedByPosition(functionsNeedingGetter)) { |
| 1439 if (isDeferred(element)) continue; |
1435 // The static function does not have the correct name. Since | 1440 // The static function does not have the correct name. Since |
1436 // [addParameterStubs] use the name to create its stubs we simply | 1441 // [addParameterStubs] use the name to create its stubs we simply |
1437 // create a fake element with the correct name. | 1442 // create a fake element with the correct name. |
1438 // Note: the callElement will not have any enclosingElement. | 1443 // Note: the callElement will not have any enclosingElement. |
1439 FunctionElement callElement = | 1444 FunctionElement callElement = |
1440 new ClosureInvocationElement(namer.closureInvocationSelectorName, | 1445 new ClosureInvocationElement(namer.closureInvocationSelectorName, |
1441 element); | 1446 element); |
1442 String staticName = namer.getName(element); | 1447 String staticName = namer.getName(element); |
1443 String invocationName = namer.instanceMethodName(callElement); | 1448 String invocationName = namer.instanceMethodName(callElement); |
1444 String fieldAccess = '$isolateProperties.$staticName'; | 1449 String fieldAccess = '$isolateProperties.$staticName'; |
(...skipping 870 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2315 nativeEmitter.assembleCode(mainBuffer); | 2320 nativeEmitter.assembleCode(mainBuffer); |
2316 emitMain(mainBuffer); | 2321 emitMain(mainBuffer); |
2317 mainBuffer.add('function init()$_{\n'); | 2322 mainBuffer.add('function init()$_{\n'); |
2318 mainBuffer.add('$isolateProperties$_=$_{}$N'); | 2323 mainBuffer.add('$isolateProperties$_=$_{}$N'); |
2319 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); | 2324 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); |
2320 addLazyInitializerFunctionIfNecessary(mainBuffer); | 2325 addLazyInitializerFunctionIfNecessary(mainBuffer); |
2321 emitFinishIsolateConstructor(mainBuffer); | 2326 emitFinishIsolateConstructor(mainBuffer); |
2322 mainBuffer.add('}\n'); | 2327 mainBuffer.add('}\n'); |
2323 compiler.assembledCode = mainBuffer.getText(); | 2328 compiler.assembledCode = mainBuffer.getText(); |
2324 | 2329 |
2325 if (generateSourceMap) { | 2330 if (!deferredBuffer.isEmpty) { |
2326 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); | 2331 String code = deferredBuffer.getText(); |
2327 String sourceMap = buildSourceMap(mainBuffer, compiledFile); | 2332 compiler.outputProvider('part', 'js') |
2328 compiler.outputProvider('', 'js.map') | 2333 ..add(code) |
2329 ..add(sourceMap) | |
2330 ..close(); | 2334 ..close(); |
| 2335 outputSourceMap(deferredBuffer, compiler.assembledCode, 'part'); |
2331 } | 2336 } |
| 2337 |
| 2338 outputSourceMap(mainBuffer, compiler.assembledCode, ''); |
2332 }); | 2339 }); |
2333 return compiler.assembledCode; | 2340 return compiler.assembledCode; |
2334 } | 2341 } |
2335 | 2342 |
2336 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { | 2343 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { |
2337 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); | 2344 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); |
2338 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); | 2345 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); |
2339 return sourceMapBuilder.build(compiledFile); | 2346 return sourceMapBuilder.build(compiledFile); |
2340 } | 2347 } |
| 2348 |
| 2349 void outputSourceMap(CodeBuffer buffer, String code, String name) { |
| 2350 if (!generateSourceMap) return; |
| 2351 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); |
| 2352 String sourceMap = buildSourceMap(mainBuffer, compiledFile); |
| 2353 compiler.outputProvider(name, 'js.map') |
| 2354 ..add(sourceMap) |
| 2355 ..close(); |
| 2356 } |
| 2357 |
| 2358 bool isDeferred(Element element) { |
| 2359 return compiler.deferredLoadTask.isDeferred(element); |
| 2360 } |
2341 } | 2361 } |
2342 | 2362 |
2343 const String GENERATED_BY = """ | 2363 const String GENERATED_BY = """ |
2344 // Generated by dart2js, the Dart to JavaScript compiler. | 2364 // Generated by dart2js, the Dart to JavaScript compiler. |
2345 """; | 2365 """; |
2346 const String HOOKS_API_USAGE = """ | 2366 const String HOOKS_API_USAGE = """ |
2347 // The code supports the following hooks: | 2367 // The code supports the following hooks: |
2348 // dartPrint(message) - if this function is defined it is called | 2368 // dartPrint(message) - if this function is defined it is called |
2349 // instead of the Dart [print] method. | 2369 // instead of the Dart [print] method. |
2350 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2370 // dartMainRunner(main) - if this function is defined, the Dart [main] |
2351 // method will not be invoked directly. | 2371 // method will not be invoked directly. |
2352 // Instead, a closure that will invoke [main] is | 2372 // Instead, a closure that will invoke [main] is |
2353 // passed to [dartMainRunner]. | 2373 // passed to [dartMainRunner]. |
2354 """; | 2374 """; |
OLD | NEW |