| Index: pkg/compiler/lib/src/js_emitter/program_builder.dart
|
| diff --git a/pkg/compiler/lib/src/js_emitter/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder.dart
|
| deleted file mode 100644
|
| index 7aae9f9e93efe5d5d018ab839250f2269e6e2df0..0000000000000000000000000000000000000000
|
| --- a/pkg/compiler/lib/src/js_emitter/program_builder.dart
|
| +++ /dev/null
|
| @@ -1,769 +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 'js_emitter.dart' show computeMixinClass;
|
| -import 'model.dart';
|
| -
|
| -import '../common.dart';
|
| -import '../js/js.dart' as js;
|
| -
|
| -import '../js_backend/js_backend.dart' show
|
| - Namer,
|
| - JavaScriptBackend,
|
| - JavaScriptConstantCompiler;
|
| -
|
| -import 'js_emitter.dart' show
|
| - ClassStubGenerator,
|
| - CodeEmitterTask,
|
| - InterceptorStubGenerator,
|
| - MainCallStubGenerator,
|
| - ParameterStubGenerator,
|
| - RuntimeTypeGenerator,
|
| - TypeTestProperties;
|
| -
|
| -import '../elements/elements.dart' show ParameterElement, MethodElement;
|
| -
|
| -import '../universe/universe.dart' show Universe, TypeMaskSet;
|
| -import '../deferred_load.dart' show DeferredLoadTask, OutputUnit;
|
| -
|
| -part 'registry.dart';
|
| -
|
| -class ProgramBuilder {
|
| - final Compiler _compiler;
|
| - final Namer namer;
|
| - final CodeEmitterTask _task;
|
| -
|
| - final Registry _registry;
|
| -
|
| - /// True if the program should store function types in the metadata.
|
| - bool _storeFunctionTypesInMetadata = false;
|
| -
|
| - 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 [Fragment]. We need this to
|
| - /// generate the deferredLoadingMap (to know which hunks to load).
|
| - final Map<OutputUnit, Fragment> _outputs = <OutputUnit, Fragment>{};
|
| -
|
| - /// 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>{};
|
| -
|
| - Set<Class> _unneededNativeClasses;
|
| -
|
| - Program buildProgram({bool storeFunctionTypesInMetadata: false}) {
|
| - this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata;
|
| - // Note: In rare cases (mostly tests) output units can be empty. This
|
| - // happens when the deferred code is dead-code eliminated but we still need
|
| - // to check that the library has been loaded.
|
| - _compiler.deferredLoadTask.allOutputUnits.forEach(
|
| - _registry.registerOutputUnit);
|
| - _task.outputClassLists.forEach(_registry.registerElements);
|
| - _task.outputStaticLists.forEach(_registry.registerElements);
|
| - _task.outputConstantLists.forEach(_registerConstants);
|
| - _task.outputStaticNonFinalFieldLists.forEach(_registry.registerElements);
|
| -
|
| - // 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'$');
|
| -
|
| - // We need to run the native-preparation before we build the output. The
|
| - // preparation code, in turn needs the classes to be set up.
|
| - // We thus build the classes before building their containers.
|
| - _task.outputClassLists.forEach((OutputUnit _, List<ClassElement> classes) {
|
| - classes.forEach(_buildClass);
|
| - });
|
| -
|
| - // 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]);
|
| - assert(c.superclass != null);
|
| - }
|
| - if (c is MixinApplication) {
|
| - c.setMixinClass(_classes[computeMixinClass(element)]);
|
| - assert(c.mixinClass != null);
|
| - }
|
| - });
|
| -
|
| - List<Class> nativeClasses = _task.nativeClassesAndSubclasses
|
| - .map((ClassElement classElement) => _classes[classElement])
|
| - .toList();
|
| -
|
| - _unneededNativeClasses =
|
| - _task.nativeEmitter.prepareNativeClasses(nativeClasses);
|
| -
|
| - MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap);
|
| - Iterable<Fragment> deferredFragments =
|
| - _registry.deferredLibrariesMap.map(_buildDeferredFragment);
|
| -
|
| - List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount);
|
| - fragments[0] = mainFragment;
|
| - fragments.setAll(1, deferredFragments);
|
| -
|
| - _markEagerClasses();
|
| -
|
| - List<Holder> holders = _registry.holders.toList(growable: false);
|
| -
|
| - bool needsNativeSupport = _compiler.enqueuer.codegen.nativeEnqueuer
|
| - .hasInstantiatedNativeClasses();
|
| -
|
| - assert(!needsNativeSupport || nativeClasses.isNotEmpty);
|
| -
|
| - List<js.TokenFinalizer> finalizers = [_task.metadataCollector];
|
| - if (backend.namer is js.TokenFinalizer) {
|
| - var namingFinalizer = backend.namer;
|
| - finalizers.add(namingFinalizer);
|
| - }
|
| -
|
| - return new Program(
|
| - fragments,
|
| - holders,
|
| - _buildLoadMap(),
|
| - _buildTypeToInterceptorMap(),
|
| - _task.metadataCollector,
|
| - finalizers,
|
| - needsNativeSupport: needsNativeSupport,
|
| - outputContainsConstantList: _task.outputContainsConstantList,
|
| - hasIsolateSupport: _compiler.hasIsolateSupport);
|
| - }
|
| -
|
| - void _markEagerClasses() {
|
| - _markEagerInterceptorClasses();
|
| - }
|
| -
|
| - /// Builds a map from loadId to outputs-to-load.
|
| - Map<String, List<Fragment>> _buildLoadMap() {
|
| - Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{};
|
| - _compiler.deferredLoadTask.hunksToLoad
|
| - .forEach((String loadId, List<OutputUnit> outputUnits) {
|
| - loadMap[loadId] = outputUnits
|
| - .map((OutputUnit unit) => _outputs[unit])
|
| - .toList(growable: false);
|
| - });
|
| - return loadMap;
|
| - }
|
| -
|
| - js.Expression _buildTypeToInterceptorMap() {
|
| - InterceptorStubGenerator stubGenerator =
|
| - new InterceptorStubGenerator(_compiler, namer, backend);
|
| - return stubGenerator.generateTypeToInterceptorMap();
|
| - }
|
| -
|
| - MainFragment _buildMainFragment(LibrariesMap librariesMap) {
|
| - // Construct the main output from the libraries and the registered holders.
|
| - MainFragment result = new MainFragment(
|
| - librariesMap.outputUnit,
|
| - "", // The empty string is the name for the main output file.
|
| - _buildInvokeMain(),
|
| - _buildLibraries(librariesMap),
|
| - _buildStaticNonFinalFields(librariesMap),
|
| - _buildStaticLazilyInitializedFields(librariesMap),
|
| - _buildConstants(librariesMap));
|
| - _outputs[librariesMap.outputUnit] = result;
|
| - return result;
|
| - }
|
| -
|
| - js.Statement _buildInvokeMain() {
|
| - MainCallStubGenerator generator =
|
| - new MainCallStubGenerator(_compiler, backend, backend.emitter);
|
| - return generator.generateInvokeMain();
|
| - }
|
| -
|
| - DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) {
|
| - DeferredFragment result = new DeferredFragment(
|
| - librariesMap.outputUnit,
|
| - backend.deferredPartFileName(librariesMap.name, addExtension: false),
|
| - librariesMap.name,
|
| - _buildLibraries(librariesMap),
|
| - _buildStaticNonFinalFields(librariesMap),
|
| - _buildStaticLazilyInitializedFields(librariesMap),
|
| - _buildConstants(librariesMap));
|
| - _outputs[librariesMap.outputUnit] = result;
|
| - return result;
|
| - }
|
| -
|
| - List<Constant> _buildConstants(LibrariesMap librariesMap) {
|
| - List<ConstantValue> constantValues =
|
| - _task.outputConstantLists[librariesMap.outputUnit];
|
| - if (constantValues == null) return const <Constant>[];
|
| - return constantValues.map((ConstantValue value) => _constants[value])
|
| - .toList(growable: false);
|
| - }
|
| -
|
| - List<StaticField> _buildStaticNonFinalFields(LibrariesMap librariesMap) {
|
| - List<VariableElement> staticNonFinalFields =
|
| - _task.outputStaticNonFinalFieldLists[librariesMap.outputUnit];
|
| - if (staticNonFinalFields == null) return const <StaticField>[];
|
| -
|
| - return staticNonFinalFields
|
| - .map(_buildStaticField)
|
| - .toList(growable: false);
|
| - }
|
| -
|
| - StaticField _buildStaticField(Element element) {
|
| - JavaScriptConstantCompiler handler = backend.constants;
|
| - ConstantValue initialValue = handler.getInitialValueFor(element);
|
| - // TODO(zarah): The holder should not be registered during building of
|
| - // a static field.
|
| - _registry.registerHolder(namer.globalObjectForConstant(initialValue));
|
| - js.Expression code = _task.emitter.constantReference(initialValue);
|
| - js.Name name = namer.globalPropertyName(element);
|
| - bool isFinal = false;
|
| - bool isLazy = false;
|
| -
|
| - // TODO(floitsch): we shouldn't update the registry in the middle of
|
| - // building a static field. (Note that the $ holder is already registered
|
| - // earlier).
|
| - return new StaticField(element,
|
| - name, _registry.registerHolder(r'$'), code,
|
| - isFinal, isLazy);
|
| - }
|
| -
|
| - List<StaticField> _buildStaticLazilyInitializedFields(
|
| - LibrariesMap librariesMap) {
|
| - // TODO(floitsch): lazy fields should just be in their respective
|
| - // libraries.
|
| - if (librariesMap != _registry.mainLibrariesMap) {
|
| - 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) {
|
| - 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;
|
| -
|
| - js.Name name = namer.globalPropertyName(element);
|
| - bool isFinal = element.isFinal;
|
| - bool isLazy = true;
|
| - // TODO(floitsch): we shouldn't update the registry in the middle of
|
| - // building a static field. (Note that the $ holder is already registered
|
| - // earlier).
|
| - return new StaticField(element,
|
| - name, _registry.registerHolder(r'$'), code,
|
| - isFinal, isLazy);
|
| - }
|
| -
|
| - List<Library> _buildLibraries(LibrariesMap librariesMap) {
|
| - List<Library> libraries = new List<Library>(librariesMap.length);
|
| - int count = 0;
|
| - librariesMap.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();
|
| -
|
| - if (library == backend.interceptorsLibrary) {
|
| - statics.addAll(_generateGetInterceptorMethods());
|
| - statics.addAll(_generateOneShotInterceptors());
|
| - }
|
| -
|
| - List<Class> classes = elements
|
| - .where((e) => e is ClassElement)
|
| - .map((ClassElement classElement) => _classes[classElement])
|
| - .where((Class cls) =>
|
| - !cls.isNative || !_unneededNativeClasses.contains(cls))
|
| - .toList(growable: false);
|
| -
|
| - bool visitStatics = true;
|
| - List<Field> staticFieldsForReflection = _buildFields(library, visitStatics);
|
| -
|
| - return new Library(library, uri, statics, classes,
|
| - staticFieldsForReflection);
|
| - }
|
| -
|
| - /// HACK for Incremental Compilation.
|
| - ///
|
| - /// Returns a class that contains the fields of a class.
|
| - Class buildFieldsHackForIncrementalCompilation(ClassElement element) {
|
| - assert(_compiler.hasIncrementalSupport);
|
| -
|
| - List<Field> instanceFields = _buildFields(element, false);
|
| - js.Name name = namer.className(element);
|
| -
|
| - return new Class(
|
| - element, name, null, [], instanceFields, [], [], [], [], [], null,
|
| - isDirectlyInstantiated: true,
|
| - onlyForRti: false,
|
| - isNative: element.isNative);
|
| - }
|
| -
|
| - Class _buildClass(ClassElement element) {
|
| - bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element);
|
| -
|
| - List<Method> methods = [];
|
| - List<StubMethod> callStubs = <StubMethod>[];
|
| -
|
| - ClassStubGenerator classStubGenerator =
|
| - new ClassStubGenerator(_compiler, namer, backend);
|
| - RuntimeTypeGenerator runtimeTypeGenerator =
|
| - new RuntimeTypeGenerator(_compiler, _task, namer);
|
| -
|
| - void visitMember(ClassElement enclosing, Element member) {
|
| - assert(invariant(element, member.isDeclaration));
|
| - assert(invariant(element, element == enclosing));
|
| -
|
| - if (Elements.isNonAbstractInstanceMember(member)) {
|
| - // TODO(herhut): Remove once _buildMethod can no longer return null.
|
| - Method method = _buildMethod(member);
|
| - if (method != null) methods.add(method);
|
| - }
|
| - if (member.isGetter || member.isField) {
|
| - Map<Selector, TypeMaskSet> selectors =
|
| - _compiler.codegenWorld.invocationsByName(member.name);
|
| - if (selectors != null && !selectors.isEmpty) {
|
| -
|
| - Map<js.Name, js.Expression> callStubsForMember =
|
| - classStubGenerator.generateCallStubsForGetter(member, selectors);
|
| - callStubsForMember.forEach((js.Name name, js.Expression code) {
|
| - callStubs.add(_buildStubMethod(name, code, element: member));
|
| - });
|
| - }
|
| - }
|
| - }
|
| -
|
| - List<StubMethod> typeVariableReaderStubs =
|
| - runtimeTypeGenerator.generateTypeVariableReaderStubs(element);
|
| -
|
| - List<StubMethod> noSuchMethodStubs = <StubMethod>[];
|
| - if (backend.enabledNoSuchMethod && element == _compiler.objectClass) {
|
| - Map<js.Name, Selector> selectors =
|
| - classStubGenerator.computeSelectorsForNsmHandlers();
|
| - selectors.forEach((js.Name name, Selector selector) {
|
| - noSuchMethodStubs
|
| - .add(classStubGenerator.generateStubForNoSuchMethod(name,
|
| - selector));
|
| - });
|
| - }
|
| -
|
| - if (element == backend.closureClass) {
|
| - // We add a special getter here to allow for tearing off a closure from
|
| - // itself.
|
| - js.Name name = namer.getterForMember(Selector.CALL_NAME);
|
| - js.Fun function = js.js('function() { return this; }');
|
| - callStubs.add(_buildStubMethod(name, function));
|
| - }
|
| -
|
| - ClassElement implementation = element.implementation;
|
| -
|
| - // MixinApplications run through the members of their mixin. Here, we are
|
| - // only interested in direct members.
|
| - if (!onlyForRti && !element.isMixinApplication) {
|
| - implementation.forEachMember(visitMember, includeBackendMembers: true);
|
| - }
|
| -
|
| - List<Field> instanceFields =
|
| - onlyForRti ? const <Field>[] : _buildFields(element, false);
|
| - List<Field> staticFieldsForReflection =
|
| - onlyForRti ? const <Field>[] : _buildFields(element, true);
|
| -
|
| - TypeTestProperties typeTests =
|
| - runtimeTypeGenerator.generateIsTests(
|
| - element,
|
| - storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata);
|
| -
|
| - List<StubMethod> isChecks = <StubMethod>[];
|
| - typeTests.properties.forEach((js.Name name, js.Node code) {
|
| - isChecks.add(_buildStubMethod(name, code));
|
| - });
|
| -
|
| - js.Name name = namer.className(element);
|
| - String holderName = namer.globalObjectFor(element);
|
| - // TODO(floitsch): we shouldn't update the registry in the middle of
|
| - // building a class.
|
| - Holder holder = _registry.registerHolder(holderName);
|
| - bool isInstantiated =
|
| - _compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
|
| -
|
| - Class result;
|
| - if (element.isMixinApplication && !onlyForRti) {
|
| - assert(!element.isNative);
|
| - assert(methods.isEmpty);
|
| -
|
| - result = new MixinApplication(element,
|
| - name, holder,
|
| - instanceFields,
|
| - staticFieldsForReflection,
|
| - callStubs,
|
| - typeVariableReaderStubs,
|
| - isChecks,
|
| - typeTests.functionTypeIndex,
|
| - isDirectlyInstantiated: isInstantiated,
|
| - onlyForRti: onlyForRti);
|
| - } else {
|
| - result = new Class(element,
|
| - name, holder, methods, instanceFields,
|
| - staticFieldsForReflection,
|
| - callStubs,
|
| - typeVariableReaderStubs,
|
| - noSuchMethodStubs,
|
| - isChecks,
|
| - typeTests.functionTypeIndex,
|
| - isDirectlyInstantiated: isInstantiated,
|
| - onlyForRti: onlyForRti,
|
| - isNative: element.isNative);
|
| - }
|
| - _classes[element] = result;
|
| - return result;
|
| - }
|
| -
|
| - bool _methodNeedsStubs(FunctionElement method) {
|
| - return !method.functionSignature.optionalParameters.isEmpty;
|
| - }
|
| -
|
| - bool _methodCanBeReflected(FunctionElement method) {
|
| - return backend.isAccessibleByReflection(method) ||
|
| - // During incremental compilation, we have to assume that reflection
|
| - // *might* get enabled.
|
| - _compiler.hasIncrementalSupport;
|
| - }
|
| -
|
| - bool _methodCanBeApplied(FunctionElement method) {
|
| - return _compiler.enabledFunctionApply &&
|
| - _compiler.world.getMightBePassedToApply(method);
|
| - }
|
| -
|
| - // TODO(herhut): Refactor incremental compilation and remove method.
|
| - Method buildMethodHackForIncrementalCompilation(FunctionElement element) {
|
| - assert(_compiler.hasIncrementalSupport);
|
| - if (element.isInstanceMember) {
|
| - return _buildMethod(element);
|
| - } else {
|
| - return _buildStaticMethod(element);
|
| - }
|
| - }
|
| -
|
| - /* Map | List */ _computeParameterDefaultValues(FunctionSignature signature) {
|
| - var /* Map | List */ optionalParameterDefaultValues;
|
| - if (signature.optionalParametersAreNamed) {
|
| - optionalParameterDefaultValues = new Map<String, ConstantValue>();
|
| - signature.forEachOptionalParameter((ParameterElement parameter) {
|
| - ConstantValue def =
|
| - backend.constants.getConstantValueForVariable(parameter);
|
| - optionalParameterDefaultValues[parameter.name] = def;
|
| - });
|
| - } else {
|
| - optionalParameterDefaultValues = <ConstantValue>[];
|
| - signature.forEachOptionalParameter((ParameterElement parameter) {
|
| - ConstantValue def =
|
| - backend.constants.getConstantValueForVariable(parameter);
|
| - optionalParameterDefaultValues.add(def);
|
| - });
|
| - }
|
| - return optionalParameterDefaultValues;
|
| - }
|
| -
|
| - DartMethod _buildMethod(MethodElement element) {
|
| - js.Name name = namer.methodPropertyName(element);
|
| - js.Expression code = backend.generatedCode[element];
|
| -
|
| - // TODO(kasperl): Figure out under which conditions code is null.
|
| - if (code == null) return null;
|
| -
|
| - bool canTearOff = false;
|
| - js.Name tearOffName;
|
| - bool isClosure = false;
|
| - bool isNotApplyTarget = !element.isFunction || element.isAccessor;
|
| -
|
| - bool canBeReflected = _methodCanBeReflected(element);
|
| - bool canBeApplied = _methodCanBeApplied(element);
|
| -
|
| - js.Name aliasName = backend.isAliasedSuperMember(element)
|
| - ? namer.aliasedSuperMemberPropertyName(element)
|
| - : null;
|
| -
|
| - if (isNotApplyTarget) {
|
| - canTearOff = false;
|
| - } else {
|
| - if (element.enclosingClass.isClosure) {
|
| - canTearOff = false;
|
| - isClosure = true;
|
| - } else {
|
| - // Careful with operators.
|
| - canTearOff = universe.hasInvokedGetter(element, _compiler.world) ||
|
| - (canBeReflected && !element.isOperator);
|
| - assert(canTearOff ||
|
| - !universe.methodsNeedingSuperGetter.contains(element));
|
| - tearOffName = namer.getterForElement(element);
|
| - }
|
| - }
|
| -
|
| - if (canTearOff) {
|
| - assert(invariant(element, !element.isGenerativeConstructor));
|
| - assert(invariant(element, !element.isGenerativeConstructorBody));
|
| - assert(invariant(element, !element.isConstructor));
|
| - }
|
| -
|
| - js.Name callName = null;
|
| - if (canTearOff) {
|
| - Selector callSelector =
|
| - new Selector.fromElement(element).toCallSelector();
|
| - callName = namer.invocationName(callSelector);
|
| - }
|
| -
|
| - DartType memberType;
|
| - if (element.isGenerativeConstructorBody) {
|
| - // TODO(herhut): Why does this need to be normalized away? We never need
|
| - // this information anyway as they cannot be torn off or
|
| - // reflected.
|
| - var body = element;
|
| - memberType = body.constructor.type;
|
| - } else {
|
| - memberType = element.type;
|
| - }
|
| -
|
| - js.Expression functionType;
|
| - if (canTearOff || canBeReflected) {
|
| - OutputUnit outputUnit =
|
| - _compiler.deferredLoadTask.outputUnitForElement(element);
|
| - functionType = _generateFunctionType(memberType, outputUnit);
|
| - }
|
| -
|
| - int requiredParameterCount;
|
| - var /* List | Map */ optionalParameterDefaultValues;
|
| - if (canBeApplied || canBeReflected) {
|
| - FunctionSignature signature = element.functionSignature;
|
| - requiredParameterCount = signature.requiredParameterCount;
|
| - optionalParameterDefaultValues =
|
| - _computeParameterDefaultValues(signature);
|
| - }
|
| -
|
| - return new InstanceMethod(element, name, code,
|
| - _generateParameterStubs(element, canTearOff), callName,
|
| - needsTearOff: canTearOff, tearOffName: tearOffName,
|
| - isClosure: isClosure, aliasName: aliasName,
|
| - canBeApplied: canBeApplied, canBeReflected: canBeReflected,
|
| - requiredParameterCount: requiredParameterCount,
|
| - optionalParameterDefaultValues: optionalParameterDefaultValues,
|
| - functionType: functionType);
|
| - }
|
| -
|
| - js.Expression _generateFunctionType(DartType type, OutputUnit outputUnit) {
|
| - if (type.containsTypeVariables) {
|
| - js.Expression thisAccess = js.js(r'this.$receiver');
|
| - return backend.rti.getSignatureEncoding(type, thisAccess);
|
| - } else {
|
| - return backend.emitter.metadataCollector
|
| - .reifyTypeForOutputUnit(type, outputUnit);
|
| - }
|
| - }
|
| -
|
| - List<ParameterStubMethod> _generateParameterStubs(MethodElement element,
|
| - bool canTearOff) {
|
| -
|
| - if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[];
|
| -
|
| - ParameterStubGenerator generator =
|
| - new ParameterStubGenerator(_compiler, namer, backend);
|
| - return generator.generateParameterStubs(element, canTearOff: canTearOff);
|
| - }
|
| -
|
| - /// Builds a stub method.
|
| - ///
|
| - /// Stub methods may have an element that can be used for code-size
|
| - /// attribution.
|
| - Method _buildStubMethod(js.Name name, js.Expression code,
|
| - {Element element}) {
|
| - return new StubMethod(name, code, element: element);
|
| - }
|
| -
|
| - // The getInterceptor methods directly access the prototype of classes.
|
| - // We must evaluate these classes eagerly so that the prototype is
|
| - // accessible.
|
| - void _markEagerInterceptorClasses() {
|
| - Map<js.Name, 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<StaticStubMethod> _generateGetInterceptorMethods() {
|
| - InterceptorStubGenerator stubGenerator =
|
| - new InterceptorStubGenerator(_compiler, namer, backend);
|
| -
|
| - String holderName = namer.globalObjectFor(backend.interceptorsLibrary);
|
| - // TODO(floitsch): we shouldn't update the registry in the middle of
|
| - // generating the interceptor methods.
|
| - Holder holder = _registry.registerHolder(holderName);
|
| -
|
| - Map<js.Name, Set<ClassElement>> specializedGetInterceptors =
|
| - backend.specializedGetInterceptors;
|
| - List<js.Name> names = specializedGetInterceptors.keys.toList()..sort();
|
| - return names.map((js.Name name) {
|
| - Set<ClassElement> classes = specializedGetInterceptors[name];
|
| - js.Expression code = stubGenerator.generateGetInterceptorMethod(classes);
|
| - return new StaticStubMethod(name, holder, code);
|
| - });
|
| - }
|
| -
|
| - List<Field> _buildFields(Element holder, bool visitStatics) {
|
| - List<Field> fields = <Field>[];
|
| - _task.oldEmitter.classEmitter.visitFields(
|
| - holder, visitStatics, (VariableElement field,
|
| - js.Name name,
|
| - js.Name accessorName,
|
| - bool needsGetter,
|
| - bool needsSetter,
|
| - bool needsCheckedSetter) {
|
| - assert(invariant(field, field.isDeclaration));
|
| -
|
| - int getterFlags = 0;
|
| - if (needsGetter) {
|
| - if (visitStatics || !backend.fieldHasInterceptedGetter(field)) {
|
| - getterFlags = 1;
|
| - } else {
|
| - getterFlags += 2;
|
| - // TODO(sra): 'isInterceptorClass' might not be the correct test
|
| - // for methods forced to use the interceptor convention because
|
| - // the method's class was elsewhere mixed-in to an interceptor.
|
| - if (!backend.isInterceptorClass(holder)) {
|
| - getterFlags += 1;
|
| - }
|
| - }
|
| - }
|
| -
|
| - int setterFlags = 0;
|
| - if (needsSetter) {
|
| - if (visitStatics || !backend.fieldHasInterceptedSetter(field)) {
|
| - setterFlags = 1;
|
| - } else {
|
| - setterFlags += 2;
|
| - if (!backend.isInterceptorClass(holder)) {
|
| - setterFlags += 1;
|
| - }
|
| - }
|
| - }
|
| -
|
| - fields.add(new Field(field, name, accessorName,
|
| - getterFlags, setterFlags,
|
| - needsCheckedSetter));
|
| - });
|
| -
|
| - return fields;
|
| - }
|
| -
|
| - Iterable<StaticStubMethod> _generateOneShotInterceptors() {
|
| - InterceptorStubGenerator stubGenerator =
|
| - new InterceptorStubGenerator(_compiler, namer, backend);
|
| -
|
| - String holderName = namer.globalObjectFor(backend.interceptorsLibrary);
|
| - // TODO(floitsch): we shouldn't update the registry in the middle of
|
| - // generating the interceptor methods.
|
| - Holder holder = _registry.registerHolder(holderName);
|
| -
|
| - List<js.Name> names = backend.oneShotInterceptors.keys.toList()..sort();
|
| - return names.map((js.Name name) {
|
| - js.Expression code = stubGenerator.generateOneShotInterceptor(name);
|
| - return new StaticStubMethod(name, holder, code);
|
| - });
|
| - }
|
| -
|
| - StaticDartMethod _buildStaticMethod(FunctionElement element) {
|
| - js.Name name = namer.methodPropertyName(element);
|
| - String holder = namer.globalObjectFor(element);
|
| - js.Expression code = backend.generatedCode[element];
|
| -
|
| - bool isApplyTarget = !element.isConstructor && !element.isAccessor;
|
| - bool canBeApplied = _methodCanBeApplied(element);
|
| - bool canBeReflected = _methodCanBeReflected(element);
|
| -
|
| - bool needsTearOff = isApplyTarget &&
|
| - (canBeReflected ||
|
| - universe.staticFunctionsNeedingGetter.contains(element));
|
| -
|
| - js.Name tearOffName =
|
| - needsTearOff ? namer.staticClosureName(element) : null;
|
| -
|
| -
|
| - js.Name callName = null;
|
| - if (needsTearOff) {
|
| - Selector callSelector =
|
| - new Selector.fromElement(element).toCallSelector();
|
| - callName = namer.invocationName(callSelector);
|
| - }
|
| - js.Expression functionType;
|
| - DartType type = element.type;
|
| - if (needsTearOff || canBeReflected) {
|
| - OutputUnit outputUnit =
|
| - _compiler.deferredLoadTask.outputUnitForElement(element);
|
| - functionType = _generateFunctionType(type, outputUnit);
|
| - }
|
| -
|
| - int requiredParameterCount;
|
| - var /* List | Map */ optionalParameterDefaultValues;
|
| - if (canBeApplied || canBeReflected) {
|
| - FunctionSignature signature = element.functionSignature;
|
| - requiredParameterCount = signature.requiredParameterCount;
|
| - optionalParameterDefaultValues =
|
| - _computeParameterDefaultValues(signature);
|
| - }
|
| -
|
| - // TODO(floitsch): we shouldn't update the registry in the middle of
|
| - // building a static method.
|
| - return new StaticDartMethod(element,
|
| - name, _registry.registerHolder(holder), code,
|
| - _generateParameterStubs(element, needsTearOff),
|
| - callName,
|
| - needsTearOff: needsTearOff,
|
| - tearOffName: tearOffName,
|
| - canBeApplied: canBeApplied,
|
| - canBeReflected: canBeReflected,
|
| - requiredParameterCount: requiredParameterCount,
|
| - optionalParameterDefaultValues:
|
| - optionalParameterDefaultValues,
|
| - functionType: functionType);
|
| - }
|
| -
|
| - void _registerConstants(OutputUnit outputUnit,
|
| - Iterable<ConstantValue> constantValues) {
|
| - // `constantValues` is null if an outputUnit doesn't contain any constants.
|
| - if (constantValues == null) return;
|
| - for (ConstantValue constantValue in constantValues) {
|
| - _registry.registerConstant(outputUnit, constantValue);
|
| - assert(!_constants.containsKey(constantValue));
|
| - js.Name name = namer.constantName(constantValue);
|
| - String constantObject = namer.globalObjectForConstant(constantValue);
|
| - Holder holder = _registry.registerHolder(constantObject);
|
| - Constant constant = new Constant(name, holder, constantValue);
|
| - _constants[constantValue] = constant;
|
| - }
|
| - }
|
| -}
|
|
|