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