Chromium Code Reviews| 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, |
| 11 Namer, | 11 Namer, |
| 12 ConstantEmitter; | 12 ConstantEmitter; |
| 13 | 13 |
| 14 import '../js_emitter.dart' show | |
| 15 NativeEmitter; | |
| 16 | |
| 14 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show | 17 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show |
| 15 DEFERRED_LIBRARY_URIS, | 18 DEFERRED_LIBRARY_URIS, |
| 16 DEFERRED_LIBRARY_HASHES, | 19 DEFERRED_LIBRARY_HASHES, |
| 17 GET_TYPE_FROM_NAME, | 20 GET_TYPE_FROM_NAME, |
| 18 INITIALIZE_LOADED_HUNK, | 21 INITIALIZE_LOADED_HUNK, |
| 22 INTERCEPTORS_BY_TAG, | |
| 19 IS_HUNK_INITIALIZED, | 23 IS_HUNK_INITIALIZED, |
| 20 IS_HUNK_LOADED, | 24 IS_HUNK_LOADED, |
| 25 LEAF_TAGS, | |
| 21 TYPE_TO_INTERCEPTOR_MAP; | 26 TYPE_TO_INTERCEPTOR_MAP; |
| 22 | 27 |
| 23 import '../js_emitter.dart' show NativeGenerator; | 28 import '../js_emitter.dart' show NativeGenerator; |
| 24 import '../model.dart'; | 29 import '../model.dart'; |
| 25 | 30 |
| 26 class ModelEmitter { | 31 class ModelEmitter { |
| 27 final Compiler compiler; | 32 final Compiler compiler; |
| 28 final Namer namer; | 33 final Namer namer; |
| 29 final ConstantEmitter constantEmitter; | 34 final ConstantEmitter constantEmitter; |
| 35 final NativeEmitter nativeEmitter; | |
| 30 | 36 |
| 31 JavaScriptBackend get backend => compiler.backend; | 37 JavaScriptBackend get backend => compiler.backend; |
| 32 | 38 |
| 33 /// For deferred loading we communicate the initializers via this global var. | 39 /// For deferred loading we communicate the initializers via this global var. |
| 34 static const String deferredInitializersGlobal = | 40 static const String deferredInitializersGlobal = |
| 35 r"$__dart_deferred_initializers__"; | 41 r"$__dart_deferred_initializers__"; |
| 36 | 42 |
| 37 static const String deferredExtension = "part.js"; | 43 static const String deferredExtension = "part.js"; |
| 38 | 44 |
| 39 ModelEmitter(Compiler compiler, Namer namer) | 45 ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter) |
| 40 : this.compiler = compiler, | 46 : this.compiler = compiler, |
| 41 this.namer = namer, | 47 this.namer = namer, |
| 42 constantEmitter = | 48 constantEmitter = |
| 43 new ConstantEmitter(compiler, namer, makeConstantListTemplate); | 49 new ConstantEmitter(compiler, namer, makeConstantListTemplate); |
| 44 | 50 |
| 45 js.Expression generateEmbeddedGlobalAccess(String global) { | 51 js.Expression generateEmbeddedGlobalAccess(String global) { |
| 46 // TODO(floitsch): We should not use "init" for globals. | 52 // TODO(floitsch): We should not use "init" for globals. |
| 47 return js.js("init.$global"); | 53 return js.js("init.$global"); |
| 48 } | 54 } |
| 49 | 55 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; | 87 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; |
| 82 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; | 88 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; |
| 83 } | 89 } |
| 84 | 90 |
| 85 js.Statement emitMainFragment(Program program) { | 91 js.Statement emitMainFragment(Program program) { |
| 86 MainFragment fragment = program.fragments.first; | 92 MainFragment fragment = program.fragments.first; |
| 87 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList(); | 93 List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList(); |
| 88 elements.add( | 94 elements.add( |
| 89 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); | 95 emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); |
| 90 | 96 |
| 91 js.Statement nativeBoilerplate; | 97 js.Expression code = new js.ArrayInitializer(elements); |
| 98 | |
| 99 Map<String, dynamic> holes = | |
| 100 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | |
| 101 'holders': emitHolders(fragment.holders), | |
| 102 'cyclicThrow': | |
| 103 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), | |
| 104 'outputContainsConstantList': program.outputContainsConstantList, | |
| 105 'embeddedGlobals': emitEmbeddedGlobals(program), | |
| 106 'constants': emitConstants(fragment.constants), | |
| 107 'staticNonFinals': | |
| 108 emitStaticNonFinalFields(fragment.staticNonFinalFields), | |
| 109 'eagerClasses': emitEagerClassInitializations(fragment.libraries), | |
| 110 'main': fragment.main, | |
| 111 'code': code}; | |
| 112 | |
| 113 holes.addAll(nativeHoles(program)); | |
| 114 | |
| 115 return js.js.statement(boilerplate, holes); | |
| 116 } | |
| 117 | |
| 118 Map<String, dynamic> nativeHoles(Program program) { | |
| 119 Map<String, dynamic> nativeHoles = <String, dynamic>{}; | |
| 120 | |
| 121 js.Statement nativeIsolateAffinityTagInitialization; | |
| 92 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { | 122 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { |
| 93 nativeBoilerplate = | 123 nativeIsolateAffinityTagInitialization = |
| 94 NativeGenerator.generateIsolateAffinityTagInitialization( | 124 NativeGenerator.generateIsolateAffinityTagInitialization( |
| 95 backend, | 125 backend, |
| 96 generateEmbeddedGlobalAccess, | 126 generateEmbeddedGlobalAccess, |
| 97 // TODO(floitsch): convertToFastObject. | 127 // TODO(floitsch): convertToFastObject. |
| 98 js.js("(function(x) { return x; })", [])); | 128 js.js("(function(x) { return x; })", [])); |
| 99 } else { | 129 } else { |
| 100 nativeBoilerplate = js.js.statement(";"); | 130 nativeIsolateAffinityTagInitialization = js.js.statement(";"); |
| 101 } | 131 } |
| 132 nativeHoles['nativeIsolateAffinityTagInitialization'] = | |
| 133 nativeIsolateAffinityTagInitialization; | |
| 102 | 134 |
| 103 js.Expression code = new js.ArrayInitializer(elements); | |
| 104 | 135 |
| 105 return js.js.statement( | 136 js.Expression nativeInfoAccess = js.js('nativeInfo', []); |
| 106 boilerplate, | 137 js.Expression constructorAccess = js.js('constructor', []); |
| 107 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 138 Function subclassReadGenerator = (js.Expression subclass) { |
| 108 'holders': emitHolders(fragment.holders), | 139 return js.js('holdersMap[#][#].ensureResolved()', [subclass, subclass]); |
| 109 'cyclicThrow': | 140 }; |
| 110 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), | 141 js.Expression interceptorsByTagAccess = |
| 111 'outputContainsConstantList': program.outputContainsConstantList, | 142 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG); |
| 112 'embeddedGlobals': emitEmbeddedGlobals(program), | 143 js.Expression leafTagsAccess = |
| 113 'constants': emitConstants(fragment.constants), | 144 generateEmbeddedGlobalAccess(LEAF_TAGS); |
| 114 'staticNonFinals': emitStaticNonFinalFields(fragment.staticNonFinalFiel ds), | 145 js.Statement nativeInfoHandler = nativeEmitter.buildNativeInfoHandler( |
| 115 'nativeBoilerplate': nativeBoilerplate, | 146 nativeInfoAccess, |
| 116 'eagerClasses': emitEagerClassInitializations(fragment.libraries), | 147 constructorAccess, |
| 117 'main': fragment.main, | 148 subclassReadGenerator, |
| 118 'code': code}); | 149 interceptorsByTagAccess, |
| 150 leafTagsAccess); | |
| 151 | |
| 152 nativeHoles['hasNativeClasses'] = program.outputContainsNativeClasses; | |
| 153 nativeHoles['hasNotNativeClasses'] = !program.outputContainsNativeClasses; | |
| 154 nativeHoles['nativeInfoHandler'] = nativeInfoHandler; | |
| 155 | |
| 156 return nativeHoles; | |
| 119 } | 157 } |
| 120 | 158 |
| 121 js.Block emitHolders(List<Holder> holders) { | 159 js.Block emitHolders(List<Holder> holders) { |
| 122 // The top-level variables for holders must *not* be renamed by the | 160 // The top-level variables for holders must *not* be renamed by the |
| 123 // JavaScript pretty printer because a lot of code already uses the | 161 // JavaScript pretty printer because a lot of code already uses the |
| 124 // non-renamed names. The generated code looks like this: | 162 // non-renamed names. The generated code looks like this: |
| 125 // | 163 // |
| 126 // var H = {}, ..., G = {}; | 164 // var H = {}, ..., G = {}; |
| 127 // var holders = [ H, ..., G ]; | 165 // var holders = [ H, ..., G ]; |
| 128 // | 166 // |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 158 globals.add(emitInitializeLoadedHunk()); | 196 globals.add(emitInitializeLoadedHunk()); |
| 159 } | 197 } |
| 160 | 198 |
| 161 globals.add(emitGetTypeFromName()); | 199 globals.add(emitGetTypeFromName()); |
| 162 | 200 |
| 163 if (program.typeToInterceptorMap != null) { | 201 if (program.typeToInterceptorMap != null) { |
| 164 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), | 202 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), |
| 165 program.typeToInterceptorMap)); | 203 program.typeToInterceptorMap)); |
| 166 } | 204 } |
| 167 | 205 |
| 206 if (program.outputContainsNativeClasses) { | |
| 207 globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG), | |
| 208 js.js('Object.create(null)', []))); | |
| 209 globals.add(new js.Property(js.string(LEAF_TAGS), | |
| 210 js.js('Object.create(null)', []))); | |
| 211 } | |
| 212 | |
| 168 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); | 213 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); |
| 169 | 214 |
| 170 List<js.Statement> statements = | 215 List<js.Statement> statements = |
| 171 [new js.ExpressionStatement( | 216 [new js.ExpressionStatement( |
| 172 new js.VariableDeclarationList( | 217 new js.VariableDeclarationList( |
| 173 [new js.VariableInitialization( | 218 [new js.VariableInitialization( |
| 174 new js.VariableDeclaration("init", allowRename: false), | 219 new js.VariableDeclaration("init", allowRename: false), |
| 175 globalsObject)]))]; | 220 globalsObject)]))]; |
| 176 return new js.Block(statements); | 221 return new js.Block(statements); |
| 177 } | 222 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 } | 326 } |
| 282 | 327 |
| 283 List<js.Statement> instantiations = | 328 List<js.Statement> instantiations = |
| 284 libraries.expand((Library library) => library.classes) | 329 libraries.expand((Library library) => library.classes) |
| 285 .where((Class cls) => cls.isEager) | 330 .where((Class cls) => cls.isEager) |
| 286 .map(createInstantiation) | 331 .map(createInstantiation) |
| 287 .toList(growable: false); | 332 .toList(growable: false); |
| 288 return new js.Block(instantiations); | 333 return new js.Block(instantiations); |
| 289 } | 334 } |
| 290 | 335 |
| 336 // This string should be referenced wherever JavaScript code makes assumptions | |
| 337 // on the mixin format. | |
| 338 static final String nativeInfoDescription = | |
| 339 "A class is encoded as follows:" | |
| 340 " [name, class-code, holder-index], or " | |
| 341 " [name, class-code, native-info, holder-index]."; | |
| 342 | |
| 291 js.Expression emitLibrary(Library library) { | 343 js.Expression emitLibrary(Library library) { |
| 292 Iterable staticDescriptors = library.statics.expand((e) => | 344 Iterable staticDescriptors = library.statics.expand((StaticMethod m) => |
| 293 [ js.string(e.name), js.number(e.holder.index), emitStaticMethod(e) ]); | 345 [js.string(m.name), js.number(m.holder.index), emitStaticMethod(m)]); |
| 294 Iterable classDescriptors = library.classes.expand((e) => | 346 |
| 295 [ js.string(e.name), js.number(e.holder.index), emitClass(e) ]); | 347 Iterable classDescriptors = library.classes.expand((Class cls) { |
| 348 js.LiteralString name = js.string(cls.name); | |
| 349 js.LiteralNumber holderIndex = js.number(cls.holder.index); | |
| 350 js.Expression emittedClass = emitClass(cls); | |
| 351 if (cls.nativeInfo == null) { | |
| 352 return [name, emittedClass, holderIndex]; | |
| 353 } else { | |
| 354 return [name, emittedClass, js.string(cls.nativeInfo), holderIndex]; | |
| 355 } | |
| 356 }); | |
| 296 | 357 |
| 297 js.Expression staticArray = | 358 js.Expression staticArray = |
| 298 new js.ArrayInitializer(staticDescriptors.toList(growable: false)); | 359 new js.ArrayInitializer(staticDescriptors.toList(growable: false)); |
| 299 js.Expression classArray = | 360 js.Expression classArray = |
| 300 new js.ArrayInitializer(classDescriptors.toList(growable: false)); | 361 new js.ArrayInitializer(classDescriptors.toList(growable: false)); |
| 301 | 362 |
| 302 return new js.ArrayInitializer([staticArray, classArray]); | 363 return new js.ArrayInitializer([staticArray, classArray]); |
| 303 } | 364 } |
| 304 | 365 |
| 305 js.Expression _generateConstructor(Class cls) { | 366 js.Expression _generateConstructor(Class cls) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 399 | 460 |
| 400 static final String boilerplate = """ | 461 static final String boilerplate = """ |
| 401 { | 462 { |
| 402 // Declare deferred-initializer global. | 463 // Declare deferred-initializer global. |
| 403 #deferredInitializer; | 464 #deferredInitializer; |
| 404 | 465 |
| 405 !function(start, program) { | 466 !function(start, program) { |
| 406 | 467 |
| 407 // Initialize holder objects. | 468 // Initialize holder objects. |
| 408 #holders; | 469 #holders; |
| 470 var nativeInfos = Object.create(null); | |
| 409 | 471 |
| 410 function setupProgram() { | 472 function setupProgram() { |
| 411 for (var i = 0; i < program.length - 1; i++) { | 473 for (var i = 0; i < program.length - 1; i++) { |
| 412 setupLibrary(program[i]); | 474 setupLibrary(program[i]); |
| 413 } | 475 } |
| 414 setupLazyStatics(program[i]); | 476 setupLazyStatics(program[i]); |
| 415 } | 477 } |
| 416 | 478 |
| 417 function setupLibrary(library) { | 479 function setupLibrary(library) { |
| 418 var statics = library[0]; | 480 var statics = library[0]; |
| 419 for (var i = 0; i < statics.length; i += 3) { | 481 for (var i = 0; i < statics.length; i += 3) { |
| 420 var holderIndex = statics[i + 1]; | 482 var holderIndex = statics[i + 1]; |
| 421 setupStatic(statics[i], holders[holderIndex], statics[i + 2]); | 483 setupStatic(statics[i], holders[holderIndex], statics[i + 2]); |
| 422 } | 484 } |
| 423 | 485 |
| 424 var classes = library[1]; | 486 var classes = library[1]; |
| 425 for (var i = 0; i < classes.length; i += 3) { | 487 for (var i = 0; i < classes.length; i += 3) { |
| 426 var holderIndex = classes[i + 1]; | 488 var name = classes[i]; |
| 427 holdersMap[classes[i]] = holders[holderIndex]; | 489 var cls = classes[i + 1]; |
| 428 setupClass(classes[i], holders[holderIndex], classes[i + 2]); | 490 |
| 491 if (#hasNativeClasses) { | |
| 492 // $nativeInfoDescription. | |
| 493 var indexOrNativeInfo = classes[i + 2]; | |
| 494 if (typeof indexOrNativeInfo == "number") { | |
| 495 var holderIndex = classes[i + 2]; | |
| 496 } else { | |
| 497 nativeInfos[name] = indexOrNativeInfo; | |
| 498 holderIndex = classes[i + 3]; | |
| 499 i++; | |
| 500 } | |
| 501 } | |
| 502 | |
| 503 if (#hasNotNativeClasses) { | |
|
zarah
2015/01/28 10:54:40
hasNoNativeClasses
floitsch
2015/01/28 13:28:27
Done.
| |
| 504 var holderIndex = classes[i + 2]; | |
| 505 } | |
| 506 | |
| 507 holdersMap[name] = holders[holderIndex]; | |
| 508 setupClass(name, holders[holderIndex], cls); | |
| 429 } | 509 } |
| 430 } | 510 } |
| 431 | 511 |
| 432 function setupLazyStatics(statics) { | 512 function setupLazyStatics(statics) { |
| 433 for (var i = 0; i < statics.length; i += 4) { | 513 for (var i = 0; i < statics.length; i += 4) { |
| 434 var name = statics[i]; | 514 var name = statics[i]; |
| 435 var getterName = statics[i + 1]; | 515 var getterName = statics[i + 1]; |
| 436 var holderIndex = statics[i + 2]; | 516 var holderIndex = statics[i + 2]; |
| 437 var initializer = statics[i + 3]; | 517 var initializer = statics[i + 3]; |
| 438 setupLazyStatic(name, getterName, holders[holderIndex], initializer); | 518 setupLazyStatic(name, getterName, holders[holderIndex], initializer); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 558 function makeConstList(list) { | 638 function makeConstList(list) { |
| 559 // By assigning a function to the properties they become part of the | 639 // By assigning a function to the properties they become part of the |
| 560 // hidden class. The actual values of the fields don't matter, since we | 640 // hidden class. The actual values of the fields don't matter, since we |
| 561 // only check if they exist. | 641 // only check if they exist. |
| 562 list.immutable\$list = Array; | 642 list.immutable\$list = Array; |
| 563 list.fixed\$length = Array; | 643 list.fixed\$length = Array; |
| 564 return list; | 644 return list; |
| 565 } | 645 } |
| 566 } | 646 } |
| 567 | 647 |
| 648 if (#hasNativeClasses) { | |
| 649 function handleNativeClassInfos() { | |
| 650 for (var nativeClass in nativeInfos) { | |
| 651 var constructor = holdersMap[nativeClass][nativeClass].ensureResolved(); | |
| 652 var nativeInfo = nativeInfos[nativeClass]; | |
| 653 #nativeInfoHandler; | |
| 654 } | |
| 655 } | |
| 656 } | |
| 657 | |
| 568 setupProgram(); | 658 setupProgram(); |
| 569 | 659 |
| 570 // Initialize constants. | 660 // Initialize constants. |
| 571 #constants; | 661 #constants; |
| 572 | 662 |
| 573 // Initialize globals. | 663 // Initialize globals. |
| 574 #embeddedGlobals; | 664 #embeddedGlobals; |
| 575 | 665 |
| 666 // TODO(floitsch): this order means that native classes may not be | |
| 667 // referenced from constants. I'm mostly afraid of things like using them as | |
| 668 // generic arguments (which should be fine, but maybe there are other | |
| 669 // similar things). | |
| 670 // Initialize natives. | |
| 671 if (#hasNativeClasses) handleNativeClassInfos(); | |
| 672 | |
| 576 // Initialize static non-final fields. | 673 // Initialize static non-final fields. |
| 577 #staticNonFinals; | 674 #staticNonFinals; |
| 578 | 675 |
| 579 // Add native boilerplate code. | 676 // Add native boilerplate code. |
| 580 #nativeBoilerplate; | 677 #nativeIsolateAffinityTagInitialization; |
| 581 | 678 |
| 582 // Initialize eager classes. | 679 // Initialize eager classes. |
| 583 #eagerClasses; | 680 #eagerClasses; |
| 584 | 681 |
| 585 var end = Date.now(); | 682 var end = Date.now(); |
| 586 print('Setup: ' + (end - start) + ' ms.'); | 683 print('Setup: ' + (end - start) + ' ms.'); |
| 587 | 684 |
| 588 #main(); // Start main. | 685 #main(); // Start main. |
| 589 | 686 |
| 590 }(Date.now(), #code) | 687 }(Date.now(), #code) |
| 591 }"""; | 688 }"""; |
| 592 | 689 |
| 593 } | 690 } |
| OLD | NEW |