Index: pkg/fletchc/lib/src/constructor_codegen.dart |
diff --git a/pkg/fletchc/lib/src/constructor_codegen.dart b/pkg/fletchc/lib/src/constructor_codegen.dart |
deleted file mode 100644 |
index 35973e0ae6b1e844cb8c1d02bcbacd04c0565069..0000000000000000000000000000000000000000 |
--- a/pkg/fletchc/lib/src/constructor_codegen.dart |
+++ /dev/null |
@@ -1,375 +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.constructor_codegen; |
- |
-import 'package:compiler/src/elements/elements.dart'; |
-import 'package:compiler/src/resolution/tree_elements.dart' show |
- TreeElements; |
-import 'package:compiler/src/tree/tree.dart'; |
-import 'package:compiler/src/universe/call_structure.dart' show |
- CallStructure; |
-import 'package:compiler/src/dart_types.dart'; |
- |
-import 'fletch_context.dart'; |
- |
-import 'fletch_function_builder.dart' show |
- FletchFunctionBuilder; |
- |
-import 'fletch_class_builder.dart' show |
- FletchClassBuilder; |
- |
-import 'closure_environment.dart'; |
- |
-import 'lazy_field_initializer_codegen.dart'; |
- |
-import 'codegen_visitor.dart'; |
- |
-import 'fletch_registry.dart' show |
- FletchRegistry; |
- |
-class ConstructorCodegen extends CodegenVisitor with FletchRegistryMixin { |
- final FletchRegistry registry; |
- |
- final FletchClassBuilder classBuilder; |
- |
- final Map<FieldElement, LocalValue> fieldScope = <FieldElement, LocalValue>{}; |
- |
- final List<ConstructorElement> constructors = <ConstructorElement>[]; |
- |
- ClosureEnvironment initializerClosureEnvironment; |
- |
- ConstructorCodegen(FletchFunctionBuilder functionBuilder, |
- FletchContext context, |
- TreeElements elements, |
- this.registry, |
- ClosureEnvironment closureEnvironment, |
- ConstructorElement constructor, |
- this.classBuilder) |
- : super(functionBuilder, context, elements, |
- closureEnvironment, constructor); |
- |
- ConstructorElement get constructor => element; |
- |
- BytecodeAssembler get assembler => functionBuilder.assembler; |
- |
- ClosureEnvironment get closureEnvironment { |
- if (initializerClosureEnvironment != null) { |
- return initializerClosureEnvironment; |
- } |
- return super.closureEnvironment; |
- } |
- |
- void compile() { |
- // Push all initial field values (including super-classes). |
- pushInitialFieldValues(classBuilder); |
- // The stack is now: |
- // Value for field-0 |
- // ... |
- // Value for field-n |
- // |
- FunctionSignature signature = constructor.functionSignature; |
- int parameterCount = signature.parameterCount; |
- |
- // Visit constructor and evaluate initializers and super calls. The |
- // arguments to the constructor are located before the return address. |
- inlineInitializers(constructor, -parameterCount - 1); |
- |
- handleAllocationAndBodyCall(); |
- } |
- |
- LazyFieldInitializerCodegen lazyFieldInitializerCodegenFor( |
- FletchFunctionBuilder function, |
- FieldElement field) { |
- TreeElements elements = field.resolvedAst.elements; |
- return new LazyFieldInitializerCodegen( |
- function, |
- context, |
- elements, |
- registry, |
- context.backend.createClosureEnvironment(field, elements), |
- field); |
- } |
- |
- void handleAllocationAndBodyCall() { |
- // TODO(ajohnsen): Let allocate take an offset to the field stack, so we |
- // don't have to copy all the fields? |
- // Copy all the fields to the end of the stack. |
- int fields = classBuilder.fields; |
- for (int i = 0; i < fields; i++) { |
- assembler.loadSlot(i); |
- } |
- |
- // The stack is now: |
- // Value for field-0 |
- // ... |
- // Value for field-n |
- // [super arguments] |
- // Value for field-0 |
- // ... |
- // Value for field-n |
- |
- // Create the actual instance. |
- int classConstant = functionBuilder.allocateConstantFromClass( |
- classBuilder.classId); |
- // TODO(ajohnsen): Set immutable for all-final classes. |
- assembler.allocate(classConstant, fields, immutable: element.isConst); |
- |
- // The stack is now: |
- // Value for field-0 |
- // ... |
- // Value for field-n |
- // [super arguments] |
- // instance |
- |
- // Call constructor bodies in reverse order. |
- for (int i = constructors.length - 1; i >= 0; i--) { |
- callConstructorBody(constructors[i]); |
- } |
- |
- // Return the instance. |
- assembler |
- ..ret() |
- ..methodEnd(); |
- } |
- |
- /** |
- * Visit [constructor] and inline initializers and super calls, recursively. |
- */ |
- void inlineInitializers( |
- ConstructorElement constructor, |
- int firstParameterSlot) { |
- if (checkCompileError(constructor) || |
- checkCompileError(constructor.enclosingClass)) { |
- return; |
- } |
- |
- if (constructors.indexOf(constructor) >= 0) { |
- internalError(constructor.node, |
- "Multiple visits to the same constructor"); |
- } |
- |
- if (constructor.isSynthesized) { |
- // If the constructor is implicit, invoke the defining constructor. |
- if (constructor.functionSignature.parameterCount == 0) { |
- ConstructorElement defining = constructor.definingConstructor; |
- int initSlot = assembler.stackSize; |
- loadArguments(defining, new NodeList.empty(), CallStructure.NO_ARGS); |
- inlineInitializers(defining, initSlot); |
- return; |
- } |
- |
- // Otherwise the constructor is synthesized in the context of mixin |
- // applications, use the defining constructor. |
- do { |
- constructor = constructor.definingConstructor; |
- } while (constructor.isSynthesized); |
- } |
- |
- constructors.add(constructor); |
- FunctionSignature signature = constructor.functionSignature; |
- int parameterIndex = 0; |
- |
- initializerElements = constructor.resolvedAst.elements; |
- initializerClosureEnvironment = context.backend.createClosureEnvironment( |
- constructor, initializerElements); |
- |
- // Visit parameters and add them to scope. Note the scope is the scope of |
- // locals, in VisitingCodegen. |
- signature.orderedForEachParameter((ParameterElement parameter) { |
- LocalValue value = firstParameterSlot < 0 |
- ? createLocalValueForParameter( |
- parameter, |
- parameterIndex, |
- isCapturedValueBoxed: false) |
- : createLocalValueFor( |
- parameter, |
- slot: firstParameterSlot + parameterIndex, |
- isCapturedValueBoxed: false); |
- scope[parameter] = value; |
- if (parameter.isInitializingFormal) { |
- // If it's a initializing formal, store the value into initial |
- // field value. |
- InitializingFormalElement formal = parameter; |
- value.load(assembler); |
- fieldScope[formal.fieldElement].store(assembler); |
- assembler.pop(); |
- } |
- parameterIndex++; |
- }); |
- |
- visitInitializers(constructor.node, null); |
- } |
- |
- void doFieldInitializerSet(Send node, FieldElement field) { |
- fieldScope[field].store(assembler); |
- applyVisitState(); |
- } |
- |
- // This is called for each initializer list assignment. |
- void visitFieldInitializer( |
- SendSet node, |
- FieldElement field, |
- Node initializer, |
- _) { |
- // We only want the value of the actual initializer, not the usual |
- // 'body'. |
- visitForValue(initializer); |
- doFieldInitializerSet(node, field); |
- } |
- |
- void visitSuperConstructorInvoke( |
- Send node, |
- ConstructorElement superConstructor, |
- InterfaceType type, |
- NodeList arguments, |
- CallStructure callStructure, |
- _) { |
- // Load all parameters to the constructor, onto the stack. |
- loadArguments(superConstructor, arguments, callStructure); |
- int initSlot = assembler.stackSize - |
- superConstructor.functionSignature.parameterCount; |
- var previousElements = initializerElements; |
- var previousClosureEnvironment = initializerClosureEnvironment; |
- inlineInitializers(superConstructor, initSlot); |
- initializerElements = previousElements; |
- initializerClosureEnvironment = previousClosureEnvironment; |
- } |
- |
- void visitThisConstructorInvoke( |
- Send node, |
- ConstructorElement thisConstructor, |
- NodeList arguments, |
- CallStructure callStructure, |
- _) { |
- // TODO(ajohnsen): Is this correct behavior? |
- thisConstructor = thisConstructor.implementation; |
- // Load all parameters to the constructor, onto the stack. |
- loadArguments(thisConstructor, arguments, callStructure); |
- int initSlot = assembler.stackSize - |
- thisConstructor.functionSignature.parameterCount; |
- inlineInitializers(thisConstructor, initSlot); |
- } |
- |
- void visitImplicitSuperConstructorInvoke( |
- FunctionExpression node, |
- ConstructorElement superConstructor, |
- InterfaceType type, |
- _) { |
- int initSlot = assembler.stackSize; |
- // Always load arguments, as the super-constructor may have optional |
- // parameters. |
- loadArguments( |
- superConstructor, new NodeList.empty(), CallStructure.NO_ARGS); |
- inlineInitializers(superConstructor, initSlot); |
- } |
- |
- /** |
- * Load the [arguments] for caling [constructor]. |
- * |
- * Return the number of arguments pushed onto the stack. |
- */ |
- int loadArguments( |
- ConstructorElement constructor, |
- NodeList arguments, |
- CallStructure callStructure) { |
- FunctionSignature signature = constructor.functionSignature; |
- if (!signature.hasOptionalParameters || |
- !signature.optionalParametersAreNamed || |
- callStructure.namedArgumentCount == 0) { |
- return loadPositionalArguments(arguments, signature, constructor.name); |
- } |
- |
- int argumentCount = callStructure.argumentCount; |
- int namedArgumentCount = callStructure.namedArgumentCount; |
- |
- Iterator<Node> it = arguments.iterator; |
- int unnamedArguments = argumentCount - namedArgumentCount; |
- for (int i = 0; i < unnamedArguments; i++) { |
- it.moveNext(); |
- visitForValue(it.current); |
- } |
- |
- bool directMatch = namedArgumentCount == signature.optionalParameterCount; |
- Map<String, int> namedArguments = <String, int>{}; |
- for (int i = 0; i < namedArgumentCount; i++) { |
- String name = callStructure.namedArguments[i]; |
- namedArguments[name] = assembler.stackSize; |
- it.moveNext(); |
- visitForValue(it.current); |
- if (signature.orderedOptionalParameters[i].name != name) { |
- directMatch = false; |
- } |
- } |
- if (directMatch) return argumentCount; |
- |
- // There was no direct match. Push all unnamed arguments and all named |
- // arguments that have already been evaluated, in signature order. |
- for (int i = 0; i < unnamedArguments; i++) { |
- assembler.loadLocal(argumentCount - 1); |
- } |
- |
- for (ParameterElement parameter in signature.orderedOptionalParameters) { |
- int slot = namedArguments[parameter.name]; |
- if (slot != null) { |
- assembler.loadSlot(slot); |
- } else { |
- doParameterInitializer(parameter); |
- } |
- } |
- |
- // Some parameters may have defaulted to default value, making the |
- // parameter count larger than the argument count. |
- return argumentCount + signature.parameterCount; |
- } |
- |
- void callConstructorBody(ConstructorElement constructor) { |
- FunctionExpression node = constructor.node; |
- if (node == null || node.body.asEmptyStatement() != null) return; |
- |
- int functionId = requireFunction(constructor.declaration).functionId; |
- int constructorId = |
- functionBuilder.allocateConstantFromFunction(functionId); |
- |
- FunctionSignature signature = constructor.functionSignature; |
- |
- // Prepare for constructor body invoke. |
- assembler.dup(); |
- signature.orderedForEachParameter((FormalElement parameter) { |
- // Boxed parameters are passed as boxed objects, not as the values |
- // contained within like we do for ordinary invokes |
- scope[parameter].loadRaw(assembler); |
- }); |
- |
- assembler |
- ..invokeStatic(constructorId, 1 + signature.parameterCount) |
- ..pop(); |
- } |
- |
- void pushInitialFieldValues(FletchClassBuilder classBuilder) { |
- if (classBuilder.hasSuperClass) { |
- pushInitialFieldValues(classBuilder.superclass); |
- } |
- int fieldIndex = classBuilder.superclassFields; |
- ClassElement classElement = classBuilder.element.implementation; |
- classElement.forEachInstanceField((_, FieldElement field) { |
- fieldScope[field] = new UnboxedLocalValue(fieldIndex++, field); |
- Expression initializer = field.initializer; |
- if (initializer == null) { |
- assembler.loadLiteralNull(); |
- } else { |
- // Create a LazyFieldInitializerCodegen for compiling the initializer. |
- // Note that we reuse the functionBuilder, to inline it into the |
- // constructor. |
- LazyFieldInitializerCodegen codegen = |
- lazyFieldInitializerCodegenFor(functionBuilder, field); |
- |
- // We only want the value of the actual initializer, not the usual |
- // 'body'. |
- codegen.visitForValue(initializer); |
- } |
- }); |
- assert(fieldIndex <= classBuilder.fields); |
- } |
-} |