Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Unified Diff: pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart

Issue 1220333003: dart2js: Rename emitters. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
deleted file mode 100644
index 70114db83d3ef372bcd68030a09c369e5ee999dc..0000000000000000000000000000000000000000
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
+++ /dev/null
@@ -1,2017 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart2js.js_emitter;
-
-
-class OldEmitter implements Emitter {
- final Compiler compiler;
- final CodeEmitterTask task;
-
- final ContainerBuilder containerBuilder = new ContainerBuilder();
- final ClassEmitter classEmitter = new ClassEmitter();
- final NsmEmitter nsmEmitter = new NsmEmitter();
- final InterceptorEmitter interceptorEmitter = new InterceptorEmitter();
-
- // TODO(johnniwinther): Wrap these fields in a caching strategy.
- final Set<ConstantValue> cachedEmittedConstants;
- final List<jsAst.Statement> cachedEmittedConstantsAst = <jsAst.Statement>[];
- final Map<Element, ClassBuilder> cachedClassBuilders;
- final Set<Element> cachedElements;
-
- bool needsClassSupport = false;
- bool needsMixinSupport = false;
- bool needsLazyInitializer = false;
-
- /// True if [ContainerBuilder.addMemberMethodFromInfo] used "structured info",
- /// that is, some function was needed for reflection, had stubs, or had a
- /// super alias.
- bool needsStructuredMemberInfo = false;
-
- final Namer namer;
- ConstantEmitter constantEmitter;
- NativeEmitter get nativeEmitter => task.nativeEmitter;
- TypeTestRegistry get typeTestRegistry => task.typeTestRegistry;
-
- // The full code that is written to each hunk part-file.
- Map<OutputUnit, CodeOutput> outputBuffers = new Map<OutputUnit, CodeOutput>();
-
- String classesCollector;
- Set<ClassElement> get neededClasses => task.neededClasses;
- Map<OutputUnit, List<ClassElement>> get outputClassLists
- => task.outputClassLists;
- Map<OutputUnit, List<ConstantValue>> get outputConstantLists
- => task.outputConstantLists;
- final Map<jsAst.Name, String> mangledFieldNames =
- new HashMap<jsAst.Name, String>();
- final Map<jsAst.Name, String> mangledGlobalFieldNames =
- new HashMap<jsAst.Name, String>();
- final Set<jsAst.Name> recordedMangledNames = new Set<jsAst.Name>();
-
- List<TypedefElement> get typedefsNeededForReflection =>
- task.typedefsNeededForReflection;
-
- JavaScriptBackend get backend => compiler.backend;
- TypeVariableHandler get typeVariableHandler => backend.typeVariableHandler;
-
- String get _ => space;
- String get space => compiler.enableMinification ? "" : " ";
- String get n => compiler.enableMinification ? "" : "\n";
- String get N => compiler.enableMinification ? "\n" : ";\n";
-
- /**
- * List of expressions and statements that will be included in the
- * precompiled function.
- *
- * To save space, dart2js normally generates constructors and accessors
- * dynamically. This doesn't work in CSP mode, so dart2js emits them directly
- * when in CSP mode.
- */
- Map<OutputUnit, List<jsAst.Node>> _cspPrecompiledFunctions =
- new Map<OutputUnit, List<jsAst.Node>>();
-
- Map<OutputUnit, List<jsAst.Expression>> _cspPrecompiledConstructorNames =
- new Map<OutputUnit, List<jsAst.Expression>>();
-
- /**
- * Accumulate properties for classes and libraries, describing their
- * static/top-level members.
- * Later, these members are emitted when the class or library is emitted.
- *
- * See [getElementDescriptor].
- */
- // TODO(ahe): Generate statics with their class, and store only libraries in
- // this map.
- final Map<Fragment, Map<Element, ClassBuilder>> elementDescriptors =
- new Map<Fragment, Map<Element, ClassBuilder>>();
-
- final bool generateSourceMap;
-
- OldEmitter(Compiler compiler, Namer namer, this.generateSourceMap, this.task)
- : this.compiler = compiler,
- this.namer = namer,
- cachedEmittedConstants = compiler.cacheStrategy.newSet(),
- cachedClassBuilders = compiler.cacheStrategy.newMap(),
- cachedElements = compiler.cacheStrategy.newSet() {
- constantEmitter = new ConstantEmitter(
- compiler, namer, this.constantReference, constantListGenerator);
- containerBuilder.emitter = this;
- classEmitter.emitter = this;
- nsmEmitter.emitter = this;
- interceptorEmitter.emitter = this;
- }
-
- List<jsAst.Node> cspPrecompiledFunctionFor(OutputUnit outputUnit) {
- return _cspPrecompiledFunctions.putIfAbsent(
- outputUnit,
- () => new List<jsAst.Node>());
- }
-
- List<jsAst.Expression> cspPrecompiledConstructorNamesFor(
- OutputUnit outputUnit) {
- return _cspPrecompiledConstructorNames.putIfAbsent(
- outputUnit,
- () => new List<jsAst.Expression>());
- }
-
- /// Erases the precompiled information for csp mode for all output units.
- /// Used by the incremental compiler.
- void clearCspPrecompiledNodes() {
- _cspPrecompiledFunctions.clear();
- _cspPrecompiledConstructorNames.clear();
- }
-
- @override
- bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
- if (constant.isFunction) return true; // Already emitted.
- if (constant.isPrimitive) return true; // Inlined.
- if (constant.isDummy) return true; // Inlined.
- // The name is null when the constant is already a JS constant.
- // TODO(floitsch): every constant should be registered, so that we can
- // share the ones that take up too much space (like some strings).
- if (namer.constantName(constant) == null) return true;
- return false;
- }
-
- @override
- int compareConstants(ConstantValue a, ConstantValue b) {
- // Inlined constants don't affect the order and sometimes don't even have
- // names.
- int cmp1 = isConstantInlinedOrAlreadyEmitted(a) ? 0 : 1;
- int cmp2 = isConstantInlinedOrAlreadyEmitted(b) ? 0 : 1;
- if (cmp1 + cmp2 < 2) return cmp1 - cmp2;
-
- // Emit constant interceptors first. Constant interceptors for primitives
- // might be used by code that builds other constants. See Issue 18173.
- if (a.isInterceptor != b.isInterceptor) {
- return a.isInterceptor ? -1 : 1;
- }
-
- // Sorting by the long name clusters constants with the same constructor
- // which compresses a tiny bit better.
- int r = namer.constantLongName(a).compareTo(namer.constantLongName(b));
- if (r != 0) return r;
- // Resolve collisions in the long name by using the constant name (i.e. JS
- // name) which is unique.
- // TODO(herhut): Find a better way to resolve collisions.
- return namer.constantName(a).hashCode.compareTo(
- namer.constantName(b).hashCode);
- }
-
- @override
- jsAst.Expression constantReference(ConstantValue value) {
- if (value.isFunction) {
- FunctionConstantValue functionConstant = value;
- return isolateStaticClosureAccess(functionConstant.element);
- }
-
- // We are only interested in the "isInlined" part, but it does not hurt to
- // test for the other predicates.
- if (isConstantInlinedOrAlreadyEmitted(value)) {
- return constantEmitter.generate(value);
- }
- return js('#.#', [namer.globalObjectForConstant(value),
- namer.constantName(value)]);
- }
-
- jsAst.Expression constantInitializerExpression(ConstantValue value) {
- return constantEmitter.generate(value);
- }
-
- String get name => 'CodeEmitter';
-
- String get finishIsolateConstructorName
- => '${namer.isolateName}.\$finishIsolateConstructor';
- String get isolatePropertiesName
- => '${namer.isolateName}.${namer.isolatePropertiesName}';
- String get lazyInitializerProperty
- => r'$lazy';
- String get lazyInitializerName
- => '${namer.isolateName}.${lazyInitializerProperty}';
- String get initName => 'init';
-
- jsAst.Name get makeConstListProperty
- => namer.internalGlobal('makeConstantList');
-
- /// The name of the property that contains all field names.
- ///
- /// This property is added to constructors when isolate support is enabled.
- static const String FIELD_NAMES_PROPERTY_NAME = r"$__fields__";
-
- /// For deferred loading we communicate the initializers via this global var.
- final String deferredInitializers = r"$dart_deferred_initializers$";
-
- /// Contains the global state that is needed to initialize and load a
- /// deferred library.
- String get globalsHolder => r"$globals$";
-
- @override
- jsAst.Expression generateEmbeddedGlobalAccess(String global) {
- return js(generateEmbeddedGlobalAccessString(global));
- }
-
- String generateEmbeddedGlobalAccessString(String global) {
- // TODO(floitsch): don't use 'init' as global embedder storage.
- return '$initName.$global';
- }
-
- jsAst.PropertyAccess globalPropertyAccess(Element element) {
- jsAst.Name name = namer.globalPropertyName(element);
- jsAst.PropertyAccess pa = new jsAst.PropertyAccess(
- new jsAst.VariableUse(namer.globalObjectFor(element)),
- name);
- return pa;
- }
-
- @override
- jsAst.Expression isolateLazyInitializerAccess(FieldElement element) {
- return jsAst.js('#.#', [namer.globalObjectFor(element),
- namer.lazyInitializerName(element)]);
- }
-
- @override
- jsAst.Expression isolateStaticClosureAccess(FunctionElement element) {
- return jsAst.js('#.#()',
- [namer.globalObjectFor(element), namer.staticClosureName(element)]);
- }
-
- @override
- jsAst.PropertyAccess staticFieldAccess(FieldElement element) {
- return globalPropertyAccess(element);
- }
-
- @override
- jsAst.PropertyAccess staticFunctionAccess(FunctionElement element) {
- return globalPropertyAccess(element);
- }
-
- @override
- jsAst.PropertyAccess constructorAccess(ClassElement element) {
- return globalPropertyAccess(element);
- }
-
- @override
- jsAst.PropertyAccess prototypeAccess(ClassElement element,
- bool hasBeenInstantiated) {
- return jsAst.js('#.prototype', constructorAccess(element));
- }
-
- @override
- jsAst.PropertyAccess interceptorClassAccess(ClassElement element) {
- return globalPropertyAccess(element);
- }
-
- @override
- jsAst.PropertyAccess typeAccess(Element element) {
- return globalPropertyAccess(element);
- }
-
- @override
- jsAst.Template templateForBuiltin(JsBuiltin builtin) {
- switch (builtin) {
- case JsBuiltin.dartObjectConstructor:
- return jsAst.js.expressionTemplateYielding(
- typeAccess(compiler.objectClass));
-
- case JsBuiltin.isCheckPropertyToJsConstructorName:
- int isPrefixLength = namer.operatorIsPrefix.length;
- return jsAst.js.expressionTemplateFor('#.substring($isPrefixLength)');
-
- case JsBuiltin.isFunctionType:
- return backend.rti.representationGenerator.templateForIsFunctionType;
-
- case JsBuiltin.rawRtiToJsConstructorName:
- return jsAst.js.expressionTemplateFor("#.$typeNameProperty");
-
- case JsBuiltin.rawRuntimeType:
- return jsAst.js.expressionTemplateFor("#.constructor");
-
- case JsBuiltin.createFunctionTypeRti:
- return backend.rti.representationGenerator
- .templateForCreateFunctionType;
-
- case JsBuiltin.isSubtype:
- // TODO(floitsch): move this closer to where is-check properties are
- // built.
- String isPrefix = namer.operatorIsPrefix;
- return jsAst.js.expressionTemplateFor(
- "('$isPrefix' + #) in #.prototype");
-
- case JsBuiltin.isGivenTypeRti:
- return jsAst.js.expressionTemplateFor('#.$typeNameProperty === #');
-
- case JsBuiltin.getMetadata:
- String metadataAccess =
- generateEmbeddedGlobalAccessString(embeddedNames.METADATA);
- return jsAst.js.expressionTemplateFor("$metadataAccess[#]");
-
- case JsBuiltin.getType:
- String typesAccess =
- generateEmbeddedGlobalAccessString(embeddedNames.TYPES);
- return jsAst.js.expressionTemplateFor("$typesAccess[#]");
-
- default:
- compiler.internalError(NO_LOCATION_SPANNABLE,
- "Unhandled Builtin: $builtin");
- return null;
- }
- }
-
- List<jsAst.Statement> buildTrivialNsmHandlers(){
- return nsmEmitter.buildTrivialNsmHandlers();
- }
-
- jsAst.Statement buildNativeInfoHandler(
- jsAst.Expression infoAccess,
- jsAst.Expression constructorAccess,
- jsAst.Expression subclassReadGenerator(jsAst.Expression subclass),
- jsAst.Expression interceptorsByTagAccess,
- jsAst.Expression leafTagsAccess) {
- return NativeGenerator.buildNativeInfoHandler(infoAccess, constructorAccess,
- subclassReadGenerator,
- interceptorsByTagAccess,
- leafTagsAccess);
- }
-
- jsAst.ObjectInitializer generateInterceptedNamesSet() {
- return interceptorEmitter.generateInterceptedNamesSet();
- }
-
- /// In minified mode we want to keep the name for the most common core types.
- bool _isNativeTypeNeedingReflectionName(Element element) {
- if (!element.isClass) return false;
- return (element == compiler.intClass ||
- element == compiler.doubleClass ||
- element == compiler.numClass ||
- element == compiler.stringClass ||
- element == compiler.boolClass ||
- element == compiler.nullClass ||
- element == compiler.listClass);
- }
-
- /// Returns the "reflection name" of an [Element] or [Selector].
- /// The reflection name of a getter 'foo' is 'foo'.
- /// The reflection name of a setter 'foo' is 'foo='.
- /// The reflection name of a method 'foo' is 'foo:N:M:O', where N is the
- /// number of required arguments, M is the number of optional arguments, and
- /// O is the named arguments.
- /// The reflection name of a constructor is similar to a regular method but
- /// starts with 'new '.
- /// The reflection name of class 'C' is 'C'.
- /// An anonymous mixin application has no reflection name.
- /// This is used by js_mirrors.dart.
- String getReflectionName(elementOrSelector, jsAst.Name mangledName) {
- String name = elementOrSelector.name;
- if (backend.shouldRetainName(name) ||
- elementOrSelector is Element &&
- // Make sure to retain names of unnamed constructors, and
- // for common native types.
- ((name == '' &&
- backend.isAccessibleByReflection(elementOrSelector)) ||
- _isNativeTypeNeedingReflectionName(elementOrSelector))) {
-
- // TODO(ahe): Enable the next line when I can tell the difference between
- // an instance method and a global. They may have the same mangled name.
- // if (recordedMangledNames.contains(mangledName)) return null;
- recordedMangledNames.add(mangledName);
- return getReflectionNameInternal(elementOrSelector, mangledName);
- }
- return null;
- }
-
- String getReflectionNameInternal(elementOrSelector,
- jsAst.Name mangledName) {
- String name = namer.privateName(elementOrSelector.memberName);
- if (elementOrSelector.isGetter) return name;
- if (elementOrSelector.isSetter) {
- if (mangledName is! SetterName) return '$name=';
- SetterName setterName = mangledName;
- jsAst.Name base = setterName.base;
- jsAst.Name getter = namer.deriveGetterName(base);
- mangledFieldNames.putIfAbsent(getter, () => name);
- assert(mangledFieldNames[getter] == name);
- recordedMangledNames.add(getter);
- // TODO(karlklose,ahe): we do not actually need to store information
- // about the name of this setter in the output, but it is needed for
- // marking the function as invokable by reflection.
- return '$name=';
- }
- if (elementOrSelector is Element && elementOrSelector.isClosure) {
- // Closures are synthesized and their name might conflict with existing
- // globals. Assign an illegal name, and make sure they don't clash
- // with each other.
- return " $name";
- }
- if (elementOrSelector is Selector
- || elementOrSelector.isFunction
- || elementOrSelector.isConstructor) {
- int positionalParameterCount;
- String namedArguments = '';
- bool isConstructor = false;
- if (elementOrSelector is Selector) {
- CallStructure callStructure = elementOrSelector.callStructure;
- positionalParameterCount = callStructure.positionalArgumentCount;
- namedArguments = namedParametersAsReflectionNames(callStructure);
- } else {
- FunctionElement function = elementOrSelector;
- if (function.isConstructor) {
- isConstructor = true;
- name = Elements.reconstructConstructorName(function);
- }
- FunctionSignature signature = function.functionSignature;
- positionalParameterCount = signature.requiredParameterCount;
- if (signature.optionalParametersAreNamed) {
- var names = [];
- for (Element e in signature.optionalParameters) {
- names.add(e.name);
- }
- CallStructure callStructure =
- new CallStructure(positionalParameterCount, names);
- namedArguments = namedParametersAsReflectionNames(callStructure);
- } else {
- // Named parameters are handled differently by mirrors. For unnamed
- // parameters, they are actually required if invoked
- // reflectively. Also, if you have a method c(x) and c([x]) they both
- // get the same mangled name, so they must have the same reflection
- // name.
- positionalParameterCount += signature.optionalParameterCount;
- }
- }
- String suffix = '$name:$positionalParameterCount$namedArguments';
- return (isConstructor) ? 'new $suffix' : suffix;
- }
- Element element = elementOrSelector;
- if (element.isGenerativeConstructorBody) {
- return null;
- } else if (element.isClass) {
- ClassElement cls = element;
- if (cls.isUnnamedMixinApplication) return null;
- return cls.name;
- } else if (element.isTypedef) {
- return element.name;
- }
- throw compiler.internalError(element,
- 'Do not know how to reflect on this $element.');
- }
-
- String namedParametersAsReflectionNames(CallStructure structure) {
- if (structure.isUnnamed) return '';
- String names = structure.getOrderedNamedArguments().join(':');
- return ':$names';
- }
-
- jsAst.Statement buildCspPrecompiledFunctionFor(
- OutputUnit outputUnit) {
- if (compiler.useContentSecurityPolicy) {
- // TODO(ahe): Compute a hash code.
- // TODO(sigurdm): Avoid this precompiled function. Generated
- // constructor-functions and getter/setter functions can be stored in the
- // library-description table. Setting properties on these can be moved to
- // finishClasses.
- return js.statement(r"""
- #precompiled = function ($collectedClasses$) {
- #norename;
- var $desc;
- #functions;
- return #result;
- };""",
- {'norename': new jsAst.Comment("// ::norenaming:: "),
- 'precompiled': generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED),
- 'functions': cspPrecompiledFunctionFor(outputUnit),
- 'result': new jsAst.ArrayInitializer(
- cspPrecompiledConstructorNamesFor(outputUnit))});
- } else {
- return js.comment("Constructors are generated at runtime.");
- }
- }
-
- void assembleClass(Class cls, ClassBuilder enclosingBuilder,
- Fragment fragment) {
- ClassElement classElement = cls.element;
- compiler.withCurrentElement(classElement, () {
- if (compiler.hasIncrementalSupport) {
- ClassBuilder cachedBuilder =
- cachedClassBuilders.putIfAbsent(classElement, () {
- ClassBuilder builder =
- new ClassBuilder.forClass(classElement, namer);
- classEmitter.emitClass(cls, builder, fragment);
- return builder;
- });
- invariant(classElement, cachedBuilder.fields.isEmpty);
- invariant(classElement, cachedBuilder.superName == null);
- invariant(classElement, cachedBuilder.functionType == null);
- invariant(classElement, cachedBuilder.fieldMetadata == null);
- enclosingBuilder.properties.addAll(cachedBuilder.properties);
- } else {
- classEmitter.emitClass(cls, enclosingBuilder, fragment);
- }
- });
- }
-
- void assembleStaticFunctions(Iterable<Method> staticFunctions,
- Fragment fragment) {
- if (staticFunctions == null) return;
-
- for (Method method in staticFunctions) {
- Element element = method.element;
- // We need to filter out null-elements for the interceptors.
- // TODO(floitsch): use the precomputed interceptors here.
- if (element == null) continue;
- ClassBuilder builder = new ClassBuilder.forStatics(element, namer);
- containerBuilder.addMemberMethod(method, builder);
- getElementDescriptor(element, fragment).properties
- .addAll(builder.properties);
- }
- }
-
- jsAst.Statement buildStaticNonFinalFieldInitializations(
- OutputUnit outputUnit) {
- jsAst.Statement buildInitialization(Element element,
- jsAst.Expression initialValue) {
- // Note: `namer.currentIsolate` refers to the isolate properties here.
- return js.statement('${namer.currentIsolate}.# = #',
- [namer.globalPropertyName(element), initialValue]);
- }
-
- bool inMainUnit = (outputUnit == compiler.deferredLoadTask.mainOutputUnit);
- JavaScriptConstantCompiler handler = backend.constants;
- List<jsAst.Statement> parts = <jsAst.Statement>[];
-
- Iterable<Element> fields = task.outputStaticNonFinalFieldLists[outputUnit];
- // If the outputUnit does not contain any static non-final fields, then
- // [fields] is `null`.
- if (fields != null) {
- for (Element element in fields) {
- compiler.withCurrentElement(element, () {
- ConstantValue constant = handler.getInitialValueFor(element);
- parts.add(buildInitialization(element, constantReference(constant)));
- });
- }
- }
-
- if (inMainUnit && task.outputStaticNonFinalFieldLists.length > 1) {
- // In the main output-unit we output a stub initializer for deferred
- // variables, so that `isolateProperties` stays a fast object.
- task.outputStaticNonFinalFieldLists.forEach(
- (OutputUnit fieldsOutputUnit, Iterable<VariableElement> fields) {
- if (fieldsOutputUnit == outputUnit) return; // Skip the main unit.
- for (Element element in fields) {
- compiler.withCurrentElement(element, () {
- parts.add(buildInitialization(element, jsAst.number(0)));
- });
- }
- });
- }
-
- return new jsAst.Block(parts);
- }
-
- jsAst.Statement buildLazilyInitializedStaticFields() {
- JavaScriptConstantCompiler handler = backend.constants;
- List<VariableElement> lazyFields =
- handler.getLazilyInitializedFieldsForEmission();
- if (lazyFields.isNotEmpty) {
- needsLazyInitializer = true;
- List<jsAst.Expression> laziesInfo = buildLaziesInfo(lazyFields);
- return js.statement('''
- (function(lazies) {
- for (var i = 0; i < lazies.length; ) {
- var fieldName = lazies[i++];
- var getterName = lazies[i++];
- if (#notMinified) {
- var staticName = lazies[i++];
- }
- var lazyValue = lazies[i++];
-
- // We build the lazy-check here:
- // lazyInitializer(fieldName, getterName, lazyValue, staticName);
- // 'staticName' is used for error reporting in non-minified mode.
- // 'lazyValue' must be a closure that constructs the initial value.
- if (#notMinified) {
- #lazy(fieldName, getterName, lazyValue, staticName);
- } else {
- #lazy(fieldName, getterName, lazyValue);
- }
- }
- })(#laziesInfo)
- ''', {'notMinified': !compiler.enableMinification,
- 'laziesInfo': new jsAst.ArrayInitializer(laziesInfo),
- 'lazy': js(lazyInitializerName)});
- } else {
- return js.comment("No lazy statics.");
- }
- }
-
- List<jsAst.Expression> buildLaziesInfo(List<VariableElement> lazies) {
- List<jsAst.Expression> laziesInfo = <jsAst.Expression>[];
- for (VariableElement element in Elements.sortedByPosition(lazies)) {
- jsAst.Expression code = backend.generatedCode[element];
- // The code is null if we ended up not needing the lazily
- // initialized field after all because of constant folding
- // before code generation.
- if (code == null) continue;
- laziesInfo.add(js.quoteName(namer.globalPropertyName(element)));
- laziesInfo.add(js.quoteName(namer.lazyInitializerName(element)));
- if (!compiler.enableMinification) {
- laziesInfo.add(js.string(element.name));
- }
- laziesInfo.add(code);
- }
- return laziesInfo;
- }
-
- // TODO(sra): Remove this unused function.
- jsAst.Expression buildLazilyInitializedStaticField(
- VariableElement element, {String isolateProperties}) {
- jsAst.Expression code = backend.generatedCode[element];
- // The code is null if we ended up not needing the lazily
- // initialized field after all because of constant folding
- // before code generation.
- if (code == null) return null;
- // The code only computes the initial value. We build the lazy-check
- // here:
- // lazyInitializer(fieldName, getterName, initial, name, prototype);
- // The name is used for error reporting. The 'initial' must be a
- // closure that constructs the initial value.
- if (isolateProperties != null) {
- // This is currently only used in incremental compilation to patch
- // in new lazy values.
- return js('#(#,#,#,#,#)',
- [js(lazyInitializerName),
- js.quoteName(namer.globalPropertyName(element)),
- js.quoteName(namer.lazyInitializerName(element)),
- code,
- js.string(element.name),
- isolateProperties]);
- }
-
- if (compiler.enableMinification) {
- return js('#(#,#,#)',
- [js(lazyInitializerName),
- js.quoteName(namer.globalPropertyName(element)),
- js.quoteName(namer.lazyInitializerName(element)),
- code]);
- } else {
- return js('#(#,#,#,#)',
- [js(lazyInitializerName),
- js.quoteName(namer.globalPropertyName(element)),
- js.quoteName(namer.lazyInitializerName(element)),
- code,
- js.string(element.name)]);
- }
- }
-
- jsAst.Statement buildMetadata(Program program, OutputUnit outputUnit) {
- List<jsAst.Statement> parts = <jsAst.Statement>[];
-
- jsAst.Expression types = program.metadataTypesForOutputUnit(outputUnit);
-
- if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) {
- jsAst.Expression metadataAccess =
- generateEmbeddedGlobalAccess(embeddedNames.METADATA);
- jsAst.Expression typesAccess =
- generateEmbeddedGlobalAccess(embeddedNames.TYPES);
-
- parts..add(js.statement('# = #;', [metadataAccess, program.metadata]))
- ..add(js.statement('# = #;', [typesAccess, types]));
- } else if (types != null) {
- parts.add(js.statement('var ${namer.deferredTypesName} = #;',
- types));
- }
- return new jsAst.Block(parts);
- }
-
- jsAst.Statement buildCompileTimeConstants(List<Constant> constants,
- {bool isMainFragment}) {
- assert(isMainFragment != null);
-
- if (constants.isEmpty) return js.comment("No constants in program.");
- List<jsAst.Statement> parts = <jsAst.Statement>[];
- if (compiler.hasIncrementalSupport && isMainFragment) {
- parts = cachedEmittedConstantsAst;
- }
- for (Constant constant in constants) {
- ConstantValue constantValue = constant.value;
- if (compiler.hasIncrementalSupport && isMainFragment) {
- if (cachedEmittedConstants.contains(constantValue)) continue;
- cachedEmittedConstants.add(constantValue);
- }
- parts.add(buildConstantInitializer(constantValue));
- }
-
- return new jsAst.Block(parts);
- }
-
- jsAst.Statement buildConstantInitializer(ConstantValue constant) {
- jsAst.Name name = namer.constantName(constant);
- return js.statement('#.# = #',
- [namer.globalObjectForConstant(constant), name,
- constantInitializerExpression(constant)]);
- }
-
- jsAst.Expression constantListGenerator(jsAst.Expression array) {
- // TODO(floitsch): there is no harm in caching the template.
- return js('${namer.isolateName}.#(#)', [makeConstListProperty, array]);
- }
-
- jsAst.Statement buildMakeConstantList() {
- if (task.outputContainsConstantList) {
- return js.statement(r'''
- // Functions are stored in the hidden class and not as properties in
- // the object. We never actually look at the value, but only want
- // to know if the property exists.
- #.# = function (list) {
- list.immutable$list = Array;
- list.fixed$length = Array;
- return list;
- }''',
- [namer.isolateName, makeConstListProperty]);
- } else {
- return js.comment("Output contains no constant list.");
- }
- }
-
- jsAst.Statement buildFunctionThatReturnsNull() {
- return js.statement('#.# = function() {}',
- [namer.isolateName,
- backend.rti.getFunctionThatReturnsNullName]);
- }
-
- jsAst.Expression generateFunctionThatReturnsNull() {
- return js("#.#", [namer.isolateName,
- backend.rti.getFunctionThatReturnsNullName]);
- }
-
- buildMain(jsAst.Statement invokeMain) {
- if (compiler.isMockCompilation) return js.comment("Mock compilation");
-
- List<jsAst.Statement> parts = <jsAst.Statement>[];
-
- if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) {
- parts.add(
- NativeGenerator.generateIsolateAffinityTagInitialization(
- backend,
- generateEmbeddedGlobalAccess,
- js("convertToFastObject", [])));
- }
-
- parts..add(js.comment('BEGIN invoke [main].'))
- ..add(invokeMain)
- ..add(js.comment('END invoke [main].'));
-
- return new jsAst.Block(parts);
- }
-
- jsAst.Statement buildInitFunction() {
- jsAst.Expression allClassesAccess =
- generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
- jsAst.Expression getTypeFromNameAccess =
- generateEmbeddedGlobalAccess(embeddedNames.GET_TYPE_FROM_NAME);
- jsAst.Expression interceptorsByTagAccess =
- generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG);
- jsAst.Expression leafTagsAccess =
- generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS);
- jsAst.Expression finishedClassesAccess =
- generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES);
- jsAst.Expression cyclicThrow =
- staticFunctionAccess(backend.getCyclicThrowHelper());
- jsAst.Expression laziesAccess =
- generateEmbeddedGlobalAccess(embeddedNames.LAZIES);
-
- return js.statement('''
- function init() {
- $isolatePropertiesName = Object.create(null);
- #allClasses = map();
- #getTypeFromName = function(name) {return #allClasses[name];};
- #interceptorsByTag = map();
- #leafTags = map();
- #finishedClasses = map();
-
- if (#needsLazyInitializer) {
- // [staticName] is only provided in non-minified mode. If missing, we
- // fall back to [fieldName]. Likewise, [prototype] is optional and
- // defaults to the isolateProperties object.
- $lazyInitializerName = function (fieldName, getterName, lazyValue,
- staticName, prototype) {
- if (!#lazies) #lazies = Object.create(null);
- #lazies[fieldName] = getterName;
-
- // 'prototype' will be undefined except if we are doing an update
- // during incremental compilation. In this case we put the lazy
- // field directly on the isolate instead of the isolateProperties.
- prototype = prototype || $isolatePropertiesName;
- var sentinelUndefined = {};
- var sentinelInProgress = {};
- prototype[fieldName] = sentinelUndefined;
-
- prototype[getterName] = function () {
- var result = this[fieldName];
- try {
- if (result === sentinelUndefined) {
- this[fieldName] = sentinelInProgress;
-
- try {
- result = this[fieldName] = lazyValue();
- } finally {
- // Use try-finally, not try-catch/throw as it destroys the
- // stack trace.
- if (result === sentinelUndefined)
- this[fieldName] = null;
- }
- } else {
- if (result === sentinelInProgress)
- // In minified mode, static name is not provided, so fall
- // back to the minified fieldName.
- #cyclicThrow(staticName || fieldName);
- }
-
- return result;
- } finally {
- this[getterName] = function() { return this[fieldName]; };
- }
- }
- }
- }
-
- // We replace the old Isolate function with a new one that initializes
- // all its fields with the initial (and often final) value of all
- // globals.
- //
- // We also copy over old values like the prototype, and the
- // isolateProperties themselves.
- $finishIsolateConstructorName = function (oldIsolate) {
- var isolateProperties = oldIsolate.#isolatePropertiesName;
- function Isolate() {
-
- var staticNames = Object.keys(isolateProperties);
- for (var i = 0; i < staticNames.length; i++) {
- var staticName = staticNames[i];
- this[staticName] = isolateProperties[staticName];
- }
-
- // Reset lazy initializers to null.
- // When forcing the object to fast mode (below) v8 will consider
- // functions as part the object's map. Since we will change them
- // (after the first call to the getter), we would have a map
- // transition.
- var lazies = init.lazies;
- var lazyInitializers = lazies ? Object.keys(lazies) : [];
- for (var i = 0; i < lazyInitializers.length; i++) {
- this[lazies[lazyInitializers[i]]] = null;
- }
-
- // Use the newly created object as prototype. In Chrome,
- // this creates a hidden class for the object and makes
- // sure it is fast to access.
- function ForceEfficientMap() {}
- ForceEfficientMap.prototype = this;
- new ForceEfficientMap();
-
- // Now, after being a fast map we can set the lazies again.
- for (var i = 0; i < lazyInitializers.length; i++) {
- var lazyInitName = lazies[lazyInitializers[i]];
- this[lazyInitName] = isolateProperties[lazyInitName];
- }
- }
- Isolate.prototype = oldIsolate.prototype;
- Isolate.prototype.constructor = Isolate;
- Isolate.#isolatePropertiesName = isolateProperties;
- if (#outputContainsConstantList) {
- Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty;
- }
- Isolate.#functionThatReturnsNullProperty =
- oldIsolate.#functionThatReturnsNullProperty;
- if (#hasIncrementalSupport) {
- Isolate.#lazyInitializerProperty =
- oldIsolate.#lazyInitializerProperty;
- }
- return Isolate;
- }
-
- }''', {'allClasses': allClassesAccess,
- 'getTypeFromName': getTypeFromNameAccess,
- 'interceptorsByTag': interceptorsByTagAccess,
- 'leafTags': leafTagsAccess,
- 'finishedClasses': finishedClassesAccess,
- 'needsLazyInitializer': needsLazyInitializer,
- 'lazies': laziesAccess, 'cyclicThrow': cyclicThrow,
- 'isolatePropertiesName': namer.isolatePropertiesName,
- 'outputContainsConstantList': task.outputContainsConstantList,
- 'makeConstListProperty': makeConstListProperty,
- 'functionThatReturnsNullProperty':
- backend.rti.getFunctionThatReturnsNullName,
- 'hasIncrementalSupport': compiler.hasIncrementalSupport,
- 'lazyInitializerProperty': lazyInitializerProperty,});
- }
-
- jsAst.Statement buildConvertToFastObjectFunction() {
- List<jsAst.Statement> debugCode = <jsAst.Statement>[];
- if (DEBUG_FAST_OBJECTS) {
- debugCode.add(js.statement(r'''
- // The following only works on V8 when run with option
- // "--allow-natives-syntax". We use'new Function' because the
- // miniparser does not understand V8 native syntax.
- if (typeof print === "function") {
- var HasFastProperties =
- new Function("a", "return %HasFastProperties(a)");
- print("Size of global object: "
- + String(Object.getOwnPropertyNames(properties).length)
- + ", fast properties " + HasFastProperties(properties));
- }'''));
- }
-
- return js.statement(r'''
- function convertToFastObject(properties) {
- // Create an instance that uses 'properties' as prototype. This should
- // make 'properties' a fast object.
- function MyClass() {};
- MyClass.prototype = properties;
- new MyClass();
- #;
- return properties;
- }''', [debugCode]);
- }
-
- jsAst.Statement buildConvertToSlowObjectFunction() {
- return js.statement(r'''
- function convertToSlowObject(properties) {
- // Add and remove a property to make the object transition into hashmap
- // mode.
- properties.__MAGIC_SLOW_PROPERTY = 1;
- delete properties.__MAGIC_SLOW_PROPERTY;
- return properties;
- }''');
- }
-
- jsAst.Statement buildSupportsDirectProtoAccess() {
- jsAst.Statement supportsDirectProtoAccess;
-
- if (compiler.hasIncrementalSupport) {
- supportsDirectProtoAccess = js.statement(r'''
- var supportsDirectProtoAccess = false;
- ''');
- } else {
- supportsDirectProtoAccess = js.statement(r'''
- var supportsDirectProtoAccess = (function () {
- var cls = function () {};
- cls.prototype = {'p': {}};
- var object = new cls();
- return object.__proto__ &&
- object.__proto__.p === cls.prototype.p;
- })();
- ''');
- }
-
- return supportsDirectProtoAccess;
- }
-
- jsAst.Expression generateLibraryDescriptor(LibraryElement library,
- Fragment fragment) {
- var uri = "";
- if (!compiler.enableMinification || backend.mustPreserveUris) {
- uri = library.canonicalUri;
- if (uri.scheme == 'file' && compiler.outputUri != null) {
- uri = relativize(compiler.outputUri, library.canonicalUri, false);
- }
- }
-
- String libraryName =
- (!compiler.enableMinification || backend.mustRetainLibraryNames) ?
- library.getLibraryName() :
- "";
-
- jsAst.Fun metadata = task.metadataCollector.buildMetadataFunction(library);
-
- ClassBuilder descriptor = elementDescriptors[fragment][library];
-
- jsAst.ObjectInitializer initializer;
- if (descriptor == null) {
- // Nothing of the library was emitted.
- // TODO(floitsch): this should not happen. We currently have an example
- // with language/prefix6_negative_test.dart where we have an instance
- // method without its corresponding class.
- initializer = new jsAst.ObjectInitializer([]);
- } else {
- initializer = descriptor.toObjectInitializer();
- }
-
- compiler.dumpInfoTask.registerElementAst(library, metadata);
- compiler.dumpInfoTask.registerElementAst(library, initializer);
-
- List<jsAst.Expression> parts = <jsAst.Expression>[];
- parts..add(js.string(libraryName))
- ..add(js.string(uri.toString()))
- ..add(metadata == null ? new jsAst.ArrayHole() : metadata)
- ..add(js('#', namer.globalObjectFor(library)))
- ..add(initializer);
- if (library == compiler.mainApp) {
- parts.add(js.number(1));
- }
-
- return new jsAst.ArrayInitializer(parts);
- }
-
- void assemblePrecompiledConstructor(OutputUnit outputUnit,
- jsAst.Name constructorName,
- jsAst.Expression constructorAst,
- List<jsAst.Name> fields) {
- cspPrecompiledFunctionFor(outputUnit).add(
- new jsAst.FunctionDeclaration(constructorName, constructorAst));
-
- String fieldNamesProperty = FIELD_NAMES_PROPERTY_NAME;
- bool hasIsolateSupport = compiler.hasIsolateSupport;
- jsAst.Node fieldNamesArray;
- if (hasIsolateSupport) {
- fieldNamesArray =
- new jsAst.ArrayInitializer(fields.map(js.quoteName).toList());
- } else {
- fieldNamesArray = new jsAst.LiteralNull();
- }
-
- cspPrecompiledFunctionFor(outputUnit).add(js.statement(r'''
- {
- #constructorName.#typeNameProperty = #constructorNameString;
- // IE does not have a name property.
- if (!("name" in #constructorName))
- #constructorName.name = #constructorNameString;
- $desc = $collectedClasses$.#constructorName[1];
- #constructorName.prototype = $desc;
- ''' /* next string is not a raw string */ '''
- if (#hasIsolateSupport) {
- #constructorName.$fieldNamesProperty = #fieldNamesArray;
- }
- }''',
- {"constructorName": constructorName,
- "typeNameProperty": typeNameProperty,
- "constructorNameString": js.quoteName(constructorName),
- "hasIsolateSupport": hasIsolateSupport,
- "fieldNamesArray": fieldNamesArray}));
-
- cspPrecompiledConstructorNamesFor(outputUnit).add(js('#', constructorName));
- }
-
- void assembleTypedefs(Program program) {
- Fragment mainFragment = program.mainFragment;
- OutputUnit mainOutputUnit = mainFragment.outputUnit;
-
- // Emit all required typedef declarations into the main output unit.
- // TODO(karlklose): unify required classes and typedefs to declarations
- // and have builders for each kind.
- for (TypedefElement typedef in typedefsNeededForReflection) {
- LibraryElement library = typedef.library;
- // TODO(karlklose): add a TypedefBuilder and move this code there.
- DartType type = typedef.alias;
- // TODO(zarah): reify type variables once reflection on type arguments of
- // typedefs is supported.
- jsAst.Expression typeIndex =
- task.metadataCollector.reifyType(type, ignoreTypeVariables: true);
- ClassBuilder builder = new ClassBuilder.forStatics(typedef, namer);
- builder.addPropertyByName(embeddedNames.TYPEDEF_TYPE_PROPERTY_NAME,
- typeIndex);
- builder.addPropertyByName(embeddedNames.TYPEDEF_PREDICATE_PROPERTY_NAME,
- js.boolean(true));
-
- // We can be pretty sure that the objectClass is initialized, since
- // typedefs are only emitted with reflection, which requires lots of
- // classes.
- assert(compiler.objectClass != null);
- builder.superName = namer.className(compiler.objectClass);
- jsAst.Node declaration = builder.toObjectInitializer();
- jsAst.Name mangledName = namer.globalPropertyName(typedef);
- String reflectionName = getReflectionName(typedef, mangledName);
- getElementDescriptor(library, mainFragment)
- ..addProperty(mangledName, declaration)
- ..addPropertyByName("+$reflectionName", js.string(''));
- // Also emit a trivial constructor for CSP mode.
- jsAst.Name constructorName = mangledName;
- jsAst.Expression constructorAst = js('function() {}');
- List<jsAst.Name> fieldNames = [];
- assemblePrecompiledConstructor(mainOutputUnit,
- constructorName,
- constructorAst,
- fieldNames);
- }
- }
-
- jsAst.Statement buildGlobalObjectSetup(bool isProgramSplit) {
- List<jsAst.Statement> parts = <jsAst.Statement>[];
-
- parts.add(js.comment("""
- // The global objects start as so-called "slow objects". For V8, this
- // means that it won't try to make map transitions as we add properties
- // to these objects. Later on, we attempt to turn these objects into
- // fast objects by calling "convertToFastObject" (see
- // [emitConvertToFastObjectFunction]).
- """));
-
- for (String globalObject in Namer.reservedGlobalObjectNames) {
- if (isProgramSplit) {
- String template =
- "var #globalObject = #globalsHolder.#globalObject = map();";
- parts.add(js.statement(template, {"globalObject": globalObject,
- "globalsHolder": globalsHolder}));
- } else {
- parts.add(js.statement("var #globalObject = map();",
- {"globalObject": globalObject}));
- }
-
- }
-
- return new jsAst.Block(parts);
- }
-
- jsAst.Statement buildConvertGlobalObjectToFastObjects() {
- List<jsAst.Statement> parts = <jsAst.Statement>[];
-
- for (String globalObject in Namer.reservedGlobalObjectNames) {
- parts.add(js.statement(
- '#globalObject = convertToFastObject(#globalObject);',
- {"globalObject": globalObject}));
- }
-
- return new jsAst.Block(parts);
- }
-
- jsAst.Statement buildDebugFastObjectCode() {
- List<jsAst.Statement> parts = <jsAst.Statement>[];
-
- if (DEBUG_FAST_OBJECTS) {
- parts.add(js.statement(r'''
- // The following only works on V8 when run with option
- // "--allow-natives-syntax". We use'new Function' because the
- // miniparser does not understand V8 native syntax.
- if (typeof print === "function") {
- var HasFastProperties =
- new Function("a", "return %HasFastProperties(a)");
- print("Size of global helper object: "
- + String(Object.getOwnPropertyNames(H).length)
- + ", fast properties " + HasFastProperties(H));
- print("Size of global platform object: "
- + String(Object.getOwnPropertyNames(P).length)
- + ", fast properties " + HasFastProperties(P));
- print("Size of global dart:html object: "
- + String(Object.getOwnPropertyNames(W).length)
- + ", fast properties " + HasFastProperties(W));
- print("Size of isolate properties object: "
- + String(Object.getOwnPropertyNames($).length)
- + ", fast properties " + HasFastProperties($));
- print("Size of constant object: "
- + String(Object.getOwnPropertyNames(C).length)
- + ", fast properties " + HasFastProperties(C));
- var names = Object.getOwnPropertyNames($);
- for (var i = 0; i < names.length; i++) {
- print("$." + names[i]);
- }
- }
- '''));
-
- for (String object in Namer.userGlobalObjects) {
- parts.add(js.statement('''
- if (typeof print === "function") {
- print("Size of " + #objectString + ": "
- + String(Object.getOwnPropertyNames(#object).length)
- + ", fast properties " + HasFastProperties(#object));
- }
- ''', {"object": object, "objectString": js.string(object)}));
- }
- }
-
- return new jsAst.Block(parts);
- }
-
- jsAst.Statement buildMangledNames() {
- List<jsAst.Statement> parts = <jsAst.Statement>[];
-
- if (!mangledFieldNames.isEmpty) {
- List<jsAst.Name> keys = mangledFieldNames.keys.toList()..sort();
- var properties = [];
- for (jsAst.Name key in keys) {
- var value = js.string(mangledFieldNames[key]);
- properties.add(new jsAst.Property(key, value));
- }
-
- jsAst.Expression mangledNamesAccess =
- generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES);
- var map = new jsAst.ObjectInitializer(properties);
- parts.add(js.statement('# = #', [mangledNamesAccess, map]));
- }
-
- if (!mangledGlobalFieldNames.isEmpty) {
- List<jsAst.Name> keys = mangledGlobalFieldNames.keys.toList()
- ..sort();
- List<jsAst.Property> properties = <jsAst.Property>[];
- for (jsAst.Name key in keys) {
- jsAst.Literal value = js.string(mangledGlobalFieldNames[key]);
- properties.add(new jsAst.Property(js.quoteName(key), value));
- }
- jsAst.Expression mangledGlobalNamesAccess =
- generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES);
- jsAst.ObjectInitializer map = new jsAst.ObjectInitializer(properties);
- parts.add(js.statement('# = #', [mangledGlobalNamesAccess, map]));
- }
-
- return new jsAst.Block(parts);
- }
-
- void checkEverythingEmitted(Iterable<Element> elements) {
- List<Element> pendingStatics;
- if (!compiler.hasIncrementalSupport) {
- pendingStatics =
- Elements.sortedByPosition(elements.where((e) => !e.isLibrary));
-
- pendingStatics.forEach((element) =>
- compiler.reportInfo(
- element, MessageKind.GENERIC, {'text': 'Pending statics.'}));
- }
-
- if (pendingStatics != null && !pendingStatics.isEmpty) {
- compiler.internalError(pendingStatics.first,
- 'Pending statics (see above).');
- }
- }
-
- void assembleLibrary(Library library, Fragment fragment) {
- LibraryElement libraryElement = library.element;
-
- assembleStaticFunctions(library.statics, fragment);
-
- ClassBuilder libraryBuilder =
- getElementDescriptor(libraryElement, fragment);
- for (Class cls in library.classes) {
- assembleClass(cls, libraryBuilder, fragment);
- }
-
- classEmitter.emitFields(library, libraryBuilder, emitStatics: true);
- }
-
- void assembleProgram(Program program) {
- for (Fragment fragment in program.fragments) {
- for (Library library in fragment.libraries) {
- assembleLibrary(library, fragment);
- }
- }
- assembleTypedefs(program);
- }
-
- jsAst.Program buildOutputAstForMain(Program program,
- Map<OutputUnit, _DeferredOutputUnitHash> deferredLoadHashes) {
- MainFragment mainFragment = program.mainFragment;
- OutputUnit mainOutputUnit = mainFragment.outputUnit;
- bool isProgramSplit = program.isSplit;
-
- List<jsAst.Statement> statements = <jsAst.Statement>[];
-
- statements..add(buildGeneratedBy())
- ..add(js.comment(HOOKS_API_USAGE));
-
- if (isProgramSplit) {
- /// For deferred loading we communicate the initializers via this global
- /// variable. The deferred hunks will add their initialization to this.
- /// The semicolon is important in minified mode, without it the
- /// following parenthesis looks like a call to the object literal.
- statements.add(
- js.statement('self.#deferredInitializers = '
- 'self.#deferredInitializers || Object.create(null);',
- {'deferredInitializers': deferredInitializers}));
- }
-
- // Collect the AST for the decriptors
- Map<Element, ClassBuilder> descriptors = elementDescriptors[mainFragment];
- if (descriptors == null) descriptors = const {};
-
- checkEverythingEmitted(descriptors.keys);
-
- Iterable<LibraryElement> libraries =
- task.outputLibraryLists[mainOutputUnit];
- if (libraries == null) libraries = <LibraryElement>[];
-
- List<jsAst.Expression> parts = <jsAst.Expression>[];
- for (LibraryElement library in Elements.sortedByPosition(libraries)) {
- parts.add(generateLibraryDescriptor(library, mainFragment));
- descriptors.remove(library);
- }
-
- if (descriptors.isNotEmpty) {
- List<Element> remainingLibraries = descriptors.keys
- .where((Element e) => e is LibraryElement)
- .toList();
-
- // The remaining descriptors are only accessible through reflection.
- // The program builder does not collect libraries that only
- // contain typedefs that are used for reflection.
- for (LibraryElement element in remainingLibraries) {
- assert(element is LibraryElement || compiler.hasIncrementalSupport);
- if (element is LibraryElement) {
- parts.add(generateLibraryDescriptor(element, mainFragment));
- descriptors.remove(element);
- }
- }
- }
- jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts);
-
- // Using a named function here produces easier to read stack traces in
- // Chrome/V8.
- statements.add(js.statement("""
- (function() {
- // No renaming in the top-level function to save the locals for the
- // nested context where they will be used more. We have to put the
- // comment into a hole as the parser strips out comments right away.
- #disableVariableRenaming;
- #supportsDirectProtoAccess;
-
- if (#hasIncrementalSupport) {
- #helper = #helper || Object.create(null);
- #helper.patch = function(a) { eval(a)};
- #helper.schemaChange = #schemaChange;
- #helper.addMethod = #addMethod;
- #helper.extractStubs =
- function(array, name, isStatic, originalDescriptor) {
- var descriptor = Object.create(null);
- this.addStubs(descriptor, array, name, isStatic, []);
- return descriptor;
- };
- }
-
- if (#isProgramSplit) {
- /// We collect all the global state, so it can be passed to the
- /// initializer of deferred files.
- var #globalsHolder = Object.create(null)
- }
-
- // [map] returns an object that V8 shouldn't try to optimize with a
- // hidden class. This prevents a potential performance problem where V8
- // tries to build a hidden class for an object used as a hashMap.
- // It requires fewer characters to declare a variable as a parameter than
- // with `var`.
- function map(x) {
- x = Object.create(null);
- x.x = 0;
- delete x.x;
- return x;
- }
-
- #globalObjectSetup;
-
- function #isolateName() {}
-
- if (#isProgramSplit) {
- #globalsHolder.#isolateName = #isolateName;
- #globalsHolder.#initName = #initName;
- #globalsHolder.#setupProgramName = #setupProgramName;
- }
-
- init();
-
- #mangledNames;
-
- #cspPrecompiledFunctions;
-
- #setupProgram;
-
- #functionThatReturnsNull;
-
- // The argument to reflectionDataParser is assigned to a temporary 'dart'
- // so that 'dart.' will appear as the prefix to dart methods in stack
- // traces and profile entries.
- var dart = #descriptors;
-
- #setupProgramName(dart, 0);
-
- #getInterceptorMethods;
- #oneShotInterceptors;
-
- #makeConstantList;
-
- // We abuse the short name used for the isolate here to store
- // the isolate properties. This is safe as long as the real isolate
- // object does not exist yet.
- var ${namer.currentIsolate} = #isolatePropertiesName;
-
- // Constants in checked mode call into RTI code to set type information
- // which may need getInterceptor (and one-shot interceptor) methods, so
- // we have to make sure that [emitGetInterceptorMethods] and
- // [emitOneShotInterceptors] have been called.
- #compileTimeConstants;
-
- // Static field initializations require the classes and compile-time
- // constants to be set up.
- #staticNonFinalInitializers;
-
- ${namer.currentIsolate} = null;
-
- #deferredBoilerPlate;
-
- #typeToInterceptorMap;
-
- #lazyStaticFields;
-
- #isolateName = $finishIsolateConstructorName(#isolateName);
-
- ${namer.currentIsolate} = new #isolateName();
-
- #metadata;
-
- #convertToFastObject;
- #convertToSlowObject;
-
- #convertGlobalObjectsToFastObjects;
- #debugFastObjects;
-
- #init;
-
- #main;
- })();
- """, {
- "disableVariableRenaming": js.comment("/* ::norenaming:: */"),
- "hasIncrementalSupport": compiler.hasIncrementalSupport,
- "helper": js('this.#', [namer.incrementalHelperName]),
- "schemaChange": buildSchemaChangeFunction(),
- "addMethod": buildIncrementalAddMethod(),
- "isProgramSplit": isProgramSplit,
- "supportsDirectProtoAccess": buildSupportsDirectProtoAccess(),
- "globalsHolder": globalsHolder,
- "globalObjectSetup": buildGlobalObjectSetup(isProgramSplit),
- "isolateName": namer.isolateName,
- "isolatePropertiesName": js(isolatePropertiesName),
- "initName": initName,
- "functionThatReturnsNull": buildFunctionThatReturnsNull(),
- "mangledNames": buildMangledNames(),
- "setupProgram": buildSetupProgram(program, compiler, backend, namer, this),
- "setupProgramName": setupProgramName,
- "descriptors": descriptorsAst,
- "cspPrecompiledFunctions": buildCspPrecompiledFunctionFor(mainOutputUnit),
- "getInterceptorMethods": interceptorEmitter.buildGetInterceptorMethods(),
- "oneShotInterceptors": interceptorEmitter.buildOneShotInterceptors(),
- "makeConstantList": buildMakeConstantList(),
- "compileTimeConstants": buildCompileTimeConstants(mainFragment.constants,
- isMainFragment: true),
- "deferredBoilerPlate": buildDeferredBoilerPlate(deferredLoadHashes),
- "staticNonFinalInitializers": buildStaticNonFinalFieldInitializations(
- mainOutputUnit),
- "typeToInterceptorMap":
- interceptorEmitter.buildTypeToInterceptorMap(program),
- "lazyStaticFields": buildLazilyInitializedStaticFields(),
- "metadata": buildMetadata(program, mainOutputUnit),
- "convertToFastObject": buildConvertToFastObjectFunction(),
- "convertToSlowObject": buildConvertToSlowObjectFunction(),
- "convertGlobalObjectsToFastObjects":
- buildConvertGlobalObjectToFastObjects(),
- "debugFastObjects": buildDebugFastObjectCode(),
- "init": buildInitFunction(),
- "main": buildMain(mainFragment.invokeMain)
- }));
-
- return new jsAst.Program(statements);
- }
-
- void emitMainOutputUnit(OutputUnit mainOutputUnit, jsAst.Program program) {
- LineColumnCollector lineColumnCollector;
- List<CodeOutputListener> codeOutputListeners;
- if (generateSourceMap) {
- lineColumnCollector = new LineColumnCollector();
- codeOutputListeners = <CodeOutputListener>[lineColumnCollector];
- }
-
- CodeOutput mainOutput =
- new StreamCodeOutput(compiler.outputProvider('', 'js'),
- codeOutputListeners);
- outputBuffers[mainOutputUnit] = mainOutput;
-
-
- mainOutput.addBuffer(jsAst.prettyPrint(program,
- compiler,
- monitor: compiler.dumpInfoTask));
-
- if (compiler.deferredMapUri != null) {
- outputDeferredMap();
- }
-
- if (generateSourceMap) {
- mainOutput.add(
- generateSourceMapTag(compiler.sourceMapUri, compiler.outputUri));
- }
-
- mainOutput.close();
-
- if (generateSourceMap) {
- outputSourceMap(mainOutput, lineColumnCollector, '',
- compiler.sourceMapUri, compiler.outputUri);
- }
- }
-
- /// Used by incremental compilation to patch up the prototype of
- /// [oldConstructor] for use as prototype of [newConstructor].
- jsAst.Fun buildSchemaChangeFunction() {
- if (!compiler.hasIncrementalSupport) return null;
- return js('''
-function(newConstructor, oldConstructor, superclass) {
- // Invariant: newConstructor.prototype has no interesting properties besides
- // generated accessors. These are copied to oldPrototype which will be
- // updated by other incremental changes.
- if (superclass != null) {
- this.inheritFrom(newConstructor, superclass);
- }
- var oldPrototype = oldConstructor.prototype;
- var newPrototype = newConstructor.prototype;
- var hasOwnProperty = Object.prototype.hasOwnProperty;
- for (var property in newPrototype) {
- if (hasOwnProperty.call(newPrototype, property)) {
- // Copy generated accessors.
- oldPrototype[property] = newPrototype[property];
- }
- }
- oldPrototype.__proto__ = newConstructor.prototype.__proto__;
- oldPrototype.constructor = newConstructor;
- newConstructor.prototype = oldPrototype;
- return newConstructor;
-}''');
- }
-
- /// Used by incremental compilation to patch up an object ([holder]) with a
- /// new (or updated) method. [arrayOrFunction] is either the new method, or
- /// an array containing the method (see
- /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the
- /// new method. [isStatic] tells if method is static (or
- /// top-level). [globalFunctionsAccess] is a reference to
- /// [embeddedNames.GLOBAL_FUNCTIONS].
- jsAst.Fun buildIncrementalAddMethod() {
- if (!compiler.hasIncrementalSupport) return null;
- return js(r"""
-function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
- var arrayOrFunction = originalDescriptor[name];
- var method;
- if (arrayOrFunction.constructor === Array) {
- var existing = holder[name];
- var array = arrayOrFunction;
-
- // Each method may have a number of stubs associated. For example, if an
- // instance method supports multiple arguments, a stub for each matching
- // selector. There is also a getter stub for tear-off getters. For example,
- // an instance method foo([a]) may have the following stubs: foo$0, foo$1,
- // and get$foo (here exemplified using unminified names).
- // [extractStubs] returns a JavaScript object whose own properties
- // corresponds to the stubs.
- var descriptor =
- this.extractStubs(array, name, isStatic, originalDescriptor);
- method = descriptor[name];
-
- // Iterate through the properties of descriptor and copy the stubs to the
- // existing holder (for instance methods, a prototype).
- for (var property in descriptor) {
- if (!Object.prototype.hasOwnProperty.call(descriptor, property)) continue;
- var stub = descriptor[property];
- var existingStub = holder[property];
- if (stub === method || !existingStub || !stub.$getterStub) {
- // Not replacing an existing getter stub.
- holder[property] = stub;
- continue;
- }
- if (!stub.$getterStub) {
- var error = new Error('Unexpected stub.');
- error.stub = stub;
- throw error;
- }
-
- // Existing getter stubs need special treatment as they may already have
- // been called and produced a closure.
- this.pendingStubs = this.pendingStubs || [];
- // It isn't safe to invoke the stub yet.
- this.pendingStubs.push((function(holder, stub, existingStub, existing,
- method) {
- return function() {
- var receiver = isStatic ? holder : new holder.constructor();
- // Invoke the existing stub to obtain the tear-off closure.
- existingStub = existingStub.call(receiver);
- // Invoke the new stub to create a tear-off closure we can use as a
- // prototype.
- stub = stub.call(receiver);
-
- // Copy the properties from the new tear-off's prototype to the
- // prototype of the existing tear-off.
- var newProto = stub.constructor.prototype;
- var existingProto = existingStub.constructor.prototype;
- for (var stubProperty in newProto) {
- if (!Object.prototype.hasOwnProperty.call(newProto, stubProperty))
- continue;
- existingProto[stubProperty] = newProto[stubProperty];
- }
-
- // Update all the existing stub's references to [existing] to
- // [method]. Instance tear-offs are call-by-name, so this isn't
- // necessary for those.
- if (!isStatic) return;
- for (var reference in existingStub) {
- if (existingStub[reference] === existing) {
- existingStub[reference] = method;
- }
- }
- }
- })(holder, stub, existingStub, existing, method));
- }
- } else {
- method = arrayOrFunction;
- holder[name] = method;
- }
- if (isStatic) globalFunctionsAccess[name] = method;
-}""");
- }
-
- Map<OutputUnit, jsAst.Expression> buildDescriptorsForOutputUnits(
- Program program) {
- Map<OutputUnit, jsAst.Expression> outputs =
- new Map<OutputUnit, jsAst.Expression>();
-
- for (Fragment fragment in program.deferredFragments) {
- OutputUnit outputUnit = fragment.outputUnit;
-
- Map<Element, ClassBuilder> descriptors = elementDescriptors[fragment];
-
- if (descriptors != null && descriptors.isNotEmpty) {
- Iterable<LibraryElement> libraries =
- task.outputLibraryLists[outputUnit];
- if (libraries == null) libraries = [];
-
- // TODO(johnniwinther): Avoid creating [CodeBuffer]s.
- List<jsAst.Expression> parts = <jsAst.Expression>[];
- for (LibraryElement library in Elements.sortedByPosition(libraries)) {
- parts.add(generateLibraryDescriptor(library, fragment));
- descriptors.remove(library);
- }
-
- outputs[outputUnit] = new jsAst.ArrayInitializer(parts);
- }
- }
-
- return outputs;
- }
-
- void finalizeTokensInAst(jsAst.Program main,
- Iterable<jsAst.Program> deferredParts) {
- jsAst.TokenCounter counter = new jsAst.TokenCounter();
- counter.countTokens(main);
- deferredParts.forEach(counter.countTokens);
- task.metadataCollector.finalizeTokens();
- if (backend.namer is jsAst.TokenFinalizer) {
- var finalizer = backend.namer;
- finalizer.finalizeTokens();
- }
- }
-
- int emitProgram(ProgramBuilder programBuilder) {
- Program program = programBuilder.buildProgram(
- storeFunctionTypesInMetadata: true);
-
- assembleProgram(program);
-
- // Construct the ASTs for all deferred output units.
- Map<OutputUnit, jsAst.Program> deferredParts =
- buildOutputAstForDeferredCode(program);
-
- Map<OutputUnit, _DeferredOutputUnitHash> deferredHashTokens =
- new Map<OutputUnit, _DeferredOutputUnitHash>.fromIterables(
- deferredParts.keys,
- deferredParts.keys.map((OutputUnit unit) {
- return new _DeferredOutputUnitHash(unit);
- })
- );
-
- jsAst.Program mainOutput =
- buildOutputAstForMain(program, deferredHashTokens);
-
- finalizeTokensInAst(mainOutput, deferredParts.values);
-
- // Emit deferred units first, so we have their hashes.
- // Map from OutputUnit to a hash of its content. The hash uniquely
- // identifies the code of the output-unit. It does not include
- // boilerplate JS code, like the sourcemap directives or the hash
- // itself.
- Map<OutputUnit, String> deferredLoadHashes =
- emitDeferredOutputUnits(deferredParts);
-
- deferredHashTokens.forEach((OutputUnit key, _DeferredOutputUnitHash token) {
- token.setHash(deferredLoadHashes[key]);
- });
- emitMainOutputUnit(program.mainFragment.outputUnit, mainOutput);
-
- if (backend.requiresPreamble &&
- !backend.htmlLibraryIsLoaded) {
- compiler.reportHint(NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
- }
- // Return the total program size.
- return outputBuffers.values.fold(0, (a, b) => a + b.length);
- }
-
- String generateSourceMapTag(Uri sourceMapUri, Uri fileUri) {
- if (sourceMapUri != null && fileUri != null) {
- String sourceMapFileName = relativize(fileUri, sourceMapUri, false);
- return '''
-
-//# sourceMappingURL=$sourceMapFileName
-''';
- }
- return '';
- }
-
- ClassBuilder getElementDescriptor(Element element, Fragment fragment) {
- Element owner = element.library;
- bool isClass = false;
- if (!element.isLibrary && !element.isTopLevel && !element.isNative) {
- // For static (not top level) elements, record their code in a buffer
- // specific to the class. For now, not supported for native classes and
- // native elements.
- ClassElement cls =
- element.enclosingClassOrCompilationUnit.declaration;
- if (compiler.codegenWorld.directlyInstantiatedClasses.contains(cls) &&
- !cls.isNative &&
- compiler.deferredLoadTask.outputUnitForElement(element) ==
- compiler.deferredLoadTask.outputUnitForElement(cls)) {
- owner = cls;
- }
- }
- if (owner == null) {
- compiler.internalError(element, 'Owner is null.');
- }
- return elementDescriptors
- .putIfAbsent(fragment, () => new Map<Element, ClassBuilder>())
- .putIfAbsent(owner, () {
- return new ClassBuilder(owner, namer, owner.isClass);
- });
- }
-
- /// Emits support-code for deferred loading into [output].
- jsAst.Statement buildDeferredBoilerPlate(
- Map<OutputUnit, _DeferredOutputUnitHash> deferredLoadHashes) {
- List<jsAst.Statement> parts = <jsAst.Statement>[];
-
- parts.add(js.statement('''
- {
- // Function for checking if a hunk is loaded given its hash.
- #isHunkLoaded = function(hunkHash) {
- return !!$deferredInitializers[hunkHash];
- };
- #deferredInitialized = new Object(null);
- // Function for checking if a hunk is initialized given its hash.
- #isHunkInitialized = function(hunkHash) {
- return #deferredInitialized[hunkHash];
- };
- // Function for initializing a loaded hunk, given its hash.
- #initializeLoadedHunk = function(hunkHash) {
- $deferredInitializers[hunkHash](
- #globalsHolder, ${namer.currentIsolate});
- #deferredInitialized[hunkHash] = true;
- };
- }
- ''', {"globalsHolder": globalsHolder,
- "isHunkLoaded": generateEmbeddedGlobalAccess(
- embeddedNames.IS_HUNK_LOADED),
- "isHunkInitialized": generateEmbeddedGlobalAccess(
- embeddedNames.IS_HUNK_INITIALIZED),
- "initializeLoadedHunk": generateEmbeddedGlobalAccess(
- embeddedNames.INITIALIZE_LOADED_HUNK),
- "deferredInitialized": generateEmbeddedGlobalAccess(
- embeddedNames.DEFERRED_INITIALIZED)}));
-
- // Write a javascript mapping from Deferred import load ids (derrived
- // from the import prefix.) to a list of lists of uris of hunks to load,
- // and a corresponding mapping to a list of hashes used by
- // INITIALIZE_LOADED_HUNK and IS_HUNK_LOADED.
- Map<String, List<jsAst.LiteralString>> deferredLibraryUris =
- new Map<String, List<jsAst.LiteralString>>();
- Map<String, List<_DeferredOutputUnitHash>> deferredLibraryHashes =
- new Map<String, List<_DeferredOutputUnitHash>>();
- compiler.deferredLoadTask.hunksToLoad.forEach(
- (String loadId, List<OutputUnit>outputUnits) {
- List<jsAst.LiteralString> uris = new List<jsAst.LiteralString>();
- List<_DeferredOutputUnitHash> hashes =
- new List<_DeferredOutputUnitHash>();
- deferredLibraryHashes[loadId] = new List<_DeferredOutputUnitHash>();
- for (OutputUnit outputUnit in outputUnits) {
- uris.add(js.escapedString(
- backend.deferredPartFileName(outputUnit.name)));
- hashes.add(deferredLoadHashes[outputUnit]);
- }
-
- deferredLibraryUris[loadId] = uris;
- deferredLibraryHashes[loadId] = hashes;
- });
-
- void emitMapping(String name, Map<String, List<jsAst.Expression>> mapping) {
- List<jsAst.Property> properties = new List<jsAst.Property>();
- mapping.forEach((String key, List<jsAst.Expression> values) {
- properties.add(new jsAst.Property(js.escapedString(key),
- new jsAst.ArrayInitializer(values)));
- });
- jsAst.Node initializer =
- new jsAst.ObjectInitializer(properties, isOneLiner: true);
-
- jsAst.Node globalName = generateEmbeddedGlobalAccess(name);
- parts.add(js.statement("# = #", [globalName, initializer]));
- }
-
- emitMapping(embeddedNames.DEFERRED_LIBRARY_URIS, deferredLibraryUris);
- emitMapping(embeddedNames.DEFERRED_LIBRARY_HASHES,
- deferredLibraryHashes);
-
- return new jsAst.Block(parts);
- }
-
- Map <OutputUnit, jsAst.Program> buildOutputAstForDeferredCode(
- Program program) {
- if (!program.isSplit) return const <OutputUnit, jsAst.Program>{};
-
- Map<OutputUnit, jsAst.Program> result =
- new Map<OutputUnit, jsAst.Program>();
-
- Map<OutputUnit, jsAst.Expression> deferredAsts =
- buildDescriptorsForOutputUnits(program);
-
- for (Fragment fragment in program.deferredFragments) {
- OutputUnit outputUnit = fragment.outputUnit;
- jsAst.Expression libraryDescriptor = deferredAsts[outputUnit];
- List<jsAst.Statement> body = <jsAst.Statement>[];
-
- // No renaming in the top-level function to save the locals for the
- // nested context where they will be used more.
- body.add(js.comment("/* ::norenaming:: "));
-
- for (String globalObject in Namer.reservedGlobalObjectNames) {
- body.add(js.statement('var #object = #globalsHolder.#object;',
- {'globalsHolder': globalsHolder,
- 'object': globalObject}));
- }
- body..add(js.statement('var init = #globalsHolder.init;',
- {'globalsHolder': globalsHolder}))
- ..add(js.statement('var $setupProgramName = '
- '#globalsHolder.$setupProgramName;',
- {'globalsHolder': globalsHolder}))
- ..add(js.statement('var ${namer.isolateName} = '
- '#globalsHolder.${namer.isolateName};',
- {'globalsHolder': globalsHolder}));
- String typesAccess =
- generateEmbeddedGlobalAccessString(embeddedNames.TYPES);
- if (libraryDescriptor != null) {
- // The argument to reflectionDataParser is assigned to a temporary
- // 'dart' so that 'dart.' will appear as the prefix to dart methods
- // in stack traces and profile entries.
- body.add(js.statement('var dart = #', libraryDescriptor));
-
- if (compiler.useContentSecurityPolicy) {
- body.add(buildCspPrecompiledFunctionFor(outputUnit));
- }
- body.add(
- js.statement('$setupProgramName(dart, ${typesAccess}.length);'));
- }
-
- body..add(buildMetadata(program, outputUnit))
- ..add(js.statement('${typesAccess}.push.apply(${typesAccess}, '
- '${namer.deferredTypesName});'));
-
- // Set the currentIsolate variable to the current isolate (which is
- // provided as second argument).
- body.add(js.statement("${namer.currentIsolate} = arguments[1];"));
-
- body.add(buildCompileTimeConstants(fragment.constants,
- isMainFragment: false));
- body.add(buildStaticNonFinalFieldInitializations(outputUnit));
-
- List<jsAst.Statement> statements = <jsAst.Statement>[];
-
- statements
- ..add(buildGeneratedBy())
- ..add(js.statement('${deferredInitializers}.current = '
- """function (#) {
- #
- }
- """, [globalsHolder, body]));
-
- result[outputUnit] = new jsAst.Program(statements);
- }
-
- return result;
- }
-
- /// Returns a map from OutputUnit to a hash of its content. The hash uniquely
- /// identifies the code of the output-unit. It does not include
- /// boilerplate JS code, like the sourcemap directives or the hash
- /// itself.
- Map<OutputUnit, String> emitDeferredOutputUnits(
- Map<OutputUnit, jsAst.Program> outputAsts) {
-
- Map<OutputUnit, String> hunkHashes = new Map<OutputUnit, String>();
-
- for (OutputUnit outputUnit in outputAsts.keys) {
- List<CodeOutputListener> outputListeners = <CodeOutputListener>[];
- Hasher hasher = new Hasher();
- outputListeners.add(hasher);
-
- LineColumnCollector lineColumnCollector;
- if (generateSourceMap) {
- lineColumnCollector = new LineColumnCollector();
- outputListeners.add(lineColumnCollector);
- }
-
- String partPrefix =
- backend.deferredPartFileName(outputUnit.name, addExtension: false);
- CodeOutput output = new StreamCodeOutput(
- compiler.outputProvider(partPrefix, 'part.js'),
- outputListeners);
-
- outputBuffers[outputUnit] = output;
-
- output.addBuffer(jsAst.prettyPrint(outputAsts[outputUnit],
- compiler,
- monitor: compiler.dumpInfoTask));
-
- // Make a unique hash of the code (before the sourcemaps are added)
- // This will be used to retrieve the initializing function from the global
- // variable.
- String hash = hasher.getHash();
-
- output.add('$N${deferredInitializers}["$hash"]$_=$_'
- '${deferredInitializers}.current$N');
-
- if (generateSourceMap) {
- Uri mapUri, partUri;
- Uri sourceMapUri = compiler.sourceMapUri;
- Uri outputUri = compiler.outputUri;
-
- String partName = "$partPrefix.part";
-
- if (sourceMapUri != null) {
- String mapFileName = partName + ".js.map";
- List<String> mapSegments = sourceMapUri.pathSegments.toList();
- mapSegments[mapSegments.length - 1] = mapFileName;
- mapUri = compiler.sourceMapUri.replace(pathSegments: mapSegments);
- }
-
- if (outputUri != null) {
- String partFileName = partName + ".js";
- List<String> partSegments = outputUri.pathSegments.toList();
- partSegments[partSegments.length - 1] = partFileName;
- partUri = compiler.outputUri.replace(pathSegments: partSegments);
- }
-
- output.add(generateSourceMapTag(mapUri, partUri));
- output.close();
- outputSourceMap(output, lineColumnCollector, partName,
- mapUri, partUri);
- } else {
- output.close();
- }
-
- hunkHashes[outputUnit] = hash;
- }
- return hunkHashes;
- }
-
- jsAst.Comment buildGeneratedBy() {
- String suffix = '';
- if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}';
- String msg = '// Generated by dart2js, the Dart to JavaScript '
- 'compiler$suffix.';
- return new jsAst.Comment(msg);
- }
-
- void outputSourceMap(CodeOutput output,
- LineColumnProvider lineColumnProvider,
- String name,
- [Uri sourceMapUri,
- Uri fileUri]) {
- if (!generateSourceMap) return;
- // Create a source file for the compilation output. This allows using
- // [:getLine:] to transform offsets to line numbers in [SourceMapBuilder].
- SourceMapBuilder sourceMapBuilder =
- new SourceMapBuilder(sourceMapUri, fileUri, lineColumnProvider);
- output.forEachSourceLocation(sourceMapBuilder.addMapping);
- String sourceMap = sourceMapBuilder.build();
- compiler.outputProvider(name, 'js.map')
- ..add(sourceMap)
- ..close();
- }
-
- void outputDeferredMap() {
- Map<String, dynamic> mapping = new Map<String, dynamic>();
- // Json does not support comments, so we embed the explanation in the
- // data.
- mapping["_comment"] = "This mapping shows which compiled `.js` files are "
- "needed for a given deferred library import.";
- mapping.addAll(compiler.deferredLoadTask.computeDeferredMap());
- compiler.outputProvider(compiler.deferredMapUri.path, 'deferred_map')
- ..add(const JsonEncoder.withIndent(" ").convert(mapping))
- ..close();
- }
-
- void invalidateCaches() {
- if (!compiler.hasIncrementalSupport) return;
- if (cachedElements.isEmpty) return;
- for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) {
- if (element.isInstanceMember) {
- cachedClassBuilders.remove(element.enclosingClass);
-
- nativeEmitter.cachedBuilders.remove(element.enclosingClass);
-
- }
- }
- }
-}

Powered by Google App Engine
This is Rietveld 408576698