| OLD | NEW |
| 1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE.md file. |
| 4 | 4 |
| 5 library fletchc.compiled_function; | 5 library fletchc.compiled_function; |
| 6 | 6 |
| 7 import 'package:compiler/src/constants/values.dart' show | 7 import 'package:compiler/src/constants/values.dart' show |
| 8 ConstantValue; | 8 ConstantValue; |
| 9 | 9 |
| 10 import 'package:compiler/src/constants/expressions.dart' show | 10 import 'package:compiler/src/constants/expressions.dart' show |
| 11 ConstantExpression; | 11 ConstantExpression; |
| 12 | 12 |
| 13 import 'package:compiler/src/tree/tree.dart' show | 13 import 'package:compiler/src/tree/tree.dart' show |
| 14 Expression; | 14 Expression; |
| 15 | 15 |
| 16 import 'package:compiler/src/elements/elements.dart'; | 16 import 'package:compiler/src/elements/elements.dart'; |
| 17 | 17 |
| 18 import 'fletch_constants.dart' show | 18 import 'fletch_constants.dart' show |
| 19 FletchFunctionConstant, | 19 FletchFunctionConstant, |
| 20 FletchClassConstant; | 20 FletchClassConstant; |
| 21 | 21 |
| 22 import 'package:compiler/src/universe/universe.dart' | 22 import 'package:compiler/src/universe/universe.dart' |
| 23 show Selector; | 23 show Selector; |
| 24 | 24 |
| 25 import '../bytecodes.dart' show | 25 import '../bytecodes.dart' show |
| 26 Bytecode; | 26 Bytecode; |
| 27 | 27 |
| 28 import 'compiled_class.dart' show | 28 import 'fletch_class_builder.dart' show |
| 29 CompiledClass; | 29 FletchClassBuilder; |
| 30 | 30 |
| 31 import 'fletch_context.dart'; | 31 import 'fletch_context.dart'; |
| 32 import 'bytecode_builder.dart'; | 32 import 'bytecode_builder.dart'; |
| 33 import 'debug_info.dart'; | 33 import 'debug_info.dart'; |
| 34 | 34 |
| 35 enum CompiledFunctionKind { | 35 enum FletchFunctionBuilderKind { |
| 36 NORMAL, | 36 NORMAL, |
| 37 LAZY_FIELD_INITIALIZER, | 37 LAZY_FIELD_INITIALIZER, |
| 38 INITIALIZER_LIST, | 38 INITIALIZER_LIST, |
| 39 PARAMETER_STUB, | 39 PARAMETER_STUB, |
| 40 ACCESSOR | 40 ACCESSOR |
| 41 } | 41 } |
| 42 | 42 |
| 43 class CompiledFunction { | 43 class FletchFunctionBuilder { |
| 44 final BytecodeBuilder builder; | 44 final BytecodeBuilder builder; |
| 45 final int methodId; | 45 final int methodId; |
| 46 | 46 |
| 47 /** | 47 /** |
| 48 * The signature of the CompiledFunction. | 48 * The signature of the FletchFunctionBuilder. |
| 49 * | 49 * |
| 50 * Som compiled functions does not have a signature (for example, generated | 50 * Som compiled functions does not have a signature (for example, generated |
| 51 * accessors). | 51 * accessors). |
| 52 */ | 52 */ |
| 53 final FunctionSignature signature; | 53 final FunctionSignature signature; |
| 54 | 54 |
| 55 /** | 55 /** |
| 56 * If the functions is an instance member, [memberOf] is set to the compiled | 56 * If the functions is an instance member, [memberOf] is set to the compiled |
| 57 * class. | 57 * class. |
| 58 * | 58 * |
| 59 * If [memberOf] is set, the compiled function takes an 'this' argument in | 59 * If [memberOf] is set, the compiled function takes an 'this' argument in |
| 60 * addition to that of [signature]. | 60 * addition to that of [signature]. |
| 61 */ | 61 */ |
| 62 final CompiledClass memberOf; | 62 final FletchClassBuilder memberOf; |
| 63 final String name; | 63 final String name; |
| 64 final Element element; | 64 final Element element; |
| 65 final Map<ConstantValue, int> constants = <ConstantValue, int>{}; | 65 final Map<ConstantValue, int> constants = <ConstantValue, int>{}; |
| 66 final Map<int, ConstantValue> functionConstantValues = <int, ConstantValue>{}; | 66 final Map<int, ConstantValue> functionConstantValues = <int, ConstantValue>{}; |
| 67 final Map<int, ConstantValue> classConstantValues = <int, ConstantValue>{}; | 67 final Map<int, ConstantValue> classConstantValues = <int, ConstantValue>{}; |
| 68 final Map<Selector, CompiledFunction> parameterMappings = | 68 final Map<Selector, FletchFunctionBuilder> parameterMappings = |
| 69 <Selector, CompiledFunction>{}; | 69 <Selector, FletchFunctionBuilder>{}; |
| 70 final int arity; | 70 final int arity; |
| 71 final CompiledFunctionKind kind; | 71 final FletchFunctionBuilderKind kind; |
| 72 | 72 |
| 73 DebugInfo debugInfo; | 73 DebugInfo debugInfo; |
| 74 | 74 |
| 75 CompiledFunction(this.methodId, | 75 FletchFunctionBuilder(this.methodId, |
| 76 this.name, | 76 this.name, |
| 77 this.element, | 77 this.element, |
| 78 FunctionSignature signature, | 78 FunctionSignature signature, |
| 79 CompiledClass memberOf, | 79 FletchClassBuilder memberOf, |
| 80 {this.kind: CompiledFunctionKind.NORMAL}) | 80 {this.kind: FletchFunctionBuilderKind.NORMAL}) |
| 81 : this.signature = signature, | 81 : this.signature = signature, |
| 82 this.memberOf = memberOf, | 82 this.memberOf = memberOf, |
| 83 arity = signature.parameterCount + (memberOf != null ? 1 : 0), | 83 arity = signature.parameterCount + (memberOf != null ? 1 : 0), |
| 84 builder = new BytecodeBuilder( | 84 builder = new BytecodeBuilder( |
| 85 signature.parameterCount + (memberOf != null ? 1 : 0)); | 85 signature.parameterCount + (memberOf != null ? 1 : 0)); |
| 86 | 86 |
| 87 CompiledFunction.normal(this.methodId, int argumentCount) | 87 FletchFunctionBuilder.normal(this.methodId, int argumentCount) |
| 88 : arity = argumentCount, | 88 : arity = argumentCount, |
| 89 builder = new BytecodeBuilder(argumentCount), | 89 builder = new BytecodeBuilder(argumentCount), |
| 90 kind = CompiledFunctionKind.NORMAL; | 90 kind = FletchFunctionBuilderKind.NORMAL; |
| 91 | 91 |
| 92 CompiledFunction.lazyInit(this.methodId, | 92 FletchFunctionBuilder.lazyInit(this.methodId, |
| 93 this.name, | 93 this.name, |
| 94 this.element, | 94 this.element, |
| 95 int argumentCount) | 95 int argumentCount) |
| 96 : arity = argumentCount, | 96 : arity = argumentCount, |
| 97 builder = new BytecodeBuilder(argumentCount), | 97 builder = new BytecodeBuilder(argumentCount), |
| 98 kind = CompiledFunctionKind.LAZY_FIELD_INITIALIZER; | 98 kind = FletchFunctionBuilderKind.LAZY_FIELD_INITIALIZER; |
| 99 | 99 |
| 100 CompiledFunction.parameterStub(this.methodId, int argumentCount) | 100 FletchFunctionBuilder.parameterStub(this.methodId, int argumentCount) |
| 101 : arity = argumentCount, | 101 : arity = argumentCount, |
| 102 builder = new BytecodeBuilder(argumentCount), | 102 builder = new BytecodeBuilder(argumentCount), |
| 103 kind = CompiledFunctionKind.PARAMETER_STUB; | 103 kind = FletchFunctionBuilderKind.PARAMETER_STUB; |
| 104 | 104 |
| 105 CompiledFunction.accessor(this.methodId, bool setter) | 105 FletchFunctionBuilder.accessor(this.methodId, bool setter) |
| 106 : arity = setter ? 2 : 1, | 106 : arity = setter ? 2 : 1, |
| 107 builder = new BytecodeBuilder(setter ? 2 : 1), | 107 builder = new BytecodeBuilder(setter ? 2 : 1), |
| 108 kind = CompiledFunctionKind.ACCESSOR; | 108 kind = FletchFunctionBuilderKind.ACCESSOR; |
| 109 | 109 |
| 110 void reuse() { | 110 void reuse() { |
| 111 builder.reuse(); | 111 builder.reuse(); |
| 112 constants.clear(); | 112 constants.clear(); |
| 113 functionConstantValues.clear(); | 113 functionConstantValues.clear(); |
| 114 classConstantValues.clear(); | 114 classConstantValues.clear(); |
| 115 } | 115 } |
| 116 | 116 |
| 117 bool get hasThisArgument => memberOf != null; | 117 bool get hasThisArgument => memberOf != null; |
| 118 | 118 |
| 119 bool get isLazyFieldInitializer { | 119 bool get isLazyFieldInitializer { |
| 120 return kind == CompiledFunctionKind.LAZY_FIELD_INITIALIZER; | 120 return kind == FletchFunctionBuilderKind.LAZY_FIELD_INITIALIZER; |
| 121 } | 121 } |
| 122 | 122 |
| 123 bool get isInitializerList { | 123 bool get isInitializerList { |
| 124 return kind == CompiledFunctionKind.INITIALIZER_LIST; | 124 return kind == FletchFunctionBuilderKind.INITIALIZER_LIST; |
| 125 } | 125 } |
| 126 | 126 |
| 127 bool get isAccessor { | 127 bool get isAccessor { |
| 128 return kind == CompiledFunctionKind.ACCESSOR; | 128 return kind == FletchFunctionBuilderKind.ACCESSOR; |
| 129 } | 129 } |
| 130 | 130 |
| 131 bool get isParameterStub { | 131 bool get isParameterStub { |
| 132 return kind == CompiledFunctionKind.PARAMETER_STUB; | 132 return kind == FletchFunctionBuilderKind.PARAMETER_STUB; |
| 133 } | 133 } |
| 134 | 134 |
| 135 bool get isConstructor => element != null && element.isConstructor; | 135 bool get isConstructor => element != null && element.isConstructor; |
| 136 | 136 |
| 137 int allocateConstant(ConstantValue constant) { | 137 int allocateConstant(ConstantValue constant) { |
| 138 if (constant == null) throw "bad constant"; | 138 if (constant == null) throw "bad constant"; |
| 139 return constants.putIfAbsent(constant, () => constants.length); | 139 return constants.putIfAbsent(constant, () => constants.length); |
| 140 } | 140 } |
| 141 | 141 |
| 142 int allocateConstantFromFunction(int methodId) { | 142 int allocateConstantFromFunction(int methodId) { |
| 143 FletchFunctionConstant constant = | 143 FletchFunctionConstant constant = |
| 144 functionConstantValues.putIfAbsent( | 144 functionConstantValues.putIfAbsent( |
| 145 methodId, () => new FletchFunctionConstant(methodId)); | 145 methodId, () => new FletchFunctionConstant(methodId)); |
| 146 return allocateConstant(constant); | 146 return allocateConstant(constant); |
| 147 } | 147 } |
| 148 | 148 |
| 149 int allocateConstantFromClass(int classId) { | 149 int allocateConstantFromClass(int classId) { |
| 150 FletchClassConstant constant = | 150 FletchClassConstant constant = |
| 151 classConstantValues.putIfAbsent( | 151 classConstantValues.putIfAbsent( |
| 152 classId, () => new FletchClassConstant(classId)); | 152 classId, () => new FletchClassConstant(classId)); |
| 153 return allocateConstant(constant); | 153 return allocateConstant(constant); |
| 154 } | 154 } |
| 155 | 155 |
| 156 // TODO(ajohnsen): Remove this function when usage is avoided in | 156 // TODO(ajohnsen): Remove this function when usage is avoided in |
| 157 // FletchBackend. | 157 // FletchBackend. |
| 158 void copyFrom(CompiledFunction function) { | 158 void copyFrom(FletchFunctionBuilder function) { |
| 159 builder.bytecodes.addAll(function.builder.bytecodes); | 159 builder.bytecodes.addAll(function.builder.bytecodes); |
| 160 builder.catchRanges.addAll(function.builder.catchRanges); | 160 builder.catchRanges.addAll(function.builder.catchRanges); |
| 161 constants.addAll(function.constants); | 161 constants.addAll(function.constants); |
| 162 functionConstantValues.addAll(function.functionConstantValues); | 162 functionConstantValues.addAll(function.functionConstantValues); |
| 163 classConstantValues.addAll(function.classConstantValues); | 163 classConstantValues.addAll(function.classConstantValues); |
| 164 } | 164 } |
| 165 | 165 |
| 166 bool matchesSelector(Selector selector) { | 166 bool matchesSelector(Selector selector) { |
| 167 if (!canBeCalledAs(selector)) return false; | 167 if (!canBeCalledAs(selector)) return false; |
| 168 if (selector.namedArguments.length != signature.optionalParameterCount) { | 168 if (selector.namedArguments.length != signature.optionalParameterCount) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 if (!nameSet.contains(name)) return false; | 206 if (!nameSet.contains(name)) return false; |
| 207 // TODO(5213): By removing from the set we are checking | 207 // TODO(5213): By removing from the set we are checking |
| 208 // that we are not passing the name twice. We should have this | 208 // that we are not passing the name twice. We should have this |
| 209 // check in the resolver also. | 209 // check in the resolver also. |
| 210 nameSet.remove(name); | 210 nameSet.remove(name); |
| 211 } | 211 } |
| 212 return true; | 212 return true; |
| 213 } | 213 } |
| 214 } | 214 } |
| 215 | 215 |
| 216 CompiledFunction createParameterMappingFor( | 216 FletchFunctionBuilder createParameterMappingFor( |
| 217 Selector selector, | 217 Selector selector, |
| 218 FletchContext context) { | 218 FletchContext context) { |
| 219 return parameterMappings.putIfAbsent(selector, () { | 219 return parameterMappings.putIfAbsent(selector, () { |
| 220 assert(canBeCalledAs(selector)); | 220 assert(canBeCalledAs(selector)); |
| 221 int arity = selector.argumentCount; | 221 int arity = selector.argumentCount; |
| 222 if (hasThisArgument) arity++; | 222 if (hasThisArgument) arity++; |
| 223 | 223 |
| 224 CompiledFunction compiledFunction = new CompiledFunction.parameterStub( | 224 FletchFunctionBuilder functionBuilder = |
| 225 context.backend.functions.length, | 225 new FletchFunctionBuilder.parameterStub( |
| 226 arity); | 226 context.backend.functions.length, |
| 227 context.backend.functions.add(compiledFunction); | 227 arity); |
| 228 context.backend.functions.add(functionBuilder); |
| 228 | 229 |
| 229 BytecodeBuilder builder = compiledFunction.builder; | 230 BytecodeBuilder builder = functionBuilder.builder; |
| 230 | 231 |
| 231 void loadInitializerOrNull(ParameterElement parameter) { | 232 void loadInitializerOrNull(ParameterElement parameter) { |
| 232 Expression initializer = parameter.initializer; | 233 Expression initializer = parameter.initializer; |
| 233 if (initializer != null) { | 234 if (initializer != null) { |
| 234 ConstantExpression expression = context.compileConstant( | 235 ConstantExpression expression = context.compileConstant( |
| 235 initializer, | 236 initializer, |
| 236 parameter.memberContext.resolvedAst.elements, | 237 parameter.memberContext.resolvedAst.elements, |
| 237 isConst: true); | 238 isConst: true); |
| 238 int constId = compiledFunction.allocateConstant( | 239 int constId = functionBuilder.allocateConstant( |
| 239 context.getConstantValue(expression)); | 240 context.getConstantValue(expression)); |
| 240 builder.loadConst(constId); | 241 builder.loadConst(constId); |
| 241 } else { | 242 } else { |
| 242 builder.loadLiteralNull(); | 243 builder.loadLiteralNull(); |
| 243 } | 244 } |
| 244 } | 245 } |
| 245 | 246 |
| 246 // Load this. | 247 // Load this. |
| 247 if (hasThisArgument) builder.loadParameter(0); | 248 if (hasThisArgument) builder.loadParameter(0); |
| 248 | 249 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 266 loadInitializerOrNull(parameter); | 267 loadInitializerOrNull(parameter); |
| 267 } | 268 } |
| 268 } | 269 } |
| 269 index++; | 270 index++; |
| 270 }); | 271 }); |
| 271 | 272 |
| 272 // TODO(ajohnsen): We have to be extra careful when overriding a | 273 // TODO(ajohnsen): We have to be extra careful when overriding a |
| 273 // method that takes optional arguments. We really should | 274 // method that takes optional arguments. We really should |
| 274 // enumerate all the stubs in the superclasses and make sure | 275 // enumerate all the stubs in the superclasses and make sure |
| 275 // they're overridden. | 276 // they're overridden. |
| 276 int constId = compiledFunction.allocateConstantFromFunction(methodId); | 277 int constId = functionBuilder.allocateConstantFromFunction(methodId); |
| 277 builder | 278 builder |
| 278 ..invokeStatic(constId, index) | 279 ..invokeStatic(constId, index) |
| 279 ..ret() | 280 ..ret() |
| 280 ..methodEnd(); | 281 ..methodEnd(); |
| 281 | 282 |
| 282 if (memberOf != null) { | 283 if (memberOf != null) { |
| 283 int fletchSelector = context.toFletchSelector(selector); | 284 int fletchSelector = context.toFletchSelector(selector); |
| 284 memberOf.addToMethodTable(fletchSelector, compiledFunction); | 285 memberOf.addToMethodTable(fletchSelector, functionBuilder); |
| 285 } | 286 } |
| 286 | 287 |
| 287 return compiledFunction; | 288 return functionBuilder; |
| 288 }); | 289 }); |
| 289 } | 290 } |
| 290 | 291 |
| 291 String verboseToString() { | 292 String verboseToString() { |
| 292 StringBuffer sb = new StringBuffer(); | 293 StringBuffer sb = new StringBuffer(); |
| 293 | 294 |
| 294 sb.writeln("Method $methodId, Arity=${builder.functionArity}"); | 295 sb.writeln("Method $methodId, Arity=${builder.functionArity}"); |
| 295 sb.writeln("Constants:"); | 296 sb.writeln("Constants:"); |
| 296 constants.forEach((constant, int index) { | 297 constants.forEach((constant, int index) { |
| 297 if (constant is ConstantValue) { | 298 if (constant is ConstantValue) { |
| 298 constant = constant.toStructuredString(); | 299 constant = constant.toStructuredString(); |
| 299 } | 300 } |
| 300 sb.writeln(" #$index: $constant"); | 301 sb.writeln(" #$index: $constant"); |
| 301 }); | 302 }); |
| 302 | 303 |
| 303 sb.writeln("Bytecodes:"); | 304 sb.writeln("Bytecodes:"); |
| 304 int offset = 0; | 305 int offset = 0; |
| 305 for (Bytecode bytecode in builder.bytecodes) { | 306 for (Bytecode bytecode in builder.bytecodes) { |
| 306 sb.writeln(" $offset: $bytecode"); | 307 sb.writeln(" $offset: $bytecode"); |
| 307 offset += bytecode.size; | 308 offset += bytecode.size; |
| 308 } | 309 } |
| 309 | 310 |
| 310 return '$sb'; | 311 return '$sb'; |
| 311 } | 312 } |
| 312 } | 313 } |
| OLD | NEW |