| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library dart2js.new_js_emitter.model_emitter; | 5 library dart2js.new_js_emitter.model_emitter; |
| 6 | 6 |
| 7 import '../../dart2jslib.dart' show Compiler; | 7 import '../../dart2jslib.dart' show Compiler; |
| 8 import '../../js/js.dart' as js; | 8 import '../../js/js.dart' as js; |
| 9 import '../../js_backend/js_backend.dart' show | 9 import '../../js_backend/js_backend.dart' show |
| 10 JavaScriptBackend, | 10 JavaScriptBackend, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 this.namer = namer, | 39 this.namer = namer, |
| 40 constantEmitter = | 40 constantEmitter = |
| 41 new ConstantEmitter(compiler, namer, makeConstantListTemplate); | 41 new ConstantEmitter(compiler, namer, makeConstantListTemplate); |
| 42 | 42 |
| 43 js.Expression generateEmbeddedGlobalAccess(String global) { | 43 js.Expression generateEmbeddedGlobalAccess(String global) { |
| 44 // TODO(floitsch): We should not use "init" for globals. | 44 // TODO(floitsch): We should not use "init" for globals. |
| 45 return js.js("init.$global"); | 45 return js.js("init.$global"); |
| 46 } | 46 } |
| 47 | 47 |
| 48 int emitProgram(Program program) { | 48 int emitProgram(Program program) { |
| 49 List<Output> outputs = program.outputs; | 49 List<Fragment> fragments = program.fragments; |
| 50 MainOutput mainUnit = outputs.first; | 50 MainFragment mainFragment = fragments.first; |
| 51 js.Statement mainAst = emitMainUnit(program); | 51 js.Statement mainAst = emitMainFragment(program); |
| 52 String mainCode = js.prettyPrint(mainAst, compiler).getText(); | 52 String mainCode = js.prettyPrint(mainAst, compiler).getText(); |
| 53 compiler.outputProvider(mainUnit.outputFileName, 'js') | 53 compiler.outputProvider(mainFragment.outputFileName, 'js') |
| 54 ..add(buildGeneratedBy(compiler)) | 54 ..add(buildGeneratedBy(compiler)) |
| 55 ..add(mainCode) | 55 ..add(mainCode) |
| 56 ..close(); | 56 ..close(); |
| 57 int totalSize = mainCode.length; | 57 int totalSize = mainCode.length; |
| 58 | 58 |
| 59 outputs.skip(1).forEach((DeferredOutput deferredUnit) { | 59 fragments.skip(1).forEach((DeferredFragment deferredUnit) { |
| 60 js.Expression ast = emitDeferredUnit(deferredUnit, mainUnit.holders); | 60 js.Expression ast = |
| 61 emitDeferredFragment(deferredUnit, mainFragment.holders); |
| 61 String code = js.prettyPrint(ast, compiler).getText(); | 62 String code = js.prettyPrint(ast, compiler).getText(); |
| 62 totalSize += code.length; | 63 totalSize += code.length; |
| 63 compiler.outputProvider(deferredUnit.outputFileName, deferredExtension) | 64 compiler.outputProvider(deferredUnit.outputFileName, deferredExtension) |
| 64 ..add(code) | 65 ..add(code) |
| 65 ..close(); | 66 ..close(); |
| 66 }); | 67 }); |
| 67 return totalSize; | 68 return totalSize; |
| 68 } | 69 } |
| 69 | 70 |
| 70 js.LiteralString unparse(Compiler compiler, js.Expression value) { | 71 js.LiteralString unparse(Compiler compiler, js.Expression value) { |
| 71 String text = js.prettyPrint(value, compiler).getText(); | 72 String text = js.prettyPrint(value, compiler).getText(); |
| 72 if (value is js.Fun) text = '($text)'; | 73 if (value is js.Fun) text = '($text)'; |
| 73 return js.js.escapedString(text); | 74 return js.js.escapedString(text); |
| 74 } | 75 } |
| 75 | 76 |
| 76 String buildGeneratedBy(compiler) { | 77 String buildGeneratedBy(compiler) { |
| 77 var suffix = ''; | 78 var suffix = ''; |
| 78 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; | 79 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; |
| 79 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; | 80 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; |
| 80 } | 81 } |
| 81 | 82 |
| 82 js.Statement emitMainUnit(Program program) { | 83 js.Statement emitMainFragment(Program program) { |
| 83 MainOutput unit = program.outputs.first; | 84 MainFragment fragment = program.fragments.first; |
| 84 List<js.Expression> elements = unit.libraries.map(emitLibrary).toList(); | 85 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList(); |
| 85 elements.add( | 86 elements.add( |
| 86 emitLazilyInitializedStatics(unit.staticLazilyInitializedFields)); | 87 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); |
| 87 | 88 |
| 88 js.Statement nativeBoilerplate; | 89 js.Statement nativeBoilerplate; |
| 89 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { | 90 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { |
| 90 nativeBoilerplate = | 91 nativeBoilerplate = |
| 91 NativeGenerator.generateIsolateAffinityTagInitialization( | 92 NativeGenerator.generateIsolateAffinityTagInitialization( |
| 92 backend, | 93 backend, |
| 93 generateEmbeddedGlobalAccess, | 94 generateEmbeddedGlobalAccess, |
| 94 // TODO(floitsch): convertToFastObject. | 95 // TODO(floitsch): convertToFastObject. |
| 95 js.js("(function(x) { return x; })", [])); | 96 js.js("(function(x) { return x; })", [])); |
| 96 } else { | 97 } else { |
| 97 nativeBoilerplate = js.js.statement(";"); | 98 nativeBoilerplate = js.js.statement(";"); |
| 98 } | 99 } |
| 99 | 100 |
| 100 js.Expression code = new js.ArrayInitializer(elements); | 101 js.Expression code = new js.ArrayInitializer(elements); |
| 101 | 102 |
| 102 return js.js.statement( | 103 return js.js.statement( |
| 103 boilerplate, | 104 boilerplate, |
| 104 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 105 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), |
| 105 'holders': emitHolders(unit.holders), | 106 'holders': emitHolders(fragment.holders), |
| 106 'cyclicThrow': | 107 'cyclicThrow': |
| 107 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), | 108 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), |
| 108 'outputContainsConstantList': program.outputContainsConstantList, | 109 'outputContainsConstantList': program.outputContainsConstantList, |
| 109 'embeddedGlobals': emitEmbeddedGlobals(program.loadMap), | 110 'embeddedGlobals': emitEmbeddedGlobals(program.loadMap), |
| 110 'constants': emitConstants(unit.constants), | 111 'constants': emitConstants(fragment.constants), |
| 111 'staticNonFinals': emitStaticNonFinalFields(unit.staticNonFinalFields), | 112 'staticNonFinals': emitStaticNonFinalFields(fragment.staticNonFinalFiel
ds), |
| 112 'nativeBoilerplate': nativeBoilerplate, | 113 'nativeBoilerplate': nativeBoilerplate, |
| 113 'eagerClasses': emitEagerClassInitializations(unit.libraries), | 114 'eagerClasses': emitEagerClassInitializations(fragment.libraries), |
| 114 'main': unit.main, | 115 'main': fragment.main, |
| 115 'code': code}); | 116 'code': code}); |
| 116 } | 117 } |
| 117 | 118 |
| 118 js.Block emitHolders(List<Holder> holders) { | 119 js.Block emitHolders(List<Holder> holders) { |
| 119 // The top-level variables for holders must *not* be renamed by the | 120 // The top-level variables for holders must *not* be renamed by the |
| 120 // JavaScript pretty printer because a lot of code already uses the | 121 // JavaScript pretty printer because a lot of code already uses the |
| 121 // non-renamed names. The generated code looks like this: | 122 // non-renamed names. The generated code looks like this: |
| 122 // | 123 // |
| 123 // var H = {}, ..., G = {}; | 124 // var H = {}, ..., G = {}; |
| 124 // var holders = [ H, ..., G ]; | 125 // var holders = [ H, ..., G ]; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 138 ]; | 139 ]; |
| 139 return new js.Block(statements); | 140 return new js.Block(statements); |
| 140 } | 141 } |
| 141 | 142 |
| 142 static js.Template get makeConstantListTemplate { | 143 static js.Template get makeConstantListTemplate { |
| 143 // TODO(floitsch): remove hard-coded name. | 144 // TODO(floitsch): remove hard-coded name. |
| 144 // TODO(floitsch): there is no harm in caching the template. | 145 // TODO(floitsch): there is no harm in caching the template. |
| 145 return js.js.uncachedExpressionTemplate('makeConstList(#)'); | 146 return js.js.uncachedExpressionTemplate('makeConstList(#)'); |
| 146 } | 147 } |
| 147 | 148 |
| 148 js.Block emitEmbeddedGlobals(Map<String, List<Output>> loadMap) { | 149 js.Block emitEmbeddedGlobals(Map<String, List<Fragment>> loadMap) { |
| 149 List<js.Property> globals = <js.Property>[]; | 150 List<js.Property> globals = <js.Property>[]; |
| 150 | 151 |
| 151 if (loadMap.isNotEmpty) { | 152 if (loadMap.isNotEmpty) { |
| 152 globals.addAll(emitLoadUrisAndHashes(loadMap)); | 153 globals.addAll(emitLoadUrisAndHashes(loadMap)); |
| 153 globals.add(emitIsHunkLoadedFunction()); | 154 globals.add(emitIsHunkLoadedFunction()); |
| 154 globals.add(emitInitializeLoadedHunk()); | 155 globals.add(emitInitializeLoadedHunk()); |
| 155 } | 156 } |
| 156 | 157 |
| 157 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); | 158 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); |
| 158 | 159 |
| 159 List<js.Statement> statements = | 160 List<js.Statement> statements = |
| 160 [new js.ExpressionStatement( | 161 [new js.ExpressionStatement( |
| 161 new js.VariableDeclarationList( | 162 new js.VariableDeclarationList( |
| 162 [new js.VariableInitialization( | 163 [new js.VariableInitialization( |
| 163 new js.VariableDeclaration("init", allowRename: false), | 164 new js.VariableDeclaration("init", allowRename: false), |
| 164 globalsObject)]))]; | 165 globalsObject)]))]; |
| 165 return new js.Block(statements); | 166 return new js.Block(statements); |
| 166 } | 167 } |
| 167 | 168 |
| 168 List<js.Property> emitLoadUrisAndHashes(Map<String, List<Output>> loadMap) { | 169 List<js.Property> emitLoadUrisAndHashes(Map<String, List<Fragment>> loadMap) { |
| 169 js.ArrayInitializer outputUris(List<Output> outputs) { | 170 js.ArrayInitializer outputUris(List<Fragment> fragments) { |
| 170 return js.stringArray(outputs.map((DeferredOutput output) => | 171 return js.stringArray(fragments.map((DeferredFragment fragment) => |
| 171 "${output.outputFileName}$deferredExtension")); | 172 "${fragment.outputFileName}$deferredExtension")); |
| 172 } | 173 } |
| 173 js.ArrayInitializer outputHashes(List<Output> outputs) { | 174 js.ArrayInitializer outputHashes(List<Fragment> fragments) { |
| 174 // TODO(floitsch): the hash must depend on the generated code. | 175 // TODO(floitsch): the hash must depend on the generated code. |
| 175 return js.numArray( | 176 return js.numArray( |
| 176 outputs.map((DeferredOutput output) => output.hashCode)); | 177 fragments.map((DeferredFragment fragment) => fragment.hashCode)); |
| 177 } | 178 } |
| 178 | 179 |
| 179 List<js.Property> uris = new List<js.Property>(loadMap.length); | 180 List<js.Property> uris = new List<js.Property>(loadMap.length); |
| 180 List<js.Property> hashes = new List<js.Property>(loadMap.length); | 181 List<js.Property> hashes = new List<js.Property>(loadMap.length); |
| 181 int count = 0; | 182 int count = 0; |
| 182 loadMap.forEach((String loadId, List<Output> outputList) { | 183 loadMap.forEach((String loadId, List<Fragment> fragmentList) { |
| 183 uris[count] = new js.Property(js.string(loadId), outputUris(outputList)); | 184 uris[count] = |
| 185 new js.Property(js.string(loadId), outputUris(fragmentList)); |
| 184 hashes[count] = | 186 hashes[count] = |
| 185 new js.Property(js.string(loadId), outputHashes(outputList)); | 187 new js.Property(js.string(loadId), outputHashes(fragmentList)); |
| 186 count++; | 188 count++; |
| 187 }); | 189 }); |
| 188 | 190 |
| 189 return <js.Property>[ | 191 return <js.Property>[ |
| 190 new js.Property(js.string(DEFERRED_LIBRARY_URIS), | 192 new js.Property(js.string(DEFERRED_LIBRARY_URIS), |
| 191 new js.ObjectInitializer(uris)), | 193 new js.ObjectInitializer(uris)), |
| 192 new js.Property(js.string(DEFERRED_LIBRARY_HASHES), | 194 new js.Property(js.string(DEFERRED_LIBRARY_HASHES), |
| 193 new js.ObjectInitializer(hashes)) | 195 new js.ObjectInitializer(hashes)) |
| 194 ]; | 196 ]; |
| 195 } | 197 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 207 js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }"); | 209 js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }"); |
| 208 return new js.Property(js.string(IS_HUNK_LOADED), function); | 210 return new js.Property(js.string(IS_HUNK_LOADED), function); |
| 209 } | 211 } |
| 210 | 212 |
| 211 js.Property emitInitializeLoadedHunk() { | 213 js.Property emitInitializeLoadedHunk() { |
| 212 js.Expression function = | 214 js.Expression function = |
| 213 js.js("function(hash) { eval($deferredInitializersGlobal[hash]); }"); | 215 js.js("function(hash) { eval($deferredInitializersGlobal[hash]); }"); |
| 214 return new js.Property(js.string(INITIALIZE_LOADED_HUNK), function); | 216 return new js.Property(js.string(INITIALIZE_LOADED_HUNK), function); |
| 215 } | 217 } |
| 216 | 218 |
| 217 js.Expression emitDeferredUnit(DeferredOutput unit, List<Holder> holders) { | 219 js.Expression emitDeferredFragment(DeferredFragment fragment, |
| 220 List<Holder> holders) { |
| 218 // TODO(floitsch): initialize eager classes. | 221 // TODO(floitsch): initialize eager classes. |
| 219 // TODO(floitsch): the hash must depend on the output. | 222 // TODO(floitsch): the hash must depend on the output. |
| 220 int hash = this.hashCode; | 223 int hash = this.hashCode; |
| 221 if (unit.constants.isNotEmpty) { | 224 if (fragment.constants.isNotEmpty) { |
| 222 throw new UnimplementedError("constants in deferred units"); | 225 throw new UnimplementedError("constants in deferred units"); |
| 223 } | 226 } |
| 224 js.ArrayInitializer content = | 227 js.ArrayInitializer content = |
| 225 new js.ArrayInitializer(unit.libraries.map(emitLibrary) | 228 new js.ArrayInitializer(fragment.libraries.map(emitLibrary) |
| 226 .toList(growable: false)); | 229 .toList(growable: false)); |
| 227 return js.js("$deferredInitializersGlobal[$hash] = #", content); | 230 return js.js("$deferredInitializersGlobal[$hash] = #", content); |
| 228 } | 231 } |
| 229 | 232 |
| 230 js.Block emitConstants(List<Constant> constants) { | 233 js.Block emitConstants(List<Constant> constants) { |
| 231 Iterable<js.Statement> statements = constants.map((Constant constant) { | 234 Iterable<js.Statement> statements = constants.map((Constant constant) { |
| 232 js.Expression code = | 235 js.Expression code = |
| 233 constantEmitter.initializationExpression(constant.value); | 236 constantEmitter.initializationExpression(constant.value); |
| 234 return js.js.statement("#.# = #;", | 237 return js.js.statement("#.# = #;", |
| 235 [constant.holder.name, constant.name, code]); | 238 [constant.holder.name, constant.name, code]); |
| 236 }); | 239 }); |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 569 | 572 |
| 570 var end = Date.now(); | 573 var end = Date.now(); |
| 571 print('Setup: ' + (end - start) + ' ms.'); | 574 print('Setup: ' + (end - start) + ' ms.'); |
| 572 | 575 |
| 573 #main(); // Start main. | 576 #main(); // Start main. |
| 574 | 577 |
| 575 }(Date.now(), #code) | 578 }(Date.now(), #code) |
| 576 }"""; | 579 }"""; |
| 577 | 580 |
| 578 } | 581 } |
| OLD | NEW |