| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE.md file. | |
| 4 | |
| 5 library fletchc.function_codegen; | |
| 6 | |
| 7 import 'package:compiler/src/resolution/tree_elements.dart' show | |
| 8 TreeElements; | |
| 9 | |
| 10 import 'package:compiler/src/elements/elements.dart'; | |
| 11 import 'package:compiler/src/tree/tree.dart'; | |
| 12 | |
| 13 import 'fletch_context.dart'; | |
| 14 | |
| 15 import 'fletch_function_builder.dart' show | |
| 16 FletchFunctionBuilder; | |
| 17 | |
| 18 import 'fletch_registry.dart' show | |
| 19 FletchRegistry; | |
| 20 | |
| 21 import 'closure_environment.dart'; | |
| 22 | |
| 23 import 'codegen_visitor.dart'; | |
| 24 | |
| 25 class FunctionCodegen extends CodegenVisitor with FletchRegistryMixin { | |
| 26 final FletchRegistry registry; | |
| 27 int setterResultSlot; | |
| 28 | |
| 29 FunctionCodegen(FletchFunctionBuilder functionBuilder, | |
| 30 FletchContext context, | |
| 31 TreeElements elements, | |
| 32 this.registry, | |
| 33 ClosureEnvironment closureEnvironment, | |
| 34 FunctionElement function) | |
| 35 : super(functionBuilder, context, elements, | |
| 36 closureEnvironment, function); | |
| 37 | |
| 38 FunctionElement get function => element; | |
| 39 | |
| 40 // If the function is a setter, push the argument to later be returned. | |
| 41 // TODO(ajohnsen): If the argument is semantically final, we don't have to | |
| 42 // do this. | |
| 43 bool get hasAssignmentSemantics => | |
| 44 function.isSetter || function.name == '[]='; | |
| 45 | |
| 46 void compile() { | |
| 47 if (checkCompileError(function)) { | |
| 48 assembler.methodEnd(); | |
| 49 return; | |
| 50 } | |
| 51 | |
| 52 ClassElement enclosing = function.enclosingClass; | |
| 53 // Generate implicit 'null' check for '==' functions. | |
| 54 if (enclosing != null && function.name == '==') { | |
| 55 BytecodeLabel notNull = new BytecodeLabel(); | |
| 56 assembler.loadParameter(1); | |
| 57 assembler.loadLiteralNull(); | |
| 58 assembler.identicalNonNumeric(); | |
| 59 assembler.branchIfFalse(notNull); | |
| 60 // TODO(ajohnsen): Consider creating an injected operator== into 'null', | |
| 61 // to avoid this extra check. | |
| 62 assembler.loadParameter(0); | |
| 63 assembler.loadLiteralNull(); | |
| 64 assembler.identicalNonNumeric(); | |
| 65 assembler.ret(); | |
| 66 assembler.bind(notNull); | |
| 67 } | |
| 68 | |
| 69 FunctionSignature functionSignature = function.functionSignature; | |
| 70 int parameterCount = functionSignature.parameterCount; | |
| 71 | |
| 72 if (hasAssignmentSemantics) { | |
| 73 setterResultSlot = assembler.stackSize; | |
| 74 // The result is always the last argument. | |
| 75 assembler.loadParameter(functionBuilder.arity - 1); | |
| 76 } | |
| 77 | |
| 78 // Skip 'this' if present. | |
| 79 int parameterIndex = functionBuilder.arity - parameterCount; | |
| 80 | |
| 81 functionSignature.orderedForEachParameter((ParameterElement parameter) { | |
| 82 // For constructors, the argument is passed as boxed (from the initializer | |
| 83 // inlining). | |
| 84 LocalValue value = createLocalValueForParameter( | |
| 85 parameter, | |
| 86 parameterIndex, | |
| 87 isCapturedValueBoxed: element.isGenerativeConstructor); | |
| 88 pushVariableDeclaration(value); | |
| 89 parameterIndex++; | |
| 90 }); | |
| 91 | |
| 92 ClosureInfo info = closureEnvironment.closures[function]; | |
| 93 if (info != null) { | |
| 94 int index = 0; | |
| 95 if (info.isThisFree) { | |
| 96 thisValue = new UnboxedLocalValue(assembler.stackSize, null); | |
| 97 assembler.loadParameter(0); | |
| 98 assembler.loadField(index++); | |
| 99 } | |
| 100 for (LocalElement local in info.free) { | |
| 101 pushVariableDeclaration(createLocalValueFor(local)); | |
| 102 // TODO(ajohnsen): Use a specialized helper for loading the closure. | |
| 103 assembler.loadParameter(0); | |
| 104 assembler.loadField(index++); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 FunctionExpression node = function.node; | |
| 109 if (node != null) { | |
| 110 node.body.accept(this); | |
| 111 } | |
| 112 | |
| 113 // Emit implicit 'return null' if no terminator is present. | |
| 114 if (!assembler.endsWithTerminator) generateImplicitReturn(node); | |
| 115 | |
| 116 assembler.methodEnd(); | |
| 117 } | |
| 118 | |
| 119 void generateImplicitReturn(FunctionExpression node) { | |
| 120 if (hasAssignmentSemantics) { | |
| 121 assembler.loadSlot(setterResultSlot); | |
| 122 assembler.ret(); | |
| 123 } else { | |
| 124 assembler.returnNull(); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void optionalReplaceResultValue() { | |
| 129 if (hasAssignmentSemantics) { | |
| 130 assembler.pop(); | |
| 131 assembler.loadSlot(setterResultSlot); | |
| 132 } | |
| 133 } | |
| 134 } | |
| OLD | NEW |