| 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 '../../dart_types.dart' show DartType; | 8 import '../../dart_types.dart' show DartType; |
| 9 import '../../js/js.dart' as js; | 9 import '../../js/js.dart' as js; |
| 10 import '../../js_backend/js_backend.dart' show | 10 import '../../js_backend/js_backend.dart' show |
| 11 JavaScriptBackend, | 11 JavaScriptBackend, |
| 12 Namer, | 12 Namer, |
| 13 ConstantEmitter; | 13 ConstantEmitter; |
| 14 | 14 |
| 15 import '../js_emitter.dart' show |
| 16 NativeEmitter; |
| 17 |
| 15 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show | 18 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show |
| 16 DEFERRED_LIBRARY_URIS, | 19 DEFERRED_LIBRARY_URIS, |
| 17 DEFERRED_LIBRARY_HASHES, | 20 DEFERRED_LIBRARY_HASHES, |
| 18 GET_TYPE_FROM_NAME, | 21 GET_TYPE_FROM_NAME, |
| 19 INITIALIZE_LOADED_HUNK, | 22 INITIALIZE_LOADED_HUNK, |
| 23 INTERCEPTORS_BY_TAG, |
| 20 IS_HUNK_INITIALIZED, | 24 IS_HUNK_INITIALIZED, |
| 21 IS_HUNK_LOADED, | 25 IS_HUNK_LOADED, |
| 26 LEAF_TAGS, |
| 22 MANGLED_GLOBAL_NAMES, | 27 MANGLED_GLOBAL_NAMES, |
| 23 METADATA, | 28 METADATA, |
| 24 TYPE_TO_INTERCEPTOR_MAP; | 29 TYPE_TO_INTERCEPTOR_MAP; |
| 25 | 30 |
| 26 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode; | 31 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode; |
| 27 import '../model.dart'; | 32 import '../model.dart'; |
| 28 | 33 |
| 29 | 34 |
| 30 class ModelEmitter { | 35 class ModelEmitter { |
| 31 final Compiler compiler; | 36 final Compiler compiler; |
| 32 final Namer namer; | 37 final Namer namer; |
| 33 final ConstantEmitter constantEmitter; | 38 final ConstantEmitter constantEmitter; |
| 39 final NativeEmitter nativeEmitter; |
| 34 | 40 |
| 35 JavaScriptBackend get backend => compiler.backend; | 41 JavaScriptBackend get backend => compiler.backend; |
| 36 | 42 |
| 37 /// For deferred loading we communicate the initializers via this global var. | 43 /// For deferred loading we communicate the initializers via this global var. |
| 38 static const String deferredInitializersGlobal = | 44 static const String deferredInitializersGlobal = |
| 39 r"$__dart_deferred_initializers__"; | 45 r"$__dart_deferred_initializers__"; |
| 40 | 46 |
| 41 static const String deferredExtension = "part.js"; | 47 static const String deferredExtension = "part.js"; |
| 42 | 48 |
| 43 ModelEmitter(Compiler compiler, Namer namer) | 49 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter) |
| 44 : this.compiler = compiler, | 50 : this.compiler = compiler, |
| 45 this.namer = namer, | 51 this.namer = namer, |
| 46 constantEmitter = | 52 constantEmitter = |
| 47 new ConstantEmitter(compiler, namer, makeConstantListTemplate); | 53 new ConstantEmitter(compiler, namer, makeConstantListTemplate); |
| 48 | 54 |
| 49 js.Expression generateEmbeddedGlobalAccess(String global) { | 55 js.Expression generateEmbeddedGlobalAccess(String global) { |
| 50 // TODO(floitsch): We should not use "init" for globals. | 56 // TODO(floitsch): We should not use "init" for globals. |
| 51 return js.js("init.$global"); | 57 return js.js("init.$global"); |
| 52 } | 58 } |
| 53 | 59 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; | 91 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; |
| 86 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; | 92 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; |
| 87 } | 93 } |
| 88 | 94 |
| 89 js.Statement emitMainFragment(Program program) { | 95 js.Statement emitMainFragment(Program program) { |
| 90 MainFragment fragment = program.fragments.first; | 96 MainFragment fragment = program.fragments.first; |
| 91 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList(); | 97 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList(); |
| 92 elements.add( | 98 elements.add( |
| 93 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); | 99 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); |
| 94 | 100 |
| 95 js.Statement nativeBoilerplate; | 101 js.Expression code = new js.ArrayInitializer(elements); |
| 102 |
| 103 Map<String, dynamic> holes = |
| 104 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), |
| 105 'holders': emitHolders(fragment.holders), |
| 106 'tearOff': buildTearOffCode(backend), |
| 107 'parseFunctionDescriptor': |
| 108 js.js.statement(parseFunctionDescriptorBoilerplate), |
| 109 'cyclicThrow': |
| 110 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), |
| 111 'outputContainsConstantList': program.outputContainsConstantList, |
| 112 'embeddedGlobals': emitEmbeddedGlobals(program), |
| 113 'constants': emitConstants(fragment.constants), |
| 114 'staticNonFinals': |
| 115 emitStaticNonFinalFields(fragment.staticNonFinalFields), |
| 116 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
| 117 'eagerClasses': emitEagerClassInitializations(fragment.libraries), |
| 118 'main': fragment.main, |
| 119 'code': code}; |
| 120 |
| 121 holes.addAll(nativeHoles(program)); |
| 122 |
| 123 return js.js.statement(boilerplate, holes); |
| 124 } |
| 125 |
| 126 Map<String, dynamic> nativeHoles(Program program) { |
| 127 Map<String, dynamic> nativeHoles = <String, dynamic>{}; |
| 128 |
| 129 js.Statement nativeIsolateAffinityTagInitialization; |
| 96 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { | 130 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { |
| 97 nativeBoilerplate = | 131 nativeIsolateAffinityTagInitialization = |
| 98 NativeGenerator.generateIsolateAffinityTagInitialization( | 132 NativeGenerator.generateIsolateAffinityTagInitialization( |
| 99 backend, | 133 backend, |
| 100 generateEmbeddedGlobalAccess, | 134 generateEmbeddedGlobalAccess, |
| 101 // TODO(floitsch): convertToFastObject. | 135 // TODO(floitsch): convertToFastObject. |
| 102 js.js("(function(x) { return x; })", [])); | 136 js.js("(function(x) { return x; })", [])); |
| 103 } else { | 137 } else { |
| 104 nativeBoilerplate = js.js.statement(";"); | 138 nativeIsolateAffinityTagInitialization = js.js.statement(";"); |
| 105 } | 139 } |
| 140 nativeHoles['nativeIsolateAffinityTagInitialization'] = |
| 141 nativeIsolateAffinityTagInitialization; |
| 106 | 142 |
| 107 js.Expression code = new js.ArrayInitializer(elements); | |
| 108 | 143 |
| 109 return js.js.statement( | 144 js.Expression nativeInfoAccess = js.js('nativeInfo', []); |
| 110 boilerplate, | 145 js.Expression constructorAccess = js.js('constructor', []); |
| 111 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 146 Function subclassReadGenerator = (js.Expression subclass) { |
| 112 'holders': emitHolders(fragment.holders), | 147 return js.js('holdersMap[#][#].ensureResolved()', [subclass, subclass]); |
| 113 'tearOff': buildTearOffCode(backend), | 148 }; |
| 114 'parseFunctionDescriptor': | 149 js.Expression interceptorsByTagAccess = |
| 115 js.js.statement(parseFunctionDescriptorBoilerplate), | 150 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG); |
| 116 'cyclicThrow': | 151 js.Expression leafTagsAccess = |
| 117 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), | 152 generateEmbeddedGlobalAccess(LEAF_TAGS); |
| 118 'outputContainsConstantList': program.outputContainsConstantList, | 153 js.Statement nativeInfoHandler = nativeEmitter.buildNativeInfoHandler( |
| 119 'embeddedGlobals': emitEmbeddedGlobals(program), | 154 nativeInfoAccess, |
| 120 'constants': emitConstants(fragment.constants), | 155 constructorAccess, |
| 121 'staticNonFinals': | 156 subclassReadGenerator, |
| 122 emitStaticNonFinalFields(fragment.staticNonFinalFields), | 157 interceptorsByTagAccess, |
| 123 'nativeBoilerplate': nativeBoilerplate, | 158 leafTagsAccess); |
| 124 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 159 |
| 125 'eagerClasses': emitEagerClassInitializations(fragment.libraries), | 160 nativeHoles['hasNativeClasses'] = program.outputContainsNativeClasses; |
| 126 'main': fragment.main, | 161 nativeHoles['hasNoNativeClasses'] = !program.outputContainsNativeClasses; |
| 127 'code': code}); | 162 nativeHoles['nativeInfoHandler'] = nativeInfoHandler; |
| 163 |
| 164 return nativeHoles; |
| 128 } | 165 } |
| 129 | 166 |
| 130 js.Block emitHolders(List<Holder> holders) { | 167 js.Block emitHolders(List<Holder> holders) { |
| 131 // The top-level variables for holders must *not* be renamed by the | 168 // The top-level variables for holders must *not* be renamed by the |
| 132 // JavaScript pretty printer because a lot of code already uses the | 169 // JavaScript pretty printer because a lot of code already uses the |
| 133 // non-renamed names. The generated code looks like this: | 170 // non-renamed names. The generated code looks like this: |
| 134 // | 171 // |
| 135 // var H = {}, ..., G = {}; | 172 // var H = {}, ..., G = {}; |
| 136 // var holders = [ H, ..., G ]; | 173 // var holders = [ H, ..., G ]; |
| 137 // | 174 // |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 program.typeToInterceptorMap)); | 209 program.typeToInterceptorMap)); |
| 173 } | 210 } |
| 174 | 211 |
| 175 globals.add(new js.Property(js.string(MANGLED_GLOBAL_NAMES), | 212 globals.add(new js.Property(js.string(MANGLED_GLOBAL_NAMES), |
| 176 js.js('Object.create(null)', []))); | 213 js.js('Object.create(null)', []))); |
| 177 | 214 |
| 178 globals.add(emitGetTypeFromName()); | 215 globals.add(emitGetTypeFromName()); |
| 179 | 216 |
| 180 globals.add(emitMetadata(program)); | 217 globals.add(emitMetadata(program)); |
| 181 | 218 |
| 219 if (program.outputContainsNativeClasses) { |
| 220 globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG), |
| 221 js.js('Object.create(null)', []))); |
| 222 globals.add(new js.Property(js.string(LEAF_TAGS), |
| 223 js.js('Object.create(null)', []))); |
| 224 } |
| 225 |
| 182 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); | 226 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); |
| 183 | 227 |
| 184 List<js.Statement> statements = | 228 List<js.Statement> statements = |
| 185 [new js.ExpressionStatement( | 229 [new js.ExpressionStatement( |
| 186 new js.VariableDeclarationList( | 230 new js.VariableDeclarationList( |
| 187 [new js.VariableInitialization( | 231 [new js.VariableInitialization( |
| 188 new js.VariableDeclaration("init", allowRename: false), | 232 new js.VariableDeclaration("init", allowRename: false), |
| 189 globalsObject)]))]; | 233 globalsObject)]))]; |
| 190 return new js.Block(statements); | 234 return new js.Block(statements); |
| 191 } | 235 } |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 } | 347 } |
| 304 | 348 |
| 305 List<js.Statement> instantiations = | 349 List<js.Statement> instantiations = |
| 306 libraries.expand((Library library) => library.classes) | 350 libraries.expand((Library library) => library.classes) |
| 307 .where((Class cls) => cls.isEager) | 351 .where((Class cls) => cls.isEager) |
| 308 .map(createInstantiation) | 352 .map(createInstantiation) |
| 309 .toList(growable: false); | 353 .toList(growable: false); |
| 310 return new js.Block(instantiations); | 354 return new js.Block(instantiations); |
| 311 } | 355 } |
| 312 | 356 |
| 357 // This string should be referenced wherever JavaScript code makes assumptions |
| 358 // on the mixin format. |
| 359 static final String nativeInfoDescription = |
| 360 "A class is encoded as follows:" |
| 361 " [name, class-code, holder-index], or " |
| 362 " [name, class-code, native-info, holder-index]."; |
| 363 |
| 313 js.Expression emitLibrary(Library library) { | 364 js.Expression emitLibrary(Library library) { |
| 314 Iterable staticDescriptors = library.statics.expand(emitStaticMethod); | 365 Iterable staticDescriptors = library.statics.expand(emitStaticMethod); |
| 315 Iterable classDescriptors = library.classes.expand((Class e) => | 366 |
| 316 [ js.string(e.name), js.number(e.holder.index), emitClass(e) ]); | 367 Iterable classDescriptors = library.classes.expand((Class cls) { |
| 368 js.LiteralString name = js.string(cls.name); |
| 369 js.LiteralNumber holderIndex = js.number(cls.holder.index); |
| 370 js.Expression emittedClass = emitClass(cls); |
| 371 if (cls.nativeInfo == null) { |
| 372 return [name, emittedClass, holderIndex]; |
| 373 } else { |
| 374 return [name, emittedClass, js.string(cls.nativeInfo), holderIndex]; |
| 375 } |
| 376 }); |
| 317 | 377 |
| 318 js.Expression staticArray = | 378 js.Expression staticArray = |
| 319 new js.ArrayInitializer(staticDescriptors.toList(growable: false)); | 379 new js.ArrayInitializer(staticDescriptors.toList(growable: false)); |
| 320 js.Expression classArray = | 380 js.Expression classArray = |
| 321 new js.ArrayInitializer(classDescriptors.toList(growable: false)); | 381 new js.ArrayInitializer(classDescriptors.toList(growable: false)); |
| 322 | 382 |
| 323 return new js.ArrayInitializer([staticArray, classArray]); | 383 return new js.ArrayInitializer([staticArray, classArray]); |
| 324 } | 384 } |
| 325 | 385 |
| 326 js.Expression _generateConstructor(Class cls) { | 386 js.Expression _generateConstructor(Class cls) { |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 } | 619 } |
| 560 | 620 |
| 561 static final String boilerplate = """ | 621 static final String boilerplate = """ |
| 562 { | 622 { |
| 563 // Declare deferred-initializer global. | 623 // Declare deferred-initializer global. |
| 564 #deferredInitializer; | 624 #deferredInitializer; |
| 565 | 625 |
| 566 !function(start, program) { | 626 !function(start, program) { |
| 567 // Initialize holder objects. | 627 // Initialize holder objects. |
| 568 #holders; | 628 #holders; |
| 629 var nativeInfos = Object.create(null); |
| 569 | 630 |
| 570 // Counter to generate unique names for tear offs. | 631 // Counter to generate unique names for tear offs. |
| 571 var functionCounter = 0; | 632 var functionCounter = 0; |
| 572 | 633 |
| 573 function setupProgram() { | 634 function setupProgram() { |
| 574 for (var i = 0; i < program.length - 1; i++) { | 635 for (var i = 0; i < program.length - 1; i++) { |
| 575 setupLibrary(program[i]); | 636 setupLibrary(program[i]); |
| 576 } | 637 } |
| 577 setupLazyStatics(program[i]); | 638 setupLazyStatics(program[i]); |
| 578 } | 639 } |
| 579 | 640 |
| 580 function setupLibrary(library) { | 641 function setupLibrary(library) { |
| 581 var statics = library[0]; | 642 var statics = library[0]; |
| 582 for (var i = 0; i < statics.length; i += 3) { | 643 for (var i = 0; i < statics.length; i += 3) { |
| 583 var holderIndex = statics[i + 1]; | 644 var holderIndex = statics[i + 1]; |
| 584 setupStatic(statics[i], holders[holderIndex], statics[i + 2]); | 645 setupStatic(statics[i], holders[holderIndex], statics[i + 2]); |
| 585 } | 646 } |
| 586 | 647 |
| 587 var classes = library[1]; | 648 var classes = library[1]; |
| 588 for (var i = 0; i < classes.length; i += 3) { | 649 for (var i = 0; i < classes.length; i += 3) { |
| 589 var holderIndex = classes[i + 1]; | 650 var name = classes[i]; |
| 590 holdersMap[classes[i]] = holders[holderIndex]; | 651 var cls = classes[i + 1]; |
| 591 setupClass(classes[i], holders[holderIndex], classes[i + 2]); | 652 |
| 653 if (#hasNativeClasses) { |
| 654 // $nativeInfoDescription. |
| 655 var indexOrNativeInfo = classes[i + 2]; |
| 656 if (typeof indexOrNativeInfo == "number") { |
| 657 var holderIndex = classes[i + 2]; |
| 658 } else { |
| 659 nativeInfos[name] = indexOrNativeInfo; |
| 660 holderIndex = classes[i + 3]; |
| 661 i++; |
| 662 } |
| 663 } |
| 664 |
| 665 if (#hasNoNativeClasses) { |
| 666 var holderIndex = classes[i + 2]; |
| 667 } |
| 668 |
| 669 holdersMap[name] = holders[holderIndex]; |
| 670 setupClass(name, holders[holderIndex], cls); |
| 592 } | 671 } |
| 593 } | 672 } |
| 594 | 673 |
| 595 function setupLazyStatics(statics) { | 674 function setupLazyStatics(statics) { |
| 596 for (var i = 0; i < statics.length; i += 4) { | 675 for (var i = 0; i < statics.length; i += 4) { |
| 597 var name = statics[i]; | 676 var name = statics[i]; |
| 598 var getterName = statics[i + 1]; | 677 var getterName = statics[i + 1]; |
| 599 var holderIndex = statics[i + 2]; | 678 var holderIndex = statics[i + 2]; |
| 600 var initializer = statics[i + 3]; | 679 var initializer = statics[i + 3]; |
| 601 setupLazyStatic(name, getterName, holders[holderIndex], initializer); | 680 setupLazyStatic(name, getterName, holders[holderIndex], initializer); |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 765 function makeConstList(list) { | 844 function makeConstList(list) { |
| 766 // By assigning a function to the properties they become part of the | 845 // By assigning a function to the properties they become part of the |
| 767 // hidden class. The actual values of the fields don't matter, since we | 846 // hidden class. The actual values of the fields don't matter, since we |
| 768 // only check if they exist. | 847 // only check if they exist. |
| 769 list.immutable\$list = Array; | 848 list.immutable\$list = Array; |
| 770 list.fixed\$length = Array; | 849 list.fixed\$length = Array; |
| 771 return list; | 850 return list; |
| 772 } | 851 } |
| 773 } | 852 } |
| 774 | 853 |
| 854 if (#hasNativeClasses) { |
| 855 function handleNativeClassInfos() { |
| 856 for (var nativeClass in nativeInfos) { |
| 857 var constructor = holdersMap[nativeClass][nativeClass].ensureResolved(); |
| 858 var nativeInfo = nativeInfos[nativeClass]; |
| 859 #nativeInfoHandler; |
| 860 } |
| 861 } |
| 862 } |
| 863 |
| 775 setupProgram(); | 864 setupProgram(); |
| 776 | 865 |
| 777 // Initialize constants. | 866 // Initialize constants. |
| 778 #constants; | 867 #constants; |
| 779 | 868 |
| 780 // Initialize globals. | 869 // Initialize globals. |
| 781 #embeddedGlobals; | 870 #embeddedGlobals; |
| 782 | 871 |
| 872 // TODO(floitsch): this order means that native classes may not be |
| 873 // referenced from constants. I'm mostly afraid of things like using them as |
| 874 // generic arguments (which should be fine, but maybe there are other |
| 875 // similar things). |
| 876 // Initialize natives. |
| 877 if (#hasNativeClasses) handleNativeClassInfos(); |
| 878 |
| 783 // Initialize static non-final fields. | 879 // Initialize static non-final fields. |
| 784 #staticNonFinals; | 880 #staticNonFinals; |
| 785 | 881 |
| 786 // Add native boilerplate code. | 882 // Add native boilerplate code. |
| 787 #nativeBoilerplate; | 883 #nativeIsolateAffinityTagInitialization; |
| 788 | 884 |
| 789 // Initialize eager classes. | 885 // Initialize eager classes. |
| 790 #eagerClasses; | 886 #eagerClasses; |
| 791 | 887 |
| 792 var end = Date.now(); | 888 var end = Date.now(); |
| 793 print('Setup: ' + (end - start) + ' ms.'); | 889 print('Setup: ' + (end - start) + ' ms.'); |
| 794 | 890 |
| 795 #main(); // Start main. | 891 #main(); // Start main. |
| 796 | 892 |
| 797 }(Date.now(), #code) | 893 }(Date.now(), #code) |
| 798 }"""; | 894 }"""; |
| 799 | 895 |
| 800 } | 896 } |
| OLD | NEW |