| 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.fletch_backend; | 5 library fletchc.fletch_backend; |
| 6 | 6 |
| 7 import 'dart:async' show | 7 import 'dart:async' show |
| 8 Future; | 8 Future; |
| 9 | 9 |
| 10 import 'package:compiler/src/dart2jslib.dart' show | 10 import 'package:compiler/src/dart2jslib.dart' show |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 TreeElements; | 81 TreeElements; |
| 82 | 82 |
| 83 import 'package:compiler/src/library_loader.dart' show | 83 import 'package:compiler/src/library_loader.dart' show |
| 84 LibraryLoader; | 84 LibraryLoader; |
| 85 | 85 |
| 86 import 'fletch_constants.dart' show | 86 import 'fletch_constants.dart' show |
| 87 FletchClassConstant, | 87 FletchClassConstant, |
| 88 FletchFunctionConstant, | 88 FletchFunctionConstant, |
| 89 FletchClassInstanceConstant; | 89 FletchClassInstanceConstant; |
| 90 | 90 |
| 91 import 'compiled_function.dart' show | 91 import 'fletch_function_builder.dart' show |
| 92 CompiledFunctionKind, | 92 FletchFunctionBuilderKind, |
| 93 CompiledFunction, | 93 FletchFunctionBuilder, |
| 94 DebugInfo; | 94 DebugInfo; |
| 95 | 95 |
| 96 import 'compiled_class.dart' show | 96 import 'fletch_class_builder.dart' show |
| 97 CompiledClass; | 97 FletchClassBuilder; |
| 98 | 98 |
| 99 import 'codegen_visitor.dart'; | 99 import 'codegen_visitor.dart'; |
| 100 import 'debug_info.dart'; | 100 import 'debug_info.dart'; |
| 101 import 'debug_info_constructor_codegen.dart'; | 101 import 'debug_info_constructor_codegen.dart'; |
| 102 import 'debug_info_function_codegen.dart'; | 102 import 'debug_info_function_codegen.dart'; |
| 103 import 'debug_info_lazy_field_initializer_codegen.dart'; | 103 import 'debug_info_lazy_field_initializer_codegen.dart'; |
| 104 import 'fletch_context.dart'; | 104 import 'fletch_context.dart'; |
| 105 import 'fletch_selector.dart'; | 105 import 'fletch_selector.dart'; |
| 106 import 'function_codegen.dart'; | 106 import 'function_codegen.dart'; |
| 107 import 'lazy_field_initializer_codegen.dart'; | 107 import 'lazy_field_initializer_codegen.dart'; |
| 108 import 'constructor_codegen.dart'; | 108 import 'constructor_codegen.dart'; |
| 109 import 'closure_environment.dart'; | 109 import 'closure_environment.dart'; |
| 110 import '../bytecodes.dart'; | 110 import '../bytecodes.dart'; |
| 111 import '../commands.dart'; | 111 import '../commands.dart'; |
| 112 | 112 |
| 113 class FletchBackend extends Backend { | 113 class FletchBackend extends Backend { |
| 114 static const String growableListName = '_GrowableList'; | 114 static const String growableListName = '_GrowableList'; |
| 115 static const String constantListName = '_ConstantList'; | 115 static const String constantListName = '_ConstantList'; |
| 116 static const String constantMapName = '_ConstantMap'; | 116 static const String constantMapName = '_ConstantMap'; |
| 117 static const String linkedHashMapName = '_CompactLinkedHashMap'; | 117 static const String linkedHashMapName = '_CompactLinkedHashMap'; |
| 118 static const String noSuchMethodName = '_noSuchMethod'; | 118 static const String noSuchMethodName = '_noSuchMethod'; |
| 119 static const String noSuchMethodTrampolineName = '_noSuchMethodTrampoline'; | 119 static const String noSuchMethodTrampolineName = '_noSuchMethodTrampoline'; |
| 120 | 120 |
| 121 final FletchContext context; | 121 final FletchContext context; |
| 122 | 122 |
| 123 final DartConstantTask constantCompilerTask; | 123 final DartConstantTask constantCompilerTask; |
| 124 | 124 |
| 125 final Map<FunctionElement, CompiledFunction> compiledFunctions = | 125 final Map<FunctionElement, FletchFunctionBuilder> functionBuilders = |
| 126 <FunctionElement, CompiledFunction>{}; | 126 <FunctionElement, FletchFunctionBuilder>{}; |
| 127 | 127 |
| 128 final Map<ConstructorElement, CompiledFunction> constructors = | 128 final Map<ConstructorElement, FletchFunctionBuilder> constructors = |
| 129 <ConstructorElement, CompiledFunction>{}; | 129 <ConstructorElement, FletchFunctionBuilder>{}; |
| 130 | 130 |
| 131 final List<CompiledFunction> functions = <CompiledFunction>[]; | 131 final List<FletchFunctionBuilder> functions = <FletchFunctionBuilder>[]; |
| 132 | 132 |
| 133 final Set<FunctionElement> externals = new Set<FunctionElement>(); | 133 final Set<FunctionElement> externals = new Set<FunctionElement>(); |
| 134 | 134 |
| 135 final Map<ClassElement, CompiledClass> compiledClasses = | 135 final Map<ClassElement, FletchClassBuilder> classBuilderes = |
| 136 <ClassElement, CompiledClass>{}; | 136 <ClassElement, FletchClassBuilder>{}; |
| 137 final Map<ClassElement, Set<ClassElement>> directSubclasses = | 137 final Map<ClassElement, Set<ClassElement>> directSubclasses = |
| 138 <ClassElement, Set<ClassElement>>{}; | 138 <ClassElement, Set<ClassElement>>{}; |
| 139 | 139 |
| 140 final List<CompiledClass> classes = <CompiledClass>[]; | 140 final List<FletchClassBuilder> classes = <FletchClassBuilder>[]; |
| 141 | 141 |
| 142 final Set<ClassElement> builtinClasses = new Set<ClassElement>(); | 142 final Set<ClassElement> builtinClasses = new Set<ClassElement>(); |
| 143 | 143 |
| 144 final Map<MemberElement, ClosureEnvironment> closureEnvironments = | 144 final Map<MemberElement, ClosureEnvironment> closureEnvironments = |
| 145 <MemberElement, ClosureEnvironment>{}; | 145 <MemberElement, ClosureEnvironment>{}; |
| 146 | 146 |
| 147 final Map<FunctionElement, CompiledClass> closureClasses = | 147 final Map<FunctionElement, FletchClassBuilder> closureClasses = |
| 148 <FunctionElement, CompiledClass>{}; | 148 <FunctionElement, FletchClassBuilder>{}; |
| 149 | 149 |
| 150 final Map<FieldElement, CompiledFunction> lazyFieldInitializers = | 150 final Map<FieldElement, FletchFunctionBuilder> lazyFieldInitializers = |
| 151 <FieldElement, CompiledFunction>{}; | 151 <FieldElement, FletchFunctionBuilder>{}; |
| 152 | 152 |
| 153 final Map<CompiledFunction, CompiledClass> tearoffClasses = | 153 final Map<FletchFunctionBuilder, FletchClassBuilder> tearoffClasses = |
| 154 <CompiledFunction, CompiledClass>{}; | 154 <FletchFunctionBuilder, FletchClassBuilder>{}; |
| 155 | 155 |
| 156 final Map<int, int> getters = <int, int>{}; | 156 final Map<int, int> getters = <int, int>{}; |
| 157 final Map<int, int> setters = <int, int>{}; | 157 final Map<int, int> setters = <int, int>{}; |
| 158 | 158 |
| 159 Map<CompiledClass, CompiledFunction> tearoffFunctions; | 159 Map<FletchClassBuilder, FletchFunctionBuilder> tearoffFunctions; |
| 160 | 160 |
| 161 List<Command> commands; | 161 List<Command> commands; |
| 162 | 162 |
| 163 LibraryElement fletchSystemLibrary; | 163 LibraryElement fletchSystemLibrary; |
| 164 LibraryElement fletchFFILibrary; | 164 LibraryElement fletchFFILibrary; |
| 165 LibraryElement fletchIOSystemLibrary; | 165 LibraryElement fletchIOSystemLibrary; |
| 166 LibraryElement collectionLibrary; | 166 LibraryElement collectionLibrary; |
| 167 LibraryElement mathLibrary; | 167 LibraryElement mathLibrary; |
| 168 | 168 |
| 169 FunctionElement fletchSystemEntry; | 169 FunctionElement fletchSystemEntry; |
| 170 | 170 |
| 171 FunctionElement fletchExternalInvokeMain; | 171 FunctionElement fletchExternalInvokeMain; |
| 172 | 172 |
| 173 FunctionElement fletchExternalYield; | 173 FunctionElement fletchExternalYield; |
| 174 | 174 |
| 175 FunctionElement fletchExternalNativeError; | 175 FunctionElement fletchExternalNativeError; |
| 176 | 176 |
| 177 FunctionElement fletchExternalCoroutineChange; | 177 FunctionElement fletchExternalCoroutineChange; |
| 178 | 178 |
| 179 FunctionElement fletchUnresolved; | 179 FunctionElement fletchUnresolved; |
| 180 FunctionElement fletchCompileError; | 180 FunctionElement fletchCompileError; |
| 181 | 181 |
| 182 CompiledClass compiledObjectClass; | 182 FletchClassBuilder compiledObjectClass; |
| 183 | 183 |
| 184 ClassElement stringClass; | 184 ClassElement stringClass; |
| 185 ClassElement smiClass; | 185 ClassElement smiClass; |
| 186 ClassElement mintClass; | 186 ClassElement mintClass; |
| 187 ClassElement growableListClass; | 187 ClassElement growableListClass; |
| 188 ClassElement linkedHashMapClass; | 188 ClassElement linkedHashMapClass; |
| 189 ClassElement coroutineClass; | 189 ClassElement coroutineClass; |
| 190 | 190 |
| 191 final Set<FunctionElement> alwaysEnqueue = new Set<FunctionElement>(); | 191 final Set<FunctionElement> alwaysEnqueue = new Set<FunctionElement>(); |
| 192 | 192 |
| 193 FletchBackend(FletchCompiler compiler) | 193 FletchBackend(FletchCompiler compiler) |
| 194 : this.context = compiler.context, | 194 : this.context = compiler.context, |
| 195 this.constantCompilerTask = new DartConstantTask(compiler), | 195 this.constantCompilerTask = new DartConstantTask(compiler), |
| 196 super(compiler) { | 196 super(compiler) { |
| 197 context.resolutionCallbacks = new FletchResolutionCallbacks(context); | 197 context.resolutionCallbacks = new FletchResolutionCallbacks(context); |
| 198 } | 198 } |
| 199 | 199 |
| 200 CompiledClass registerClassElement(ClassElement element) { | 200 FletchClassBuilder registerClassElement(ClassElement element) { |
| 201 if (element == null) return null; | 201 if (element == null) return null; |
| 202 assert(element.isDeclaration); | 202 assert(element.isDeclaration); |
| 203 return compiledClasses.putIfAbsent(element, () { | 203 return classBuilderes.putIfAbsent(element, () { |
| 204 directSubclasses[element] = new Set<ClassElement>(); | 204 directSubclasses[element] = new Set<ClassElement>(); |
| 205 CompiledClass superclass = registerClassElement(element.superclass); | 205 FletchClassBuilder superclass = registerClassElement(element.superclass); |
| 206 if (superclass != null) { | 206 if (superclass != null) { |
| 207 Set<ClassElement> subclasses = directSubclasses[element.superclass]; | 207 Set<ClassElement> subclasses = directSubclasses[element.superclass]; |
| 208 subclasses.add(element); | 208 subclasses.add(element); |
| 209 } | 209 } |
| 210 int id = classes.length; | 210 int id = classes.length; |
| 211 CompiledClass compiledClass = new CompiledClass(id, element, superclass); | 211 FletchClassBuilder classBuilder = new FletchClassBuilder( |
| 212 id, element, superclass); |
| 212 if (element.lookupLocalMember(Compiler.CALL_OPERATOR_NAME) != null) { | 213 if (element.lookupLocalMember(Compiler.CALL_OPERATOR_NAME) != null) { |
| 213 compiledClass.createIsFunctionEntry(this); | 214 classBuilder.createIsFunctionEntry(this); |
| 214 } | 215 } |
| 215 classes.add(compiledClass); | 216 classes.add(classBuilder); |
| 216 return compiledClass; | 217 return classBuilder; |
| 217 }); | 218 }); |
| 218 } | 219 } |
| 219 | 220 |
| 220 CompiledClass createCallableStubClass(int fields, CompiledClass superclass) { | 221 FletchClassBuilder createCallableStubClass( |
| 222 int fields, FletchClassBuilder superclass) { |
| 221 int id = classes.length; | 223 int id = classes.length; |
| 222 CompiledClass compiledClass = new CompiledClass( | 224 FletchClassBuilder classBuilder = new FletchClassBuilder( |
| 223 id, null, superclass, extraFields: fields); | 225 id, null, superclass, extraFields: fields); |
| 224 classes.add(compiledClass); | 226 classes.add(classBuilder); |
| 225 compiledClass.createIsFunctionEntry(this); | 227 classBuilder.createIsFunctionEntry(this); |
| 226 return compiledClass; | 228 return classBuilder; |
| 227 } | 229 } |
| 228 | 230 |
| 229 FletchResolutionCallbacks get resolutionCallbacks { | 231 FletchResolutionCallbacks get resolutionCallbacks { |
| 230 return context.resolutionCallbacks; | 232 return context.resolutionCallbacks; |
| 231 } | 233 } |
| 232 | 234 |
| 233 List<CompilerTask> get tasks => <CompilerTask>[]; | 235 List<CompilerTask> get tasks => <CompilerTask>[]; |
| 234 | 236 |
| 235 ConstantSystem get constantSystem { | 237 ConstantSystem get constantSystem { |
| 236 return constantCompilerTask.constantCompiler.constantSystem; | 238 return constantCompilerTask.constantCompiler.constantSystem; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 } | 276 } |
| 275 fletchExternalInvokeMain = findExternal('invokeMain'); | 277 fletchExternalInvokeMain = findExternal('invokeMain'); |
| 276 fletchExternalYield = findExternal('yield'); | 278 fletchExternalYield = findExternal('yield'); |
| 277 fletchExternalCoroutineChange = findExternal('coroutineChange'); | 279 fletchExternalCoroutineChange = findExternal('coroutineChange'); |
| 278 fletchExternalNativeError = findExternal('nativeError'); | 280 fletchExternalNativeError = findExternal('nativeError'); |
| 279 fletchUnresolved = findExternal('unresolved'); | 281 fletchUnresolved = findExternal('unresolved'); |
| 280 world.registerStaticUse(fletchUnresolved); | 282 world.registerStaticUse(fletchUnresolved); |
| 281 fletchCompileError = findExternal('compileError'); | 283 fletchCompileError = findExternal('compileError'); |
| 282 world.registerStaticUse(fletchCompileError); | 284 world.registerStaticUse(fletchCompileError); |
| 283 | 285 |
| 284 CompiledClass loadClass(String name, LibraryElement library) { | 286 FletchClassBuilder loadClass(String name, LibraryElement library) { |
| 285 var classImpl = library.findLocal(name); | 287 var classImpl = library.findLocal(name); |
| 286 if (classImpl == null) classImpl = library.implementation.find(name); | 288 if (classImpl == null) classImpl = library.implementation.find(name); |
| 287 if (classImpl == null) { | 289 if (classImpl == null) { |
| 288 compiler.internalError(library, "Internal class '$name' not found."); | 290 compiler.internalError(library, "Internal class '$name' not found."); |
| 289 return null; | 291 return null; |
| 290 } | 292 } |
| 291 // TODO(ahe): Register in ResolutionCallbacks. The 3 lines below should | 293 // TODO(ahe): Register in ResolutionCallbacks. The 3 lines below should |
| 292 // not happen at this point in time. | 294 // not happen at this point in time. |
| 293 classImpl.ensureResolved(compiler); | 295 classImpl.ensureResolved(compiler); |
| 294 CompiledClass compiledClass = registerClassElement(classImpl); | 296 FletchClassBuilder classBuilder = registerClassElement(classImpl); |
| 295 world.registerInstantiatedType(classImpl.rawType, registry); | 297 world.registerInstantiatedType(classImpl.rawType, registry); |
| 296 // TODO(ahe): This is a hack to let both the world and the codegen know | 298 // TODO(ahe): This is a hack to let both the world and the codegen know |
| 297 // about the instantiated type. | 299 // about the instantiated type. |
| 298 registry.registerInstantiatedType(classImpl.rawType); | 300 registry.registerInstantiatedType(classImpl.rawType); |
| 299 return compiledClass; | 301 return classBuilder; |
| 300 } | 302 } |
| 301 | 303 |
| 302 CompiledClass loadBuiltinClass(String name, LibraryElement library) { | 304 FletchClassBuilder loadBuiltinClass(String name, LibraryElement library) { |
| 303 CompiledClass compiledClass = loadClass(name, library); | 305 FletchClassBuilder classBuilder = loadClass(name, library); |
| 304 builtinClasses.add(compiledClass.element); | 306 builtinClasses.add(classBuilder.element); |
| 305 return compiledClass; | 307 return classBuilder; |
| 306 } | 308 } |
| 307 | 309 |
| 308 compiledObjectClass = loadBuiltinClass("Object", compiler.coreLibrary); | 310 compiledObjectClass = loadBuiltinClass("Object", compiler.coreLibrary); |
| 309 smiClass = loadBuiltinClass("_Smi", compiler.coreLibrary).element; | 311 smiClass = loadBuiltinClass("_Smi", compiler.coreLibrary).element; |
| 310 mintClass = loadBuiltinClass("_Mint", compiler.coreLibrary).element; | 312 mintClass = loadBuiltinClass("_Mint", compiler.coreLibrary).element; |
| 311 stringClass = loadBuiltinClass("_StringImpl", compiler.coreLibrary).element; | 313 stringClass = loadBuiltinClass("_StringImpl", compiler.coreLibrary).element; |
| 312 // TODO(ahe): Register _ConstantList through ResolutionCallbacks. | 314 // TODO(ahe): Register _ConstantList through ResolutionCallbacks. |
| 313 loadBuiltinClass(constantListName, fletchSystemLibrary); | 315 loadBuiltinClass(constantListName, fletchSystemLibrary); |
| 314 loadBuiltinClass(constantMapName, fletchSystemLibrary); | 316 loadBuiltinClass(constantMapName, fletchSystemLibrary); |
| 315 loadBuiltinClass("_DoubleImpl", compiler.coreLibrary); | 317 loadBuiltinClass("_DoubleImpl", compiler.coreLibrary); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 /// The patch parser (pkg/compiler/lib/src/patch_parser.dart). The patch | 366 /// The patch parser (pkg/compiler/lib/src/patch_parser.dart). The patch |
| 365 /// parser looks for an annotation on the form "@patch", where "patch" is | 367 /// parser looks for an annotation on the form "@patch", where "patch" is |
| 366 /// compile-time constant instance of [patchAnnotationClass]. | 368 /// compile-time constant instance of [patchAnnotationClass]. |
| 367 ClassElement get patchAnnotationClass { | 369 ClassElement get patchAnnotationClass { |
| 368 // TODO(ahe): Introduce a proper constant class to identify constants. For | 370 // TODO(ahe): Introduce a proper constant class to identify constants. For |
| 369 // now, we simply put "const patch = "patch";" in the beginning of patch | 371 // now, we simply put "const patch = "patch";" in the beginning of patch |
| 370 // files. | 372 // files. |
| 371 return super.stringImplementation; | 373 return super.stringImplementation; |
| 372 } | 374 } |
| 373 | 375 |
| 374 CompiledClass createClosureClass( | 376 FletchClassBuilder createClosureClass( |
| 375 FunctionElement closure, | 377 FunctionElement closure, |
| 376 ClosureEnvironment closureEnvironment) { | 378 ClosureEnvironment closureEnvironment) { |
| 377 return closureClasses.putIfAbsent(closure, () { | 379 return closureClasses.putIfAbsent(closure, () { |
| 378 ClosureInfo info = closureEnvironment.closures[closure]; | 380 ClosureInfo info = closureEnvironment.closures[closure]; |
| 379 int fields = info.free.length; | 381 int fields = info.free.length; |
| 380 if (info.isThisFree) fields++; | 382 if (info.isThisFree) fields++; |
| 381 return createCallableStubClass(fields, compiledObjectClass); | 383 return createCallableStubClass(fields, compiledObjectClass); |
| 382 }); | 384 }); |
| 383 } | 385 } |
| 384 | 386 |
| 385 /** | 387 /** |
| 386 * Create a tearoff class for function [function]. | 388 * Create a tearoff class for function [function]. |
| 387 * | 389 * |
| 388 * The class will have one method named 'call', accepting the same arguments | 390 * The class will have one method named 'call', accepting the same arguments |
| 389 * as [function]. The method will load the arguments received and statically | 391 * as [function]. The method will load the arguments received and statically |
| 390 * call [function] (essential a tail-call). | 392 * call [function] (essential a tail-call). |
| 391 * | 393 * |
| 392 * If [function] is an instance member, the class will have one field, the | 394 * If [function] is an instance member, the class will have one field, the |
| 393 * instance. | 395 * instance. |
| 394 */ | 396 */ |
| 395 CompiledClass createTearoffClass(CompiledFunction function) { | 397 FletchClassBuilder createTearoffClass(FletchFunctionBuilder function) { |
| 396 return tearoffClasses.putIfAbsent(function, () { | 398 return tearoffClasses.putIfAbsent(function, () { |
| 397 FunctionSignature signature = function.signature; | 399 FunctionSignature signature = function.signature; |
| 398 bool hasThis = function.hasThisArgument; | 400 bool hasThis = function.hasThisArgument; |
| 399 CompiledClass compiledClass = createCallableStubClass( | 401 FletchClassBuilder classBuilder = createCallableStubClass( |
| 400 hasThis ? 1 : 0, | 402 hasThis ? 1 : 0, |
| 401 compiledObjectClass); | 403 compiledObjectClass); |
| 402 CompiledFunction compiledFunction = new CompiledFunction( | 404 FletchFunctionBuilder functionBuilder = new FletchFunctionBuilder( |
| 403 functions.length, | 405 functions.length, |
| 404 'call', | 406 'call', |
| 405 null, | 407 null, |
| 406 signature, | 408 signature, |
| 407 compiledClass); | 409 classBuilder); |
| 408 functions.add(compiledFunction); | 410 functions.add(functionBuilder); |
| 409 | 411 |
| 410 BytecodeBuilder builder = compiledFunction.builder; | 412 BytecodeBuilder builder = functionBuilder.builder; |
| 411 int argumentCount = signature.parameterCount; | 413 int argumentCount = signature.parameterCount; |
| 412 if (hasThis) { | 414 if (hasThis) { |
| 413 argumentCount++; | 415 argumentCount++; |
| 414 // If the tearoff has a 'this' value, load it. It's the only field | 416 // If the tearoff has a 'this' value, load it. It's the only field |
| 415 // in the tearoff class. | 417 // in the tearoff class. |
| 416 builder | 418 builder |
| 417 ..loadParameter(0) | 419 ..loadParameter(0) |
| 418 ..loadField(0); | 420 ..loadField(0); |
| 419 } | 421 } |
| 420 for (int i = 0; i < signature.parameterCount; i++) { | 422 for (int i = 0; i < signature.parameterCount; i++) { |
| 421 // The closure-class is at parameter index 0, so argument i is at | 423 // The closure-class is at parameter index 0, so argument i is at |
| 422 // i + 1. | 424 // i + 1. |
| 423 builder.loadParameter(i + 1); | 425 builder.loadParameter(i + 1); |
| 424 } | 426 } |
| 425 int constId = compiledFunction.allocateConstantFromFunction( | 427 int constId = functionBuilder.allocateConstantFromFunction( |
| 426 function.methodId); | 428 function.methodId); |
| 427 // TODO(ajohnsen): Create a tail-call bytecode, so we don't have to | 429 // TODO(ajohnsen): Create a tail-call bytecode, so we don't have to |
| 428 // load all the arguments. | 430 // load all the arguments. |
| 429 builder | 431 builder |
| 430 ..invokeStatic(constId, argumentCount) | 432 ..invokeStatic(constId, argumentCount) |
| 431 ..ret() | 433 ..ret() |
| 432 ..methodEnd(); | 434 ..methodEnd(); |
| 433 | 435 |
| 434 String symbol = context.getCallSymbol(signature); | 436 String symbol = context.getCallSymbol(signature); |
| 435 int id = context.getSymbolId(symbol); | 437 int id = context.getSymbolId(symbol); |
| 436 int fletchSelector = FletchSelector.encodeMethod( | 438 int fletchSelector = FletchSelector.encodeMethod( |
| 437 id, | 439 id, |
| 438 signature.parameterCount); | 440 signature.parameterCount); |
| 439 compiledClass.addToMethodTable(fletchSelector, compiledFunction); | 441 classBuilder.addToMethodTable(fletchSelector, functionBuilder); |
| 440 | 442 |
| 441 if (hasThis && function.memberOf.element != null) { | 443 if (hasThis && function.memberOf.element != null) { |
| 442 // Create == function that tests for equality. | 444 // Create == function that tests for equality. |
| 443 int isSelector = context.toFletchTearoffIsSelector( | 445 int isSelector = context.toFletchTearoffIsSelector( |
| 444 function.name, | 446 function.name, |
| 445 function.memberOf.element); | 447 function.memberOf.element); |
| 446 compiledClass.addIsSelector(isSelector); | 448 classBuilder.addIsSelector(isSelector); |
| 447 | 449 |
| 448 CompiledFunction equal = new CompiledFunction.normal( | 450 FletchFunctionBuilder equal = new FletchFunctionBuilder.normal( |
| 449 functions.length, | 451 functions.length, |
| 450 2); | 452 2); |
| 451 functions.add(equal); | 453 functions.add(equal); |
| 452 | 454 |
| 453 BytecodeLabel isFalse = new BytecodeLabel(); | 455 BytecodeLabel isFalse = new BytecodeLabel(); |
| 454 equal.builder | 456 equal.builder |
| 455 // First test for class. This ensures it's the exact function that | 457 // First test for class. This ensures it's the exact function that |
| 456 // we expect. | 458 // we expect. |
| 457 ..loadParameter(1) | 459 ..loadParameter(1) |
| 458 ..invokeTest(isSelector, 0) | 460 ..invokeTest(isSelector, 0) |
| 459 ..branchIfFalse(isFalse) | 461 ..branchIfFalse(isFalse) |
| 460 // Then test that the receiver is identical. | 462 // Then test that the receiver is identical. |
| 461 ..loadParameter(0) | 463 ..loadParameter(0) |
| 462 ..loadField(0) | 464 ..loadField(0) |
| 463 ..loadParameter(1) | 465 ..loadParameter(1) |
| 464 ..loadField(0) | 466 ..loadField(0) |
| 465 ..identicalNonNumeric() | 467 ..identicalNonNumeric() |
| 466 ..branchIfFalse(isFalse) | 468 ..branchIfFalse(isFalse) |
| 467 ..loadLiteralTrue() | 469 ..loadLiteralTrue() |
| 468 ..ret() | 470 ..ret() |
| 469 ..bind(isFalse) | 471 ..bind(isFalse) |
| 470 ..loadLiteralFalse() | 472 ..loadLiteralFalse() |
| 471 ..ret() | 473 ..ret() |
| 472 ..methodEnd(); | 474 ..methodEnd(); |
| 473 | 475 |
| 474 int id = context.getSymbolId("=="); | 476 int id = context.getSymbolId("=="); |
| 475 int equalsSelector = FletchSelector.encodeMethod(id, 1); | 477 int equalsSelector = FletchSelector.encodeMethod(id, 1); |
| 476 compiledClass.addToMethodTable(equalsSelector, equal); | 478 classBuilder.addToMethodTable(equalsSelector, equal); |
| 477 | 479 |
| 478 // Create hashCode getter. We simply xor the object hashCode and the | 480 // Create hashCode getter. We simply xor the object hashCode and the |
| 479 // method id of the tearoff'ed function. | 481 // method id of the tearoff'ed function. |
| 480 CompiledFunction hashCode = new CompiledFunction.accessor( | 482 FletchFunctionBuilder hashCode = new FletchFunctionBuilder.accessor( |
| 481 functions.length, | 483 functions.length, |
| 482 false); | 484 false); |
| 483 functions.add(hashCode); | 485 functions.add(hashCode); |
| 484 | 486 |
| 485 int hashCodeSelector = FletchSelector.encodeGetter( | 487 int hashCodeSelector = FletchSelector.encodeGetter( |
| 486 context.getSymbolId("hashCode")); | 488 context.getSymbolId("hashCode")); |
| 487 int xorSelector = FletchSelector.encodeMethod( | 489 int xorSelector = FletchSelector.encodeMethod( |
| 488 context.getSymbolId("^"), 1); | 490 context.getSymbolId("^"), 1); |
| 489 hashCode.builder | 491 hashCode.builder |
| 490 ..loadParameter(0) | 492 ..loadParameter(0) |
| 491 ..loadField(0) | 493 ..loadField(0) |
| 492 ..invokeMethod(hashCodeSelector, 0) | 494 ..invokeMethod(hashCodeSelector, 0) |
| 493 ..loadLiteral(function.methodId) | 495 ..loadLiteral(function.methodId) |
| 494 ..invokeMethod(xorSelector, 1) | 496 ..invokeMethod(xorSelector, 1) |
| 495 ..ret() | 497 ..ret() |
| 496 ..methodEnd(); | 498 ..methodEnd(); |
| 497 | 499 |
| 498 compiledClass.addToMethodTable(hashCodeSelector, hashCode); | 500 classBuilder.addToMethodTable(hashCodeSelector, hashCode); |
| 499 } | 501 } |
| 500 return compiledClass; | 502 return classBuilder; |
| 501 }); | 503 }); |
| 502 } | 504 } |
| 503 | 505 |
| 504 CompiledFunction createCompiledFunction(FunctionElement function) { | 506 FletchFunctionBuilder createFletchFunctionBuilder(FunctionElement function) { |
| 505 assert(function.memberContext == function); | 507 assert(function.memberContext == function); |
| 506 | 508 |
| 507 CompiledClass holderClass; | 509 FletchClassBuilder holderClass; |
| 508 if (function.isInstanceMember || function.isGenerativeConstructor) { | 510 if (function.isInstanceMember || function.isGenerativeConstructor) { |
| 509 ClassElement enclosingClass = function.enclosingClass.declaration; | 511 ClassElement enclosingClass = function.enclosingClass.declaration; |
| 510 holderClass = registerClassElement(enclosingClass); | 512 holderClass = registerClassElement(enclosingClass); |
| 511 } | 513 } |
| 512 return internalCreateCompiledFunction( | 514 return internalCreateFletchFunctionBuilder( |
| 513 function, | 515 function, |
| 514 function.name, | 516 function.name, |
| 515 holderClass); | 517 holderClass); |
| 516 } | 518 } |
| 517 | 519 |
| 518 CompiledFunction internalCreateCompiledFunction( | 520 FletchFunctionBuilder internalCreateFletchFunctionBuilder( |
| 519 FunctionElement function, | 521 FunctionElement function, |
| 520 String name, | 522 String name, |
| 521 CompiledClass holderClass) { | 523 FletchClassBuilder holderClass) { |
| 522 return compiledFunctions.putIfAbsent(function.declaration, () { | 524 return functionBuilders.putIfAbsent(function.declaration, () { |
| 523 FunctionTypedElement implementation = function.implementation; | 525 FunctionTypedElement implementation = function.implementation; |
| 524 CompiledFunction compiledFunction = new CompiledFunction( | 526 FletchFunctionBuilder functionBuilder = new FletchFunctionBuilder( |
| 525 functions.length, | 527 functions.length, |
| 526 name, | 528 name, |
| 527 function, | 529 function, |
| 528 // Parameter initializers are expressed in the potential | 530 // Parameter initializers are expressed in the potential |
| 529 // implementation. | 531 // implementation. |
| 530 implementation.functionSignature, | 532 implementation.functionSignature, |
| 531 holderClass, | 533 holderClass, |
| 532 kind: function.isAccessor | 534 kind: function.isAccessor |
| 533 ? CompiledFunctionKind.ACCESSOR | 535 ? FletchFunctionBuilderKind.ACCESSOR |
| 534 : CompiledFunctionKind.NORMAL); | 536 : FletchFunctionBuilderKind.NORMAL); |
| 535 functions.add(compiledFunction); | 537 functions.add(functionBuilder); |
| 536 return compiledFunction; | 538 return functionBuilder; |
| 537 }); | 539 }); |
| 538 } | 540 } |
| 539 | 541 |
| 540 int functionMethodId(FunctionElement function) { | 542 int functionMethodId(FunctionElement function) { |
| 541 return createCompiledFunction(function).methodId; | 543 return createFletchFunctionBuilder(function).methodId; |
| 542 } | 544 } |
| 543 | 545 |
| 544 CompiledFunction compiledFunctionFromTearoffClass(CompiledClass klass) { | 546 FletchFunctionBuilder functionBuilderFromTearoffClass( |
| 547 FletchClassBuilder klass) { |
| 545 if (tearoffFunctions == null) { | 548 if (tearoffFunctions == null) { |
| 546 tearoffFunctions = <CompiledClass, CompiledFunction>{}; | 549 tearoffFunctions = <FletchClassBuilder, FletchFunctionBuilder>{}; |
| 547 tearoffClasses.forEach((k, v) => tearoffFunctions[v] = k); | 550 tearoffClasses.forEach((k, v) => tearoffFunctions[v] = k); |
| 548 } | 551 } |
| 549 return tearoffFunctions[klass]; | 552 return tearoffFunctions[klass]; |
| 550 } | 553 } |
| 551 | 554 |
| 552 void ensureDebugInfo(CompiledFunction function) { | 555 void ensureDebugInfo(FletchFunctionBuilder function) { |
| 553 if (function.debugInfo != null) return; | 556 if (function.debugInfo != null) return; |
| 554 function.debugInfo = new DebugInfo(function); | 557 function.debugInfo = new DebugInfo(function); |
| 555 AstElement element = function.element; | 558 AstElement element = function.element; |
| 556 if (element == null) return; | 559 if (element == null) return; |
| 557 List<Bytecode> expectedBytecodes = function.builder.bytecodes; | 560 List<Bytecode> expectedBytecodes = function.builder.bytecodes; |
| 558 element = element.implementation; | 561 element = element.implementation; |
| 559 TreeElements elements = element.resolvedAst.elements; | 562 TreeElements elements = element.resolvedAst.elements; |
| 560 ClosureEnvironment closureEnvironment = createClosureEnvironment( | 563 ClosureEnvironment closureEnvironment = createClosureEnvironment( |
| 561 element, | 564 element, |
| 562 elements); | 565 elements); |
| 563 CodegenVisitor codegen; | 566 CodegenVisitor codegen; |
| 564 if (function.isLazyFieldInitializer) { | 567 if (function.isLazyFieldInitializer) { |
| 565 codegen = new DebugInfoLazyFieldInitializerCodegen( | 568 codegen = new DebugInfoLazyFieldInitializerCodegen( |
| 566 function, | 569 function, |
| 567 context, | 570 context, |
| 568 elements, | 571 elements, |
| 569 null, | 572 null, |
| 570 closureEnvironment, | 573 closureEnvironment, |
| 571 element, | 574 element, |
| 572 compiler); | 575 compiler); |
| 573 } else if (function.isInitializerList) { | 576 } else if (function.isInitializerList) { |
| 574 ClassElement enclosingClass = element.enclosingClass; | 577 ClassElement enclosingClass = element.enclosingClass; |
| 575 CompiledClass compiledClass = compiledClasses[enclosingClass]; | 578 FletchClassBuilder classBuilder = classBuilderes[enclosingClass]; |
| 576 codegen = new DebugInfoConstructorCodegen( | 579 codegen = new DebugInfoConstructorCodegen( |
| 577 function, | 580 function, |
| 578 context, | 581 context, |
| 579 elements, | 582 elements, |
| 580 null, | 583 null, |
| 581 closureEnvironment, | 584 closureEnvironment, |
| 582 element, | 585 element, |
| 583 compiledClass, | 586 classBuilder, |
| 584 compiler); | 587 compiler); |
| 585 } else { | 588 } else { |
| 586 codegen = new DebugInfoFunctionCodegen( | 589 codegen = new DebugInfoFunctionCodegen( |
| 587 function, | 590 function, |
| 588 context, | 591 context, |
| 589 elements, | 592 elements, |
| 590 null, | 593 null, |
| 591 closureEnvironment, | 594 closureEnvironment, |
| 592 element, | 595 element, |
| 593 compiler); | 596 compiler); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 636 void codegenFunction( | 639 void codegenFunction( |
| 637 FunctionElement function, | 640 FunctionElement function, |
| 638 TreeElements elements, | 641 TreeElements elements, |
| 639 Registry registry) { | 642 Registry registry) { |
| 640 registry.registerStaticInvocation(fletchSystemEntry); | 643 registry.registerStaticInvocation(fletchSystemEntry); |
| 641 | 644 |
| 642 ClosureEnvironment closureEnvironment = createClosureEnvironment( | 645 ClosureEnvironment closureEnvironment = createClosureEnvironment( |
| 643 function, | 646 function, |
| 644 elements); | 647 elements); |
| 645 | 648 |
| 646 CompiledFunction compiledFunction; | 649 FletchFunctionBuilder functionBuilder; |
| 647 | 650 |
| 648 if (function.memberContext != function) { | 651 if (function.memberContext != function) { |
| 649 compiledFunction = internalCreateCompiledFunction( | 652 functionBuilder = internalCreateFletchFunctionBuilder( |
| 650 function, | 653 function, |
| 651 Compiler.CALL_OPERATOR_NAME, | 654 Compiler.CALL_OPERATOR_NAME, |
| 652 createClosureClass(function, closureEnvironment)); | 655 createClosureClass(function, closureEnvironment)); |
| 653 } else { | 656 } else { |
| 654 compiledFunction = createCompiledFunction(function); | 657 functionBuilder = createFletchFunctionBuilder(function); |
| 655 } | 658 } |
| 656 | 659 |
| 657 FunctionCodegen codegen = new FunctionCodegen( | 660 FunctionCodegen codegen = new FunctionCodegen( |
| 658 compiledFunction, | 661 functionBuilder, |
| 659 context, | 662 context, |
| 660 elements, | 663 elements, |
| 661 registry, | 664 registry, |
| 662 closureEnvironment, | 665 closureEnvironment, |
| 663 function); | 666 function); |
| 664 | 667 |
| 665 if (isNative(function)) { | 668 if (isNative(function)) { |
| 666 codegenNativeFunction(function, codegen); | 669 codegenNativeFunction(function, codegen); |
| 667 } else if (isExternal(function)) { | 670 } else if (isExternal(function)) { |
| 668 codegenExternalFunction(function, codegen); | 671 codegenExternalFunction(function, codegen); |
| 669 } else { | 672 } else { |
| 670 codegen.compile(); | 673 codegen.compile(); |
| 671 } | 674 } |
| 672 | 675 |
| 673 // TODO(ahe): Don't do this. | 676 // TODO(ahe): Don't do this. |
| 674 compiler.enqueuer.codegen.generatedCode[function.declaration] = null; | 677 compiler.enqueuer.codegen.generatedCode[function.declaration] = null; |
| 675 | 678 |
| 676 if (compiledFunction.memberOf != null && | 679 if (functionBuilder.memberOf != null && |
| 677 !function.isGenerativeConstructor) { | 680 !function.isGenerativeConstructor) { |
| 678 // Inject the function into the method table of the 'holderClass' class. | 681 // Inject the function into the method table of the 'holderClass' class. |
| 679 // Note that while constructor bodies has a this argument, we don't inject | 682 // Note that while constructor bodies has a this argument, we don't inject |
| 680 // them into the method table. | 683 // them into the method table. |
| 681 String symbol = context.getSymbolForFunction( | 684 String symbol = context.getSymbolForFunction( |
| 682 compiledFunction.name, | 685 functionBuilder.name, |
| 683 function.functionSignature, | 686 function.functionSignature, |
| 684 function.library); | 687 function.library); |
| 685 int id = context.getSymbolId(symbol); | 688 int id = context.getSymbolId(symbol); |
| 686 int arity = function.functionSignature.parameterCount; | 689 int arity = function.functionSignature.parameterCount; |
| 687 SelectorKind kind = SelectorKind.Method; | 690 SelectorKind kind = SelectorKind.Method; |
| 688 if (function.isGetter) kind = SelectorKind.Getter; | 691 if (function.isGetter) kind = SelectorKind.Getter; |
| 689 if (function.isSetter) kind = SelectorKind.Setter; | 692 if (function.isSetter) kind = SelectorKind.Setter; |
| 690 int fletchSelector = FletchSelector.encode(id, kind, arity); | 693 int fletchSelector = FletchSelector.encode(id, kind, arity); |
| 691 int methodId = compiledFunction.methodId; | 694 int methodId = functionBuilder.methodId; |
| 692 compiledFunction.memberOf.addToMethodTable( | 695 functionBuilder.memberOf.addToMethodTable( |
| 693 fletchSelector, compiledFunction); | 696 fletchSelector, functionBuilder); |
| 694 // Inject method into all mixin usages. | 697 // Inject method into all mixin usages. |
| 695 Iterable<ClassElement> mixinUsage = | 698 Iterable<ClassElement> mixinUsage = |
| 696 compiler.world.mixinUsesOf(function.enclosingClass); | 699 compiler.world.mixinUsesOf(function.enclosingClass); |
| 697 for (ClassElement usage in mixinUsage) { | 700 for (ClassElement usage in mixinUsage) { |
| 698 // TODO(ajohnsen): Consider having multiple 'memberOf' in | 701 // TODO(ajohnsen): Consider having multiple 'memberOf' in |
| 699 // CompiledFunction, to avoid duplicates. | 702 // FletchFunctionBuilder, to avoid duplicates. |
| 700 // Create a copy with a unique 'memberOf', so we can detect missing | 703 // Create a copy with a unique 'memberOf', so we can detect missing |
| 701 // stubs for the mixin applications as well. | 704 // stubs for the mixin applications as well. |
| 702 CompiledClass compiledUsage = registerClassElement(usage); | 705 FletchClassBuilder compiledUsage = registerClassElement(usage); |
| 703 FunctionTypedElement implementation = function.implementation; | 706 FunctionTypedElement implementation = function.implementation; |
| 704 CompiledFunction copy = new CompiledFunction( | 707 FletchFunctionBuilder copy = new FletchFunctionBuilder( |
| 705 functions.length, | 708 functions.length, |
| 706 function.name, | 709 function.name, |
| 707 implementation, | 710 implementation, |
| 708 implementation.functionSignature, | 711 implementation.functionSignature, |
| 709 compiledUsage, | 712 compiledUsage, |
| 710 kind: function.isAccessor | 713 kind: function.isAccessor |
| 711 ? CompiledFunctionKind.ACCESSOR | 714 ? FletchFunctionBuilderKind.ACCESSOR |
| 712 : CompiledFunctionKind.NORMAL); | 715 : FletchFunctionBuilderKind.NORMAL); |
| 713 functions.add(copy); | 716 functions.add(copy); |
| 714 compiledUsage.addToMethodTable(fletchSelector, copy); | 717 compiledUsage.addToMethodTable(fletchSelector, copy); |
| 715 copy.copyFrom(compiledFunction); | 718 copy.copyFrom(functionBuilder); |
| 716 } | 719 } |
| 717 } | 720 } |
| 718 | 721 |
| 719 if (compiler.verbose) { | 722 if (compiler.verbose) { |
| 720 compiler.log(compiledFunction.verboseToString()); | 723 compiler.log(functionBuilder.verboseToString()); |
| 721 } | 724 } |
| 722 } | 725 } |
| 723 | 726 |
| 724 void codegenNativeFunction( | 727 void codegenNativeFunction( |
| 725 FunctionElement function, | 728 FunctionElement function, |
| 726 FunctionCodegen codegen) { | 729 FunctionCodegen codegen) { |
| 727 String name = '.${function.name}'; | 730 String name = '.${function.name}'; |
| 728 | 731 |
| 729 ClassElement enclosingClass = function.enclosingClass; | 732 ClassElement enclosingClass = function.enclosingClass; |
| 730 if (enclosingClass != null) name = '${enclosingClass.name}$name'; | 733 if (enclosingClass != null) name = '${enclosingClass.name}$name'; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 MemberElement member = element.memberContext; | 854 MemberElement member = element.memberContext; |
| 852 return closureEnvironments.putIfAbsent(member, () { | 855 return closureEnvironments.putIfAbsent(member, () { |
| 853 ClosureVisitor environment = new ClosureVisitor(member, elements); | 856 ClosureVisitor environment = new ClosureVisitor(member, elements); |
| 854 return environment.compute(); | 857 return environment.compute(); |
| 855 }); | 858 }); |
| 856 } | 859 } |
| 857 | 860 |
| 858 void createParameterMatchingStubs() { | 861 void createParameterMatchingStubs() { |
| 859 int length = functions.length; | 862 int length = functions.length; |
| 860 for (int i = 0; i < length; i++) { | 863 for (int i = 0; i < length; i++) { |
| 861 CompiledFunction function = functions[i]; | 864 FletchFunctionBuilder function = functions[i]; |
| 862 if (!function.hasThisArgument || function.isAccessor) continue; | 865 if (!function.hasThisArgument || function.isAccessor) continue; |
| 863 String name = function.name; | 866 String name = function.name; |
| 864 Set<Selector> usage = compiler.resolverWorld.invokedNames[name]; | 867 Set<Selector> usage = compiler.resolverWorld.invokedNames[name]; |
| 865 if (usage == null) continue; | 868 if (usage == null) continue; |
| 866 for (Selector use in usage) { | 869 for (Selector use in usage) { |
| 867 // TODO(ajohnsen): Somehow filter out private selectors of other | 870 // TODO(ajohnsen): Somehow filter out private selectors of other |
| 868 // libraries. | 871 // libraries. |
| 869 if (function.canBeCalledAs(use) && | 872 if (function.canBeCalledAs(use) && |
| 870 !function.matchesSelector(use)) { | 873 !function.matchesSelector(use)) { |
| 871 function.createParameterMappingFor(use, context); | 874 function.createParameterMappingFor(use, context); |
| 872 } | 875 } |
| 873 } | 876 } |
| 874 } | 877 } |
| 875 } | 878 } |
| 876 | 879 |
| 877 void createTearoffStubs() { | 880 void createTearoffStubs() { |
| 878 int length = functions.length; | 881 int length = functions.length; |
| 879 for (int i = 0; i < length; i++) { | 882 for (int i = 0; i < length; i++) { |
| 880 CompiledFunction function = functions[i]; | 883 FletchFunctionBuilder function = functions[i]; |
| 881 if (!function.hasThisArgument || function.isAccessor) continue; | 884 if (!function.hasThisArgument || function.isAccessor) continue; |
| 882 String name = function.name; | 885 String name = function.name; |
| 883 if (compiler.resolverWorld.invokedGetters.containsKey(name)) { | 886 if (compiler.resolverWorld.invokedGetters.containsKey(name)) { |
| 884 createTearoffGetterForFunction(function); | 887 createTearoffGetterForFunction(function); |
| 885 } | 888 } |
| 886 } | 889 } |
| 887 } | 890 } |
| 888 | 891 |
| 889 void createTearoffGetterForFunction(CompiledFunction function) { | 892 void createTearoffGetterForFunction(FletchFunctionBuilder function) { |
| 890 CompiledClass tearoffClass = createTearoffClass(function); | 893 FletchClassBuilder tearoffClass = createTearoffClass(function); |
| 891 CompiledFunction getter = new CompiledFunction.accessor( | 894 FletchFunctionBuilder getter = new FletchFunctionBuilder.accessor( |
| 892 functions.length, | 895 functions.length, |
| 893 false); | 896 false); |
| 894 functions.add(getter); | 897 functions.add(getter); |
| 895 int constId = getter.allocateConstantFromClass(tearoffClass.id); | 898 int constId = getter.allocateConstantFromClass(tearoffClass.id); |
| 896 getter.builder | 899 getter.builder |
| 897 ..loadParameter(0) | 900 ..loadParameter(0) |
| 898 ..allocate(constId, tearoffClass.fields) | 901 ..allocate(constId, tearoffClass.fields) |
| 899 ..ret() | 902 ..ret() |
| 900 ..methodEnd(); | 903 ..methodEnd(); |
| 901 // If the name is private, we need the library. | 904 // If the name is private, we need the library. |
| 902 // Invariant: We only generate public stubs, e.g. 'call'. | 905 // Invariant: We only generate public stubs, e.g. 'call'. |
| 903 LibraryElement library; | 906 LibraryElement library; |
| 904 if (function.memberOf.element != null) { | 907 if (function.memberOf.element != null) { |
| 905 library = function.memberOf.element.library; | 908 library = function.memberOf.element.library; |
| 906 } | 909 } |
| 907 int fletchSelector = context.toFletchSelector( | 910 int fletchSelector = context.toFletchSelector( |
| 908 new Selector.getter(function.name, library)); | 911 new Selector.getter(function.name, library)); |
| 909 function.memberOf.addToMethodTable(fletchSelector, getter); | 912 function.memberOf.addToMethodTable(fletchSelector, getter); |
| 910 } | 913 } |
| 911 | 914 |
| 912 int assembleProgram() { | 915 int assembleProgram() { |
| 913 createTearoffStubs(); | 916 createTearoffStubs(); |
| 914 createParameterMatchingStubs(); | 917 createParameterMatchingStubs(); |
| 915 | 918 |
| 916 for (CompiledClass compiledClass in classes) { | 919 for (FletchClassBuilder classBuilder in classes) { |
| 917 compiledClass.createIsEntries(this); | 920 classBuilder.createIsEntries(this); |
| 918 // TODO(ajohnsen): Currently, the CodegenRegistry does not enqueue fields. | 921 // TODO(ajohnsen): Currently, the CodegenRegistry does not enqueue fields. |
| 919 // This is a workaround, where we basically add getters for all fields. | 922 // This is a workaround, where we basically add getters for all fields. |
| 920 compiledClass.createImplicitAccessors(this); | 923 classBuilder.createImplicitAccessors(this); |
| 921 } | 924 } |
| 922 | 925 |
| 923 List<Command> commands = <Command>[ | 926 List<Command> commands = <Command>[ |
| 924 const NewMap(MapId.methods), | 927 const NewMap(MapId.methods), |
| 925 const NewMap(MapId.classes), | 928 const NewMap(MapId.classes), |
| 926 const NewMap(MapId.constants), | 929 const NewMap(MapId.constants), |
| 927 ]; | 930 ]; |
| 928 | 931 |
| 929 List<Function> deferredActions = <Function>[]; | 932 List<Function> deferredActions = <Function>[]; |
| 930 | 933 |
| 931 functions.forEach((f) => pushNewFunction(f, commands, deferredActions)); | 934 functions.forEach((f) => pushNewFunction(f, commands, deferredActions)); |
| 932 | 935 |
| 933 int changes = 0; | 936 int changes = 0; |
| 934 | 937 |
| 935 for (CompiledClass compiledClass in classes) { | 938 for (FletchClassBuilder classBuilder in classes) { |
| 936 ClassElement element = compiledClass.element; | 939 ClassElement element = classBuilder.element; |
| 937 if (builtinClasses.contains(element)) { | 940 if (builtinClasses.contains(element)) { |
| 938 int nameId = context.getSymbolId(element.name); | 941 int nameId = context.getSymbolId(element.name); |
| 939 commands.add(new PushBuiltinClass(nameId, compiledClass.fields)); | 942 commands.add(new PushBuiltinClass(nameId, classBuilder.fields)); |
| 940 } else { | 943 } else { |
| 941 commands.add(new PushNewClass(compiledClass.fields)); | 944 commands.add(new PushNewClass(classBuilder.fields)); |
| 942 } | 945 } |
| 943 | 946 |
| 944 commands.add(const Dup()); | 947 commands.add(const Dup()); |
| 945 commands.add(new PopToMap(MapId.classes, compiledClass.id)); | 948 commands.add(new PopToMap(MapId.classes, classBuilder.id)); |
| 946 | 949 |
| 947 Map<int, int> methodTable = compiledClass.computeMethodTable(this); | 950 Map<int, int> methodTable = classBuilder.computeMethodTable(this); |
| 948 methodTable.forEach((int selector, int methodId) { | 951 methodTable.forEach((int selector, int methodId) { |
| 949 commands.add(new PushNewInteger(selector)); | 952 commands.add(new PushNewInteger(selector)); |
| 950 commands.add(new PushFromMap(MapId.methods, methodId)); | 953 commands.add(new PushFromMap(MapId.methods, methodId)); |
| 951 }); | 954 }); |
| 952 commands.add(new ChangeMethodTable(methodTable.length)); | 955 commands.add(new ChangeMethodTable(methodTable.length)); |
| 953 | 956 |
| 954 changes++; | 957 changes++; |
| 955 } | 958 } |
| 956 | 959 |
| 957 context.forEachStatic((element, index) { | 960 context.forEachStatic((element, index) { |
| 958 CompiledFunction initializer = lazyFieldInitializers[element]; | 961 FletchFunctionBuilder initializer = lazyFieldInitializers[element]; |
| 959 if (initializer != null) { | 962 if (initializer != null) { |
| 960 commands.add(new PushFromMap(MapId.methods, initializer.methodId)); | 963 commands.add(new PushFromMap(MapId.methods, initializer.methodId)); |
| 961 commands.add(const PushNewInitializer()); | 964 commands.add(const PushNewInitializer()); |
| 962 } else { | 965 } else { |
| 963 commands.add(const PushNull()); | 966 commands.add(const PushNull()); |
| 964 } | 967 } |
| 965 }); | 968 }); |
| 966 commands.add(new ChangeStatics(context.staticIndices.length)); | 969 commands.add(new ChangeStatics(context.staticIndices.length)); |
| 967 changes++; | 970 changes++; |
| 968 | 971 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 992 ListConstantValue value = constant; | 995 ListConstantValue value = constant; |
| 993 addList(constant.entries); | 996 addList(constant.entries); |
| 994 } else if (constant.isMap) { | 997 } else if (constant.isMap) { |
| 995 MapConstantValue value = constant; | 998 MapConstantValue value = constant; |
| 996 addList(value.keys); | 999 addList(value.keys); |
| 997 addList(value.values); | 1000 addList(value.values); |
| 998 commands.add(new PushConstantMap(value.length * 2)); | 1001 commands.add(new PushConstantMap(value.length * 2)); |
| 999 } else if (constant.isConstructedObject) { | 1002 } else if (constant.isConstructedObject) { |
| 1000 ConstructedConstantValue value = constant; | 1003 ConstructedConstantValue value = constant; |
| 1001 ClassElement classElement = value.type.element; | 1004 ClassElement classElement = value.type.element; |
| 1002 CompiledClass compiledClass = compiledClasses[classElement]; | 1005 FletchClassBuilder classBuilder = classBuilderes[classElement]; |
| 1003 for (ConstantValue field in value.fields.values) { | 1006 for (ConstantValue field in value.fields.values) { |
| 1004 int fieldId = context.compiledConstants[field]; | 1007 int fieldId = context.compiledConstants[field]; |
| 1005 commands.add(new PushFromMap(MapId.constants, fieldId)); | 1008 commands.add(new PushFromMap(MapId.constants, fieldId)); |
| 1006 } | 1009 } |
| 1007 commands | 1010 commands |
| 1008 ..add(new PushFromMap(MapId.classes, compiledClass.id)) | 1011 ..add(new PushFromMap(MapId.classes, classBuilder.id)) |
| 1009 ..add(const PushNewInstance()); | 1012 ..add(const PushNewInstance()); |
| 1010 } else if (constant is FletchClassInstanceConstant) { | 1013 } else if (constant is FletchClassInstanceConstant) { |
| 1011 commands | 1014 commands |
| 1012 ..add(new PushFromMap(MapId.classes, constant.classId)) | 1015 ..add(new PushFromMap(MapId.classes, constant.classId)) |
| 1013 ..add(const PushNewInstance()); | 1016 ..add(const PushNewInstance()); |
| 1014 } else { | 1017 } else { |
| 1015 throw "Unsupported constant: ${constant.toStructuredString()}"; | 1018 throw "Unsupported constant: ${constant.toStructuredString()}"; |
| 1016 } | 1019 } |
| 1017 commands.add(new PopToMap(MapId.constants, id)); | 1020 commands.add(new PopToMap(MapId.constants, id)); |
| 1018 }); | 1021 }); |
| 1019 | 1022 |
| 1020 for (CompiledClass compiledClass in classes) { | 1023 for (FletchClassBuilder classBuilder in classes) { |
| 1021 CompiledClass superclass = compiledClass.superclass; | 1024 FletchClassBuilder superclass = classBuilder.superclass; |
| 1022 if (superclass == null) continue; | 1025 if (superclass == null) continue; |
| 1023 commands.add(new PushFromMap(MapId.classes, compiledClass.id)); | 1026 commands.add(new PushFromMap(MapId.classes, classBuilder.id)); |
| 1024 commands.add(new PushFromMap(MapId.classes, superclass.id)); | 1027 commands.add(new PushFromMap(MapId.classes, superclass.id)); |
| 1025 commands.add(const ChangeSuperClass()); | 1028 commands.add(const ChangeSuperClass()); |
| 1026 changes++; | 1029 changes++; |
| 1027 } | 1030 } |
| 1028 | 1031 |
| 1029 for (Function action in deferredActions) { | 1032 for (Function action in deferredActions) { |
| 1030 action(); | 1033 action(); |
| 1031 changes++; | 1034 changes++; |
| 1032 } | 1035 } |
| 1033 | 1036 |
| 1034 commands.add(new CommitChanges(changes)); | 1037 commands.add(new CommitChanges(changes)); |
| 1035 | 1038 |
| 1036 commands.add(const PushNewInteger(0)); | 1039 commands.add(const PushNewInteger(0)); |
| 1037 | 1040 |
| 1038 commands.add(new PushFromMap( | 1041 commands.add(new PushFromMap( |
| 1039 MapId.methods, | 1042 MapId.methods, |
| 1040 compiledFunctions[fletchSystemEntry].methodId)); | 1043 functionBuilders[fletchSystemEntry].methodId)); |
| 1041 | 1044 |
| 1042 this.commands = commands; | 1045 this.commands = commands; |
| 1043 | 1046 |
| 1044 return 0; | 1047 return 0; |
| 1045 } | 1048 } |
| 1046 | 1049 |
| 1047 void pushNewFunction( | 1050 void pushNewFunction( |
| 1048 CompiledFunction compiledFunction, | 1051 FletchFunctionBuilder functionBuilder, |
| 1049 List<Command> commands, | 1052 List<Command> commands, |
| 1050 List<Function> deferredActions) { | 1053 List<Function> deferredActions) { |
| 1051 int arity = compiledFunction.builder.functionArity; | 1054 int arity = functionBuilder.builder.functionArity; |
| 1052 int constantCount = compiledFunction.constants.length; | 1055 int constantCount = functionBuilder.constants.length; |
| 1053 int methodId = compiledFunction.methodId; | 1056 int methodId = functionBuilder.methodId; |
| 1054 | 1057 |
| 1055 assert(functions[methodId] == compiledFunction); | 1058 assert(functions[methodId] == functionBuilder); |
| 1056 assert(compiledFunction.builder.bytecodes.isNotEmpty); | 1059 assert(functionBuilder.builder.bytecodes.isNotEmpty); |
| 1057 | 1060 |
| 1058 compiledFunction.constants.forEach((constant, int index) { | 1061 functionBuilder.constants.forEach((constant, int index) { |
| 1059 if (constant is ConstantValue) { | 1062 if (constant is ConstantValue) { |
| 1060 if (constant is FletchFunctionConstant) { | 1063 if (constant is FletchFunctionConstant) { |
| 1061 commands.add(const PushNull()); | 1064 commands.add(const PushNull()); |
| 1062 deferredActions.add(() { | 1065 deferredActions.add(() { |
| 1063 commands | 1066 commands |
| 1064 ..add(new PushFromMap(MapId.methods, methodId)) | 1067 ..add(new PushFromMap(MapId.methods, methodId)) |
| 1065 ..add(new PushFromMap(MapId.methods, constant.methodId)) | 1068 ..add(new PushFromMap(MapId.methods, constant.methodId)) |
| 1066 ..add(new ChangeMethodLiteral(index)); | 1069 ..add(new ChangeMethodLiteral(index)); |
| 1067 }); | 1070 }); |
| 1068 } else if (constant is FletchClassConstant) { | 1071 } else if (constant is FletchClassConstant) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1088 } | 1091 } |
| 1089 } else { | 1092 } else { |
| 1090 throw "Unsupported constant: ${constant.runtimeType}"; | 1093 throw "Unsupported constant: ${constant.runtimeType}"; |
| 1091 } | 1094 } |
| 1092 }); | 1095 }); |
| 1093 | 1096 |
| 1094 commands.add( | 1097 commands.add( |
| 1095 new PushNewFunction( | 1098 new PushNewFunction( |
| 1096 arity, | 1099 arity, |
| 1097 constantCount, | 1100 constantCount, |
| 1098 compiledFunction.builder.bytecodes, | 1101 functionBuilder.builder.bytecodes, |
| 1099 compiledFunction.builder.catchRanges)); | 1102 functionBuilder.builder.catchRanges)); |
| 1100 | 1103 |
| 1101 commands.add(new PopToMap(MapId.methods, methodId)); | 1104 commands.add(new PopToMap(MapId.methods, methodId)); |
| 1102 } | 1105 } |
| 1103 | 1106 |
| 1104 bool registerDeferredLoading(Spannable node, Registry registry) { | 1107 bool registerDeferredLoading(Spannable node, Registry registry) { |
| 1105 compiler.reportWarning( | 1108 compiler.reportWarning( |
| 1106 node, | 1109 node, |
| 1107 MessageKind.GENERIC, | 1110 MessageKind.GENERIC, |
| 1108 {'text': "Deferred loading is not supported."}); | 1111 {'text': "Deferred loading is not supported."}); |
| 1109 return false; | 1112 return false; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1182 return element; | 1185 return element; |
| 1183 } | 1186 } |
| 1184 | 1187 |
| 1185 int compileLazyFieldInitializer(FieldElement field, Registry registry) { | 1188 int compileLazyFieldInitializer(FieldElement field, Registry registry) { |
| 1186 int index = context.getStaticFieldIndex(field, null); | 1189 int index = context.getStaticFieldIndex(field, null); |
| 1187 | 1190 |
| 1188 if (field.initializer == null) return index; | 1191 if (field.initializer == null) return index; |
| 1189 | 1192 |
| 1190 if (lazyFieldInitializers.containsKey(field)) return index; | 1193 if (lazyFieldInitializers.containsKey(field)) return index; |
| 1191 | 1194 |
| 1192 CompiledFunction compiledFunction = new CompiledFunction.lazyInit( | 1195 FletchFunctionBuilder functionBuilder = new FletchFunctionBuilder.lazyInit( |
| 1193 functions.length, | 1196 functions.length, |
| 1194 "${field.name} lazy initializer", | 1197 "${field.name} lazy initializer", |
| 1195 field, | 1198 field, |
| 1196 0); | 1199 0); |
| 1197 functions.add(compiledFunction); | 1200 functions.add(functionBuilder); |
| 1198 lazyFieldInitializers[field] = compiledFunction; | 1201 lazyFieldInitializers[field] = functionBuilder; |
| 1199 | 1202 |
| 1200 TreeElements elements = field.resolvedAst.elements; | 1203 TreeElements elements = field.resolvedAst.elements; |
| 1201 | 1204 |
| 1202 ClosureEnvironment closureEnvironment = createClosureEnvironment( | 1205 ClosureEnvironment closureEnvironment = createClosureEnvironment( |
| 1203 field, | 1206 field, |
| 1204 elements); | 1207 elements); |
| 1205 | 1208 |
| 1206 LazyFieldInitializerCodegen codegen = new LazyFieldInitializerCodegen( | 1209 LazyFieldInitializerCodegen codegen = new LazyFieldInitializerCodegen( |
| 1207 compiledFunction, | 1210 functionBuilder, |
| 1208 context, | 1211 context, |
| 1209 elements, | 1212 elements, |
| 1210 registry, | 1213 registry, |
| 1211 closureEnvironment, | 1214 closureEnvironment, |
| 1212 field); | 1215 field); |
| 1213 | 1216 |
| 1214 codegen.compile(); | 1217 codegen.compile(); |
| 1215 | 1218 |
| 1216 return index; | 1219 return index; |
| 1217 } | 1220 } |
| 1218 | 1221 |
| 1219 CompiledFunction compileConstructor(ConstructorElement constructor, | 1222 FletchFunctionBuilder compileConstructor(ConstructorElement constructor, |
| 1220 Registry registry) { | 1223 Registry registry) { |
| 1221 assert(constructor.isDeclaration); | 1224 assert(constructor.isDeclaration); |
| 1222 CompiledFunction compiledFunction = constructors[constructor]; | 1225 FletchFunctionBuilder functionBuilder = constructors[constructor]; |
| 1223 if (compiledFunction != null) return compiledFunction; | 1226 if (functionBuilder != null) return functionBuilder; |
| 1224 | 1227 |
| 1225 ClassElement classElement = constructor.enclosingClass; | 1228 ClassElement classElement = constructor.enclosingClass; |
| 1226 CompiledClass compiledClass = registerClassElement(classElement); | 1229 FletchClassBuilder classBuilder = registerClassElement(classElement); |
| 1227 | 1230 |
| 1228 ConstructorElement implementation = constructor.implementation; | 1231 ConstructorElement implementation = constructor.implementation; |
| 1229 | 1232 |
| 1230 if (compiler.verbose) { | 1233 if (compiler.verbose) { |
| 1231 // TODO(johnniwinther): Use reportVerboseInfo once added. | 1234 // TODO(johnniwinther): Use reportVerboseInfo once added. |
| 1232 compiler.reportHint( | 1235 compiler.reportHint( |
| 1233 constructor, | 1236 constructor, |
| 1234 MessageKind.GENERIC, | 1237 MessageKind.GENERIC, |
| 1235 {'text': 'Compiling constructor ${implementation.name}'}); | 1238 {'text': 'Compiling constructor ${implementation.name}'}); |
| 1236 } | 1239 } |
| 1237 | 1240 |
| 1238 TreeElements elements = implementation.resolvedAst.elements; | 1241 TreeElements elements = implementation.resolvedAst.elements; |
| 1239 | 1242 |
| 1240 ClosureEnvironment closureEnvironment = createClosureEnvironment( | 1243 ClosureEnvironment closureEnvironment = createClosureEnvironment( |
| 1241 implementation, | 1244 implementation, |
| 1242 elements); | 1245 elements); |
| 1243 | 1246 |
| 1244 compiledFunction = new CompiledFunction( | 1247 functionBuilder = new FletchFunctionBuilder( |
| 1245 functions.length, | 1248 functions.length, |
| 1246 implementation.name, | 1249 implementation.name, |
| 1247 implementation, | 1250 implementation, |
| 1248 implementation.functionSignature, | 1251 implementation.functionSignature, |
| 1249 null, | 1252 null, |
| 1250 kind: CompiledFunctionKind.INITIALIZER_LIST); | 1253 kind: FletchFunctionBuilderKind.INITIALIZER_LIST); |
| 1251 functions.add(compiledFunction); | 1254 functions.add(functionBuilder); |
| 1252 constructors[constructor] = compiledFunction; | 1255 constructors[constructor] = functionBuilder; |
| 1253 | 1256 |
| 1254 ConstructorCodegen codegen = new ConstructorCodegen( | 1257 ConstructorCodegen codegen = new ConstructorCodegen( |
| 1255 compiledFunction, | 1258 functionBuilder, |
| 1256 context, | 1259 context, |
| 1257 elements, | 1260 elements, |
| 1258 registry, | 1261 registry, |
| 1259 closureEnvironment, | 1262 closureEnvironment, |
| 1260 implementation, | 1263 implementation, |
| 1261 compiledClass); | 1264 classBuilder); |
| 1262 | 1265 |
| 1263 codegen.compile(); | 1266 codegen.compile(); |
| 1264 | 1267 |
| 1265 if (compiler.verbose) { | 1268 if (compiler.verbose) { |
| 1266 compiler.log(compiledFunction.verboseToString()); | 1269 compiler.log(functionBuilder.verboseToString()); |
| 1267 } | 1270 } |
| 1268 | 1271 |
| 1269 return compiledFunction; | 1272 return functionBuilder; |
| 1270 } | 1273 } |
| 1271 | 1274 |
| 1272 /** | 1275 /** |
| 1273 * Generate a getter for field [fieldIndex]. | 1276 * Generate a getter for field [fieldIndex]. |
| 1274 */ | 1277 */ |
| 1275 int makeGetter(int fieldIndex) { | 1278 int makeGetter(int fieldIndex) { |
| 1276 return getters.putIfAbsent(fieldIndex, () { | 1279 return getters.putIfAbsent(fieldIndex, () { |
| 1277 CompiledFunction stub = new CompiledFunction.accessor( | 1280 FletchFunctionBuilder stub = new FletchFunctionBuilder.accessor( |
| 1278 functions.length, | 1281 functions.length, |
| 1279 false); | 1282 false); |
| 1280 functions.add(stub); | 1283 functions.add(stub); |
| 1281 stub.builder | 1284 stub.builder |
| 1282 ..loadParameter(0) | 1285 ..loadParameter(0) |
| 1283 ..loadField(fieldIndex) | 1286 ..loadField(fieldIndex) |
| 1284 ..ret() | 1287 ..ret() |
| 1285 ..methodEnd(); | 1288 ..methodEnd(); |
| 1286 return stub.methodId; | 1289 return stub.methodId; |
| 1287 }); | 1290 }); |
| 1288 } | 1291 } |
| 1289 | 1292 |
| 1290 /** | 1293 /** |
| 1291 * Generate a setter for field [fieldIndex]. | 1294 * Generate a setter for field [fieldIndex]. |
| 1292 */ | 1295 */ |
| 1293 int makeSetter(int fieldIndex) { | 1296 int makeSetter(int fieldIndex) { |
| 1294 return setters.putIfAbsent(fieldIndex, () { | 1297 return setters.putIfAbsent(fieldIndex, () { |
| 1295 CompiledFunction stub = new CompiledFunction.accessor( | 1298 FletchFunctionBuilder stub = new FletchFunctionBuilder.accessor( |
| 1296 functions.length, | 1299 functions.length, |
| 1297 true); | 1300 true); |
| 1298 functions.add(stub); | 1301 functions.add(stub); |
| 1299 stub.builder | 1302 stub.builder |
| 1300 ..loadParameter(0) | 1303 ..loadParameter(0) |
| 1301 ..loadParameter(1) | 1304 ..loadParameter(1) |
| 1302 ..storeField(fieldIndex) | 1305 ..storeField(fieldIndex) |
| 1303 // Top is at this point the rhs argument, thus the return value. | 1306 // Top is at this point the rhs argument, thus the return value. |
| 1304 ..ret() | 1307 ..ret() |
| 1305 ..methodEnd(); | 1308 ..methodEnd(); |
| 1306 return stub.methodId; | 1309 return stub.methodId; |
| 1307 }); | 1310 }); |
| 1308 } | 1311 } |
| 1309 | 1312 |
| 1310 void generateUnimplementedError( | 1313 void generateUnimplementedError( |
| 1311 Spannable spannable, | 1314 Spannable spannable, |
| 1312 String reason, | 1315 String reason, |
| 1313 CompiledFunction function) { | 1316 FletchFunctionBuilder function) { |
| 1314 compiler.reportError( | 1317 compiler.reportError( |
| 1315 spannable, MessageKind.GENERIC, {'text': reason}); | 1318 spannable, MessageKind.GENERIC, {'text': reason}); |
| 1316 var constString = constantSystem.createString( | 1319 var constString = constantSystem.createString( |
| 1317 new DartString.literal(reason)); | 1320 new DartString.literal(reason)); |
| 1318 context.markConstantUsed(constString); | 1321 context.markConstantUsed(constString); |
| 1319 function | 1322 function |
| 1320 ..builder.loadConst(function.allocateConstant(constString)) | 1323 ..builder.loadConst(function.allocateConstant(constString)) |
| 1321 ..builder.emitThrow(); | 1324 ..builder.emitThrow(); |
| 1322 } | 1325 } |
| 1323 | 1326 |
| 1324 void forgetElement(Element element) { | 1327 void forgetElement(Element element) { |
| 1325 CompiledFunction compiledFunction = compiledFunctions[element]; | 1328 FletchFunctionBuilder functionBuilder = functionBuilders[element]; |
| 1326 if (compiledFunction == null) return; | 1329 if (functionBuilder == null) return; |
| 1327 compiledFunction.reuse(); | 1330 functionBuilder.reuse(); |
| 1328 } | 1331 } |
| 1329 } | 1332 } |
| OLD | NEW |