| Index: sdk/lib/_internal/compiler/implementation/js_emitter/program_builder.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/program_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/program_builder.dart
|
| deleted file mode 100644
|
| index 3738340a2d96e84ee7983bc1ee65e63d613ea701..0000000000000000000000000000000000000000
|
| --- a/sdk/lib/_internal/compiler/implementation/js_emitter/program_builder.dart
|
| +++ /dev/null
|
| @@ -1,405 +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.
|
| -
|
| -library dart2js.js_emitter.program_builder;
|
| -
|
| -import 'model.dart';
|
| -import '../common.dart';
|
| -import '../js/js.dart' as js;
|
| -
|
| -import '../js_backend/js_backend.dart' show
|
| - Namer,
|
| - JavaScriptBackend,
|
| - JavaScriptConstantCompiler;
|
| -
|
| -import '../closure.dart' show ClosureFieldElement;
|
| -
|
| -import 'js_emitter.dart' as emitterTask show
|
| - CodeEmitterTask,
|
| - Emitter,
|
| - InterceptorStubGenerator;
|
| -
|
| -import '../universe/universe.dart' show Universe;
|
| -import '../deferred_load.dart' show DeferredLoadTask, OutputUnit;
|
| -
|
| -part 'registry.dart';
|
| -
|
| -class ProgramBuilder {
|
| - final Compiler _compiler;
|
| - final Namer namer;
|
| - final emitterTask.CodeEmitterTask _task;
|
| -
|
| - final Registry _registry;
|
| -
|
| - ProgramBuilder(Compiler compiler,
|
| - this.namer,
|
| - this._task)
|
| - : this._compiler = compiler,
|
| - this._registry = new Registry(compiler);
|
| -
|
| - JavaScriptBackend get backend => _compiler.backend;
|
| - Universe get universe => _compiler.codegenWorld;
|
| -
|
| - /// Mapping from [ClassElement] to constructed [Class]. We need this to
|
| - /// update the superclass in the [Class].
|
| - final Map<ClassElement, Class> _classes = <ClassElement, Class>{};
|
| -
|
| - /// Mapping from [OutputUnit] to constructed [Output]. We need this to
|
| - /// generate the deferredLoadingMap (to know which hunks to load).
|
| - final Map<OutputUnit, Output> _outputs = <OutputUnit, Output>{};
|
| -
|
| - /// Mapping from [ConstantValue] to constructed [Constant]. We need this to
|
| - /// update field-initializers to point to the ConstantModel.
|
| - final Map<ConstantValue, Constant> _constants = <ConstantValue, Constant>{};
|
| -
|
| - Program buildProgram() {
|
| - _task.outputClassLists.forEach(_registry.registerElements);
|
| - _task.outputStaticLists.forEach(_registry.registerElements);
|
| - _task.outputConstantLists.forEach(_registerConstants);
|
| -
|
| - // TODO(kasperl): There's code that implicitly needs access to the special
|
| - // $ holder so we have to register that. Can we track if we have to?
|
| - _registry.registerHolder(r'$');
|
| -
|
| - MainOutput mainOutput = _buildMainOutput(_registry.mainFragment);
|
| - Iterable<Output> deferredOutputs = _registry.deferredFragments
|
| - .map((fragment) => _buildDeferredOutput(mainOutput, fragment));
|
| -
|
| - List<Output> outputs = new List<Output>(_registry.fragmentCount);
|
| - outputs[0] = mainOutput;
|
| - outputs.setAll(1, deferredOutputs);
|
| -
|
| - Program result =
|
| - new Program(outputs, _task.outputContainsConstantList, _buildLoadMap());
|
| -
|
| - // Resolve the superclass references after we've processed all the classes.
|
| - _classes.forEach((ClassElement element, Class c) {
|
| - if (element.superclass != null) {
|
| - c.setSuperclass(_classes[element.superclass]);
|
| - }
|
| - });
|
| -
|
| - _markEagerClasses();
|
| -
|
| - return result;
|
| - }
|
| -
|
| - void _markEagerClasses() {
|
| - _markEagerInterceptorClasses();
|
| - }
|
| -
|
| - /// Builds a map from loadId to outputs-to-load.
|
| - Map<String, List<Output>> _buildLoadMap() {
|
| - List<OutputUnit> convertHunks(List<OutputUnit> hunks) {
|
| - return hunks.map((OutputUnit unit) => _outputs[unit])
|
| - .toList(growable: false);
|
| - }
|
| -
|
| - Map<String, List<Output>> loadMap = <String, List<Output>>{};
|
| - _compiler.deferredLoadTask.hunksToLoad
|
| - .forEach((String loadId, List<OutputUnit> outputUnits) {
|
| - loadMap[loadId] = outputUnits
|
| - .map((OutputUnit unit) => _outputs[unit])
|
| - .toList(growable: false);
|
| - });
|
| - return loadMap;
|
| - }
|
| -
|
| - MainOutput _buildMainOutput(Fragment fragment) {
|
| - // Construct the main output from the libraries and the registered holders.
|
| - MainOutput result = new MainOutput(
|
| - "", // The empty string is the name for the main output file.
|
| - namer.elementAccess(_compiler.mainFunction),
|
| - _buildLibraries(fragment),
|
| - _buildStaticNonFinalFields(fragment),
|
| - _buildStaticLazilyInitializedFields(fragment),
|
| - _buildConstants(fragment),
|
| - _registry.holders.toList(growable: false));
|
| - _outputs[fragment.outputUnit] = result;
|
| - return result;
|
| - }
|
| -
|
| - /// Returns a name composed of the main output file name and [name].
|
| - String _outputFileName(String name) {
|
| - assert(name != "");
|
| - String outPath = _compiler.outputUri != null
|
| - ? _compiler.outputUri.path
|
| - : "out";
|
| - String outName = outPath.substring(outPath.lastIndexOf('/') + 1);
|
| - return "${outName}_$name";
|
| - }
|
| -
|
| - DeferredOutput _buildDeferredOutput(MainOutput mainOutput,
|
| - Fragment fragment) {
|
| - DeferredOutput result = new DeferredOutput(
|
| - _outputFileName(fragment.name), fragment.name,
|
| - mainOutput,
|
| - _buildLibraries(fragment),
|
| - _buildStaticNonFinalFields(fragment),
|
| - _buildStaticLazilyInitializedFields(fragment),
|
| - _buildConstants(fragment));
|
| - _outputs[fragment.outputUnit] = result;
|
| - return result;
|
| - }
|
| -
|
| - List<Constant> _buildConstants(Fragment fragment) {
|
| - List<ConstantValue> constantValues =
|
| - _task.outputConstantLists[fragment.outputUnit];
|
| - if (constantValues == null) return const <Constant>[];
|
| - return constantValues.map((ConstantValue value) => _constants[value])
|
| - .toList(growable: false);
|
| - }
|
| -
|
| - List<StaticField> _buildStaticNonFinalFields(Fragment fragment) {
|
| - // TODO(floitsch): handle static non-final fields correctly with deferred
|
| - // libraries.
|
| - if (fragment != _registry.mainFragment) return const <StaticField>[];
|
| - Iterable<VariableElement> staticNonFinalFields =
|
| - backend.constants.getStaticNonFinalFieldsForEmission();
|
| - return Elements.sortedByPosition(staticNonFinalFields)
|
| - .map(_buildStaticField)
|
| - .toList(growable: false);
|
| - }
|
| -
|
| - StaticField _buildStaticField(Element element) {
|
| - JavaScriptConstantCompiler handler = backend.constants;
|
| - ConstantValue initialValue = handler.getInitialValueFor(element).value;
|
| - js.Expression code = _task.emitter.constantReference(initialValue);
|
| - String name = namer.getNameOfGlobalField(element);
|
| - bool isFinal = false;
|
| - bool isLazy = false;
|
| - return new StaticField(name, _registry.registerHolder(r'$'), code,
|
| - isFinal, isLazy);
|
| - }
|
| -
|
| - List<StaticField> _buildStaticLazilyInitializedFields(Fragment fragment) {
|
| - // TODO(floitsch): lazy fields should just be in their respective
|
| - // libraries.
|
| - if (fragment != _registry.mainFragment) return const <StaticField>[];
|
| -
|
| - JavaScriptConstantCompiler handler = backend.constants;
|
| - List<VariableElement> lazyFields =
|
| - handler.getLazilyInitializedFieldsForEmission();
|
| - return Elements.sortedByPosition(lazyFields)
|
| - .map(_buildLazyField)
|
| - .where((field) => field != null) // Happens when the field was unused.
|
| - .toList(growable: false);
|
| - }
|
| -
|
| - StaticField _buildLazyField(Element element) {
|
| - JavaScriptConstantCompiler handler = backend.constants;
|
| - js.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;
|
| -
|
| - String name = namer.getNameOfGlobalField(element);
|
| - bool isFinal = element.isFinal;
|
| - bool isLazy = true;
|
| - return new StaticField(name, _registry.registerHolder(r'$'), code,
|
| - isFinal, isLazy);
|
| - }
|
| -
|
| - List<Library> _buildLibraries(Fragment fragment) {
|
| - List<Library> libraries = new List<Library>(fragment.length);
|
| - int count = 0;
|
| - fragment.forEach((LibraryElement library, List<Element> elements) {
|
| - libraries[count++] = _buildLibrary(library, elements);
|
| - });
|
| - return libraries;
|
| - }
|
| -
|
| - // Note that a library-element may have multiple [Library]s, if it is split
|
| - // into multiple output units.
|
| - Library _buildLibrary(LibraryElement library, List<Element> elements) {
|
| - String uri = library.canonicalUri.toString();
|
| -
|
| - List<StaticMethod> statics = elements
|
| - .where((e) => e is FunctionElement).map(_buildStaticMethod).toList();
|
| -
|
| - statics.addAll(elements
|
| - .where((e) => e is FunctionElement)
|
| - .where((e) => universe.staticFunctionsNeedingGetter.contains(e))
|
| - .map(_buildStaticMethodTearOff));
|
| -
|
| - if (library == backend.interceptorsLibrary) {
|
| - statics.addAll(_generateGetInterceptorMethods());
|
| - statics.addAll(_generateOneShotInterceptors());
|
| - }
|
| -
|
| - List<Class> classes = elements
|
| - .where((e) => e is ClassElement)
|
| - .map(_buildClass)
|
| - .toList(growable: false);
|
| -
|
| - return new Library(uri, statics, classes);
|
| - }
|
| -
|
| - Class _buildClass(ClassElement element) {
|
| - bool isInstantiated =
|
| - _compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
|
| -
|
| - List<Method> methods = [];
|
| - List<InstanceField> fields = [];
|
| -
|
| - void visitMember(ClassElement enclosing, Element member) {
|
| - assert(invariant(element, member.isDeclaration));
|
| - assert(invariant(element, element == enclosing));
|
| -
|
| - if (Elements.isNonAbstractInstanceMember(member)) {
|
| - js.Expression code = backend.generatedCode[member];
|
| - // TODO(kasperl): Figure out under which conditions code is null.
|
| - if (code != null) methods.add(_buildMethod(member, code));
|
| - } else if (member.isField && !member.isStatic) {
|
| - fields.add(_buildInstanceField(member, enclosing));
|
| - }
|
| - }
|
| -
|
| - ClassElement implementation = element.implementation;
|
| - if (isInstantiated) {
|
| - implementation.forEachMember(visitMember, includeBackendMembers: true);
|
| - }
|
| - String name = namer.getNameOfClass(element);
|
| - String holderName = namer.globalObjectFor(element);
|
| - Holder holder = _registry.registerHolder(holderName);
|
| - Class result = new Class(name, holder, methods, fields);
|
| - _classes[element] = result;
|
| - return result;
|
| - }
|
| -
|
| - Method _buildMethod(FunctionElement element, js.Expression code) {
|
| - String name = namer.getNameOfInstanceMember(element);
|
| - return new Method(name, code);
|
| - }
|
| -
|
| - // The getInterceptor methods directly access the prototype of classes.
|
| - // We must evaluate these classes eagerly so that the prototype is
|
| - // accessible.
|
| - void _markEagerInterceptorClasses() {
|
| - Map<String, Set<ClassElement>> specializedGetInterceptors =
|
| - backend.specializedGetInterceptors;
|
| - for (Set<ClassElement> classes in specializedGetInterceptors.values) {
|
| - for (ClassElement element in classes) {
|
| - Class cls = _classes[element];
|
| - if (cls != null) cls.isEager = true;
|
| - }
|
| - }
|
| - }
|
| -
|
| - Iterable<StaticMethod> _generateGetInterceptorMethods() {
|
| - emitterTask.InterceptorStubGenerator stubGenerator =
|
| - new emitterTask.InterceptorStubGenerator(_compiler, namer, backend);
|
| -
|
| - String holderName = namer.globalObjectFor(backend.interceptorsLibrary);
|
| - Holder holder = _registry.registerHolder(holderName);
|
| -
|
| - Map<String, Set<ClassElement>> specializedGetInterceptors =
|
| - backend.specializedGetInterceptors;
|
| - List<String> names = specializedGetInterceptors.keys.toList()..sort();
|
| - return names.map((String name) {
|
| - Set<ClassElement> classes = specializedGetInterceptors[name];
|
| - js.Expression code = stubGenerator.generateGetInterceptorMethod(classes);
|
| - return new StaticMethod(name, holder, code);
|
| - });
|
| - }
|
| -
|
| - bool _fieldNeedsGetter(VariableElement field) {
|
| - assert(field.isField);
|
| - if (_fieldAccessNeverThrows(field)) return false;
|
| - return backend.shouldRetainGetter(field)
|
| - || _compiler.codegenWorld.hasInvokedGetter(field, _compiler.world);
|
| - }
|
| -
|
| - bool _fieldNeedsSetter(VariableElement field) {
|
| - assert(field.isField);
|
| - if (_fieldAccessNeverThrows(field)) return false;
|
| - return (!field.isFinal && !field.isConst)
|
| - && (backend.shouldRetainSetter(field)
|
| - || _compiler.codegenWorld.hasInvokedSetter(field, _compiler.world));
|
| - }
|
| -
|
| - // We never access a field in a closure (a captured variable) without knowing
|
| - // that it is there. Therefore we don't need to use a getter (that will throw
|
| - // if the getter method is missing), but can always access the field directly.
|
| - bool _fieldAccessNeverThrows(VariableElement field) {
|
| - return field is ClosureFieldElement;
|
| - }
|
| -
|
| - InstanceField _buildInstanceField(VariableElement field,
|
| - ClassElement holder) {
|
| - assert(invariant(field, field.isDeclaration));
|
| - String name = namer.fieldPropertyName(field);
|
| -
|
| - int getterFlags = 0;
|
| - if (_fieldNeedsGetter(field)) {
|
| - bool isIntercepted = backend.fieldHasInterceptedGetter(field);
|
| - if (isIntercepted) {
|
| - getterFlags += 2;
|
| - if (backend.isInterceptorClass(holder)) {
|
| - getterFlags += 1;
|
| - }
|
| - } else {
|
| - getterFlags = 1;
|
| - }
|
| - }
|
| -
|
| - int setterFlags = 0;
|
| - if (_fieldNeedsSetter(field)) {
|
| - bool isIntercepted = backend.fieldHasInterceptedSetter(field);
|
| - if (isIntercepted) {
|
| - setterFlags += 2;
|
| - if (backend.isInterceptorClass(holder)) {
|
| - setterFlags += 1;
|
| - }
|
| - } else {
|
| - setterFlags = 1;
|
| - }
|
| - }
|
| -
|
| - return new InstanceField(name, getterFlags, setterFlags);
|
| - }
|
| -
|
| - Iterable<StaticMethod> _generateOneShotInterceptors() {
|
| - emitterTask.InterceptorStubGenerator stubGenerator =
|
| - new emitterTask.InterceptorStubGenerator(_compiler, namer, backend);
|
| -
|
| - String holderName = namer.globalObjectFor(backend.interceptorsLibrary);
|
| - Holder holder = _registry.registerHolder(holderName);
|
| -
|
| - List<String> names = backend.oneShotInterceptors.keys.toList()..sort();
|
| - return names.map((String name) {
|
| - js.Expression code = stubGenerator.generateOneShotInterceptor(name);
|
| - return new StaticMethod(name, holder, code);
|
| - });
|
| - }
|
| -
|
| - StaticMethod _buildStaticMethod(FunctionElement element) {
|
| - String name = namer.getNameOfMember(element);
|
| - String holder = namer.globalObjectFor(element);
|
| - js.Expression code = backend.generatedCode[element];
|
| - return new StaticMethod(name, _registry.registerHolder(holder), code);
|
| - }
|
| -
|
| - StaticMethod _buildStaticMethodTearOff(FunctionElement element) {
|
| - String name = namer.getStaticClosureName(element);
|
| - String holder = namer.globalObjectFor(element);
|
| - // TODO(kasperl): This clearly doesn't work yet.
|
| - js.Expression code = js.string("<<unimplemented>>");
|
| - return new StaticMethod(name, _registry.registerHolder(holder), code);
|
| - }
|
| -
|
| - void _registerConstants(OutputUnit outputUnit,
|
| - List<ConstantValue> constantValues) {
|
| - if (constantValues == null) return;
|
| - for (ConstantValue constantValue in constantValues) {
|
| - assert(!_constants.containsKey(constantValue));
|
| - String name = namer.constantName(constantValue);
|
| - String constantObject = namer.globalObjectForConstant(constantValue);
|
| - Holder holder = _registry.registerHolder(constantObject);
|
| - Constant constant = new Constant(name, holder, constantValue);
|
| - _constants[constantValue] = constant;
|
| - };
|
| - }
|
| -}
|
|
|