| 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 part of dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
| 6 | 6 |
| 7 | 7 |
| 8 class OldEmitter implements Emitter { | 8 class OldEmitter implements Emitter { |
| 9 final Compiler compiler; | 9 final Compiler compiler; |
| 10 final CodeEmitterTask task; | 10 final CodeEmitterTask task; |
| 11 | 11 |
| 12 final ContainerBuilder containerBuilder = new ContainerBuilder(); | 12 final ContainerBuilder containerBuilder = new ContainerBuilder(); |
| 13 final ClassEmitter classEmitter = new ClassEmitter(); | 13 final ClassEmitter classEmitter = new ClassEmitter(); |
| 14 final NsmEmitter nsmEmitter = new NsmEmitter(); | 14 final NsmEmitter nsmEmitter = new NsmEmitter(); |
| 15 final InterceptorEmitter interceptorEmitter = new InterceptorEmitter(); | 15 final InterceptorEmitter interceptorEmitter = new InterceptorEmitter(); |
| 16 | 16 |
| 17 // TODO(johnniwinther): Wrap these fields in a caching strategy. | 17 // TODO(johnniwinther): Wrap these fields in a caching strategy. |
| 18 final Set<ConstantValue> cachedEmittedConstants; | 18 final Set<ConstantValue> cachedEmittedConstants; |
| 19 final CodeBuffer cachedEmittedConstantsBuffer = new CodeBuffer(); | 19 final List<jsAst.Statement> cachedEmittedConstantsAst = <jsAst.Statement>[]; |
| 20 final Map<Element, ClassBuilder> cachedClassBuilders; | 20 final Map<Element, ClassBuilder> cachedClassBuilders; |
| 21 final Set<Element> cachedElements; | 21 final Set<Element> cachedElements; |
| 22 | 22 |
| 23 bool needsClassSupport = false; | 23 bool needsClassSupport = false; |
| 24 bool needsMixinSupport = false; | 24 bool needsMixinSupport = false; |
| 25 bool needsLazyInitializer = false; | 25 bool needsLazyInitializer = false; |
| 26 | 26 |
| 27 /// True if [ContainerBuilder.addMemberMethodFromInfo] used "structured info", | 27 /// True if [ContainerBuilder.addMemberMethodFromInfo] used "structured info", |
| 28 /// that is, some function was needed for reflection, had stubs, or had a | 28 /// that is, some function was needed for reflection, had stubs, or had a |
| 29 /// super alias. | 29 /// super alias. |
| 30 bool needsStructuredMemberInfo = false; | 30 bool needsStructuredMemberInfo = false; |
| 31 | 31 |
| 32 final Namer namer; | 32 final Namer namer; |
| 33 ConstantEmitter constantEmitter; | 33 ConstantEmitter constantEmitter; |
| 34 NativeEmitter get nativeEmitter => task.nativeEmitter; | 34 NativeEmitter get nativeEmitter => task.nativeEmitter; |
| 35 TypeTestRegistry get typeTestRegistry => task.typeTestRegistry; | 35 TypeTestRegistry get typeTestRegistry => task.typeTestRegistry; |
| 36 | 36 |
| 37 // The full code that is written to each hunk part-file. | 37 // The full code that is written to each hunk part-file. |
| 38 Map<OutputUnit, CodeOutput> outputBuffers = new Map<OutputUnit, CodeOutput>(); | 38 Map<OutputUnit, CodeOutput> outputBuffers = new Map<OutputUnit, CodeOutput>(); |
| 39 | 39 |
| 40 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | |
| 41 well as in the generated code. */ | |
| 42 String isolateProperties; | |
| 43 String classesCollector; | 40 String classesCollector; |
| 44 Set<ClassElement> get neededClasses => task.neededClasses; | 41 Set<ClassElement> get neededClasses => task.neededClasses; |
| 45 Map<OutputUnit, List<ClassElement>> get outputClassLists | 42 Map<OutputUnit, List<ClassElement>> get outputClassLists |
| 46 => task.outputClassLists; | 43 => task.outputClassLists; |
| 47 Map<OutputUnit, List<ConstantValue>> get outputConstantLists | 44 Map<OutputUnit, List<ConstantValue>> get outputConstantLists |
| 48 => task.outputConstantLists; | 45 => task.outputConstantLists; |
| 49 final Map<String, String> mangledFieldNames = <String, String>{}; | 46 final Map<String, String> mangledFieldNames = <String, String>{}; |
| 50 final Map<String, String> mangledGlobalFieldNames = <String, String>{}; | 47 final Map<String, String> mangledGlobalFieldNames = <String, String>{}; |
| 51 final Set<String> recordedMangledNames = new Set<String>(); | 48 final Set<String> recordedMangledNames = new Set<String>(); |
| 52 | 49 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 () => new List<jsAst.Expression>()); | 113 () => new List<jsAst.Expression>()); |
| 117 } | 114 } |
| 118 | 115 |
| 119 /// Erases the precompiled information for csp mode for all output units. | 116 /// Erases the precompiled information for csp mode for all output units. |
| 120 /// Used by the incremental compiler. | 117 /// Used by the incremental compiler. |
| 121 void clearCspPrecompiledNodes() { | 118 void clearCspPrecompiledNodes() { |
| 122 _cspPrecompiledFunctions.clear(); | 119 _cspPrecompiledFunctions.clear(); |
| 123 _cspPrecompiledConstructorNames.clear(); | 120 _cspPrecompiledConstructorNames.clear(); |
| 124 } | 121 } |
| 125 | 122 |
| 126 void addComment(String comment, CodeOutput output) { | |
| 127 output.addBuffer(jsAst.prettyPrint(js.comment(comment), compiler)); | |
| 128 } | |
| 129 | |
| 130 @override | 123 @override |
| 131 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { | 124 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { |
| 132 if (constant.isFunction) return true; // Already emitted. | 125 if (constant.isFunction) return true; // Already emitted. |
| 133 if (constant.isPrimitive) return true; // Inlined. | 126 if (constant.isPrimitive) return true; // Inlined. |
| 134 if (constant.isDummy) return true; // Inlined. | 127 if (constant.isDummy) return true; // Inlined. |
| 135 // The name is null when the constant is already a JS constant. | 128 // The name is null when the constant is already a JS constant. |
| 136 // TODO(floitsch): every constant should be registered, so that we can | 129 // TODO(floitsch): every constant should be registered, so that we can |
| 137 // share the ones that take up too much space (like some strings). | 130 // share the ones that take up too much space (like some strings). |
| 138 if (namer.constantName(constant) == null) return true; | 131 if (namer.constantName(constant) == null) return true; |
| 139 return false; | 132 return false; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 String get initName => 'init'; | 188 String get initName => 'init'; |
| 196 | 189 |
| 197 String get makeConstListProperty => namer.internalGlobal('makeConstantList'); | 190 String get makeConstListProperty => namer.internalGlobal('makeConstantList'); |
| 198 | 191 |
| 199 /// The name of the property that contains all field names. | 192 /// The name of the property that contains all field names. |
| 200 /// | 193 /// |
| 201 /// This property is added to constructors when isolate support is enabled. | 194 /// This property is added to constructors when isolate support is enabled. |
| 202 static const String FIELD_NAMES_PROPERTY_NAME = r"$__fields__"; | 195 static const String FIELD_NAMES_PROPERTY_NAME = r"$__fields__"; |
| 203 | 196 |
| 204 /// For deferred loading we communicate the initializers via this global var. | 197 /// For deferred loading we communicate the initializers via this global var. |
| 205 final String deferredInitializers = r"$dart_deferred_initializers"; | 198 final String deferredInitializers = r"$dart_deferred_initializers$"; |
| 206 | 199 |
| 207 /// Contains the global state that is needed to initialize and load a | 200 /// Contains the global state that is needed to initialize and load a |
| 208 /// deferred library. | 201 /// deferred library. |
| 209 String get globalsHolder => namer.internalGlobal("globalsHolder"); | 202 String get globalsHolder => namer.internalGlobal("globalsHolder"); |
| 210 | 203 |
| 211 @override | 204 @override |
| 212 jsAst.Expression generateEmbeddedGlobalAccess(String global) { | 205 jsAst.Expression generateEmbeddedGlobalAccess(String global) { |
| 213 return js(generateEmbeddedGlobalAccessString(global)); | 206 return js(generateEmbeddedGlobalAccessString(global)); |
| 214 } | 207 } |
| 215 | 208 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 return nativeEmitter.buildNativeInfoHandler(infoAccess, constructorAccess, | 329 return nativeEmitter.buildNativeInfoHandler(infoAccess, constructorAccess, |
| 337 subclassReadGenerator, | 330 subclassReadGenerator, |
| 338 interceptorsByTagAccess, | 331 interceptorsByTagAccess, |
| 339 leafTagsAccess); | 332 leafTagsAccess); |
| 340 } | 333 } |
| 341 | 334 |
| 342 jsAst.ObjectInitializer generateInterceptedNamesSet() { | 335 jsAst.ObjectInitializer generateInterceptedNamesSet() { |
| 343 return interceptorEmitter.generateInterceptedNamesSet(); | 336 return interceptorEmitter.generateInterceptedNamesSet(); |
| 344 } | 337 } |
| 345 | 338 |
| 346 void emitFinishIsolateConstructorInvocation(CodeOutput output) { | |
| 347 String isolate = namer.isolateName; | |
| 348 output.add("$isolate = $finishIsolateConstructorName($isolate)$N"); | |
| 349 } | |
| 350 | |
| 351 /// In minified mode we want to keep the name for the most common core types. | 339 /// In minified mode we want to keep the name for the most common core types. |
| 352 bool _isNativeTypeNeedingReflectionName(Element element) { | 340 bool _isNativeTypeNeedingReflectionName(Element element) { |
| 353 if (!element.isClass) return false; | 341 if (!element.isClass) return false; |
| 354 return (element == compiler.intClass || | 342 return (element == compiler.intClass || |
| 355 element == compiler.doubleClass || | 343 element == compiler.doubleClass || |
| 356 element == compiler.numClass || | 344 element == compiler.numClass || |
| 357 element == compiler.stringClass || | 345 element == compiler.stringClass || |
| 358 element == compiler.boolClass || | 346 element == compiler.boolClass || |
| 359 element == compiler.nullClass || | 347 element == compiler.nullClass || |
| 360 element == compiler.listClass); | 348 element == compiler.listClass); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 } | 452 } |
| 465 | 453 |
| 466 String namedParametersAsReflectionNames(CallStructure structure) { | 454 String namedParametersAsReflectionNames(CallStructure structure) { |
| 467 if (structure.isUnnamed) return ''; | 455 if (structure.isUnnamed) return ''; |
| 468 String names = structure.getOrderedNamedArguments().join(':'); | 456 String names = structure.getOrderedNamedArguments().join(':'); |
| 469 return ':$names'; | 457 return ':$names'; |
| 470 } | 458 } |
| 471 | 459 |
| 472 jsAst.Statement buildCspPrecompiledFunctionFor( | 460 jsAst.Statement buildCspPrecompiledFunctionFor( |
| 473 OutputUnit outputUnit) { | 461 OutputUnit outputUnit) { |
| 474 // TODO(ahe): Compute a hash code. | 462 if (compiler.useContentSecurityPolicy) { |
| 475 // TODO(sigurdm): Avoid this precompiled function. Generated | 463 // TODO(ahe): Compute a hash code. |
| 476 // constructor-functions and getter/setter functions can be stored in the | 464 // TODO(sigurdm): Avoid this precompiled function. Generated |
| 477 // library-description table. Setting properties on these can be moved to | 465 // constructor-functions and getter/setter functions can be stored in the |
| 478 // finishClasses. | 466 // library-description table. Setting properties on these can be moved to |
| 479 return js.statement(''' | 467 // finishClasses. |
| 480 # = function (\$collectedClasses) { | 468 return js.statement(''' |
| 481 var \$desc; | 469 # = function (\$collectedClasses) { |
| 482 #; | 470 var \$desc; |
| 483 return #; | 471 #; |
| 484 };''', | 472 return #; |
| 485 [generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED), | 473 };''', |
| 486 cspPrecompiledFunctionFor(outputUnit), | 474 [generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED), |
| 487 new jsAst.ArrayInitializer( | 475 cspPrecompiledFunctionFor(outputUnit), |
| 488 cspPrecompiledConstructorNamesFor(outputUnit))]); | 476 new jsAst.ArrayInitializer( |
| 477 cspPrecompiledConstructorNamesFor(outputUnit))]); |
| 478 } else { |
| 479 return js.comment("Constructors are generated at runtime."); |
| 480 } |
| 489 } | 481 } |
| 490 | 482 |
| 491 void assembleClass(Class cls, ClassBuilder enclosingBuilder, | 483 void assembleClass(Class cls, ClassBuilder enclosingBuilder, |
| 492 Fragment fragment) { | 484 Fragment fragment) { |
| 493 ClassElement classElement = cls.element; | 485 ClassElement classElement = cls.element; |
| 494 compiler.withCurrentElement(classElement, () { | 486 compiler.withCurrentElement(classElement, () { |
| 495 if (compiler.hasIncrementalSupport) { | 487 if (compiler.hasIncrementalSupport) { |
| 496 ClassBuilder cachedBuilder = | 488 ClassBuilder cachedBuilder = |
| 497 cachedClassBuilders.putIfAbsent(classElement, () { | 489 cachedClassBuilders.putIfAbsent(classElement, () { |
| 498 ClassBuilder builder = new ClassBuilder(classElement, namer); | 490 ClassBuilder builder = new ClassBuilder(classElement, namer); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 519 // We need to filter out null-elements for the interceptors. | 511 // We need to filter out null-elements for the interceptors. |
| 520 // TODO(floitsch): use the precomputed interceptors here. | 512 // TODO(floitsch): use the precomputed interceptors here. |
| 521 if (element == null) continue; | 513 if (element == null) continue; |
| 522 ClassBuilder builder = new ClassBuilder(element, namer); | 514 ClassBuilder builder = new ClassBuilder(element, namer); |
| 523 containerBuilder.addMemberMethod(method, builder); | 515 containerBuilder.addMemberMethod(method, builder); |
| 524 getElementDescriptor(element, fragment).properties | 516 getElementDescriptor(element, fragment).properties |
| 525 .addAll(builder.properties); | 517 .addAll(builder.properties); |
| 526 } | 518 } |
| 527 } | 519 } |
| 528 | 520 |
| 529 void emitStaticNonFinalFieldInitializations(CodeOutput output, | 521 jsAst.Statement buildStaticNonFinalFieldInitializations( |
| 530 OutputUnit outputUnit) { | 522 OutputUnit outputUnit) { |
| 531 void emitInitialization(Element element, jsAst.Expression initialValue) { | 523 jsAst.Statement buildInitialization(Element element, |
| 532 jsAst.Expression init = | 524 jsAst.Expression initialValue) { |
| 533 js('$isolateProperties.# = #', | 525 return js.statement('${namer.currentIsolate}.# = #', |
| 534 [namer.globalPropertyName(element), initialValue]); | 526 [namer.globalPropertyName(element), initialValue]); |
| 535 output.addBuffer(jsAst.prettyPrint(init, compiler, | |
| 536 monitor: compiler.dumpInfoTask)); | |
| 537 output.add('$N'); | |
| 538 } | 527 } |
| 539 | 528 |
| 540 bool inMainUnit = (outputUnit == compiler.deferredLoadTask.mainOutputUnit); | 529 bool inMainUnit = (outputUnit == compiler.deferredLoadTask.mainOutputUnit); |
| 541 JavaScriptConstantCompiler handler = backend.constants; | 530 JavaScriptConstantCompiler handler = backend.constants; |
| 531 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 542 | 532 |
| 543 Iterable<Element> fields = task.outputStaticNonFinalFieldLists[outputUnit]; | 533 Iterable<Element> fields = task.outputStaticNonFinalFieldLists[outputUnit]; |
| 544 // If the outputUnit does not contain any static non-final fields, then | 534 // If the outputUnit does not contain any static non-final fields, then |
| 545 // [fields] is `null`. | 535 // [fields] is `null`. |
| 546 if (fields != null) { | 536 if (fields != null) { |
| 547 for (Element element in fields) { | 537 for (Element element in fields) { |
| 548 compiler.withCurrentElement(element, () { | 538 compiler.withCurrentElement(element, () { |
| 549 ConstantValue constant = handler.getInitialValueFor(element).value; | 539 ConstantValue constant = handler.getInitialValueFor(element).value; |
| 550 emitInitialization(element, constantReference(constant)); | 540 parts.add(buildInitialization(element, constantReference(constant))); |
| 551 }); | 541 }); |
| 552 } | 542 } |
| 553 } | 543 } |
| 554 | 544 |
| 555 if (inMainUnit && task.outputStaticNonFinalFieldLists.length > 1) { | 545 if (inMainUnit && task.outputStaticNonFinalFieldLists.length > 1) { |
| 556 // In the main output-unit we output a stub initializer for deferred | 546 // In the main output-unit we output a stub initializer for deferred |
| 557 // variables, so that `isolateProperties` stays a fast object. | 547 // variables, so that `isolateProperties` stays a fast object. |
| 558 task.outputStaticNonFinalFieldLists.forEach( | 548 task.outputStaticNonFinalFieldLists.forEach( |
| 559 (OutputUnit fieldsOutputUnit, Iterable<VariableElement> fields) { | 549 (OutputUnit fieldsOutputUnit, Iterable<VariableElement> fields) { |
| 560 if (fieldsOutputUnit == outputUnit) return; // Skip the main unit. | 550 if (fieldsOutputUnit == outputUnit) return; // Skip the main unit. |
| 561 for (Element element in fields) { | 551 for (Element element in fields) { |
| 562 compiler.withCurrentElement(element, () { | 552 compiler.withCurrentElement(element, () { |
| 563 emitInitialization(element, jsAst.number(0)); | 553 parts.add(buildInitialization(element, jsAst.number(0))); |
| 564 }); | 554 }); |
| 565 } | 555 } |
| 566 }); | 556 }); |
| 567 } | 557 } |
| 558 |
| 559 return new jsAst.Block(parts); |
| 568 } | 560 } |
| 569 | 561 |
| 570 void emitLazilyInitializedStaticFields(CodeOutput output) { | 562 jsAst.Statement buildLazilyInitializedStaticFields() { |
| 571 JavaScriptConstantCompiler handler = backend.constants; | 563 JavaScriptConstantCompiler handler = backend.constants; |
| 572 List<VariableElement> lazyFields = | 564 List<VariableElement> lazyFields = |
| 573 handler.getLazilyInitializedFieldsForEmission(); | 565 handler.getLazilyInitializedFieldsForEmission(); |
| 574 if (!lazyFields.isEmpty) { | 566 if (lazyFields.isNotEmpty) { |
| 575 needsLazyInitializer = true; | 567 needsLazyInitializer = true; |
| 576 List<jsAst.Expression> laziesInfo = buildLaziesInfo(lazyFields); | 568 List<jsAst.Expression> laziesInfo = buildLaziesInfo(lazyFields); |
| 577 jsAst.Statement code = js.statement(''' | 569 return js.statement(''' |
| 578 (function(lazies) { | 570 (function(lazies) { |
| 579 if (#notInMinifiedMode) { | 571 if (#notInMinifiedMode) { |
| 580 var descriptorLength = 4; | 572 var descriptorLength = 4; |
| 581 } else { | 573 } else { |
| 582 var descriptorLength = 3; | 574 var descriptorLength = 3; |
| 583 } | 575 } |
| 584 | 576 |
| 585 for (var i = 0; i < lazies.length; i += descriptorLength) { | 577 for (var i = 0; i < lazies.length; i += descriptorLength) { |
| 586 var fieldName = lazies [i]; | 578 var fieldName = lazies [i]; |
| 587 var getterName = lazies[i + 1]; | 579 var getterName = lazies[i + 1]; |
| 588 var lazyValue = lazies[i + 2]; | 580 var lazyValue = lazies[i + 2]; |
| 589 if (#notInMinifiedMode) { | 581 if (#notInMinifiedMode) { |
| 590 var staticName = lazies[i + 3]; | 582 var staticName = lazies[i + 3]; |
| 591 } | 583 } |
| 592 | 584 |
| 593 // We build the lazy-check here: | 585 // We build the lazy-check here: |
| 594 // lazyInitializer(fieldName, getterName, lazyValue, staticName); | 586 // lazyInitializer(fieldName, getterName, lazyValue, staticName); |
| 595 // 'staticName' is used for error reporting in non-minified mode. | 587 // 'staticName' is used for error reporting in non-minified mode. |
| 596 // 'lazyValue' must be a closure that constructs the initial value. | 588 // 'lazyValue' must be a closure that constructs the initial value. |
| 597 if (#notInMinifiedMode) { | 589 if (#notInMinifiedMode) { |
| 598 #lazy(fieldName, getterName, lazyValue, staticName); | 590 #lazy(fieldName, getterName, lazyValue, staticName); |
| 599 } else { | 591 } else { |
| 600 #lazy(fieldName, getterName, lazyValue); | 592 #lazy(fieldName, getterName, lazyValue); |
| 601 } | 593 } |
| 602 } | 594 } |
| 603 })(#laziesInfo) | 595 })(#laziesInfo) |
| 604 ''', {'notInMinifiedMode': !compiler.enableMinification, | 596 ''', {'notInMinifiedMode': !compiler.enableMinification, |
| 605 'laziesInfo': new jsAst.ArrayInitializer(laziesInfo), | 597 'laziesInfo': new jsAst.ArrayInitializer(laziesInfo), |
| 606 'lazy': js(lazyInitializerName)}); | 598 'lazy': js(lazyInitializerName)}); |
| 607 | 599 } else { |
| 608 output.addBuffer( | 600 return js.comment("No lazy statics."); |
| 609 jsAst.prettyPrint(code, compiler, monitor: compiler.dumpInfoTask)); | |
| 610 output.add("$N"); | |
| 611 } | 601 } |
| 612 } | 602 } |
| 613 | 603 |
| 614 List<jsAst.Expression> buildLaziesInfo(List<VariableElement> lazies) { | 604 List<jsAst.Expression> buildLaziesInfo(List<VariableElement> lazies) { |
| 615 List<jsAst.Expression> laziesInfo = <jsAst.Expression>[]; | 605 List<jsAst.Expression> laziesInfo = <jsAst.Expression>[]; |
| 616 for (VariableElement element in Elements.sortedByPosition(lazies)) { | 606 for (VariableElement element in Elements.sortedByPosition(lazies)) { |
| 617 jsAst.Expression code = backend.generatedCode[element]; | 607 jsAst.Expression code = backend.generatedCode[element]; |
| 618 // The code is null if we ended up not needing the lazily | 608 // The code is null if we ended up not needing the lazily |
| 619 // initialized field after all because of constant folding | 609 // initialized field after all because of constant folding |
| 620 // before code generation. | 610 // before code generation. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 666 } else { | 656 } else { |
| 667 return js('#(#,#,#,#)', | 657 return js('#(#,#,#,#)', |
| 668 [js(lazyInitializerName), | 658 [js(lazyInitializerName), |
| 669 js.string(namer.globalPropertyName(element)), | 659 js.string(namer.globalPropertyName(element)), |
| 670 js.string(namer.lazyInitializerName(element)), | 660 js.string(namer.lazyInitializerName(element)), |
| 671 code, | 661 code, |
| 672 js.string(element.name)]); | 662 js.string(element.name)]); |
| 673 } | 663 } |
| 674 } | 664 } |
| 675 | 665 |
| 676 void emitMetadata(Program program, CodeOutput output, OutputUnit outputUnit) { | 666 jsAst.Statement buildMetadata(Program program, OutputUnit outputUnit) { |
| 667 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 677 | 668 |
| 678 jsAst.Expression constructList(List<jsAst.Expression> list) { | 669 jsAst.Expression constructList(List<jsAst.Expression> list) { |
| 679 return new jsAst.ArrayInitializer(list == null ? [] : list); | 670 return new jsAst.ArrayInitializer(list == null ? [] : list); |
| 680 } | 671 } |
| 681 | 672 |
| 682 List<jsAst.Expression> types = program.metadataTypes[outputUnit]; | 673 List<jsAst.Expression> types = program.metadataTypes[outputUnit]; |
| 683 | 674 |
| 684 if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) { | 675 if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) { |
| 685 jsAst.Expression metadataAccess = | 676 jsAst.Expression metadataAccess = |
| 686 generateEmbeddedGlobalAccess(embeddedNames.METADATA); | 677 generateEmbeddedGlobalAccess(embeddedNames.METADATA); |
| 687 jsAst.Expression typesAccess = | 678 jsAst.Expression typesAccess = |
| 688 generateEmbeddedGlobalAccess(embeddedNames.TYPES); | 679 generateEmbeddedGlobalAccess(embeddedNames.TYPES); |
| 689 | 680 |
| 690 output.addBuffer( | 681 parts..add(js.statement('# = #;', [metadataAccess, |
| 691 jsAst.prettyPrint(new jsAst.Block([ | 682 constructList(program.metadata)])) |
| 692 js.statement('# = #;', [metadataAccess, | 683 ..add(js.statement('# = #;', [typesAccess, constructList(types)])); |
| 693 constructList(program.metadata)]), | |
| 694 js.statement('# = #;', [typesAccess, constructList(types)])]), | |
| 695 compiler, monitor: compiler.dumpInfoTask)); | |
| 696 output.add(n); | |
| 697 } else if (types != null) { | 684 } else if (types != null) { |
| 698 output.addBuffer( | 685 parts.add(js.statement('var ${namer.deferredTypesName} = #;', |
| 699 jsAst.prettyPrint( | 686 constructList(types))); |
| 700 js.statement('var ${namer.deferredTypesName} = #;', | |
| 701 constructList(types)), | |
| 702 compiler, monitor: compiler.dumpInfoTask)); | |
| 703 if (compiler.enableMinification) { | |
| 704 output.add('\n'); | |
| 705 } | |
| 706 } | 687 } |
| 688 return new jsAst.Block(parts); |
| 707 } | 689 } |
| 708 | 690 |
| 709 void emitCompileTimeConstants(CodeOutput output, | 691 jsAst.Statement buildCompileTimeConstants(List<Constant> constants, |
| 710 List<Constant> constants, | 692 {bool isMainFragment}) { |
| 711 {bool isMainFragment}) { | |
| 712 assert(isMainFragment != null); | 693 assert(isMainFragment != null); |
| 713 | 694 |
| 714 if (constants.isEmpty) return; | 695 if (constants.isEmpty) return js.comment("No constants in program."); |
| 715 CodeOutput constantOutput = output; | 696 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 716 if (compiler.hasIncrementalSupport && isMainFragment) { | 697 if (compiler.hasIncrementalSupport && isMainFragment) { |
| 717 constantOutput = cachedEmittedConstantsBuffer; | 698 parts = cachedEmittedConstantsAst; |
| 718 } | 699 } |
| 719 for (Constant constant in constants) { | 700 for (Constant constant in constants) { |
| 720 ConstantValue constantValue = constant.value; | 701 ConstantValue constantValue = constant.value; |
| 721 if (compiler.hasIncrementalSupport && isMainFragment) { | 702 if (compiler.hasIncrementalSupport && isMainFragment) { |
| 722 if (cachedEmittedConstants.contains(constantValue)) continue; | 703 if (cachedEmittedConstants.contains(constantValue)) continue; |
| 723 cachedEmittedConstants.add(constantValue); | 704 cachedEmittedConstants.add(constantValue); |
| 724 } | 705 } |
| 725 jsAst.Expression init = buildConstantInitializer(constantValue); | 706 parts.add(buildConstantInitializer(constantValue)); |
| 726 constantOutput.addBuffer( | |
| 727 jsAst.prettyPrint(init, compiler, monitor: compiler.dumpInfoTask)); | |
| 728 constantOutput.add('$N'); | |
| 729 } | 707 } |
| 730 if (compiler.hasIncrementalSupport && isMainFragment) { | 708 |
| 731 output.addBuffer(constantOutput); | 709 return new jsAst.Block(parts); |
| 732 } | |
| 733 } | 710 } |
| 734 | 711 |
| 735 jsAst.Expression buildConstantInitializer(ConstantValue constant) { | 712 jsAst.Statement buildConstantInitializer(ConstantValue constant) { |
| 736 String name = namer.constantName(constant); | 713 String name = namer.constantName(constant); |
| 737 return js('#.# = #', | 714 return js.statement('#.# = #', |
| 738 [namer.globalObjectForConstant(constant), name, | 715 [namer.globalObjectForConstant(constant), name, |
| 739 constantInitializerExpression(constant)]); | 716 constantInitializerExpression(constant)]); |
| 740 } | 717 } |
| 741 | 718 |
| 742 jsAst.Template get makeConstantListTemplate { | 719 jsAst.Template get makeConstantListTemplate { |
| 743 // TODO(floitsch): there is no harm in caching the template. | 720 // TODO(floitsch): there is no harm in caching the template. |
| 744 return jsAst.js.uncachedExpressionTemplate( | 721 return jsAst.js.uncachedExpressionTemplate( |
| 745 '${namer.isolateName}.$makeConstListProperty(#)'); | 722 '${namer.isolateName}.$makeConstListProperty(#)'); |
| 746 } | 723 } |
| 747 | 724 |
| 748 void emitMakeConstantList(CodeOutput output) { | 725 jsAst.Statement buildMakeConstantList() { |
| 749 output.addBuffer( | 726 if (task.outputContainsConstantList) { |
| 750 jsAst.prettyPrint( | 727 return js.statement(r''' |
| 751 // Functions are stored in the hidden class and not as properties in | 728 // Functions are stored in the hidden class and not as properties in |
| 752 // the object. We never actually look at the value, but only want | 729 // the object. We never actually look at the value, but only want |
| 753 // to know if the property exists. | 730 // to know if the property exists. |
| 754 js.statement(r'''#.# = function(list) { | 731 #.# = function (list) { |
| 755 list.immutable$list = Array; | 732 list.immutable$list = Array; |
| 756 list.fixed$length = Array; | 733 list.fixed$length = Array; |
| 757 return list; | 734 return list; |
| 758 }''', | 735 }''', |
| 759 [namer.isolateName, makeConstListProperty]), | 736 [namer.isolateName, makeConstListProperty]); |
| 760 compiler, monitor: compiler.dumpInfoTask)); | 737 } else { |
| 761 output.add(N); | 738 return js.comment("Output contains no constant list."); |
| 739 } |
| 762 } | 740 } |
| 763 | 741 |
| 764 void emitFunctionThatReturnsNull(CodeOutput output) { | 742 jsAst.Statement buildFunctionThatReturnsNull() { |
| 765 output.addBuffer( | 743 return js.statement('#.# = function() {}', |
| 766 jsAst.prettyPrint( | 744 [backend.namer.currentIsolate, |
| 767 js.statement('#.# = function() {}', | 745 backend.rti.getFunctionThatReturnsNullName]); |
| 768 [backend.namer.currentIsolate, | |
| 769 backend.rti.getFunctionThatReturnsNullName]), | |
| 770 compiler, monitor: compiler.dumpInfoTask)); | |
| 771 output.add(N); | |
| 772 } | 746 } |
| 773 | 747 |
| 774 jsAst.Expression generateFunctionThatReturnsNull() { | 748 jsAst.Expression generateFunctionThatReturnsNull() { |
| 775 return js("#.#", [backend.namer.currentIsolate, | 749 return js("#.#", [backend.namer.currentIsolate, |
| 776 backend.rti.getFunctionThatReturnsNullName]); | 750 backend.rti.getFunctionThatReturnsNullName]); |
| 777 } | 751 } |
| 778 | 752 |
| 779 emitMain(CodeOutput output, jsAst.Statement invokeMain) { | 753 buildMain(jsAst.Statement invokeMain) { |
| 780 if (compiler.isMockCompilation) return; | 754 if (compiler.isMockCompilation) return js.comment("Mock compilation"); |
| 755 |
| 756 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 781 | 757 |
| 782 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { | 758 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { |
| 783 jsAst.Statement nativeBoilerPlate = | 759 parts.add( |
| 784 NativeGenerator.generateIsolateAffinityTagInitialization( | 760 NativeGenerator.generateIsolateAffinityTagInitialization( |
| 785 backend, | 761 backend, |
| 786 generateEmbeddedGlobalAccess, | 762 generateEmbeddedGlobalAccess, |
| 787 js("convertToFastObject", [])); | 763 js("convertToFastObject", []))); |
| 788 output.addBuffer(jsAst.prettyPrint( | |
| 789 nativeBoilerPlate, compiler, monitor: compiler.dumpInfoTask)); | |
| 790 } | 764 } |
| 791 | 765 |
| 792 output.add(';'); | 766 parts..add(js.comment('BEGIN invoke [main].')) |
| 793 addComment('BEGIN invoke [main].', output); | 767 ..add(invokeMain) |
| 794 output.addBuffer(jsAst.prettyPrint(invokeMain, | 768 ..add(js.comment('END invoke [main].')); |
| 795 compiler, monitor: compiler.dumpInfoTask)); | 769 |
| 796 output.add(N); | 770 return new jsAst.Block(parts); |
| 797 addComment('END invoke [main].', output); | |
| 798 } | 771 } |
| 799 | 772 |
| 800 void emitInitFunction(CodeOutput output) { | 773 jsAst.Statement buildInitFunction() { |
| 801 jsAst.Expression allClassesAccess = | 774 jsAst.Expression allClassesAccess = |
| 802 generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES); | 775 generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES); |
| 803 jsAst.Expression getTypeFromNameAccess = | 776 jsAst.Expression getTypeFromNameAccess = |
| 804 generateEmbeddedGlobalAccess(embeddedNames.GET_TYPE_FROM_NAME); | 777 generateEmbeddedGlobalAccess(embeddedNames.GET_TYPE_FROM_NAME); |
| 805 jsAst.Expression interceptorsByTagAccess = | 778 jsAst.Expression interceptorsByTagAccess = |
| 806 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG); | 779 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG); |
| 807 jsAst.Expression leafTagsAccess = | 780 jsAst.Expression leafTagsAccess = |
| 808 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS); | 781 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS); |
| 809 jsAst.Expression finishedClassesAccess = | 782 jsAst.Expression finishedClassesAccess = |
| 810 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES); | 783 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES); |
| 811 jsAst.Expression cyclicThrow = | 784 jsAst.Expression cyclicThrow = |
| 812 staticFunctionAccess(backend.getCyclicThrowHelper()); | 785 staticFunctionAccess(backend.getCyclicThrowHelper()); |
| 813 jsAst.Expression laziesAccess = | 786 jsAst.Expression laziesAccess = |
| 814 generateEmbeddedGlobalAccess(embeddedNames.LAZIES); | 787 generateEmbeddedGlobalAccess(embeddedNames.LAZIES); |
| 815 | 788 |
| 816 jsAst.FunctionDeclaration decl = js.statement(''' | 789 return js.statement(''' |
| 817 function init() { | 790 function init() { |
| 818 $isolateProperties = Object.create(null); | 791 $isolatePropertiesName = Object.create(null); |
| 819 #allClasses = Object.create(null); | 792 #allClasses = Object.create(null); |
| 820 #getTypeFromName = function(name) {return #allClasses[name];}; | 793 #getTypeFromName = function(name) {return #allClasses[name];}; |
| 821 #interceptorsByTag = Object.create(null); | 794 #interceptorsByTag = Object.create(null); |
| 822 #leafTags = Object.create(null); | 795 #leafTags = Object.create(null); |
| 823 #finishedClasses = Object.create(null); | 796 #finishedClasses = Object.create(null); |
| 824 | 797 |
| 825 if (#needsLazyInitializer) { | 798 if (#needsLazyInitializer) { |
| 826 // [staticName] is only provided in non-minified mode. If missing, we | 799 // [staticName] is only provided in non-minified mode. If missing, we |
| 827 // fall back to [fieldName]. Likewise, [prototype] is optional and | 800 // fall back to [fieldName]. Likewise, [prototype] is optional and |
| 828 // defaults to the isolateProperties object. | 801 // defaults to the isolateProperties object. |
| 829 $lazyInitializerName = function (fieldName, getterName, lazyValue, | 802 $lazyInitializerName = function (fieldName, getterName, lazyValue, |
| 830 staticName, prototype) { | 803 staticName, prototype) { |
| 831 if (!#lazies) #lazies = Object.create(null); | 804 if (!#lazies) #lazies = Object.create(null); |
| 832 #lazies[fieldName] = getterName; | 805 #lazies[fieldName] = getterName; |
| 833 | 806 |
| 834 // 'prototype' will be undefined except if we are doing an update | 807 // 'prototype' will be undefined except if we are doing an update |
| 835 // during incremental compilation. In this case we put the lazy | 808 // during incremental compilation. In this case we put the lazy |
| 836 // field directly on the isolate instead of the isolateProperties. | 809 // field directly on the isolate instead of the isolateProperties. |
| 837 prototype = prototype || $isolateProperties; | 810 prototype = prototype || $isolatePropertiesName; |
| 838 var sentinelUndefined = {}; | 811 var sentinelUndefined = {}; |
| 839 var sentinelInProgress = {}; | 812 var sentinelInProgress = {}; |
| 840 prototype[fieldName] = sentinelUndefined; | 813 prototype[fieldName] = sentinelUndefined; |
| 841 | 814 |
| 842 prototype[getterName] = function () { | 815 prototype[getterName] = function () { |
| 843 var result = this[fieldName]; | 816 var result = this[fieldName]; |
| 844 try { | 817 try { |
| 845 if (result === sentinelUndefined) { | 818 if (result === sentinelUndefined) { |
| 846 this[fieldName] = sentinelInProgress; | 819 this[fieldName] = sentinelInProgress; |
| 847 | 820 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 'interceptorsByTag': interceptorsByTagAccess, | 899 'interceptorsByTag': interceptorsByTagAccess, |
| 927 'leafTags': leafTagsAccess, | 900 'leafTags': leafTagsAccess, |
| 928 'finishedClasses': finishedClassesAccess, | 901 'finishedClasses': finishedClassesAccess, |
| 929 'needsLazyInitializer': needsLazyInitializer, | 902 'needsLazyInitializer': needsLazyInitializer, |
| 930 'lazies': laziesAccess, 'cyclicThrow': cyclicThrow, | 903 'lazies': laziesAccess, 'cyclicThrow': cyclicThrow, |
| 931 'isolatePropertiesName': namer.isolatePropertiesName, | 904 'isolatePropertiesName': namer.isolatePropertiesName, |
| 932 'outputContainsConstantList': task.outputContainsConstantList, | 905 'outputContainsConstantList': task.outputContainsConstantList, |
| 933 'makeConstListProperty': makeConstListProperty, | 906 'makeConstListProperty': makeConstListProperty, |
| 934 'hasIncrementalSupport': compiler.hasIncrementalSupport, | 907 'hasIncrementalSupport': compiler.hasIncrementalSupport, |
| 935 'lazyInitializerProperty': lazyInitializerProperty,}); | 908 'lazyInitializerProperty': lazyInitializerProperty,}); |
| 936 | |
| 937 output.addBuffer( | |
| 938 jsAst.prettyPrint(decl, compiler, monitor: compiler.dumpInfoTask)); | |
| 939 if (compiler.enableMinification) { | |
| 940 output.add('\n'); | |
| 941 } | |
| 942 } | 909 } |
| 943 | 910 |
| 944 void emitConvertToFastObjectFunction(CodeOutput output) { | 911 jsAst.Statement buildConvertToFastObjectFunction() { |
| 945 List<jsAst.Statement> debugCode = <jsAst.Statement>[]; | 912 List<jsAst.Statement> debugCode = <jsAst.Statement>[]; |
| 946 if (DEBUG_FAST_OBJECTS) { | 913 if (DEBUG_FAST_OBJECTS) { |
| 947 debugCode.add(js.statement(r''' | 914 debugCode.add(js.statement(r''' |
| 948 // The following only works on V8 when run with option | 915 // The following only works on V8 when run with option |
| 949 // "--allow-natives-syntax". We use'new Function' because the | 916 // "--allow-natives-syntax". We use'new Function' because the |
| 950 // miniparser does not understand V8 native syntax. | 917 // miniparser does not understand V8 native syntax. |
| 951 if (typeof print === "function") { | 918 if (typeof print === "function") { |
| 952 var HasFastProperties = | 919 var HasFastProperties = |
| 953 new Function("a", "return %HasFastProperties(a)"); | 920 new Function("a", "return %HasFastProperties(a)"); |
| 954 print("Size of global object: " | 921 print("Size of global object: " |
| 955 + String(Object.getOwnPropertyNames(properties).length) | 922 + String(Object.getOwnPropertyNames(properties).length) |
| 956 + ", fast properties " + HasFastProperties(properties)); | 923 + ", fast properties " + HasFastProperties(properties)); |
| 957 }''')); | 924 }''')); |
| 958 } | 925 } |
| 959 | 926 |
| 960 jsAst.Statement convertToFastObject = js.statement(r''' | 927 return js.statement(r''' |
| 961 function convertToFastObject(properties) { | 928 function convertToFastObject(properties) { |
| 962 // Create an instance that uses 'properties' as prototype. This should | 929 // Create an instance that uses 'properties' as prototype. This should |
| 963 // make 'properties' a fast object. | 930 // make 'properties' a fast object. |
| 964 function MyClass() {}; | 931 function MyClass() {}; |
| 965 MyClass.prototype = properties; | 932 MyClass.prototype = properties; |
| 966 new MyClass(); | 933 new MyClass(); |
| 967 #; | 934 #; |
| 968 return properties; | 935 return properties; |
| 969 }''', [debugCode]); | 936 }''', [debugCode]); |
| 970 | |
| 971 output.addBuffer(jsAst.prettyPrint(convertToFastObject, compiler)); | |
| 972 output.add(N); | |
| 973 } | 937 } |
| 974 | 938 |
| 975 void emitConvertToSlowObjectFunction(CodeOutput output) { | 939 jsAst.Statement buildConvertToSlowObjectFunction() { |
| 976 jsAst.Statement convertToSlowObject = js.statement(r''' | 940 return js.statement(r''' |
| 977 function convertToSlowObject(properties) { | 941 function convertToSlowObject(properties) { |
| 978 // Add and remove a property to make the object transition into hashmap | 942 // Add and remove a property to make the object transition into hashmap |
| 979 // mode. | 943 // mode. |
| 980 properties.__MAGIC_SLOW_PROPERTY = 1; | 944 properties.__MAGIC_SLOW_PROPERTY = 1; |
| 981 delete properties.__MAGIC_SLOW_PROPERTY; | 945 delete properties.__MAGIC_SLOW_PROPERTY; |
| 982 return properties; | 946 return properties; |
| 983 }'''); | 947 }'''); |
| 984 | |
| 985 output.addBuffer(jsAst.prettyPrint(convertToSlowObject, compiler)); | |
| 986 output.add(N); | |
| 987 } | 948 } |
| 988 | 949 |
| 989 void emitSupportsDirectProtoAccess(CodeOutput output) { | 950 jsAst.Statement buildSupportsDirectProtoAccess() { |
| 990 jsAst.Statement supportsDirectProtoAccess; | 951 jsAst.Statement supportsDirectProtoAccess; |
| 991 | 952 |
| 992 if (compiler.hasIncrementalSupport) { | 953 if (compiler.hasIncrementalSupport) { |
| 993 supportsDirectProtoAccess = js.statement(r''' | 954 supportsDirectProtoAccess = js.statement(r''' |
| 994 var supportsDirectProtoAccess = false; | 955 var supportsDirectProtoAccess = false; |
| 995 '''); | 956 '''); |
| 996 } else { | 957 } else { |
| 997 supportsDirectProtoAccess = js.statement(r''' | 958 supportsDirectProtoAccess = js.statement(r''' |
| 998 var supportsDirectProtoAccess = (function () { | 959 var supportsDirectProtoAccess = (function () { |
| 999 var cls = function () {}; | 960 var cls = function () {}; |
| 1000 cls.prototype = {'p': {}}; | 961 cls.prototype = {'p': {}}; |
| 1001 var object = new cls(); | 962 var object = new cls(); |
| 1002 return object.__proto__ && | 963 return object.__proto__ && |
| 1003 object.__proto__.p === cls.prototype.p; | 964 object.__proto__.p === cls.prototype.p; |
| 1004 })(); | 965 })(); |
| 1005 '''); | 966 '''); |
| 1006 } | 967 } |
| 1007 | 968 |
| 1008 output.addBuffer(jsAst.prettyPrint(supportsDirectProtoAccess, compiler)); | 969 return supportsDirectProtoAccess; |
| 1009 output.add(N); | |
| 1010 } | 970 } |
| 1011 | 971 |
| 1012 jsAst.Expression generateLibraryDescriptor(LibraryElement library, | 972 jsAst.Expression generateLibraryDescriptor(LibraryElement library, |
| 1013 Fragment fragment) { | 973 Fragment fragment) { |
| 1014 var uri = ""; | 974 var uri = ""; |
| 1015 if (!compiler.enableMinification || backend.mustPreserveUris) { | 975 if (!compiler.enableMinification || backend.mustPreserveUris) { |
| 1016 uri = library.canonicalUri; | 976 uri = library.canonicalUri; |
| 1017 if (uri.scheme == 'file' && compiler.outputUri != null) { | 977 if (uri.scheme == 'file' && compiler.outputUri != null) { |
| 1018 uri = relativize(compiler.outputUri, library.canonicalUri, false); | 978 uri = relativize(compiler.outputUri, library.canonicalUri, false); |
| 1019 } | 979 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1039 initializer = descriptor.toObjectInitializer(); | 999 initializer = descriptor.toObjectInitializer(); |
| 1040 } | 1000 } |
| 1041 | 1001 |
| 1042 compiler.dumpInfoTask.registerElementAst(library, metadata); | 1002 compiler.dumpInfoTask.registerElementAst(library, metadata); |
| 1043 compiler.dumpInfoTask.registerElementAst(library, initializer); | 1003 compiler.dumpInfoTask.registerElementAst(library, initializer); |
| 1044 | 1004 |
| 1045 List<jsAst.Expression> parts = <jsAst.Expression>[]; | 1005 List<jsAst.Expression> parts = <jsAst.Expression>[]; |
| 1046 parts..add(js.string(libraryName)) | 1006 parts..add(js.string(libraryName)) |
| 1047 ..add(js.string(uri.toString())) | 1007 ..add(js.string(uri.toString())) |
| 1048 ..add(metadata == null ? new jsAst.ArrayHole() : metadata) | 1008 ..add(metadata == null ? new jsAst.ArrayHole() : metadata) |
| 1049 ..add(js.name(namer.globalObjectFor(library))) | 1009 ..add(js('#', namer.globalObjectFor(library))) |
| 1050 ..add(initializer); | 1010 ..add(initializer); |
| 1051 if (library == compiler.mainApp) { | 1011 if (library == compiler.mainApp) { |
| 1052 parts.add(js.number(1)); | 1012 parts.add(js.number(1)); |
| 1053 } | 1013 } |
| 1054 | 1014 |
| 1055 return new jsAst.ArrayInitializer(parts); | 1015 return new jsAst.ArrayInitializer(parts); |
| 1056 } | 1016 } |
| 1057 | 1017 |
| 1058 void assemblePrecompiledConstructor(OutputUnit outputUnit, | 1018 void assemblePrecompiledConstructor(OutputUnit outputUnit, |
| 1059 String constructorName, | 1019 String constructorName, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1125 String constructorName = mangledName; | 1085 String constructorName = mangledName; |
| 1126 jsAst.Expression constructorAst = js('function() {}'); | 1086 jsAst.Expression constructorAst = js('function() {}'); |
| 1127 List<String> fieldNames = []; | 1087 List<String> fieldNames = []; |
| 1128 assemblePrecompiledConstructor(mainOutputUnit, | 1088 assemblePrecompiledConstructor(mainOutputUnit, |
| 1129 constructorName, | 1089 constructorName, |
| 1130 constructorAst, | 1090 constructorAst, |
| 1131 fieldNames); | 1091 fieldNames); |
| 1132 } | 1092 } |
| 1133 } | 1093 } |
| 1134 | 1094 |
| 1135 void emitMangledNames(CodeOutput output) { | 1095 jsAst.Statement buildGlobalObjectSetup(bool isProgramSplit) { |
| 1096 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 1097 |
| 1098 parts.add(js.comment(""" |
| 1099 // The global objects start as so-called "slow objects". For V8, this |
| 1100 // means that it won't try to make map transitions as we add properties |
| 1101 // to these objects. Later on, we attempt to turn these objects into |
| 1102 // fast objects by calling "convertToFastObject" (see |
| 1103 // [emitConvertToFastObjectFunction]). |
| 1104 """)); |
| 1105 |
| 1106 for (String globalObject in Namer.reservedGlobalObjectNames) { |
| 1107 if (isProgramSplit) { |
| 1108 String template = |
| 1109 "var #globalObject = #globalsHolder.#globalObject = map();"; |
| 1110 parts.add(js.statement(template, {"globalObject": globalObject, |
| 1111 "globalsHolder": globalsHolder})); |
| 1112 } else { |
| 1113 parts.add(js.statement("var #globalObject = map();", |
| 1114 {"globalObject": globalObject})); |
| 1115 } |
| 1116 |
| 1117 } |
| 1118 |
| 1119 return new jsAst.Block(parts); |
| 1120 } |
| 1121 |
| 1122 jsAst.Statement buildConvertGlobalObjectToFastObjects() { |
| 1123 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 1124 |
| 1125 for (String globalObject in Namer.reservedGlobalObjectNames) { |
| 1126 parts.add(js.statement( |
| 1127 '#globalObject = convertToFastObject(#globalObject);', |
| 1128 {"globalObject": globalObject})); |
| 1129 } |
| 1130 |
| 1131 return new jsAst.Block(parts); |
| 1132 } |
| 1133 |
| 1134 jsAst.Statement buildDebugFastObjectCode() { |
| 1135 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 1136 |
| 1137 if (DEBUG_FAST_OBJECTS) { |
| 1138 parts.add(js.statement(r''' |
| 1139 // The following only works on V8 when run with option |
| 1140 // "--allow-natives-syntax". We use'new Function' because the |
| 1141 // miniparser does not understand V8 native syntax. |
| 1142 if (typeof print === "function") { |
| 1143 var HasFastProperties = |
| 1144 new Function("a", "return %HasFastProperties(a)"); |
| 1145 print("Size of global helper object: " |
| 1146 + String(Object.getOwnPropertyNames(H).length) |
| 1147 + ", fast properties " + HasFastProperties(H)); |
| 1148 print("Size of global platform object: " |
| 1149 + String(Object.getOwnPropertyNames(P).length) |
| 1150 + ", fast properties " + HasFastProperties(P)); |
| 1151 print("Size of global dart:html object: " |
| 1152 + String(Object.getOwnPropertyNames(W).length) |
| 1153 + ", fast properties " + HasFastProperties(W)); |
| 1154 print("Size of isolate properties object: " |
| 1155 + String(Object.getOwnPropertyNames($).length) |
| 1156 + ", fast properties " + HasFastProperties($)); |
| 1157 print("Size of constant object: " |
| 1158 + String(Object.getOwnPropertyNames(C).length) |
| 1159 + ", fast properties " + HasFastProperties(C)); |
| 1160 var names = Object.getOwnPropertyNames($); |
| 1161 for (var i = 0; i < names.length; i++) { |
| 1162 print("$." + names[i]); |
| 1163 } |
| 1164 } |
| 1165 ''')); |
| 1166 |
| 1167 for (String object in Namer.userGlobalObjects) { |
| 1168 parts.add(js.statement(''' |
| 1169 if (typeof print === "function") { |
| 1170 print("Size of " + #objectString + ": " |
| 1171 + String(Object.getOwnPropertyNames(#object).length) |
| 1172 + ", fast properties " + HasFastProperties(#object)); |
| 1173 } |
| 1174 ''', {"object": object, "objectString": js.string(object)})); |
| 1175 } |
| 1176 } |
| 1177 |
| 1178 return new jsAst.Block(parts); |
| 1179 } |
| 1180 |
| 1181 jsAst.Statement buildMangledNames() { |
| 1182 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 1183 |
| 1136 if (!mangledFieldNames.isEmpty) { | 1184 if (!mangledFieldNames.isEmpty) { |
| 1137 var keys = mangledFieldNames.keys.toList(); | 1185 var keys = mangledFieldNames.keys.toList(); |
| 1138 keys.sort(); | 1186 keys.sort(); |
| 1139 var properties = []; | 1187 var properties = []; |
| 1140 for (String key in keys) { | 1188 for (String key in keys) { |
| 1141 var value = js.string('${mangledFieldNames[key]}'); | 1189 var value = js.string('${mangledFieldNames[key]}'); |
| 1142 properties.add(new jsAst.Property(js.string(key), value)); | 1190 properties.add(new jsAst.Property(js.string(key), value)); |
| 1143 } | 1191 } |
| 1144 | 1192 |
| 1145 jsAst.Expression mangledNamesAccess = | 1193 jsAst.Expression mangledNamesAccess = |
| 1146 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES); | 1194 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES); |
| 1147 var map = new jsAst.ObjectInitializer(properties); | 1195 var map = new jsAst.ObjectInitializer(properties); |
| 1148 output.addBuffer( | 1196 parts.add(js.statement('# = #', [mangledNamesAccess, map])); |
| 1149 jsAst.prettyPrint( | |
| 1150 js.statement('# = #', [mangledNamesAccess, map]), | |
| 1151 compiler, | |
| 1152 monitor: compiler.dumpInfoTask)); | |
| 1153 if (compiler.enableMinification) { | |
| 1154 output.add(';'); | |
| 1155 } | |
| 1156 } | 1197 } |
| 1198 |
| 1157 if (!mangledGlobalFieldNames.isEmpty) { | 1199 if (!mangledGlobalFieldNames.isEmpty) { |
| 1158 var keys = mangledGlobalFieldNames.keys.toList(); | 1200 var keys = mangledGlobalFieldNames.keys.toList(); |
| 1159 keys.sort(); | 1201 keys.sort(); |
| 1160 var properties = []; | 1202 var properties = []; |
| 1161 for (String key in keys) { | 1203 for (String key in keys) { |
| 1162 var value = js.string('${mangledGlobalFieldNames[key]}'); | 1204 var value = js.string('${mangledGlobalFieldNames[key]}'); |
| 1163 properties.add(new jsAst.Property(js.string(key), value)); | 1205 properties.add(new jsAst.Property(js.string(key), value)); |
| 1164 } | 1206 } |
| 1165 jsAst.Expression mangledGlobalNamesAccess = | 1207 jsAst.Expression mangledGlobalNamesAccess = |
| 1166 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES); | 1208 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES); |
| 1167 var map = new jsAst.ObjectInitializer(properties); | 1209 var map = new jsAst.ObjectInitializer(properties); |
| 1168 output.addBuffer( | 1210 parts.add(js.statement('# = #', [mangledGlobalNamesAccess, map])); |
| 1169 jsAst.prettyPrint( | |
| 1170 js.statement('# = #', [mangledGlobalNamesAccess, map]), | |
| 1171 compiler, | |
| 1172 monitor: compiler.dumpInfoTask)); | |
| 1173 if (compiler.enableMinification) { | |
| 1174 output.add(';'); | |
| 1175 } | |
| 1176 } | 1211 } |
| 1212 |
| 1213 return new jsAst.Block(parts); |
| 1177 } | 1214 } |
| 1178 | 1215 |
| 1179 void checkEverythingEmitted(Iterable<Element> elements) { | 1216 void checkEverythingEmitted(Iterable<Element> elements) { |
| 1180 List<Element> pendingStatics; | 1217 List<Element> pendingStatics; |
| 1181 if (!compiler.hasIncrementalSupport) { | 1218 if (!compiler.hasIncrementalSupport) { |
| 1182 pendingStatics = | 1219 pendingStatics = |
| 1183 Elements.sortedByPosition(elements.where((e) => !e.isLibrary)); | 1220 Elements.sortedByPosition(elements.where((e) => !e.isLibrary)); |
| 1184 | 1221 |
| 1185 pendingStatics.forEach((element) => | 1222 pendingStatics.forEach((element) => |
| 1186 compiler.reportInfo( | 1223 compiler.reportInfo( |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1228 codeOutputListeners = <CodeOutputListener>[lineColumnCollector]; | 1265 codeOutputListeners = <CodeOutputListener>[lineColumnCollector]; |
| 1229 } | 1266 } |
| 1230 | 1267 |
| 1231 CodeOutput mainOutput = | 1268 CodeOutput mainOutput = |
| 1232 new StreamCodeOutput(compiler.outputProvider('', 'js'), | 1269 new StreamCodeOutput(compiler.outputProvider('', 'js'), |
| 1233 codeOutputListeners); | 1270 codeOutputListeners); |
| 1234 outputBuffers[mainOutputUnit] = mainOutput; | 1271 outputBuffers[mainOutputUnit] = mainOutput; |
| 1235 | 1272 |
| 1236 bool isProgramSplit = program.isSplit; | 1273 bool isProgramSplit = program.isSplit; |
| 1237 | 1274 |
| 1238 mainOutput.add(buildGeneratedBy()); | 1275 List<jsAst.Statement> statements = <jsAst.Statement>[]; |
| 1239 addComment(HOOKS_API_USAGE, mainOutput); | 1276 |
| 1277 statements..add(buildGeneratedBy()) |
| 1278 ..add(js.comment(HOOKS_API_USAGE)); |
| 1240 | 1279 |
| 1241 if (isProgramSplit) { | 1280 if (isProgramSplit) { |
| 1242 /// For deferred loading we communicate the initializers via this global | 1281 /// For deferred loading we communicate the initializers via this global |
| 1243 /// variable. The deferred hunks will add their initialization to this. | 1282 /// variable. The deferred hunks will add their initialization to this. |
| 1244 /// The semicolon is important in minified mode, without it the | 1283 /// The semicolon is important in minified mode, without it the |
| 1245 /// following parenthesis looks like a call to the object literal. | 1284 /// following parenthesis looks like a call to the object literal. |
| 1246 mainOutput.add( | 1285 statements.add( |
| 1247 'self.${deferredInitializers} = self.${deferredInitializers} || ' | 1286 js.statement('self.#deferredInitializers = ' |
| 1248 'Object.create(null);$n'); | 1287 'self.#deferredInitializers || Object.create(null);', |
| 1288 {'deferredInitializers': deferredInitializers})); |
| 1249 } | 1289 } |
| 1250 | 1290 |
| 1251 // Using a named function here produces easier to read stack traces in | 1291 // Collect the AST for the decriptors |
| 1252 // Chrome/V8. | |
| 1253 mainOutput.add('(function(${namer.currentIsolate})$_{\n'); | |
| 1254 emitSupportsDirectProtoAccess(mainOutput); | |
| 1255 if (compiler.hasIncrementalSupport) { | |
| 1256 mainOutput.addBuffer(jsAst.prettyPrint(js.statement( | |
| 1257 """ | |
| 1258 { | |
| 1259 #helper = #helper || Object.create(null); | |
| 1260 #helper.patch = function(a) { eval(a)}; | |
| 1261 #helper.schemaChange = #schemaChange; | |
| 1262 #helper.addMethod = #addMethod; | |
| 1263 #helper.extractStubs = function(array, name, isStatic, originalDescriptor) { | |
| 1264 var descriptor = Object.create(null); | |
| 1265 this.addStubs(descriptor, array, name, isStatic, []); | |
| 1266 return descriptor; | |
| 1267 }; | |
| 1268 }""", | |
| 1269 { 'helper': js('this.#', [namer.incrementalHelperName]), | |
| 1270 'schemaChange': buildSchemaChangeFunction(), | |
| 1271 'addMethod': buildIncrementalAddMethod() }), compiler)); | |
| 1272 } | |
| 1273 if (isProgramSplit) { | |
| 1274 /// We collect all the global state, so it can be passed to the | |
| 1275 /// initializer of deferred files. | |
| 1276 mainOutput.add('var ${globalsHolder}$_=${_}Object.create(null)$N'); | |
| 1277 } | |
| 1278 | |
| 1279 jsAst.Statement mapFunction = js.statement(''' | |
| 1280 // [map] returns an object that V8 shouldn't try to optimize with a hidden | |
| 1281 // class. This prevents a potential performance problem where V8 tries to build | |
| 1282 // a hidden class for an object used as a hashMap. | |
| 1283 // It requires fewer characters to declare a variable as a parameter than | |
| 1284 // with `var`. | |
| 1285 function map(x) { | |
| 1286 x = Object.create(null); | |
| 1287 x.x = 0; | |
| 1288 delete x.x; | |
| 1289 return x; | |
| 1290 } | |
| 1291 '''); | |
| 1292 mainOutput.addBuffer(jsAst.prettyPrint(mapFunction, compiler)); | |
| 1293 for (String globalObject in Namer.reservedGlobalObjectNames) { | |
| 1294 // The global objects start as so-called "slow objects". For V8, this | |
| 1295 // means that it won't try to make map transitions as we add properties | |
| 1296 // to these objects. Later on, we attempt to turn these objects into | |
| 1297 // fast objects by calling "convertToFastObject" (see | |
| 1298 // [emitConvertToFastObjectFunction]). | |
| 1299 mainOutput.add('var ${globalObject}$_=${_}'); | |
| 1300 if(isProgramSplit) { | |
| 1301 mainOutput.add('${globalsHolder}.$globalObject$_=${_}'); | |
| 1302 } | |
| 1303 mainOutput.add('map()$N'); | |
| 1304 } | |
| 1305 | |
| 1306 mainOutput.add('function ${namer.isolateName}()$_{}\n'); | |
| 1307 if (isProgramSplit) { | |
| 1308 mainOutput.add( | |
| 1309 '${globalsHolder}.${namer.isolateName}$_=$_${namer.isolateName}$N' | |
| 1310 '${globalsHolder}.$initName$_=${_}$initName$N' | |
| 1311 '${globalsHolder}.$setupProgramName$_=$_' | |
| 1312 '$setupProgramName$N'); | |
| 1313 } | |
| 1314 mainOutput.add('init()$N$n'); | |
| 1315 mainOutput.add('$isolateProperties$_=$_$isolatePropertiesName$N'); | |
| 1316 | |
| 1317 emitFunctionThatReturnsNull(mainOutput); | |
| 1318 | |
| 1319 Iterable<LibraryElement> libraries = | |
| 1320 task.outputLibraryLists[mainOutputUnit]; | |
| 1321 if (libraries == null) libraries = []; | |
| 1322 emitMangledNames(mainOutput); | |
| 1323 | |
| 1324 Map<Element, ClassBuilder> descriptors = elementDescriptors[mainFragment]; | 1292 Map<Element, ClassBuilder> descriptors = elementDescriptors[mainFragment]; |
| 1325 if (descriptors == null) descriptors = const {}; | 1293 if (descriptors == null) descriptors = const {}; |
| 1326 | 1294 |
| 1327 checkEverythingEmitted(descriptors.keys); | 1295 checkEverythingEmitted(descriptors.keys); |
| 1328 | 1296 |
| 1297 Iterable<LibraryElement> libraries = |
| 1298 task.outputLibraryLists[mainOutputUnit]; |
| 1299 if (libraries == null) libraries = []; |
| 1300 |
| 1329 List<jsAst.Expression> parts = <jsAst.Expression>[]; | 1301 List<jsAst.Expression> parts = <jsAst.Expression>[]; |
| 1330 for (LibraryElement library in Elements.sortedByPosition(libraries)) { | 1302 for (LibraryElement library in Elements.sortedByPosition(libraries)) { |
| 1331 parts.add(generateLibraryDescriptor(library, mainFragment)); | 1303 parts.add(generateLibraryDescriptor(library, mainFragment)); |
| 1332 descriptors.remove(library); | 1304 descriptors.remove(library); |
| 1333 } | 1305 } |
| 1334 | 1306 |
| 1335 if (descriptors.isNotEmpty) { | 1307 if (descriptors.isNotEmpty) { |
| 1336 List<Element> remainingLibraries = descriptors.keys | 1308 List<Element> remainingLibraries = descriptors.keys |
| 1337 .where((Element e) => e is LibraryElement) | 1309 .where((Element e) => e is LibraryElement) |
| 1338 .toList(); | 1310 .toList(); |
| 1339 | 1311 |
| 1340 // The remaining descriptors are only accessible through reflection. | 1312 // The remaining descriptors are only accessible through reflection. |
| 1341 // The program builder does not collect libraries that only | 1313 // The program builder does not collect libraries that only |
| 1342 // contain typedefs that are used for reflection. | 1314 // contain typedefs that are used for reflection. |
| 1343 for (LibraryElement element in remainingLibraries) { | 1315 for (LibraryElement element in remainingLibraries) { |
| 1344 assert(element is LibraryElement || compiler.hasIncrementalSupport); | 1316 assert(element is LibraryElement || compiler.hasIncrementalSupport); |
| 1345 if (element is LibraryElement) { | 1317 if (element is LibraryElement) { |
| 1346 parts.add(generateLibraryDescriptor(element, mainFragment)); | 1318 parts.add(generateLibraryDescriptor(element, mainFragment)); |
| 1347 descriptors.remove(element); | 1319 descriptors.remove(element); |
| 1348 } | 1320 } |
| 1349 } | 1321 } |
| 1350 } | 1322 } |
| 1351 jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts); | 1323 jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts); |
| 1352 | 1324 |
| 1353 bool needsNativeSupport = program.needsNativeSupport; | 1325 // Using a named function here produces easier to read stack traces in |
| 1354 mainOutput.addBuffer( | 1326 // Chrome/V8. |
| 1355 jsAst.prettyPrint( | 1327 statements.add(js.statement(""" |
| 1356 buildSetupProgram(program, compiler, backend, namer, this), | 1328 (function() { |
| 1357 compiler)); | 1329 // No renaming in the top-level function to save the locals for the |
| 1330 // nested context where they will be used more. We have to put the |
| 1331 // comment into a hole as the parser strips out comments right away. |
| 1332 #disableVariableRenaming; |
| 1333 #supportsDirectProtoAccess; |
| 1358 | 1334 |
| 1359 // The argument to reflectionDataParser is assigned to a temporary 'dart' | 1335 if (#hasIncrementalSupport) { |
| 1360 // so that 'dart.' will appear as the prefix to dart methods in stack | 1336 #helper = #helper || Object.create(null); |
| 1361 // traces and profile entries. | 1337 #helper.patch = function(a) { eval(a)}; |
| 1362 mainOutput..add('var dart =') | 1338 #helper.schemaChange = #schemaChange; |
| 1363 ..addBuffer(jsAst.prettyPrint(descriptorsAst, compiler, | 1339 #helper.addMethod = #addMethod; |
| 1364 monitor: compiler.dumpInfoTask)) | 1340 #helper.extractStubs = |
| 1365 ..add('$N'); | 1341 function(array, name, isStatic, originalDescriptor) { |
| 1366 if (compiler.useContentSecurityPolicy) { | 1342 var descriptor = Object.create(null); |
| 1367 jsAst.Statement precompiledFunctionAst = | 1343 this.addStubs(descriptor, array, name, isStatic, []); |
| 1368 buildCspPrecompiledFunctionFor(mainOutputUnit); | 1344 return descriptor; |
| 1369 mainOutput.addBuffer( | 1345 }; |
| 1370 jsAst.prettyPrint( | 1346 } |
| 1371 precompiledFunctionAst, | |
| 1372 compiler, | |
| 1373 monitor: compiler.dumpInfoTask, | |
| 1374 allowVariableMinification: false)); | |
| 1375 mainOutput.add(N); | |
| 1376 } | |
| 1377 | 1347 |
| 1378 mainOutput.add('$setupProgramName(dart, 0)$N'); | 1348 if (#isProgramSplit) { |
| 1349 /// We collect all the global state, so it can be passed to the |
| 1350 /// initializer of deferred files. |
| 1351 var #globalsHolder = Object.create(null) |
| 1352 } |
| 1379 | 1353 |
| 1380 interceptorEmitter.emitGetInterceptorMethods(mainOutput); | 1354 // [map] returns an object that V8 shouldn't try to optimize with a |
| 1381 interceptorEmitter.emitOneShotInterceptors(mainOutput); | 1355 // hidden class. This prevents a potential performance problem where V8 |
| 1356 // tries to build a hidden class for an object used as a hashMap. |
| 1357 // It requires fewer characters to declare a variable as a parameter than |
| 1358 // with `var`. |
| 1359 function map(x) { |
| 1360 x = Object.create(null); |
| 1361 x.x = 0; |
| 1362 delete x.x; |
| 1363 return x; |
| 1364 } |
| 1382 | 1365 |
| 1383 if (task.outputContainsConstantList) { | 1366 #globalObjectSetup; |
| 1384 emitMakeConstantList(mainOutput); | |
| 1385 } | |
| 1386 | 1367 |
| 1387 // Constants in checked mode call into RTI code to set type information | 1368 function #isolateName() {} |
| 1388 // which may need getInterceptor (and one-shot interceptor) methods, so | |
| 1389 // we have to make sure that [emitGetInterceptorMethods] and | |
| 1390 // [emitOneShotInterceptors] have been called. | |
| 1391 emitCompileTimeConstants( | |
| 1392 mainOutput, mainFragment.constants, isMainFragment: true); | |
| 1393 | 1369 |
| 1394 emitDeferredBoilerPlate(mainOutput, deferredLoadHashes); | 1370 if (#isProgramSplit) { |
| 1371 #globalsHolder.#isolateName = #isolateName; |
| 1372 #globalsHolder.#initName = #initName; |
| 1373 #globalsHolder.#setupProgramName = #setupProgramName; |
| 1374 } |
| 1375 |
| 1376 init(); |
| 1377 |
| 1378 var ${namer.currentIsolate} = #isolatePropertiesName; |
| 1379 |
| 1380 #functionThatReturnsNull; |
| 1381 |
| 1382 #mangledNames; |
| 1383 |
| 1384 #setupProgram; |
| 1385 |
| 1386 // The argument to reflectionDataParser is assigned to a temporary 'dart' |
| 1387 // so that 'dart.' will appear as the prefix to dart methods in stack |
| 1388 // traces and profile entries. |
| 1389 var dart = #descriptors; |
| 1390 |
| 1391 #setupProgramName(dart, 0); |
| 1392 |
| 1393 #cspPrecompiledFunctions; |
| 1394 |
| 1395 #getInterceptorMethods; |
| 1396 #oneShotInterceptors; |
| 1397 |
| 1398 #makeConstantList; |
| 1399 |
| 1400 // Constants in checked mode call into RTI code to set type information |
| 1401 // which may need getInterceptor (and one-shot interceptor) methods, so |
| 1402 // we have to make sure that [emitGetInterceptorMethods] and |
| 1403 // [emitOneShotInterceptors] have been called. |
| 1404 #compileTimeConstants; |
| 1405 |
| 1406 // Static field initializations require the classes and compile-time |
| 1407 // constants to be set up. |
| 1408 #staticNonFinalInitializers; |
| 1409 |
| 1410 #deferredBoilerPlate; |
| 1411 |
| 1412 #typeToInterceptorMap; |
| 1413 |
| 1414 #lazyStaticFields; |
| 1415 |
| 1416 ${namer.currentIsolate} = null; |
| 1417 |
| 1418 #isolateName = $finishIsolateConstructorName(#isolateName); |
| 1419 |
| 1420 ${namer.currentIsolate} = new #isolateName(); |
| 1421 |
| 1422 #metadata; |
| 1423 |
| 1424 #convertToFastObject; |
| 1425 #convertToSlowObject; |
| 1426 |
| 1427 #convertGlobalObjectsToFastObjects; |
| 1428 #debugFastObjects; |
| 1429 |
| 1430 #init; |
| 1431 |
| 1432 #main; |
| 1433 })(); |
| 1434 """, { |
| 1435 "disableVariableRenaming": js.comment("/* ::norenaming:: */"), |
| 1436 "hasIncrementalSupport": compiler.hasIncrementalSupport, |
| 1437 "helper": js('this.#', [namer.incrementalHelperName]), |
| 1438 "schemaChange": buildSchemaChangeFunction(), |
| 1439 "addMethod": buildIncrementalAddMethod(), |
| 1440 "isProgramSplit": isProgramSplit, |
| 1441 "supportsDirectProtoAccess": buildSupportsDirectProtoAccess(), |
| 1442 "globalsHolder": globalsHolder, |
| 1443 "globalObjectSetup": buildGlobalObjectSetup(isProgramSplit), |
| 1444 "isolateName": namer.isolateName, |
| 1445 "isolatePropertiesName": js(isolatePropertiesName), |
| 1446 "initName": initName, |
| 1447 "functionThatReturnsNull": buildFunctionThatReturnsNull(), |
| 1448 "mangledNames": buildMangledNames(), |
| 1449 "setupProgram": buildSetupProgram(program, compiler, backend, namer, this)
, |
| 1450 "setupProgramName": setupProgramName, |
| 1451 "descriptors": descriptorsAst, |
| 1452 "cspPrecompiledFunctions": buildCspPrecompiledFunctionFor(mainOutputUnit), |
| 1453 "getInterceptorMethods": interceptorEmitter.buildGetInterceptorMethods(), |
| 1454 "oneShotInterceptors": interceptorEmitter.buildOneShotInterceptors(), |
| 1455 "makeConstantList": buildMakeConstantList(), |
| 1456 "compileTimeConstants": buildCompileTimeConstants(mainFragment.constants, |
| 1457 isMainFragment: true), |
| 1458 "deferredBoilerPlate": buildDeferredBoilerPlate(deferredLoadHashes), |
| 1459 "staticNonFinalInitializers": buildStaticNonFinalFieldInitializations( |
| 1460 mainOutputUnit), |
| 1461 "typeToInterceptorMap": |
| 1462 interceptorEmitter.buildTypeToInterceptorMap(program), |
| 1463 "lazyStaticFields": buildLazilyInitializedStaticFields(), |
| 1464 "metadata": buildMetadata(program, mainOutputUnit), |
| 1465 "convertToFastObject": buildConvertToFastObjectFunction(), |
| 1466 "convertToSlowObject": buildConvertToSlowObjectFunction(), |
| 1467 "convertGlobalObjectsToFastObjects": |
| 1468 buildConvertGlobalObjectToFastObjects(), |
| 1469 "debugFastObjects": buildDebugFastObjectCode(), |
| 1470 "init": buildInitFunction(), |
| 1471 "main": buildMain(mainFragment.invokeMain) |
| 1472 })); |
| 1473 |
| 1474 mainOutput.addBuffer(jsAst.prettyPrint(new jsAst.Program(statements), |
| 1475 compiler, |
| 1476 monitor: compiler.dumpInfoTask)); |
| 1395 | 1477 |
| 1396 if (compiler.deferredMapUri != null) { | 1478 if (compiler.deferredMapUri != null) { |
| 1397 outputDeferredMap(); | 1479 outputDeferredMap(); |
| 1398 } | 1480 } |
| 1399 | 1481 |
| 1400 // Static field initializations require the classes and compile-time | |
| 1401 // constants to be set up. | |
| 1402 emitStaticNonFinalFieldInitializations(mainOutput, mainOutputUnit); | |
| 1403 interceptorEmitter.emitTypeToInterceptorMap(program, mainOutput); | |
| 1404 if (compiler.enableMinification) { | |
| 1405 mainOutput.add(';'); | |
| 1406 } | |
| 1407 emitLazilyInitializedStaticFields(mainOutput); | |
| 1408 | |
| 1409 mainOutput.add('\n'); | |
| 1410 | |
| 1411 emitMetadata(program, mainOutput, mainOutputUnit); | |
| 1412 | |
| 1413 isolateProperties = isolatePropertiesName; | |
| 1414 // The following code should not use the short-hand for the | |
| 1415 // initialStatics. | |
| 1416 mainOutput.add('${namer.currentIsolate}$_=${_}null$N'); | |
| 1417 | |
| 1418 emitFinishIsolateConstructorInvocation(mainOutput); | |
| 1419 mainOutput.add( | |
| 1420 '${namer.currentIsolate}$_=${_}new ${namer.isolateName}()$N'); | |
| 1421 | |
| 1422 emitConvertToFastObjectFunction(mainOutput); | |
| 1423 emitConvertToSlowObjectFunction(mainOutput); | |
| 1424 | |
| 1425 for (String globalObject in Namer.reservedGlobalObjectNames) { | |
| 1426 mainOutput.add('$globalObject = convertToFastObject($globalObject)$N'); | |
| 1427 } | |
| 1428 if (DEBUG_FAST_OBJECTS) { | |
| 1429 mainOutput.add(r''' | |
| 1430 // The following only works on V8 when run with option | |
| 1431 // "--allow-natives-syntax". We use'new Function' because the | |
| 1432 // miniparser does not understand V8 native syntax. | |
| 1433 if (typeof print === "function") { | |
| 1434 var HasFastProperties = | |
| 1435 new Function("a", "return %HasFastProperties(a)"); | |
| 1436 print("Size of global helper object: " | |
| 1437 + String(Object.getOwnPropertyNames(H).length) | |
| 1438 + ", fast properties " + HasFastProperties(H)); | |
| 1439 print("Size of global platform object: " | |
| 1440 + String(Object.getOwnPropertyNames(P).length) | |
| 1441 + ", fast properties " + HasFastProperties(P)); | |
| 1442 print("Size of global dart:html object: " | |
| 1443 + String(Object.getOwnPropertyNames(W).length) | |
| 1444 + ", fast properties " + HasFastProperties(W)); | |
| 1445 print("Size of isolate properties object: " | |
| 1446 + String(Object.getOwnPropertyNames($).length) | |
| 1447 + ", fast properties " + HasFastProperties($)); | |
| 1448 print("Size of constant object: " | |
| 1449 + String(Object.getOwnPropertyNames(C).length) | |
| 1450 + ", fast properties " + HasFastProperties(C)); | |
| 1451 var names = Object.getOwnPropertyNames($); | |
| 1452 for (var i = 0; i < names.length; i++) { | |
| 1453 print("$." + names[i]); | |
| 1454 } | |
| 1455 } | |
| 1456 '''); | |
| 1457 for (String object in Namer.userGlobalObjects) { | |
| 1458 mainOutput.add(''' | |
| 1459 if (typeof print === "function") { | |
| 1460 print("Size of $object: " | |
| 1461 + String(Object.getOwnPropertyNames($object).length) | |
| 1462 + ", fast properties " + HasFastProperties($object)); | |
| 1463 } | |
| 1464 '''); | |
| 1465 } | |
| 1466 } | |
| 1467 | |
| 1468 emitInitFunction(mainOutput); | |
| 1469 emitMain(mainOutput, mainFragment.invokeMain); | |
| 1470 | |
| 1471 mainOutput.add('})()\n'); | |
| 1472 | |
| 1473 | |
| 1474 if (generateSourceMap) { | 1482 if (generateSourceMap) { |
| 1475 mainOutput.add( | 1483 mainOutput.add( |
| 1476 generateSourceMapTag(compiler.sourceMapUri, compiler.outputUri)); | 1484 generateSourceMapTag(compiler.sourceMapUri, compiler.outputUri)); |
| 1477 } | 1485 } |
| 1478 | 1486 |
| 1479 mainOutput.close(); | 1487 mainOutput.close(); |
| 1480 | 1488 |
| 1481 if (generateSourceMap) { | 1489 if (generateSourceMap) { |
| 1482 outputSourceMap(mainOutput, lineColumnCollector, '', | 1490 outputSourceMap(mainOutput, lineColumnCollector, '', |
| 1483 compiler.sourceMapUri, compiler.outputUri); | 1491 compiler.sourceMapUri, compiler.outputUri); |
| 1484 } | 1492 } |
| 1485 } | 1493 } |
| 1486 | 1494 |
| 1487 /// Used by incremental compilation to patch up the prototype of | 1495 /// Used by incremental compilation to patch up the prototype of |
| 1488 /// [oldConstructor] for use as prototype of [newConstructor]. | 1496 /// [oldConstructor] for use as prototype of [newConstructor]. |
| 1489 jsAst.Fun buildSchemaChangeFunction() { | 1497 jsAst.Fun buildSchemaChangeFunction() { |
| 1498 if (!compiler.hasIncrementalSupport) return null; |
| 1490 return js(''' | 1499 return js(''' |
| 1491 function(newConstructor, oldConstructor, superclass) { | 1500 function(newConstructor, oldConstructor, superclass) { |
| 1492 // Invariant: newConstructor.prototype has no interesting properties besides | 1501 // Invariant: newConstructor.prototype has no interesting properties besides |
| 1493 // generated accessors. These are copied to oldPrototype which will be | 1502 // generated accessors. These are copied to oldPrototype which will be |
| 1494 // updated by other incremental changes. | 1503 // updated by other incremental changes. |
| 1495 if (superclass != null) { | 1504 if (superclass != null) { |
| 1496 this.inheritFrom(newConstructor, superclass); | 1505 this.inheritFrom(newConstructor, superclass); |
| 1497 } | 1506 } |
| 1498 var oldPrototype = oldConstructor.prototype; | 1507 var oldPrototype = oldConstructor.prototype; |
| 1499 var newPrototype = newConstructor.prototype; | 1508 var newPrototype = newConstructor.prototype; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1512 } | 1521 } |
| 1513 | 1522 |
| 1514 /// Used by incremental compilation to patch up an object ([holder]) with a | 1523 /// Used by incremental compilation to patch up an object ([holder]) with a |
| 1515 /// new (or updated) method. [arrayOrFunction] is either the new method, or | 1524 /// new (or updated) method. [arrayOrFunction] is either the new method, or |
| 1516 /// an array containing the method (see | 1525 /// an array containing the method (see |
| 1517 /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the | 1526 /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the |
| 1518 /// new method. [isStatic] tells if method is static (or | 1527 /// new method. [isStatic] tells if method is static (or |
| 1519 /// top-level). [globalFunctionsAccess] is a reference to | 1528 /// top-level). [globalFunctionsAccess] is a reference to |
| 1520 /// [embeddedNames.GLOBAL_FUNCTIONS]. | 1529 /// [embeddedNames.GLOBAL_FUNCTIONS]. |
| 1521 jsAst.Fun buildIncrementalAddMethod() { | 1530 jsAst.Fun buildIncrementalAddMethod() { |
| 1531 if (!compiler.hasIncrementalSupport) return null; |
| 1522 return js(r""" | 1532 return js(r""" |
| 1523 function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { | 1533 function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { |
| 1524 var arrayOrFunction = originalDescriptor[name]; | 1534 var arrayOrFunction = originalDescriptor[name]; |
| 1525 var method; | 1535 var method; |
| 1526 if (arrayOrFunction.constructor === Array) { | 1536 if (arrayOrFunction.constructor === Array) { |
| 1527 var existing = holder[name]; | 1537 var existing = holder[name]; |
| 1528 var array = arrayOrFunction; | 1538 var array = arrayOrFunction; |
| 1529 | 1539 |
| 1530 // Each method may have a number of stubs associated. For example, if an | 1540 // Each method may have a number of stubs associated. For example, if an |
| 1531 // instance method supports multiple arguments, a stub for each matching | 1541 // instance method supports multiple arguments, a stub for each matching |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1632 | 1642 |
| 1633 return emitDeferredCode(program, outputs); | 1643 return emitDeferredCode(program, outputs); |
| 1634 } | 1644 } |
| 1635 | 1645 |
| 1636 int emitProgram(ProgramBuilder programBuilder) { | 1646 int emitProgram(ProgramBuilder programBuilder) { |
| 1637 Program program = programBuilder.buildProgram( | 1647 Program program = programBuilder.buildProgram( |
| 1638 storeFunctionTypesInMetadata: true); | 1648 storeFunctionTypesInMetadata: true); |
| 1639 | 1649 |
| 1640 assembleProgram(program); | 1650 assembleProgram(program); |
| 1641 | 1651 |
| 1642 // Shorten the code by using [namer.currentIsolate] as temporary. | |
| 1643 isolateProperties = namer.currentIsolate; | |
| 1644 | |
| 1645 // Emit deferred units first, so we have their hashes. | 1652 // Emit deferred units first, so we have their hashes. |
| 1646 // Map from OutputUnit to a hash of its content. The hash uniquely | 1653 // Map from OutputUnit to a hash of its content. The hash uniquely |
| 1647 // identifies the code of the output-unit. It does not include | 1654 // identifies the code of the output-unit. It does not include |
| 1648 // boilerplate JS code, like the sourcemap directives or the hash | 1655 // boilerplate JS code, like the sourcemap directives or the hash |
| 1649 // itself. | 1656 // itself. |
| 1650 Map<OutputUnit, String> deferredLoadHashes = | 1657 Map<OutputUnit, String> deferredLoadHashes = |
| 1651 emitDeferredOutputUnits(program); | 1658 emitDeferredOutputUnits(program); |
| 1652 emitMainOutputUnit(program, deferredLoadHashes); | 1659 emitMainOutputUnit(program, deferredLoadHashes); |
| 1653 | 1660 |
| 1654 if (backend.requiresPreamble && | 1661 if (backend.requiresPreamble && |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1687 } | 1694 } |
| 1688 if (owner == null) { | 1695 if (owner == null) { |
| 1689 compiler.internalError(element, 'Owner is null.'); | 1696 compiler.internalError(element, 'Owner is null.'); |
| 1690 } | 1697 } |
| 1691 return elementDescriptors | 1698 return elementDescriptors |
| 1692 .putIfAbsent(fragment, () => new Map<Element, ClassBuilder>()) | 1699 .putIfAbsent(fragment, () => new Map<Element, ClassBuilder>()) |
| 1693 .putIfAbsent(owner, () => new ClassBuilder(owner, namer)); | 1700 .putIfAbsent(owner, () => new ClassBuilder(owner, namer)); |
| 1694 } | 1701 } |
| 1695 | 1702 |
| 1696 /// Emits support-code for deferred loading into [output]. | 1703 /// Emits support-code for deferred loading into [output]. |
| 1697 void emitDeferredBoilerPlate(CodeOutput output, | 1704 jsAst.Statement buildDeferredBoilerPlate( |
| 1698 Map<OutputUnit, String> deferredLoadHashes) { | 1705 Map<OutputUnit, String> deferredLoadHashes) { |
| 1699 jsAst.Statement functions = js.statement(''' | 1706 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 1707 |
| 1708 parts.add(js.statement(''' |
| 1700 { | 1709 { |
| 1701 // Function for checking if a hunk is loaded given its hash. | 1710 // Function for checking if a hunk is loaded given its hash. |
| 1702 #isHunkLoaded = function(hunkHash) { | 1711 #isHunkLoaded = function(hunkHash) { |
| 1703 return !!$deferredInitializers[hunkHash]; | 1712 return !!$deferredInitializers[hunkHash]; |
| 1704 }; | 1713 }; |
| 1705 #deferredInitialized = new Object(null); | 1714 #deferredInitialized = new Object(null); |
| 1706 // Function for checking if a hunk is initialized given its hash. | 1715 // Function for checking if a hunk is initialized given its hash. |
| 1707 #isHunkInitialized = function(hunkHash) { | 1716 #isHunkInitialized = function(hunkHash) { |
| 1708 return #deferredInitialized[hunkHash]; | 1717 return #deferredInitialized[hunkHash]; |
| 1709 }; | 1718 }; |
| 1710 // Function for initializing a loaded hunk, given its hash. | 1719 // Function for initializing a loaded hunk, given its hash. |
| 1711 #initializeLoadedHunk = function(hunkHash) { | 1720 #initializeLoadedHunk = function(hunkHash) { |
| 1712 $deferredInitializers[hunkHash]( | 1721 $deferredInitializers[hunkHash]( |
| 1713 $globalsHolder, ${namer.currentIsolate}); | 1722 $globalsHolder, ${namer.currentIsolate}); |
| 1714 #deferredInitialized[hunkHash] = true; | 1723 #deferredInitialized[hunkHash] = true; |
| 1715 }; | 1724 }; |
| 1716 } | 1725 } |
| 1717 ''', {"isHunkLoaded": generateEmbeddedGlobalAccess( | 1726 ''', {"isHunkLoaded": generateEmbeddedGlobalAccess( |
| 1718 embeddedNames.IS_HUNK_LOADED), | 1727 embeddedNames.IS_HUNK_LOADED), |
| 1719 "isHunkInitialized": generateEmbeddedGlobalAccess( | 1728 "isHunkInitialized": generateEmbeddedGlobalAccess( |
| 1720 embeddedNames.IS_HUNK_INITIALIZED), | 1729 embeddedNames.IS_HUNK_INITIALIZED), |
| 1721 "initializeLoadedHunk": generateEmbeddedGlobalAccess( | 1730 "initializeLoadedHunk": generateEmbeddedGlobalAccess( |
| 1722 embeddedNames.INITIALIZE_LOADED_HUNK), | 1731 embeddedNames.INITIALIZE_LOADED_HUNK), |
| 1723 "deferredInitialized": generateEmbeddedGlobalAccess( | 1732 "deferredInitialized": generateEmbeddedGlobalAccess( |
| 1724 embeddedNames.DEFERRED_INITIALIZED)}); | 1733 embeddedNames.DEFERRED_INITIALIZED)})); |
| 1725 output.addBuffer(jsAst.prettyPrint(functions, | 1734 |
| 1726 compiler, monitor: compiler.dumpInfoTask)); | |
| 1727 // Write a javascript mapping from Deferred import load ids (derrived | 1735 // Write a javascript mapping from Deferred import load ids (derrived |
| 1728 // from the import prefix.) to a list of lists of uris of hunks to load, | 1736 // from the import prefix.) to a list of lists of uris of hunks to load, |
| 1729 // and a corresponding mapping to a list of hashes used by | 1737 // and a corresponding mapping to a list of hashes used by |
| 1730 // INITIALIZE_LOADED_HUNK and IS_HUNK_LOADED. | 1738 // INITIALIZE_LOADED_HUNK and IS_HUNK_LOADED. |
| 1731 Map<String, List<String>> deferredLibraryUris = | 1739 Map<String, List<String>> deferredLibraryUris = |
| 1732 new Map<String, List<String>>(); | 1740 new Map<String, List<String>>(); |
| 1733 Map<String, List<String>> deferredLibraryHashes = | 1741 Map<String, List<String>> deferredLibraryHashes = |
| 1734 new Map<String, List<String>>(); | 1742 new Map<String, List<String>>(); |
| 1735 compiler.deferredLoadTask.hunksToLoad.forEach( | 1743 compiler.deferredLoadTask.hunksToLoad.forEach( |
| 1736 (String loadId, List<OutputUnit>outputUnits) { | 1744 (String loadId, List<OutputUnit>outputUnits) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1750 List<jsAst.Property> properties = new List<jsAst.Property>(); | 1758 List<jsAst.Property> properties = new List<jsAst.Property>(); |
| 1751 mapping.forEach((String key, List<String> values) { | 1759 mapping.forEach((String key, List<String> values) { |
| 1752 properties.add(new jsAst.Property(js.escapedString(key), | 1760 properties.add(new jsAst.Property(js.escapedString(key), |
| 1753 new jsAst.ArrayInitializer( | 1761 new jsAst.ArrayInitializer( |
| 1754 values.map(js.escapedString).toList()))); | 1762 values.map(js.escapedString).toList()))); |
| 1755 }); | 1763 }); |
| 1756 jsAst.Node initializer = | 1764 jsAst.Node initializer = |
| 1757 new jsAst.ObjectInitializer(properties, isOneLiner: true); | 1765 new jsAst.ObjectInitializer(properties, isOneLiner: true); |
| 1758 | 1766 |
| 1759 jsAst.Node globalName = generateEmbeddedGlobalAccess(name); | 1767 jsAst.Node globalName = generateEmbeddedGlobalAccess(name); |
| 1760 output.addBuffer(jsAst.prettyPrint( | 1768 parts.add(js.statement("# = #", [globalName, initializer])); |
| 1761 js("# = #", [globalName, initializer]), | |
| 1762 compiler, monitor: compiler.dumpInfoTask)); | |
| 1763 output.add('$N'); | |
| 1764 } | 1769 } |
| 1765 | 1770 |
| 1766 emitMapping(embeddedNames.DEFERRED_LIBRARY_URIS, deferredLibraryUris); | 1771 emitMapping(embeddedNames.DEFERRED_LIBRARY_URIS, deferredLibraryUris); |
| 1767 emitMapping(embeddedNames.DEFERRED_LIBRARY_HASHES, | 1772 emitMapping(embeddedNames.DEFERRED_LIBRARY_HASHES, |
| 1768 deferredLibraryHashes); | 1773 deferredLibraryHashes); |
| 1774 |
| 1775 return new jsAst.Block(parts); |
| 1769 } | 1776 } |
| 1770 | 1777 |
| 1771 /// Emits code for all output units except the main. | 1778 /// Emits code for all output units except the main. |
| 1772 /// Returns a mapping from outputUnit to a hash of the corresponding hunk that | 1779 /// Returns a mapping from outputUnit to a hash of the corresponding hunk that |
| 1773 /// can be used for calling the initializer. | 1780 /// can be used for calling the initializer. |
| 1774 Map<OutputUnit, String> emitDeferredCode( | 1781 Map<OutputUnit, String> emitDeferredCode( |
| 1775 Program program, | 1782 Program program, |
| 1776 Map<OutputUnit, jsAst.Expression> deferredAsts) { | 1783 Map<OutputUnit, jsAst.Expression> deferredAsts) { |
| 1777 | 1784 |
| 1778 Map<OutputUnit, String> hunkHashes = new Map<OutputUnit, String>(); | 1785 Map<OutputUnit, String> hunkHashes = new Map<OutputUnit, String>(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1793 } | 1800 } |
| 1794 | 1801 |
| 1795 String partPrefix = | 1802 String partPrefix = |
| 1796 backend.deferredPartFileName(outputUnit.name, addExtension: false); | 1803 backend.deferredPartFileName(outputUnit.name, addExtension: false); |
| 1797 CodeOutput output = new StreamCodeOutput( | 1804 CodeOutput output = new StreamCodeOutput( |
| 1798 compiler.outputProvider(partPrefix, 'part.js'), | 1805 compiler.outputProvider(partPrefix, 'part.js'), |
| 1799 outputListeners); | 1806 outputListeners); |
| 1800 | 1807 |
| 1801 outputBuffers[outputUnit] = output; | 1808 outputBuffers[outputUnit] = output; |
| 1802 | 1809 |
| 1803 output | 1810 List<jsAst.Statement> body = <jsAst.Statement>[]; |
| 1804 ..add(buildGeneratedBy()) | 1811 |
| 1805 ..add('${deferredInitializers}.current$_=$_' | 1812 // No renaming in the top-level function to save the locals for the |
| 1806 'function$_(${globalsHolder}) {$N'); | 1813 // nested context where they will be used more. |
| 1814 body.add(js.comment("/* ::norenaming:: ")); |
| 1815 |
| 1807 for (String globalObject in Namer.reservedGlobalObjectNames) { | 1816 for (String globalObject in Namer.reservedGlobalObjectNames) { |
| 1808 output | 1817 body.add(js.statement('var #object = ${globalsHolder}.#object;', |
| 1809 .add('var $globalObject$_=$_' | 1818 {'object': globalObject})); |
| 1810 '${globalsHolder}.$globalObject$N'); | |
| 1811 } | 1819 } |
| 1812 output | 1820 body..add(js.statement('var init = ${globalsHolder}.init;')) |
| 1813 ..add('var init$_=$_${globalsHolder}.init$N') | 1821 ..add(js.statement('var $setupProgramName = ' |
| 1814 ..add('var $setupProgramName$_=$_' | 1822 '$globalsHolder.$setupProgramName;')) |
| 1815 '$globalsHolder.$setupProgramName$N') | 1823 ..add(js.statement('var ${namer.isolateName} = ' |
| 1816 ..add('var ${namer.isolateName}$_=$_' | 1824 '${globalsHolder}.${namer.isolateName};')); |
| 1817 '${globalsHolder}.${namer.isolateName}$N'); | |
| 1818 String typesAccess = | 1825 String typesAccess = |
| 1819 generateEmbeddedGlobalAccessString(embeddedNames.TYPES); | 1826 generateEmbeddedGlobalAccessString(embeddedNames.TYPES); |
| 1820 if (libraryDescriptor != null) { | 1827 if (libraryDescriptor != null) { |
| 1821 // TODO(ahe): This defines a lot of properties on the | 1828 // TODO(ahe): This defines a lot of properties on the |
| 1822 // Isolate.prototype object. We know this will turn it into a | 1829 // Isolate.prototype object. We know this will turn it into a |
| 1823 // slow object in V8, so instead we should do something similar | 1830 // slow object in V8, so instead we should do something similar |
| 1824 // to Isolate.$finishIsolateConstructor. | 1831 // to Isolate.$finishIsolateConstructor. |
| 1825 output | 1832 body..add(js.statement('var ${namer.currentIsolate} = ' |
| 1826 ..add('var ${namer.currentIsolate}$_=$_$isolatePropertiesName$N') | 1833 '$isolatePropertiesName;')) |
| 1827 // The argument to reflectionDataParser is assigned to a temporary | 1834 // The argument to reflectionDataParser is assigned to a temporary |
| 1828 // 'dart' so that 'dart.' will appear as the prefix to dart methods | 1835 // 'dart' so that 'dart.' will appear as the prefix to dart methods |
| 1829 // in stack traces and profile entries. | 1836 // in stack traces and profile entries. |
| 1830 ..add('var dart = $n ') | 1837 ..add(js.statement('var dart = #', libraryDescriptor)); |
| 1831 ..addBuffer(jsAst.prettyPrint(libraryDescriptor, compiler, | |
| 1832 monitor: compiler.dumpInfoTask)) | |
| 1833 ..add('$N'); | |
| 1834 | 1838 |
| 1835 if (compiler.useContentSecurityPolicy) { | 1839 if (compiler.useContentSecurityPolicy) { |
| 1836 jsAst.Statement precompiledFunctionAst = | 1840 body.add(buildCspPrecompiledFunctionFor(outputUnit)); |
| 1837 buildCspPrecompiledFunctionFor(outputUnit); | |
| 1838 | |
| 1839 output.addBuffer( | |
| 1840 jsAst.prettyPrint( | |
| 1841 precompiledFunctionAst, compiler, | |
| 1842 monitor: compiler.dumpInfoTask, | |
| 1843 allowVariableMinification: false)); | |
| 1844 output.add(N); | |
| 1845 } | 1841 } |
| 1846 output.add('$setupProgramName(dart, ${typesAccess}.length)$N'); | 1842 body.add( |
| 1843 js.statement('$setupProgramName(dart, ${typesAccess}.length);')); |
| 1847 } | 1844 } |
| 1848 | 1845 |
| 1849 if (task.metadataCollector.types[outputUnit] != null) { | 1846 if (task.metadataCollector.types[outputUnit] != null) { |
| 1850 emitMetadata(program, output, outputUnit); | 1847 body..add(buildMetadata(program, outputUnit)) |
| 1851 output.add('${typesAccess}.' | 1848 ..add(js.statement('${typesAccess}.push.apply(${typesAccess}, ' |
| 1852 'push.apply(${typesAccess},$_${namer.deferredTypesName})$N'); | 1849 '${namer.deferredTypesName});')); |
| 1853 } | 1850 } |
| 1854 | 1851 |
| 1855 // Set the currentIsolate variable to the current isolate (which is | 1852 // Set the currentIsolate variable to the current isolate (which is |
| 1856 // provided as second argument). | 1853 // provided as second argument). |
| 1857 // We need to do this, because we use the same variable for setting up | 1854 // We need to do this, because we use the same variable for setting up |
| 1858 // the isolate-properties and for storing the current isolate. During | 1855 // the isolate-properties and for storing the current isolate. During |
| 1859 // the setup (the code above this lines) we must set the variable to | 1856 // the setup (the code above this lines) we must set the variable to |
| 1860 // the isolate-properties. | 1857 // the isolate-properties. |
| 1861 // After we have done the setup it must point to the current Isolate. | 1858 // After we have done the setup it must point to the current Isolate. |
| 1862 // Otherwise all methods/functions accessing isolate variables will | 1859 // Otherwise all methods/functions accessing isolate variables will |
| 1863 // access the wrong object. | 1860 // access the wrong object. |
| 1864 output.add("${namer.currentIsolate}$_=${_}arguments[1]$N"); | 1861 body.add(js.statement("${namer.currentIsolate} = arguments[1];")); |
| 1865 | 1862 |
| 1866 emitCompileTimeConstants( | 1863 body.add(buildCompileTimeConstants(fragment.constants, |
| 1867 output, fragment.constants, isMainFragment: false); | 1864 isMainFragment: false)); |
| 1868 emitStaticNonFinalFieldInitializations(output, outputUnit); | 1865 body.add(buildStaticNonFinalFieldInitializations(outputUnit)); |
| 1869 | 1866 |
| 1870 output.add('}$N'); | 1867 List<jsAst.Statement> statements = <jsAst.Statement>[]; |
| 1868 |
| 1869 statements..add(buildGeneratedBy()) |
| 1870 ..add(js.statement('${deferredInitializers}.current = ' |
| 1871 """function (${globalsHolder}) { |
| 1872 # |
| 1873 } |
| 1874 """, [body])); |
| 1875 |
| 1876 output.addBuffer(jsAst.prettyPrint(new jsAst.Program(statements), |
| 1877 compiler, |
| 1878 monitor: compiler.dumpInfoTask)); |
| 1879 |
| 1871 // Make a unique hash of the code (before the sourcemaps are added) | 1880 // Make a unique hash of the code (before the sourcemaps are added) |
| 1872 // This will be used to retrieve the initializing function from the global | 1881 // This will be used to retrieve the initializing function from the global |
| 1873 // variable. | 1882 // variable. |
| 1874 String hash = hasher.getHash(); | 1883 String hash = hasher.getHash(); |
| 1875 | 1884 |
| 1876 output.add('${deferredInitializers}["$hash"]$_=$_' | 1885 output.add('$N${deferredInitializers}["$hash"]$_=$_' |
| 1877 '${deferredInitializers}.current$N'); | 1886 '${deferredInitializers}.current$N'); |
| 1878 | 1887 |
| 1879 if (generateSourceMap) { | 1888 if (generateSourceMap) { |
| 1880 | |
| 1881 Uri mapUri, partUri; | 1889 Uri mapUri, partUri; |
| 1882 Uri sourceMapUri = compiler.sourceMapUri; | 1890 Uri sourceMapUri = compiler.sourceMapUri; |
| 1883 Uri outputUri = compiler.outputUri; | 1891 Uri outputUri = compiler.outputUri; |
| 1884 | 1892 |
| 1885 String partName = "$partPrefix.part"; | 1893 String partName = "$partPrefix.part"; |
| 1886 | 1894 |
| 1887 if (sourceMapUri != null) { | 1895 if (sourceMapUri != null) { |
| 1888 String mapFileName = partName + ".js.map"; | 1896 String mapFileName = partName + ".js.map"; |
| 1889 List<String> mapSegments = sourceMapUri.pathSegments.toList(); | 1897 List<String> mapSegments = sourceMapUri.pathSegments.toList(); |
| 1890 mapSegments[mapSegments.length - 1] = mapFileName; | 1898 mapSegments[mapSegments.length - 1] = mapFileName; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1904 mapUri, partUri); | 1912 mapUri, partUri); |
| 1905 } else { | 1913 } else { |
| 1906 output.close(); | 1914 output.close(); |
| 1907 } | 1915 } |
| 1908 | 1916 |
| 1909 hunkHashes[outputUnit] = hash; | 1917 hunkHashes[outputUnit] = hash; |
| 1910 } | 1918 } |
| 1911 return hunkHashes; | 1919 return hunkHashes; |
| 1912 } | 1920 } |
| 1913 | 1921 |
| 1914 String buildGeneratedBy() { | 1922 jsAst.Comment buildGeneratedBy() { |
| 1915 var suffix = ''; | 1923 String suffix = ''; |
| 1916 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; | 1924 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; |
| 1917 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; | 1925 String msg = '// Generated by dart2js, the Dart to JavaScript ' |
| 1926 'compiler$suffix.'; |
| 1927 return new jsAst.Comment(msg); |
| 1918 } | 1928 } |
| 1919 | 1929 |
| 1920 void outputSourceMap(CodeOutput output, | 1930 void outputSourceMap(CodeOutput output, |
| 1921 LineColumnProvider lineColumnProvider, | 1931 LineColumnProvider lineColumnProvider, |
| 1922 String name, | 1932 String name, |
| 1923 [Uri sourceMapUri, | 1933 [Uri sourceMapUri, |
| 1924 Uri fileUri]) { | 1934 Uri fileUri]) { |
| 1925 if (!generateSourceMap) return; | 1935 if (!generateSourceMap) return; |
| 1926 // Create a source file for the compilation output. This allows using | 1936 // Create a source file for the compilation output. This allows using |
| 1927 // [:getLine:] to transform offsets to line numbers in [SourceMapBuilder]. | 1937 // [:getLine:] to transform offsets to line numbers in [SourceMapBuilder]. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1952 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { | 1962 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { |
| 1953 if (element.isInstanceMember) { | 1963 if (element.isInstanceMember) { |
| 1954 cachedClassBuilders.remove(element.enclosingClass); | 1964 cachedClassBuilders.remove(element.enclosingClass); |
| 1955 | 1965 |
| 1956 nativeEmitter.cachedBuilders.remove(element.enclosingClass); | 1966 nativeEmitter.cachedBuilders.remove(element.enclosingClass); |
| 1957 | 1967 |
| 1958 } | 1968 } |
| 1959 } | 1969 } |
| 1960 } | 1970 } |
| 1961 } | 1971 } |
| OLD | NEW |