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

Unified Diff: pkg/fletchc/lib/src/fletch_backend.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 11 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
« no previous file with comments | « pkg/fletchc/lib/src/find_position_visitor.dart ('k') | pkg/fletchc/lib/src/fletch_class_builder.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/fletchc/lib/src/fletch_backend.dart
diff --git a/pkg/fletchc/lib/src/fletch_backend.dart b/pkg/fletchc/lib/src/fletch_backend.dart
deleted file mode 100644
index 9470a09cfa631f8c34db352e197cfcc1fdad0399..0000000000000000000000000000000000000000
--- a/pkg/fletchc/lib/src/fletch_backend.dart
+++ /dev/null
@@ -1,1788 +0,0 @@
-// Copyright (c) 2015, the Dartino 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.md file.
-
-library fletchc.fletch_backend;
-
-import 'dart:async' show
- Future;
-
-import 'dart:collection' show
- Queue;
-
-import 'package:compiler/src/common/backend_api.dart' show
- Backend,
- ImpactTransformer;
-
-import 'package:compiler/src/common/tasks.dart' show
- CompilerTask;
-
-import 'package:compiler/src/enqueue.dart' show
- Enqueuer,
- ResolutionEnqueuer;
-
-import 'package:compiler/src/diagnostics/messages.dart' show
- MessageKind;
-
-import 'package:compiler/src/diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
-
-import 'package:compiler/src/common/registry.dart' show
- Registry;
-
-import 'package:compiler/src/dart_types.dart' show
- DartType,
- InterfaceType;
-
-import 'package:compiler/src/tree/tree.dart' show
- DartString,
- EmptyStatement,
- Expression;
-
-import 'package:compiler/src/elements/elements.dart' show
- AbstractFieldElement,
- AstElement,
- ClassElement,
- ConstructorElement,
- Element,
- ExecutableElement,
- FieldElement,
- FormalElement,
- FunctionElement,
- FunctionSignature,
- FunctionTypedElement,
- LibraryElement,
- MemberElement,
- Name,
- ParameterElement,
- PublicName;
-
-import 'package:compiler/src/universe/selector.dart' show
- Selector;
-
-import 'package:compiler/src/universe/use.dart' show
- DynamicUse,
- StaticUse,
- TypeUse,
- TypeUseKind;
-
-import 'package:compiler/src/universe/call_structure.dart' show
- CallStructure;
-
-import 'package:compiler/src/common.dart' show
- Spannable;
-
-import 'package:compiler/src/elements/modelx.dart' show
- FunctionElementX;
-
-import 'package:compiler/src/dart_backend/dart_backend.dart' show
- DartConstantTask;
-
-import 'package:compiler/src/constants/constant_system.dart' show
- ConstantSystem;
-
-import 'package:compiler/src/compile_time_constants.dart' show
- BackendConstantEnvironment;
-
-import 'package:compiler/src/constants/values.dart' show
- ConstantValue,
- ConstructedConstantValue,
- FunctionConstantValue,
- ListConstantValue,
- MapConstantValue,
- StringConstantValue;
-
-import 'package:compiler/src/constants/expressions.dart' show
- ConstantExpression;
-
-import 'package:compiler/src/resolution/tree_elements.dart' show
- TreeElements;
-
-import 'package:compiler/src/library_loader.dart' show
- LibraryLoader;
-
-import 'package:persistent/persistent.dart' show
- PersistentMap;
-
-import 'fletch_function_builder.dart' show
- FletchFunctionBuilder;
-
-import 'fletch_class_builder.dart' show
- FletchClassBuilder;
-
-import 'fletch_system_builder.dart' show
- FletchSystemBuilder;
-
-import '../incremental_backend.dart' show
- IncrementalFletchBackend;
-
-import 'fletch_enqueuer.dart' show
- FletchEnqueueTask,
- shouldReportEnqueuingOfElement;
-
-import 'fletch_registry.dart' show
- ClosureKind,
- FletchRegistry;
-
-import 'diagnostic.dart' show
- throwInternalError;
-
-import 'package:compiler/src/common/names.dart' show
- Identifiers,
- Names;
-
-import 'package:compiler/src/universe/world_impact.dart' show
- TransformedWorldImpact,
- WorldImpact,
- WorldImpactBuilder;
-
-import 'class_debug_info.dart';
-import 'codegen_visitor.dart';
-import 'debug_info.dart';
-import 'debug_info_constructor_codegen.dart';
-import 'debug_info_function_codegen.dart';
-import 'debug_info_lazy_field_initializer_codegen.dart';
-import 'fletch_context.dart';
-import 'fletch_selector.dart';
-import 'function_codegen.dart';
-import 'lazy_field_initializer_codegen.dart';
-import 'constructor_codegen.dart';
-import 'closure_environment.dart';
-
-import '../bytecodes.dart';
-import '../vm_commands.dart';
-import '../fletch_system.dart';
-import 'package:compiler/src/common/resolution.dart';
-
-const FletchSystem BASE_FLETCH_SYSTEM = const FletchSystem(
- const PersistentMap<int, FletchFunction>(),
- const PersistentMap<Element, FletchFunction>(),
- const PersistentMap<ConstructorElement, FletchFunction>(),
- const PersistentMap<int, int>(),
- const PersistentMap<int, FletchClass>(),
- const PersistentMap<ClassElement, FletchClass>(),
- const PersistentMap<int, FletchConstant>(),
- const PersistentMap<ConstantValue, FletchConstant>(),
- const PersistentMap<int, String>(),
- const PersistentMap<int, int>(),
- const PersistentMap<int, int>(),
- const PersistentMap<ParameterStubSignature, FletchFunction>());
-
-class FletchBackend extends Backend
- implements IncrementalFletchBackend {
- static const String growableListName = '_GrowableList';
- static const String constantListName = '_ConstantList';
- static const String constantByteListName = '_ConstantByteList';
- static const String constantMapName = '_ConstantMap';
- static const String fletchNoSuchMethodErrorName = 'FletchNoSuchMethodError';
- static const String noSuchMethodName = '_noSuchMethod';
- static const String noSuchMethodTrampolineName = '_noSuchMethodTrampoline';
-
- final FletchContext context;
-
- final DartConstantTask constantCompilerTask;
-
- /// Constructors that need to have an initilizer compiled. See
- /// [compilePendingConstructorInitializers].
- final Queue<FletchFunctionBuilder> pendingConstructorInitializers =
- new Queue<FletchFunctionBuilder>();
-
- final Set<FunctionElement> externals = new Set<FunctionElement>();
-
- // TODO(ahe): This should be queried from World.
- final Map<ClassElement, Set<ClassElement>> directSubclasses =
- <ClassElement, Set<ClassElement>>{};
-
- /// Set of classes that have special meaning to the Fletch VM. They're
- /// created using [PushBuiltinClass] instead of [PushNewClass].
- // TODO(ahe): Move this to FletchSystem?
- final Set<ClassElement> builtinClasses = new Set<ClassElement>();
-
- // TODO(ahe): This should be invalidated by a new [FletchSystem].
- final Map<MemberElement, ClosureEnvironment> closureEnvironments =
- <MemberElement, ClosureEnvironment>{};
-
- // TODO(ahe): This should be moved to [FletchSystem].
- final Map<FunctionElement, FletchClassBuilder> closureClasses =
- <FunctionElement, FletchClassBuilder>{};
-
- // TODO(ahe): This should be moved to [FletchSystem].
- final Map<FieldElement, FletchFunctionBuilder> lazyFieldInitializers =
- <FieldElement, FletchFunctionBuilder>{};
-
- // TODO(ahe): This should be moved to [FletchSystem].
- Map<FletchClassBuilder, FletchFunctionBuilder> tearoffFunctions;
-
- FletchCompilerImplementation get compiler => super.compiler;
-
- LibraryElement fletchSystemLibrary;
- LibraryElement fletchFFILibrary;
- LibraryElement collectionLibrary;
- LibraryElement mathLibrary;
- LibraryElement get asyncLibrary => compiler.asyncLibrary;
- LibraryElement fletchLibrary;
-
- FunctionElement fletchSystemEntry;
-
- FunctionElement fletchExternalInvokeMain;
-
- FunctionElement fletchExternalYield;
-
- FunctionElement fletchExternalNativeError;
-
- FunctionElement fletchExternalCoroutineChange;
-
- FunctionElement fletchUnresolved;
- FunctionElement fletchCompileError;
-
- FletchClassBuilder compiledObjectClass;
-
- ClassElement smiClass;
- ClassElement mintClass;
- ClassElement growableListClass;
- ClassElement fletchNoSuchMethodErrorClass;
- ClassElement bigintClass;
- ClassElement uint32DigitsClass;
-
- FletchClassBuilder compiledClosureClass;
-
- /// Holds a reference to the class Coroutine if it exists.
- ClassElement coroutineClass;
-
- FletchSystemBuilder systemBuilder;
-
- final Set<FunctionElement> alwaysEnqueue = new Set<FunctionElement>();
-
- FletchImpactTransformer impactTransformer;
-
- FletchBackend(FletchCompilerImplementation compiler)
- : this.context = compiler.context,
- this.constantCompilerTask = new DartConstantTask(compiler),
- this.systemBuilder = new FletchSystemBuilder(BASE_FLETCH_SYSTEM),
- super(compiler) {
- this.impactTransformer = new FletchImpactTransformer(this);
- }
-
- void newSystemBuilder(FletchSystem predecessorSystem) {
- systemBuilder = new FletchSystemBuilder(predecessorSystem);
- }
-
- FletchClassBuilder registerClassElement(ClassElement element) {
- if (element == null) return null;
- assert(element.isDeclaration);
-
- FletchClassBuilder classBuilder =
- systemBuilder.lookupClassBuilderByElement(element);
- if (classBuilder != null) return classBuilder;
-
- directSubclasses[element] = new Set<ClassElement>();
- FletchClassBuilder superclass = registerClassElement(element.superclass);
- if (superclass != null) {
- Set<ClassElement> subclasses = directSubclasses[element.superclass];
- subclasses.add(element);
- }
- classBuilder = systemBuilder.newClassBuilder(
- element, superclass, builtinClasses.contains(element));
-
- // TODO(ajohnsen): Currently, the FletchRegistry does not enqueue fields.
- // This is a workaround, where we basically add getters for all fields.
- classBuilder.updateImplicitAccessors(this);
-
- Element callMember = element.lookupLocalMember(Identifiers.call);
- if (callMember != null && callMember.isFunction) {
- FunctionElement function = callMember;
- classBuilder.createIsFunctionEntry(
- this, function.functionSignature.parameterCount);
- }
- return classBuilder;
- }
-
- FletchClassBuilder createCallableStubClass(
- int fields, int arity, FletchClassBuilder superclass) {
- FletchClassBuilder classBuilder = systemBuilder.newClassBuilder(
- null, superclass, false, extraFields: fields);
- classBuilder.createIsFunctionEntry(this, arity);
- return classBuilder;
- }
-
- List<CompilerTask> get tasks => <CompilerTask>[];
-
- ConstantSystem get constantSystem {
- return constantCompilerTask.constantCompiler.constantSystem;
- }
-
- BackendConstantEnvironment get constants => constantCompilerTask;
-
- bool classNeedsRti(ClassElement cls) => false;
-
- bool methodNeedsRti(FunctionElement function) => false;
-
- void enqueueHelpers(ResolutionEnqueuer world, Registry incomingRegistry) {
- FletchRegistry registry = new FletchRegistry(compiler);
- compiler.patchAnnotationClass = patchAnnotationClass;
-
- bool hasMissingHelpers = false;
- loadHelperMethods((String name) {
- LibraryElement library = fletchSystemLibrary;
- Element helper = library.findLocal(name);
- // TODO(ahe): Make it cleaner.
- if (helper != null && helper.isAbstractField) {
- AbstractFieldElement abstractField = helper;
- helper = abstractField.getter;
- }
- if (helper == null) {
- hasMissingHelpers = true;
- compiler.reporter.reportErrorMessage(
- library, MessageKind.GENERIC,
- {'text': "Required implementation method '$name' not found."});
- }
- return helper;
- });
- if (hasMissingHelpers) {
- throwInternalError(
- "Some implementation methods are missing, see details above");
- }
- world.registerStaticUse(
- new StaticUse.staticInvoke(fletchCompileError, CallStructure.ONE_ARG));
- world.registerStaticUse(
- new StaticUse.staticInvoke(fletchSystemEntry, CallStructure.ONE_ARG));
- world.registerStaticUse(
- new StaticUse.staticInvoke(fletchUnresolved, CallStructure.ONE_ARG));
-
- loadHelperClasses((
- String name,
- LibraryElement library,
- {bool builtin: false}) {
- var classImpl = library.findLocal(name);
- if (classImpl == null) classImpl = library.implementation.find(name);
- if (classImpl == null) {
- compiler.reporter.reportErrorMessage(
- library, MessageKind.GENERIC,
- {'text': "Required implementation class '$name' not found."});
- hasMissingHelpers = true;
- return null;
- }
- if (hasMissingHelpers) return null;
- if (builtin) builtinClasses.add(classImpl);
- {
- // TODO(ahe): Register in ResolutionCallbacks. The lines in this block
- // should not happen at this point in time.
- classImpl.ensureResolved(compiler.resolution);
- world.registerInstantiatedType(classImpl.rawType);
- // TODO(ahe): This is a hack to let both the world and the codegen know
- // about the instantiated type.
- registry.registerInstantiatedType(classImpl.rawType);
- }
- return registerClassElement(classImpl);
- });
- if (hasMissingHelpers) {
- throwInternalError(
- "Some implementation classes are missing, see details above");
- }
-
- // Register list constructors to world.
- // TODO(ahe): Register growableListClass through ResolutionCallbacks.
- growableListClass.constructors.forEach((Element element) {
- world.registerStaticUse(new StaticUse.constructorInvoke(element, null));
- });
-
- // TODO(ajohnsen): Remove? String interpolation does not enqueue '+'.
- // Investigate what else it may enqueue, could be StringBuilder, and then
- // consider using that instead.
- world.registerDynamicUse(
- new DynamicUse(new Selector.binaryOperator('+'), null));
-
- world.registerDynamicUse(new DynamicUse(
- new Selector.call(new PublicName('add'), CallStructure.ONE_ARG), null));
-
- alwaysEnqueue.add(
- compiler.coreClasses.objectClass.implementation.lookupLocalMember(
- noSuchMethodTrampolineName));
- alwaysEnqueue.add(
- compiler.coreClasses.objectClass.implementation.lookupLocalMember(
- noSuchMethodName));
-
- if (coroutineClass != null) {
- builtinClasses.add(coroutineClass);
- alwaysEnqueue.add(coroutineClass.lookupLocalMember("_coroutineStart"));
- }
-
- for (FunctionElement element in alwaysEnqueue) {
- world.registerStaticUse(new StaticUse.foreignUse(element));
- }
- }
-
- void loadHelperMethods(
- FunctionElement findHelper(String name)) {
-
- FunctionElement findExternal(String name) {
- FunctionElement helper = findHelper(name);
- if (helper != null) externals.add(helper);
- return helper;
- }
-
- fletchSystemEntry = findHelper('entry');
- fletchExternalInvokeMain = findExternal('invokeMain');
- fletchExternalYield = findExternal('yield');
- fletchExternalCoroutineChange = findExternal('coroutineChange');
- fletchExternalNativeError = findExternal('nativeError');
- fletchUnresolved = findExternal('unresolved');
- fletchCompileError = findExternal('compileError');
- }
-
- void loadHelperClasses(
- FletchClassBuilder loadClass(
- String name,
- LibraryElement library,
- {bool builtin})) {
- compiledObjectClass =
- loadClass("Object", compiler.coreLibrary, builtin: true);
- compiledClosureClass =
- loadClass("_TearOffClosure", compiler.coreLibrary, builtin: true);
- smiClass = loadClass("_Smi", compiler.coreLibrary, builtin: true)?.element;
- mintClass =
- loadClass("_Mint", compiler.coreLibrary, builtin: true)?.element;
- loadClass("_OneByteString", compiler.coreLibrary, builtin: true);
- loadClass("_TwoByteString", compiler.coreLibrary, builtin: true);
- // TODO(ahe): Register _ConstantList through ResolutionCallbacks.
- loadClass(constantListName, fletchSystemLibrary, builtin: true);
- loadClass(constantByteListName, fletchSystemLibrary, builtin: true);
- loadClass(constantMapName, fletchSystemLibrary, builtin: true);
- loadClass("_DoubleImpl", compiler.coreLibrary, builtin: true);
- loadClass("Null", compiler.coreLibrary, builtin: true);
- loadClass("bool", compiler.coreLibrary, builtin: true);
- loadClass("StackOverflowError", compiler.coreLibrary, builtin: true);
- loadClass("Port", fletchLibrary, builtin: true);
- loadClass("Process", fletchLibrary, builtin: true);
- loadClass("ProcessDeath", fletchLibrary, builtin: true);
- loadClass("ForeignMemory", fletchFFILibrary, builtin: true);
- if (context.enableBigint) {
- bigintClass = loadClass("_Bigint", compiler.coreLibrary)?.element;
- uint32DigitsClass =
- loadClass("_Uint32Digits", compiler.coreLibrary)?.element;
- }
- growableListClass =
- loadClass(growableListName, fletchSystemLibrary)?.element;
- fletchNoSuchMethodErrorClass =
- loadClass(fletchNoSuchMethodErrorName,
- fletchSystemLibrary,
- builtin: true)?.element;
-
- // This class is optional.
- coroutineClass = fletchSystemLibrary.implementation.find("Coroutine");
- if (coroutineClass != null) {
- coroutineClass.ensureResolved(compiler.resolution);
- }
- }
-
- void onElementResolved(Element element, TreeElements elements) {
- if (alwaysEnqueue.contains(element)) {
- var registry = new FletchRegistry(compiler);
- if (element.isStatic || element.isTopLevel) {
- registry.registerStaticUse(new StaticUse.foreignUse(element));
- } else {
- registry.registerDynamicUse(new Selector.fromElement(element));
- }
- }
- }
-
- ClassElement get intImplementation => smiClass;
-
- /// Class of annotations to mark patches in patch files.
- ///
- /// The patch parser (pkg/compiler/lib/src/patch_parser.dart). The patch
- /// parser looks for an annotation on the form "@patch", where "patch" is
- /// compile-time constant instance of [patchAnnotationClass].
- ClassElement get patchAnnotationClass {
- // TODO(ahe): Introduce a proper constant class to identify constants. For
- // now, we simply put "const patch = "patch";" in fletch._system.
- return super.stringImplementation;
- }
-
- FletchClassBuilder createClosureClass(
- FunctionElement closure,
- ClosureEnvironment closureEnvironment) {
- return closureClasses.putIfAbsent(closure, () {
- ClosureInfo info = closureEnvironment.closures[closure];
- int fields = info.free.length;
- if (info.isThisFree) fields++;
- return createCallableStubClass(
- fields,
- closure.functionSignature.parameterCount,
- compiledClosureClass);
- });
- }
-
- /**
- * Create a tearoff class for function [function].
- *
- * The class will have one method named 'call', accepting the same arguments
- * as [function]. The method will load the arguments received and statically
- * call [function] (essential a tail-call).
- *
- * If [function] is an instance member, the class will have one field, the
- * instance.
- */
- FletchClassBuilder createTearoffClass(FletchFunctionBase function) {
- FletchClassBuilder tearoffClass =
- systemBuilder.getTearoffClassBuilder(function, compiledClosureClass);
- if (tearoffClass != null) return tearoffClass;
- FunctionSignature signature = function.signature;
- bool hasThis = function.isInstanceMember;
- tearoffClass = createCallableStubClass(
- hasThis ? 1 : 0,
- signature.parameterCount,
- compiledClosureClass);
-
- FletchFunctionBuilder functionBuilder =
- systemBuilder.newTearOff(function, tearoffClass.classId);
-
- BytecodeAssembler assembler = functionBuilder.assembler;
- int argumentCount = signature.parameterCount;
- if (hasThis) {
- argumentCount++;
- // If the tearoff has a 'this' value, load it. It's the only field
- // in the tearoff class.
- assembler
- ..loadParameter(0)
- ..loadField(0);
- }
- for (int i = 0; i < signature.parameterCount; i++) {
- // The closure-class is at parameter index 0, so argument i is at
- // i + 1.
- assembler.loadParameter(i + 1);
- }
- int constId = functionBuilder.allocateConstantFromFunction(
- function.functionId);
- // TODO(ajohnsen): Create a tail-call bytecode, so we don't have to
- // load all the arguments.
- assembler
- ..invokeStatic(constId, argumentCount)
- ..ret()
- ..methodEnd();
-
- String symbol = context.getCallSymbol(signature);
- int id = context.getSymbolId(symbol);
- int fletchSelector = FletchSelector.encodeMethod(
- id,
- signature.parameterCount);
- tearoffClass.addToMethodTable(fletchSelector, functionBuilder);
-
- if (!function.isInstanceMember) return tearoffClass;
-
- ClassElement classElement =
- systemBuilder.lookupClassBuilder(function.memberOf).element;
- if (classElement == null) return tearoffClass;
-
- // Create == function that tests for equality.
- int isSelector = context.toFletchTearoffIsSelector(
- function.name,
- classElement);
- tearoffClass.addIsSelector(isSelector);
-
- FletchFunctionBuilder equal = systemBuilder.newFunctionBuilder(
- FletchFunctionKind.NORMAL,
- 2);
-
- BytecodeLabel isFalse = new BytecodeLabel();
- equal.assembler
- // First test for class. This ensures it's the exact function that
- // we expect.
- ..loadParameter(1)
- ..invokeTest(isSelector, 0)
- ..branchIfFalse(isFalse)
- // Then test that the receiver is identical.
- ..loadParameter(0)
- ..loadField(0)
- ..loadParameter(1)
- ..loadField(0)
- ..identicalNonNumeric()
- ..branchIfFalse(isFalse)
- ..loadLiteralTrue()
- ..ret()
- ..bind(isFalse)
- ..loadLiteralFalse()
- ..ret()
- ..methodEnd();
-
- id = context.getSymbolId("==");
- int equalsSelector = FletchSelector.encodeMethod(id, 1);
- tearoffClass.addToMethodTable(equalsSelector, equal);
-
- // Create hashCode getter. We simply add the object hashCode and the
- // method id of the tearoff'ed function.
- FletchFunctionBuilder hashCode = systemBuilder.newFunctionBuilder(
- FletchFunctionKind.ACCESSOR,
- 1);
-
- int hashCodeSelector = FletchSelector.encodeGetter(
- context.getSymbolId("hashCode"));
-
- // TODO(ajohnsen): Use plus, we plus is always enqueued. Consider using
- // xor when we have a way to enqueue it from here.
- int plusSelector = FletchSelector.encodeMethod(
- context.getSymbolId("+"), 1);
-
- hashCode.assembler
- ..loadParameter(0)
- ..loadField(0)
- ..invokeMethod(hashCodeSelector, 0)
- ..loadLiteral(function.functionId)
- ..invokeMethod(plusSelector, 1)
- ..ret()
- ..methodEnd();
-
- tearoffClass.addToMethodTable(hashCodeSelector, hashCode);
-
- return tearoffClass;
- }
-
- FletchFunctionBase getFunctionForElement(FunctionElement element) {
- assert(element.memberContext == element);
-
- FletchFunctionBase function =
- systemBuilder.lookupFunctionByElement(element);
- if (function != null) return function;
-
- return createFletchFunctionBuilder(element);
- }
-
- /// Get the constructor initializer function for [constructor]. The function
- /// will be created the first time it's called for [constructor].
- ///
- /// See [compilePendingConstructorInitializers] for an overview of
- /// constructor intializers and constructor bodies.
- FletchFunctionBase getConstructorInitializerFunction(
- ConstructorElement constructor) {
- assert(constructor.isDeclaration);
- constructor = constructor.implementation;
- FletchFunctionBase base =
- systemBuilder.lookupConstructorInitializerByElement(constructor);
- if (base != null) return base;
-
- FletchFunctionBuilder builder = systemBuilder.newConstructorInitializer(
- constructor);
- pendingConstructorInitializers.addFirst(builder);
-
- return builder;
- }
-
- FletchFunctionBuilder createFletchFunctionBuilder(FunctionElement function) {
- assert(function.memberContext == function);
-
- FletchClassBuilder holderClass;
- if (function.isInstanceMember || function.isGenerativeConstructor) {
- ClassElement enclosingClass = function.enclosingClass.declaration;
- holderClass = registerClassElement(enclosingClass);
- }
- return internalCreateFletchFunctionBuilder(
- function,
- function.name,
- holderClass);
- }
-
- FletchFunctionBuilder internalCreateFletchFunctionBuilder(
- FunctionElement function,
- String name,
- FletchClassBuilder holderClass) {
- FletchFunctionBuilder functionBuilder =
- systemBuilder.lookupFunctionBuilderByElement(function.declaration);
- if (functionBuilder != null) return functionBuilder;
-
- FunctionTypedElement implementation = function.implementation;
- int memberOf = holderClass != null ? holderClass.classId : null;
- return systemBuilder.newFunctionBuilderWithSignature(
- name,
- function,
- // Parameter initializers are expressed in the potential
- // implementation.
- implementation.functionSignature,
- memberOf,
- kind: function.isAccessor
- ? FletchFunctionKind.ACCESSOR
- : FletchFunctionKind.NORMAL,
- mapByElement: function.declaration);
- }
-
- ClassDebugInfo createClassDebugInfo(FletchClass klass) {
- return new ClassDebugInfo(klass);
- }
-
- DebugInfo createDebugInfo(
- FletchFunction function,
- FletchSystem currentSystem) {
- DebugInfo debugInfo = new DebugInfo(function);
- AstElement element = function.element;
- if (element == null) return debugInfo;
- List<Bytecode> expectedBytecodes = function.bytecodes;
- element = element.implementation;
- TreeElements elements = element.resolvedAst.elements;
- ClosureEnvironment closureEnvironment = createClosureEnvironment(
- element,
- elements);
- CodegenVisitor codegen;
- FletchFunctionBuilder builder =
- new FletchFunctionBuilder.fromFletchFunction(function);
- if (function.isLazyFieldInitializer) {
- codegen = new DebugInfoLazyFieldInitializerCodegen(
- debugInfo,
- builder,
- context,
- elements,
- closureEnvironment,
- element,
- compiler);
- } else if (function.isInitializerList) {
- ClassElement enclosingClass = element.enclosingClass;
- // TODO(ajohnsen): Don't depend on the class builder.
- FletchClassBuilder classBuilder =
- systemBuilder.lookupClassBuilderByElement(enclosingClass.declaration);
- codegen = new DebugInfoConstructorCodegen(
- debugInfo,
- builder,
- context,
- elements,
- closureEnvironment,
- element,
- classBuilder,
- compiler);
- } else {
- codegen = new DebugInfoFunctionCodegen(
- debugInfo,
- builder,
- context,
- elements,
- closureEnvironment,
- element,
- compiler);
- }
- if (isNative(element)) {
- compiler.reporter.withCurrentElement(element, () {
- codegenNativeFunction(element, codegen);
- });
- } else if (isExternal(element)) {
- compiler.reporter.withCurrentElement(element, () {
- codegenExternalFunction(element, codegen);
- });
- } else {
- compiler.reporter.withCurrentElement(element, () { codegen.compile(); });
- }
- // The debug codegen should generate the same bytecodes as the original
- // codegen. If that is not the case debug information will be useless.
- if (!Bytecode.identicalBytecodes(expectedBytecodes,
- codegen.assembler.bytecodes)) {
- throw 'Debug info code different from running code.';
- }
- return debugInfo;
- }
-
- codegen(_) {
- new UnsupportedError(
- "Method [codegen] not supported, use [compileElement] instead");
- }
-
- /// Invoked by [FletchEnqueuer] once per element that needs to be compiled.
- ///
- /// This is used to generate the bytecodes for [declaration].
- void compileElement(
- AstElement declaration,
- TreeElements treeElements,
- FletchRegistry registry) {
- AstElement element = declaration.implementation;
- compiler.reporter.withCurrentElement(element, () {
- assert(declaration.isDeclaration);
- context.compiler.reportVerboseInfo(element, 'Compiling $element');
- if (element.isFunction ||
- element.isGetter ||
- element.isSetter ||
- element.isGenerativeConstructor ||
- element.isFactoryConstructor) {
- // For a generative constructor, this means compile the constructor
- // body. See [compilePendingConstructorInitializers] for an overview of
- // how constructor initializers and constructor bodies are compiled.
- codegenFunction(element, treeElements, registry);
- } else if (element.isField) {
- context.compiler.reportVerboseInfo(
- element, "Asked to compile a field, but don't know how");
- } else {
- compiler.reporter.internalError(
- element, "Uninimplemented element kind: ${element.kind}");
- }
- });
- }
-
- /// Invoked by [FletchEnqueuer] once per [selector] that may invoke
- /// [declaration].
- ///
- /// This is used to generate stubs for [declaration].
- void compileElementUsage(
- AstElement declaration,
- Selector selector,
- TreeElements treeElements,
- FletchRegistry registry) {
- AstElement element = declaration.implementation;
- compiler.reporter.withCurrentElement(element, () {
- assert(declaration.isDeclaration);
- context.compiler.reportVerboseInfo(element, 'Compiling $element');
- if (!element.isInstanceMember && !isLocalFunction(element)) {
- // No stub needed. Optional arguments are handled at call-site.
- } else if (element.isFunction) {
- FletchFunctionBase function =
- systemBuilder.lookupFunctionByElement(element.declaration);
- CallStructure callStructure = selector.callStructure;
- FunctionSignature signature = function.signature;
- if (selector.isGetter) {
- if (shouldReportEnqueuingOfElement(compiler, element)) {
- context.compiler.reportVerboseInfo(
- element, 'Adding tear-off stub');
- }
- createTearoffGetterForFunction(
- function, isSpecialCallMethod: element.name == "call");
- } else if (selector.isCall &&
- callStructure.signatureApplies(signature) &&
- !isExactParameterMatch(signature, callStructure)) {
- if (shouldReportEnqueuingOfElement(compiler, element)) {
- context.compiler.reportVerboseInfo(
- element, 'Adding stub for $selector');
- }
- FletchFunctionBase stub = createParameterStub(function, selector);
- patchClassWithStub(
- stub, selector, function.memberOf, isLocalFunction(element));
- }
- } else if (element.isGetter || element.isSetter) {
- // No stub needed. If a getter returns a closure, the VM's
- // no-such-method handling will do the right thing.
- } else {
- context.compiler.reportVerboseInfo(
- element, "Asked to compile this, but don't know how");
- }
- });
- }
-
- /// Invoked by [FletchEnqueuer] once per `call` [selector] that may invoke
- /// [declaration] as an implicit closure (for example, a tear-off).
- ///
- /// This is used to generate parameter stubs for the closures.
- void compileClosurizationUsage(
- AstElement declaration,
- Selector selector,
- TreeElements treeElements,
- FletchRegistry registry,
- ClosureKind kind) {
- AstElement element = declaration.implementation;
- compiler.reporter.withCurrentElement(element, () {
- assert(declaration.isDeclaration);
- if (shouldReportEnqueuingOfElement(compiler, element)) {
- context.compiler.reportVerboseInfo(
- element, 'Need tear-off parameter stub $selector');
- }
- FletchFunctionBase function =
- systemBuilder.lookupFunctionByElement(element.declaration);
- if (function == null) {
- compiler.reporter.internalError(
- element, "Has no fletch function, but used as tear-off");
- }
- if (selector.isGetter) {
- // This is a special tear-off getter.
-
- // TODO(ahe): This code should probably use [kind] to detect the
- // various cases instead of [isLocalFunction] and looking at names.
-
- assert(selector.memberName == Names.CALL_NAME);
- if (isLocalFunction(element) ||
- memberName(element) == Names.CALL_NAME) {
- createTearoffGetterForFunction(
- function, isSpecialCallMethod: true);
- return;
- }
- int stub = systemBuilder.lookupTearOffById(function.functionId);
- if (stub == null) {
- compiler.reporter.internalError(
- element, "No tear-off stub to compile `call` tear-off");
- } else {
- function = systemBuilder.lookupFunction(stub);
- createTearoffGetterForFunction(function, isSpecialCallMethod: true);
- return;
- }
- }
- switch (kind) {
- case ClosureKind.tearOff:
- case ClosureKind.superTearOff:
- if (memberName(element) == Names.CALL_NAME) {
- // This is really a functionLikeTearOff.
- break;
- }
- // A tear-off has a corresponding stub in a closure class. Look up
- // that stub:
- int stub = systemBuilder.lookupTearOffById(function.functionId);
- if (stub == null) {
- compiler.reporter
- .internalError(element, "Couldn't find tear-off stub");
- } else {
- function = systemBuilder.lookupFunction(stub);
- }
- break;
-
- case ClosureKind.localFunction:
- // A local function already is a member of its closure class, and
- // doesn't have a stub.
- break;
-
- case ClosureKind.functionLike:
- case ClosureKind.functionLikeTearOff:
- compiler.reporter.internalError(element, "Unimplemented: $kind");
- break;
- }
-
- if (!isExactParameterMatch(function.signature, selector.callStructure)) {
- FletchFunctionBase stub = createParameterStub(function, selector);
- patchClassWithStub(stub, selector, function.memberOf, true);
- }
- });
- }
-
- void codegenFunction(
- FunctionElement function,
- TreeElements elements,
- FletchRegistry registry) {
- registry.registerStaticUse(new StaticUse.foreignUse(fletchSystemEntry));
-
- ClosureEnvironment closureEnvironment = createClosureEnvironment(
- function,
- elements);
-
- FletchFunctionBuilder functionBuilder;
-
- if (function.memberContext != function) {
- functionBuilder = internalCreateFletchFunctionBuilder(
- function,
- Identifiers.call,
- createClosureClass(function, closureEnvironment));
- } else {
- functionBuilder = createFletchFunctionBuilder(function);
- }
-
- FunctionCodegen codegen = new FunctionCodegen(
- functionBuilder,
- context,
- elements,
- registry,
- closureEnvironment,
- function);
-
- if (isNative(function)) {
- codegenNativeFunction(function, codegen);
- } else if (isExternal(function)) {
- codegenExternalFunction(function, codegen);
- } else {
- codegen.compile();
- }
-
- if (functionBuilder.isInstanceMember && !function.isGenerativeConstructor) {
- // Inject the function into the method table of the 'holderClass' class.
- // Note that while constructor bodies has a this argument, we don't inject
- // them into the method table.
- String symbol = context.getSymbolForFunction(
- functionBuilder.name,
- function.functionSignature,
- function.library);
- int id = context.getSymbolId(symbol);
- int arity = function.functionSignature.parameterCount;
- SelectorKind kind = SelectorKind.Method;
- if (function.isGetter) kind = SelectorKind.Getter;
- if (function.isSetter) kind = SelectorKind.Setter;
- int fletchSelector = FletchSelector.encode(id, kind, arity);
- FletchClassBuilder classBuilder =
- systemBuilder.lookupClassBuilder(functionBuilder.memberOf);
- classBuilder.addToMethodTable(fletchSelector, functionBuilder);
- // Inject method into all mixin usages.
- getMixinApplicationsOfClass(classBuilder).forEach((ClassElement usage) {
- FletchClassBuilder compiledUsage = registerClassElement(usage);
- compiledUsage.addToMethodTable(fletchSelector, functionBuilder);
- });
- }
-
- if (compiler.verbose) {
- context.compiler.reportVerboseInfo(
- function, functionBuilder.verboseToString());
- }
- }
-
- List<ClassElement> getMixinApplicationsOfClass(FletchClassBuilder builder) {
- ClassElement element = builder.element;
- if (element == null) return [];
- List<ClassElement> mixinUsage =
- compiler.world.mixinUsesOf(element).toList();
- for (int i = 0; i < mixinUsage.length; i++) {
- ClassElement usage = mixinUsage[i];
- // Recursively add mixin-usage of the current 'usage'.
- assert(!compiler.world.mixinUsesOf(usage).any(mixinUsage.contains));
- mixinUsage.addAll(compiler.world.mixinUsesOf(usage));
- }
- return mixinUsage;
- }
-
- void codegenNativeFunction(
- FunctionElement function,
- FunctionCodegen codegen) {
- String name = '.${function.name}';
-
- ClassElement enclosingClass = function.enclosingClass;
- if (enclosingClass != null) name = '${enclosingClass.name}$name';
-
- FletchNativeDescriptor descriptor = context.nativeDescriptors[name];
- if (descriptor == null) {
- throw "Unsupported native function: $name";
- }
-
- if (name == "Coroutine._coroutineNewStack") {
- // The static native method `Coroutine._coroutineNewStack` will invoke
- // the instance method `Coroutine._coroutineStart`.
- if (coroutineClass == null) {
- compiler.reporter.internalError(
- function, "required class [Coroutine] not found");
- }
- FunctionElement coroutineStart =
- coroutineClass.lookupLocalMember("_coroutineStart");
- Selector selector = new Selector.fromElement(coroutineStart);
- new FletchRegistry(compiler)
- ..registerDynamicUse(selector);
- } else if (name == "Process._spawn") {
- // The native method `Process._spawn` will do a closure invoke with 0, 1,
- // or 2 arguments.
- new FletchRegistry(compiler)
- ..registerDynamicUse(new Selector.callClosure(0))
- ..registerDynamicUse(new Selector.callClosure(1))
- ..registerDynamicUse(new Selector.callClosure(2));
- }
-
- int arity = codegen.assembler.functionArity;
- if (name == "Port.send" ||
- name == "Port._sendList" ||
- name == "Port._sendExit") {
- codegen.assembler.invokeNativeYield(arity, descriptor.index);
- } else {
- if (descriptor.isDetachable) {
- codegen.assembler.invokeDetachableNative(arity, descriptor.index);
- } else {
- codegen.assembler.invokeNative(arity, descriptor.index);
- }
- }
-
- EmptyStatement empty = function.node.body.asEmptyStatement();
- if (empty != null) {
- // A native method without a body.
- codegen.assembler
- ..emitThrow()
- ..methodEnd();
- } else {
- codegen.compile();
- }
- }
-
- void codegenExternalFunction(
- FunctionElement function,
- FunctionCodegen codegen) {
- if (function == fletchExternalYield) {
- codegenExternalYield(function, codegen);
- } else if (function == context.compiler.identicalFunction.implementation) {
- codegenIdentical(function, codegen);
- } else if (function == fletchExternalInvokeMain) {
- codegenExternalInvokeMain(function, codegen);
- } else if (function.name == noSuchMethodTrampolineName &&
- function.library == compiler.coreLibrary) {
- codegenExternalNoSuchMethodTrampoline(function, codegen);
- } else {
- DiagnosticMessage message = context.compiler.reporter
- .createMessage(function.node,
- MessageKind.GENERIC,
- {'text':
- 'External function "${function.name}" is not supported'});
- compiler.reporter.reportError(message);
- codegen
- ..doCompileError(message)
- ..assembler.ret()
- ..assembler.methodEnd();
- }
- }
-
- void codegenIdentical(
- FunctionElement function,
- FunctionCodegen codegen) {
- codegen.assembler
- ..loadParameter(0)
- ..loadParameter(1)
- ..identical()
- ..ret()
- ..methodEnd();
- }
-
- void codegenExternalYield(
- FunctionElement function,
- FunctionCodegen codegen) {
- codegen.assembler
- ..loadParameter(0)
- ..processYield()
- ..ret()
- ..methodEnd();
- }
-
- void codegenExternalInvokeMain(
- FunctionElement function,
- FunctionCodegen codegen) {
- compiler.reporter.internalError(
- function, "[codegenExternalInvokeMain] not implemented.");
- // TODO(ahe): This code shouldn't normally be called, only if invokeMain is
- // torn off. Perhaps we should just say we don't support that.
- }
-
- void codegenExternalNoSuchMethodTrampoline(
- FunctionElement function,
- FunctionCodegen codegen) {
- // NOTE: The number of arguments to the [noSuchMethodName] function must be
- // kept in sync with:
- // src/vm/interpreter.cc:HandleEnterNoSuchMethod
- int id = context.getSymbolId(
- context.mangleName(new Name(noSuchMethodName, compiler.coreLibrary)));
- int fletchSelector = FletchSelector.encodeMethod(id, 3);
- BytecodeLabel skipGetter = new BytecodeLabel();
- codegen.assembler
- ..enterNoSuchMethod(skipGetter)
- // First invoke the getter.
- ..invokeSelector(2)
- // Then invoke 'call', with the receiver being the result of the
- // previous invokeSelector.
- ..invokeSelector(1)
- ..exitNoSuchMethod()
- ..bind(skipGetter)
- ..invokeMethod(fletchSelector, 1)
- ..exitNoSuchMethod()
- ..methodEnd();
- }
-
- bool isNative(Element element) {
- if (element is FunctionElement) {
- for (var metadata in element.metadata) {
- // TODO(ahe): This code should ensure that @native resolves to precisely
- // the native variable in dart:fletch._system.
- if (metadata.constant == null) continue;
- ConstantValue value = context.getConstantValue(metadata.constant);
- if (!value.isString) continue;
- StringConstantValue stringValue = value;
- if (stringValue.toDartString().slowToString() != 'native') continue;
- return true;
- }
- }
- return false;
- }
-
- bool isExternal(Element element) {
- if (element is FunctionElement) return element.isExternal;
- return false;
- }
-
- bool get canHandleCompilationFailed => true;
-
- ClosureEnvironment createClosureEnvironment(
- ExecutableElement element,
- TreeElements elements) {
- MemberElement member = element.memberContext;
- return closureEnvironments.putIfAbsent(member, () {
- ClosureVisitor environment = new ClosureVisitor(member, elements);
- return environment.compute();
- });
- }
-
- void markFunctionConstantAsUsed(FunctionConstantValue value) {
- // TODO(ajohnsen): Use registry in CodegenVisitor to register the used
- // constants.
- FunctionElement function = value.element;
- createTearoffClass(createFletchFunctionBuilder(function));
- // Be sure to actually enqueue the function for compilation.
- FletchRegistry registry = new FletchRegistry(compiler);
- registry.registerStaticUse(new StaticUse.foreignUse(function));
- }
-
- FletchFunctionBase createParameterStub(
- FletchFunctionBase function,
- Selector selector) {
- CallStructure callStructure = selector.callStructure;
- assert(callStructure.signatureApplies(function.signature));
- ParameterStubSignature signature = new ParameterStubSignature(
- function.functionId, callStructure);
- FletchFunctionBase stub = systemBuilder.lookupParameterStub(signature);
- if (stub != null) return stub;
-
- int arity = selector.argumentCount;
- if (function.isInstanceMember) arity++;
-
- FletchFunctionBuilder builder = systemBuilder.newFunctionBuilder(
- FletchFunctionKind.PARAMETER_STUB,
- arity);
-
- BytecodeAssembler assembler = builder.assembler;
-
- void loadInitializerOrNull(ParameterElement parameter) {
- Expression initializer = parameter.initializer;
- if (initializer != null) {
- ConstantExpression expression = context.compileConstant(
- initializer,
- parameter.memberContext.resolvedAst.elements,
- isConst: true);
- int constId = builder.allocateConstant(
- context.getConstantValue(expression));
- assembler.loadConst(constId);
- } else {
- assembler.loadLiteralNull();
- }
- }
-
- // Load this.
- if (function.isInstanceMember) assembler.loadParameter(0);
-
- int index = function.isInstanceMember ? 1 : 0;
- function.signature.orderedForEachParameter((ParameterElement parameter) {
- if (!parameter.isOptional) {
- assembler.loadParameter(index);
- } else if (parameter.isNamed) {
- int parameterIndex = selector.namedArguments.indexOf(parameter.name);
- if (parameterIndex >= 0) {
- if (function.isInstanceMember) parameterIndex++;
- int position = selector.positionalArgumentCount + parameterIndex;
- assembler.loadParameter(position);
- } else {
- loadInitializerOrNull(parameter);
- }
- } else {
- if (index < arity) {
- assembler.loadParameter(index);
- } else {
- loadInitializerOrNull(parameter);
- }
- }
- index++;
- });
-
- // TODO(ajohnsen): We have to be extra careful when overriding a
- // method that takes optional arguments. We really should
- // enumerate all the stubs in the superclasses and make sure
- // they're overridden.
- int constId = builder.allocateConstantFromFunction(function.functionId);
- assembler
- ..invokeStatic(constId, index)
- ..ret()
- ..methodEnd();
-
- systemBuilder.registerParameterStub(signature, builder);
-
- return builder;
- }
-
- void patchClassWithStub(
- FletchFunctionBase stub,
- Selector selector,
- int classId,
- bool isClosureClass) {
- int fletchSelector = context.toFletchSelector(selector);
- FletchClassBuilder classBuilder = systemBuilder.lookupClassBuilder(classId);
- if (classBuilder == null) {
- if (isClosureClass) {
- classBuilder =
- systemBuilder.newPatchClassBuilder(classId, compiledClosureClass);
- } else {
- FletchClass klass = systemBuilder.lookupClass(classId);
- assert(klass.element != null);
- classBuilder = registerClassElement(klass.element);
- }
- }
- classBuilder.addToMethodTable(fletchSelector, stub);
-
- // Inject parameter stub into all mixin usages.
- getMixinApplicationsOfClass(classBuilder).forEach((ClassElement usage) {
- FletchClassBuilder classBuilder =
- systemBuilder.lookupClassBuilderByElement(usage);
- classBuilder.addToMethodTable(fletchSelector, stub);
- });
- }
-
- /// Create a tear-off getter for [function]. If [isSpecialCallMethod] is
- /// `true`, this is the special case for `someClosure.call` which should
- /// always return `someClosure`. This implies that when [isSpecialCallMethod]
- /// is true, we assume [function] is already a member of a closure class (or
- /// a class with a `call` method [ClosureKind.functionLike]) and that the
- /// getter should be added to that class.
- void createTearoffGetterForFunction(
- FletchFunctionBuilder function,
- {bool isSpecialCallMethod}) {
- if (isSpecialCallMethod == null) {
- throw new ArgumentError("isSpecialCallMethod");
- }
- FletchFunctionBuilder getter = systemBuilder.newFunctionBuilder(
- FletchFunctionKind.ACCESSOR,
- 1);
- // If the getter is of 'call', return the instance instead.
- if (isSpecialCallMethod) {
- getter.assembler
- ..loadParameter(0)
- ..ret()
- ..methodEnd();
- } else {
- FletchClassBuilder tearoffClass = createTearoffClass(function);
- int constId = getter.allocateConstantFromClass(tearoffClass.classId);
- getter.assembler
- ..loadParameter(0)
- ..allocate(constId, tearoffClass.fields)
- ..ret()
- ..methodEnd();
- }
- // If the name is private, we need the library.
- // Invariant: We only generate public stubs, e.g. 'call'.
- LibraryElement library;
- if (function.element != null) {
- library = function.element.library;
- }
- // TODO(sigurdm): Avoid allocating new name here.
- Name name = new Name(function.name, library);
- int fletchSelector = context.toFletchSelector(
- new Selector.getter(name));
- FletchClassBuilder classBuilder = systemBuilder.lookupClassBuilder(
- function.memberOf);
- classBuilder.addToMethodTable(fletchSelector, getter);
-
- // Inject getter into all mixin usages.
- getMixinApplicationsOfClass(classBuilder).forEach((ClassElement usage) {
- FletchClassBuilder classBuilder =
- systemBuilder.lookupClassBuilderByElement(usage);
- classBuilder.addToMethodTable(fletchSelector, getter);
- });
- }
-
- void compileTypeTest(ClassElement element, InterfaceType type) {
- assert(element.isDeclaration);
- int fletchSelector = context.toFletchIsSelector(type.element);
- FletchClassBuilder builder =
- systemBuilder.lookupClassBuilderByElement(element);
- if (builder != null) {
- context.compiler.reportVerboseInfo(
- element, 'Adding is-selector for $type');
- builder.addIsSelector(fletchSelector);
- }
- }
-
- int assembleProgram() => 0;
-
- FletchDelta computeDelta() {
-
- if (fletchSystemLibrary == null && compiler.compilationFailed) {
- // TODO(ahe): Ensure fletchSystemLibrary is not null.
- return null;
- }
-
- List<VmCommand> commands = <VmCommand>[
- const NewMap(MapId.methods),
- const NewMap(MapId.classes),
- const NewMap(MapId.constants),
- ];
-
- FletchSystem system = systemBuilder.computeSystem(context, commands);
-
- commands.add(const PushNewInteger(0));
- commands.add(new PushFromMap(
- MapId.methods,
- system.lookupFunctionByElement(fletchSystemEntry).functionId));
-
- return new FletchDelta(system, systemBuilder.predecessorSystem, commands);
- }
-
- bool enableCodegenWithErrorsIfSupported(Spannable spannable) {
- return true;
- }
-
- bool enableDeferredLoadingIfSupported(Spannable spannable, Registry registry) {
- return false;
- }
-
- bool registerDeferredLoading(Spannable node, Registry registry) {
- compiler.reporter.reportWarningMessage(
- node,
- MessageKind.GENERIC,
- {'text': "Deferred loading is not supported."});
- return false;
- }
-
- bool get supportsReflection => false;
-
- // TODO(sigurdm): Support async/await on the mobile platform.
- bool get supportsAsyncAwait {
- return !compiler.platformConfigUri.path.contains("embedded");
- }
-
- Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
- if (library.isPlatformLibrary) {
- String path = library.canonicalUri.path;
- switch(path) {
- case 'fletch._system':
- fletchSystemLibrary = library;
- break;
- case 'fletch.ffi':
- fletchFFILibrary = library;
- break;
- case 'fletch.collection':
- collectionLibrary = library;
- break;
- case 'math':
- mathLibrary = library;
- break;
- case 'fletch':
- fletchLibrary = library;
- break;
- }
-
- if (!library.isPatched) {
- // Apply patch, if any.
- Uri patchUri = compiler.resolvePatchUri(library.canonicalUri.path);
- if (patchUri != null) {
- return compiler.patchParser.patchLibrary(loader, patchUri, library);
- }
- }
- }
- return null;
- }
-
- bool isBackendLibrary(LibraryElement library) {
- return library == fletchSystemLibrary;
- }
-
- /// Return non-null to enable patching. Possible return values are 'new' and
- /// 'old'. Referring to old and new emitter. Since the new emitter is the
- /// future, we assume 'old' will go away. So it seems the best option for
- /// Fletch is 'new'.
- String get patchVersion => 'new';
-
- FunctionElement resolveExternalFunction(FunctionElement element) {
- if (element.isPatched) {
- FunctionElementX patch = element.patch;
- compiler.reporter.withCurrentElement(patch, () {
- patch.parseNode(compiler.parsing);
- patch.computeType(compiler.resolution);
- });
- element = patch;
- // TODO(ahe): Don't use ensureResolved (fix TODO in isNative instead).
- element.metadata.forEach((m) => m.ensureResolved(compiler.resolution));
- } else if (element.library == fletchSystemLibrary) {
- // Nothing needed for now.
- } else if (element.library == compiler.coreLibrary) {
- // Nothing needed for now.
- } else if (element.library == mathLibrary) {
- // Nothing needed for now.
- } else if (element.library == asyncLibrary) {
- // Nothing needed for now.
- } else if (element.library == fletchLibrary) {
- // Nothing needed for now.
- } else if (externals.contains(element)) {
- // Nothing needed for now.
- } else {
- compiler.reporter.reportErrorMessage(
- element, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
- }
- return element;
- }
-
- int compileLazyFieldInitializer(
- FieldElement field,
- FletchRegistry registry) {
- int index = context.getStaticFieldIndex(field, null);
-
- if (field.initializer == null) return index;
-
- if (lazyFieldInitializers.containsKey(field)) return index;
-
- FletchFunctionBuilder functionBuilder = systemBuilder.newFunctionBuilder(
- FletchFunctionKind.LAZY_FIELD_INITIALIZER,
- 0,
- name: "${field.name} lazy initializer",
- element: field);
- lazyFieldInitializers[field] = functionBuilder;
-
- TreeElements elements = field.resolvedAst.elements;
-
- ClosureEnvironment closureEnvironment = createClosureEnvironment(
- field,
- elements);
-
- LazyFieldInitializerCodegen codegen = new LazyFieldInitializerCodegen(
- functionBuilder,
- context,
- elements,
- registry,
- closureEnvironment,
- field);
-
- codegen.compile();
-
- return index;
- }
-
- /// Compiles the initializer part of a constructor.
- ///
- /// See [compilePendingConstructorInitializers] for an overview of how
- /// constructor initializer and bodies are compiled.
- void compileConstructorInitializer(FletchFunctionBuilder functionBuilder) {
- ConstructorElement constructor = functionBuilder.element;
- assert(constructor.isImplementation);
- compiler.reporter.withCurrentElement(constructor, () {
- assert(functionBuilder ==
- systemBuilder.lookupConstructorInitializerByElement(constructor));
- context.compiler.reportVerboseInfo(
- constructor, 'Compiling constructor initializer $constructor');
-
- TreeElements elements = constructor.resolvedAst.elements;
-
- // TODO(ahe): We shouldn't create a registry, but we have to as long as
- // the enqueuer doesn't support elements with more than one compilation
- // artifact.
- FletchRegistry registry = new FletchRegistry(compiler);
-
- FletchClassBuilder classBuilder =
- registerClassElement(constructor.enclosingClass.declaration);
-
- ClosureEnvironment closureEnvironment =
- createClosureEnvironment(constructor, elements);
-
- ConstructorCodegen codegen = new ConstructorCodegen(
- functionBuilder,
- context,
- elements,
- registry,
- closureEnvironment,
- constructor,
- classBuilder);
-
- codegen.compile();
-
- if (compiler.verbose) {
- context.compiler.reportVerboseInfo(
- constructor, functionBuilder.verboseToString());
- }
- });
- }
-
- /**
- * Generate a getter for field [fieldIndex].
- */
- int makeGetter(int fieldIndex) {
- return systemBuilder.getGetterByFieldIndex(fieldIndex);
- }
-
- /**
- * Generate a setter for field [fieldIndex].
- */
- int makeSetter(int fieldIndex) {
- return systemBuilder.getSetterByFieldIndex(fieldIndex);
- }
-
- void generateUnimplementedError(
- Spannable spannable,
- String reason,
- FletchFunctionBuilder function,
- {bool suppressHint: false}) {
- if (!suppressHint) {
- compiler.reporter.reportHintMessage(
- spannable, MessageKind.GENERIC, {'text': reason});
- }
- var constString = constantSystem.createString(
- new DartString.literal(reason));
- context.markConstantUsed(constString);
- function
- ..assembler.loadConst(function.allocateConstant(constString))
- ..assembler.emitThrow();
- }
-
- void forEachSubclassOf(ClassElement cls, void f(ClassElement cls)) {
- Queue<ClassElement> queue = new Queue<ClassElement>();
- queue.add(cls);
- while (queue.isNotEmpty) {
- ClassElement cls = queue.removeFirst();
- if (compiler.world.isInstantiated(cls.declaration)) {
- queue.addAll(compiler.world.strictSubclassesOf(cls));
- }
- f(cls);
- }
- }
-
- void newElement(Element element) {
- if (element.isField && element.isInstanceMember) {
- forEachSubclassOf(element.enclosingClass, (ClassElement cls) {
- FletchClassBuilder builder = registerClassElement(cls);
- builder.addField(element);
- });
- }
- }
-
- void replaceFunctionUsageElement(Element element, List<Element> users) {
- for (Element user in users) {
- systemBuilder.replaceUsage(user, element);
- }
- }
-
- void forgetElement(Element element) {
- // TODO(ahe): The front-end should remove the element from
- // elementsWithCompileTimeErrors.
- compiler.elementsWithCompileTimeErrors.remove(element);
- FletchFunctionBase function =
- systemBuilder.lookupFunctionByElement(element);
- if (function == null) return;
- systemBuilder.forgetFunction(function);
- }
-
- void removeField(FieldElement element) {
- if (!element.isInstanceMember) return;
- ClassElement enclosingClass = element.enclosingClass;
- forEachSubclassOf(enclosingClass, (ClassElement cls) {
- FletchClassBuilder builder = registerClassElement(cls);
- builder.removeField(element);
- });
- }
-
- void removeFunction(FunctionElement element) {
- FletchFunctionBase function =
- systemBuilder.lookupFunctionByElement(element);
- if (function == null) return;
- if (element.isInstanceMember) {
- ClassElement enclosingClass = element.enclosingClass;
- FletchClassBuilder builder = registerClassElement(enclosingClass);
- builder.removeFromMethodTable(function);
- }
- }
-
- /// Invoked during codegen enqueuing to compile constructor initializers.
- ///
- /// There's only one [Element] representing a constructor, but Fletch uses
- /// two different functions for implementing a constructor.
- ///
- /// The first function takes care of allocating the instance and initializing
- /// fields (called the constructor initializer), the other function
- /// implements the body of the constructor (what is between the curly
- /// braces). A constructor initializer never calls constructor initializers
- /// of a superclass. Instead field initializers from the superclass are
- /// inlined in the constructor initializer. The constructor initializer will
- /// call all the constructor bodies from superclasses in the correct order.
- ///
- /// The constructor bodies are basically special instance methods that can
- /// only be called from constructor initializers. Unlike constructor bodies,
- /// we only need constructor initializer for classes that are directly
- /// instantiated (excluding, for example, abstract classes).
- ///
- /// Given this, we compile constructor bodies when the normal enqueuer tells
- /// us to compile a generative constructor (see [codegen]), and track
- /// constructor initializers in a separate queue.
- void compilePendingConstructorInitializers() {
- while (pendingConstructorInitializers.isNotEmpty) {
- compileConstructorInitializer(
- pendingConstructorInitializers.removeLast());
- }
- }
-
- bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassElement> recentClasses) {
- if (enqueuer is! ResolutionEnqueuer) {
- compilePendingConstructorInitializers();
- }
- return true;
- }
-
- FletchEnqueueTask makeEnqueuer() => new FletchEnqueueTask(compiler);
-
- static bool isExactParameterMatch(
- FunctionSignature signature,
- CallStructure callStructure) {
- if (!callStructure.signatureApplies(signature)) {
- return false;
- }
- if (!signature.hasOptionalParameters) {
- // There are no optional parameters, and the signature applies, so this
- // is an exact match.
- return true;
- }
- if (!signature.optionalParametersAreNamed) {
- // The optional parameters aren't named which means that they are
- // optional positional parameters. So we have an exact match if the
- // number of parameters matches the number of arguments.
- return callStructure.argumentCount == signature.parameterCount;
- }
- // Otherwise, the optional parameters are named, and we have an exact match
- // if the named arguments in the call occur in the same order as the
- // parameters in the signature.
- if (callStructure.namedArguments.length !=
- signature.optionalParameterCount) {
- return false;
- }
- int index = 0;
- for (var parameter in signature.orderedOptionalParameters) {
- if (parameter.name != callStructure.namedArguments[index++]) return false;
- }
- return true;
- }
-
- static FletchBackend createInstance(FletchCompilerImplementation compiler) {
- return new FletchBackend(compiler);
- }
-
- Uri resolvePatchUri(String libraryName, Uri libraryRoot) {
- throw "Not implemented";
- }
-
-}
-
-class FletchImpactTransformer extends ImpactTransformer {
- final FletchBackend backend;
-
- FletchImpactTransformer(this.backend);
-
- @override
- WorldImpact transformResolutionImpact(ResolutionImpact worldImpact) {
- TransformedWorldImpact transformed =
- new TransformedWorldImpact(worldImpact);
-
- bool anyChange = false;
-
- if (worldImpact.constSymbolNames.isNotEmpty) {
- ClassElement symbolClass =
- backend.compiler.coreClasses.symbolClass.declaration;
- transformed.registerTypeUse(
- new TypeUse.instantiation(symbolClass.rawType));
- transformed.registerStaticUse(
- new StaticUse.foreignUse(
- symbolClass.lookupConstructor("")));
- anyChange = true;
- }
-
- for (MapLiteralUse mapLiteralUse in worldImpact.mapLiterals) {
- if (mapLiteralUse.isConstant) continue;
- transformed.registerTypeUse(
- new TypeUse.instantiation(backend.mapImplementation.rawType));
- transformed.registerStaticUse(
- new StaticUse.constructorInvoke(
- backend.mapImplementation.lookupConstructor(""),
- CallStructure.NO_ARGS));
- anyChange = true;
- }
- return anyChange ? transformed : worldImpact;
- }
-
- @override
- transformCodegenImpact(impact) => throw "unimplemented";
-}
-
-bool isLocalFunction(Element element) {
- if (!element.isFunction) return false;
- if (element is ExecutableElement) {
- return element.memberContext != element;
- }
- return false;
-}
-
-Name memberName(AstElement element) {
- if (isLocalFunction(element)) return null;
- MemberElement member = element;
- return member.memberName;
-}
« no previous file with comments | « pkg/fletchc/lib/src/find_position_visitor.dart ('k') | pkg/fletchc/lib/src/fletch_class_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698