| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart 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 file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.js_emitter.program_builder; | 5 library dart2js.js_emitter.program_builder; |
| 6 | 6 |
| 7 import '../js_emitter.dart' show | 7 import '../js_emitter.dart' |
| 8 ClassStubGenerator, | 8 show |
| 9 CodeEmitterTask, | 9 ClassStubGenerator, |
| 10 computeMixinClass, | 10 CodeEmitterTask, |
| 11 Emitter, | 11 computeMixinClass, |
| 12 InterceptorStubGenerator, | 12 Emitter, |
| 13 MainCallStubGenerator, | 13 InterceptorStubGenerator, |
| 14 ParameterStubGenerator, | 14 MainCallStubGenerator, |
| 15 RuntimeTypeGenerator, | 15 ParameterStubGenerator, |
| 16 TypeTestProperties; | 16 RuntimeTypeGenerator, |
| 17 TypeTestProperties; |
| 17 import '../model.dart'; | 18 import '../model.dart'; |
| 18 | 19 |
| 19 import '../../closure.dart' show | 20 import '../../closure.dart' show ClosureFieldElement; |
| 20 ClosureFieldElement; | |
| 21 import '../../common.dart'; | 21 import '../../common.dart'; |
| 22 import '../../common/names.dart' show | 22 import '../../common/names.dart' show Names, Selectors; |
| 23 Names, | 23 import '../../compiler.dart' show Compiler; |
| 24 Selectors; | 24 import '../../constants/values.dart' |
| 25 import '../../compiler.dart' show | 25 show ConstantValue, InterceptorConstantValue; |
| 26 Compiler; | 26 import '../../core_types.dart' show CoreClasses; |
| 27 import '../../constants/values.dart' show | 27 import '../../dart_types.dart' show DartType, FunctionType, TypedefType; |
| 28 ConstantValue, | 28 import '../../elements/elements.dart' |
| 29 InterceptorConstantValue; | 29 show |
| 30 import '../../core_types.dart' show | 30 ClassElement, |
| 31 CoreClasses; | 31 Element, |
| 32 import '../../dart_types.dart' show | 32 Elements, |
| 33 DartType, | 33 FieldElement, |
| 34 FunctionType, | 34 FunctionElement, |
| 35 TypedefType; | 35 FunctionSignature, |
| 36 import '../../elements/elements.dart' show | 36 GetterElement, |
| 37 ClassElement, | 37 LibraryElement, |
| 38 Element, | 38 MethodElement, |
| 39 Elements, | 39 Name, |
| 40 FieldElement, | 40 ParameterElement, |
| 41 FunctionElement, | 41 TypedefElement, |
| 42 FunctionSignature, | 42 VariableElement; |
| 43 GetterElement, | |
| 44 LibraryElement, | |
| 45 MethodElement, | |
| 46 Name, | |
| 47 ParameterElement, | |
| 48 TypedefElement, | |
| 49 VariableElement; | |
| 50 import '../../js/js.dart' as js; | 43 import '../../js/js.dart' as js; |
| 51 import '../../js_backend/backend_helpers.dart' show | 44 import '../../js_backend/backend_helpers.dart' show BackendHelpers; |
| 52 BackendHelpers; | 45 import '../../js_backend/js_backend.dart' |
| 53 import '../../js_backend/js_backend.dart' show | 46 show Namer, JavaScriptBackend, JavaScriptConstantCompiler, StringBackedName; |
| 54 Namer, | 47 import '../../universe/selector.dart' show Selector; |
| 55 JavaScriptBackend, | 48 import '../../universe/universe.dart' show Universe, SelectorConstraints; |
| 56 JavaScriptConstantCompiler, | 49 import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit; |
| 57 StringBackedName; | |
| 58 import '../../universe/selector.dart' show | |
| 59 Selector; | |
| 60 import '../../universe/universe.dart' show | |
| 61 Universe, | |
| 62 SelectorConstraints; | |
| 63 import '../../deferred_load.dart' show | |
| 64 DeferredLoadTask, | |
| 65 OutputUnit; | |
| 66 | 50 |
| 67 part 'collector.dart'; | 51 part 'collector.dart'; |
| 68 part 'registry.dart'; | 52 part 'registry.dart'; |
| 69 part 'field_visitor.dart'; | 53 part 'field_visitor.dart'; |
| 70 | 54 |
| 71 /// Builds a self-contained representation of the program that can then be | 55 /// Builds a self-contained representation of the program that can then be |
| 72 /// emitted more easily by the individual emitters. | 56 /// emitted more easily by the individual emitters. |
| 73 class ProgramBuilder { | 57 class ProgramBuilder { |
| 74 final Compiler _compiler; | 58 final Compiler _compiler; |
| 75 final Namer namer; | 59 final Namer namer; |
| 76 final CodeEmitterTask _task; | 60 final CodeEmitterTask _task; |
| 77 | 61 |
| 78 /// Contains the collected information the program builder used to build | 62 /// Contains the collected information the program builder used to build |
| 79 /// the model. | 63 /// the model. |
| 80 // The collector will be filled on the first call to `buildProgram`. | 64 // The collector will be filled on the first call to `buildProgram`. |
| 81 // It is stored and publicly exposed for backwards compatibility. New code | 65 // It is stored and publicly exposed for backwards compatibility. New code |
| 82 // (and in particular new emitters) should not use it. | 66 // (and in particular new emitters) should not use it. |
| 83 final Collector collector; | 67 final Collector collector; |
| 84 | 68 |
| 85 final Registry _registry; | 69 final Registry _registry; |
| 86 | 70 |
| 87 /// True if the program should store function types in the metadata. | 71 /// True if the program should store function types in the metadata. |
| 88 bool _storeFunctionTypesInMetadata = false; | 72 bool _storeFunctionTypesInMetadata = false; |
| 89 | 73 |
| 90 ProgramBuilder(Compiler compiler, | 74 ProgramBuilder(Compiler compiler, Namer namer, this._task, Emitter emitter, |
| 91 Namer namer, | 75 Set<ClassElement> rtiNeededClasses) |
| 92 this._task, | |
| 93 Emitter emitter, | |
| 94 Set<ClassElement> rtiNeededClasses) | |
| 95 : this._compiler = compiler, | 76 : this._compiler = compiler, |
| 96 this.namer = namer, | 77 this.namer = namer, |
| 97 this.collector = | 78 this.collector = |
| 98 new Collector(compiler, namer, rtiNeededClasses, emitter), | 79 new Collector(compiler, namer, rtiNeededClasses, emitter), |
| 99 this._registry = new Registry(compiler); | 80 this._registry = new Registry(compiler); |
| 100 | 81 |
| 101 JavaScriptBackend get backend => _compiler.backend; | 82 JavaScriptBackend get backend => _compiler.backend; |
| 102 BackendHelpers get helpers => backend.helpers; | 83 BackendHelpers get helpers => backend.helpers; |
| 103 Universe get universe => _compiler.codegenWorld; | 84 Universe get universe => _compiler.codegenWorld; |
| 104 | 85 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 123 | 104 |
| 124 Set<Class> _unneededNativeClasses; | 105 Set<Class> _unneededNativeClasses; |
| 125 | 106 |
| 126 Program buildProgram({bool storeFunctionTypesInMetadata: false}) { | 107 Program buildProgram({bool storeFunctionTypesInMetadata: false}) { |
| 127 collector.collect(); | 108 collector.collect(); |
| 128 | 109 |
| 129 this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata; | 110 this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata; |
| 130 // Note: In rare cases (mostly tests) output units can be empty. This | 111 // Note: In rare cases (mostly tests) output units can be empty. This |
| 131 // happens when the deferred code is dead-code eliminated but we still need | 112 // happens when the deferred code is dead-code eliminated but we still need |
| 132 // to check that the library has been loaded. | 113 // to check that the library has been loaded. |
| 133 _compiler.deferredLoadTask.allOutputUnits.forEach( | 114 _compiler.deferredLoadTask.allOutputUnits |
| 134 _registry.registerOutputUnit); | 115 .forEach(_registry.registerOutputUnit); |
| 135 collector.outputClassLists.forEach(_registry.registerElements); | 116 collector.outputClassLists.forEach(_registry.registerElements); |
| 136 collector.outputStaticLists.forEach(_registry.registerElements); | 117 collector.outputStaticLists.forEach(_registry.registerElements); |
| 137 collector.outputConstantLists.forEach(_registerConstants); | 118 collector.outputConstantLists.forEach(_registerConstants); |
| 138 collector.outputStaticNonFinalFieldLists.forEach( | 119 collector.outputStaticNonFinalFieldLists |
| 139 _registry.registerElements); | 120 .forEach(_registry.registerElements); |
| 140 | 121 |
| 141 // We always add the current isolate holder. | 122 // We always add the current isolate holder. |
| 142 _registerStaticStateHolder(); | 123 _registerStaticStateHolder(); |
| 143 | 124 |
| 144 // We need to run the native-preparation before we build the output. The | 125 // We need to run the native-preparation before we build the output. The |
| 145 // preparation code, in turn needs the classes to be set up. | 126 // preparation code, in turn needs the classes to be set up. |
| 146 // We thus build the classes before building their containers. | 127 // We thus build the classes before building their containers. |
| 147 collector.outputClassLists.forEach((OutputUnit _, List<ClassElement> classes
) { | 128 collector.outputClassLists |
| 129 .forEach((OutputUnit _, List<ClassElement> classes) { |
| 148 classes.forEach(_buildClass); | 130 classes.forEach(_buildClass); |
| 149 }); | 131 }); |
| 150 | 132 |
| 151 // Resolve the superclass references after we've processed all the classes. | 133 // Resolve the superclass references after we've processed all the classes. |
| 152 _classes.forEach((ClassElement element, Class c) { | 134 _classes.forEach((ClassElement element, Class c) { |
| 153 if (element.superclass != null) { | 135 if (element.superclass != null) { |
| 154 c.setSuperclass(_classes[element.superclass]); | 136 c.setSuperclass(_classes[element.superclass]); |
| 155 assert(c.superclass != null); | 137 assert(c.superclass != null); |
| 156 } | 138 } |
| 157 if (c is MixinApplication) { | 139 if (c is MixinApplication) { |
| 158 c.setMixinClass(_classes[computeMixinClass(element)]); | 140 c.setMixinClass(_classes[computeMixinClass(element)]); |
| 159 assert(c.mixinClass != null); | 141 assert(c.mixinClass != null); |
| 160 } | 142 } |
| 161 }); | 143 }); |
| 162 | 144 |
| 163 List<Class> nativeClasses = collector.nativeClassesAndSubclasses | 145 List<Class> nativeClasses = collector.nativeClassesAndSubclasses |
| 164 .map((ClassElement classElement) => _classes[classElement]) | 146 .map((ClassElement classElement) => _classes[classElement]) |
| 165 .toList(); | 147 .toList(); |
| 166 | 148 |
| 167 Set<ClassElement> interceptorClassesNeededByConstants = | 149 Set<ClassElement> interceptorClassesNeededByConstants = |
| 168 collector.computeInterceptorsReferencedFromConstants(); | 150 collector.computeInterceptorsReferencedFromConstants(); |
| 169 Set<ClassElement> classesModifiedByEmitRTISupport = | 151 Set<ClassElement> classesModifiedByEmitRTISupport = |
| 170 _task.typeTestRegistry.computeClassesModifiedByEmitRuntimeTypeSupport(); | 152 _task.typeTestRegistry.computeClassesModifiedByEmitRuntimeTypeSupport(); |
| 171 | 153 |
| 172 | |
| 173 _unneededNativeClasses = _task.nativeEmitter.prepareNativeClasses( | 154 _unneededNativeClasses = _task.nativeEmitter.prepareNativeClasses( |
| 174 nativeClasses, interceptorClassesNeededByConstants, | 155 nativeClasses, |
| 156 interceptorClassesNeededByConstants, |
| 175 classesModifiedByEmitRTISupport); | 157 classesModifiedByEmitRTISupport); |
| 176 | 158 |
| 177 _addJsInteropStubs(_registry.mainLibrariesMap); | 159 _addJsInteropStubs(_registry.mainLibrariesMap); |
| 178 | 160 |
| 179 MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap); | 161 MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap); |
| 180 Iterable<Fragment> deferredFragments = | 162 Iterable<Fragment> deferredFragments = |
| 181 _registry.deferredLibrariesMap.map(_buildDeferredFragment); | 163 _registry.deferredLibrariesMap.map(_buildDeferredFragment); |
| 182 | 164 |
| 183 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount); | 165 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount); |
| 184 fragments[0] = mainFragment; | 166 fragments[0] = mainFragment; |
| 185 fragments.setAll(1, deferredFragments); | 167 fragments.setAll(1, deferredFragments); |
| 186 | 168 |
| 187 _markEagerClasses(); | 169 _markEagerClasses(); |
| 188 | 170 |
| 189 List<Holder> holders = _registry.holders.toList(growable: false); | 171 List<Holder> holders = _registry.holders.toList(growable: false); |
| 190 | 172 |
| 191 bool needsNativeSupport = _compiler.enqueuer.codegen.nativeEnqueuer | 173 bool needsNativeSupport = _compiler.enqueuer.codegen.nativeEnqueuer |
| 192 .hasInstantiatedNativeClasses(); | 174 .hasInstantiatedNativeClasses(); |
| 193 | 175 |
| 194 assert(!needsNativeSupport || nativeClasses.isNotEmpty); | 176 assert(!needsNativeSupport || nativeClasses.isNotEmpty); |
| 195 | 177 |
| 196 List<js.TokenFinalizer> finalizers = [_task.metadataCollector]; | 178 List<js.TokenFinalizer> finalizers = [_task.metadataCollector]; |
| 197 if (backend.namer is js.TokenFinalizer) { | 179 if (backend.namer is js.TokenFinalizer) { |
| 198 var namingFinalizer = backend.namer; | 180 var namingFinalizer = backend.namer; |
| 199 finalizers.add(namingFinalizer); | 181 finalizers.add(namingFinalizer); |
| 200 } | 182 } |
| 201 | 183 |
| 202 return new Program( | 184 return new Program(fragments, holders, _buildLoadMap(), _symbolsMap, |
| 203 fragments, | 185 _buildTypeToInterceptorMap(), _task.metadataCollector, finalizers, |
| 204 holders, | |
| 205 _buildLoadMap(), | |
| 206 _symbolsMap, | |
| 207 _buildTypeToInterceptorMap(), | |
| 208 _task.metadataCollector, | |
| 209 finalizers, | |
| 210 needsNativeSupport: needsNativeSupport, | 186 needsNativeSupport: needsNativeSupport, |
| 211 outputContainsConstantList: collector.outputContainsConstantList, | 187 outputContainsConstantList: collector.outputContainsConstantList, |
| 212 hasIsolateSupport: _compiler.hasIsolateSupport); | 188 hasIsolateSupport: _compiler.hasIsolateSupport); |
| 213 } | 189 } |
| 214 | 190 |
| 215 void _markEagerClasses() { | 191 void _markEagerClasses() { |
| 216 _markEagerInterceptorClasses(); | 192 _markEagerInterceptorClasses(); |
| 217 } | 193 } |
| 218 | 194 |
| 219 /// Builds a map from loadId to outputs-to-load. | 195 /// Builds a map from loadId to outputs-to-load. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 231 js.Expression _buildTypeToInterceptorMap() { | 207 js.Expression _buildTypeToInterceptorMap() { |
| 232 InterceptorStubGenerator stubGenerator = | 208 InterceptorStubGenerator stubGenerator = |
| 233 new InterceptorStubGenerator(_compiler, namer, backend); | 209 new InterceptorStubGenerator(_compiler, namer, backend); |
| 234 return stubGenerator.generateTypeToInterceptorMap(); | 210 return stubGenerator.generateTypeToInterceptorMap(); |
| 235 } | 211 } |
| 236 | 212 |
| 237 MainFragment _buildMainFragment(LibrariesMap librariesMap) { | 213 MainFragment _buildMainFragment(LibrariesMap librariesMap) { |
| 238 // Construct the main output from the libraries and the registered holders. | 214 // Construct the main output from the libraries and the registered holders. |
| 239 MainFragment result = new MainFragment( | 215 MainFragment result = new MainFragment( |
| 240 librariesMap.outputUnit, | 216 librariesMap.outputUnit, |
| 241 "", // The empty string is the name for the main output file. | 217 "", // The empty string is the name for the main output file. |
| 242 _buildInvokeMain(), | 218 _buildInvokeMain(), |
| 243 _buildLibraries(librariesMap), | 219 _buildLibraries(librariesMap), |
| 244 _buildStaticNonFinalFields(librariesMap), | 220 _buildStaticNonFinalFields(librariesMap), |
| 245 _buildStaticLazilyInitializedFields(librariesMap), | 221 _buildStaticLazilyInitializedFields(librariesMap), |
| 246 _buildConstants(librariesMap)); | 222 _buildConstants(librariesMap)); |
| 247 _outputs[librariesMap.outputUnit] = result; | 223 _outputs[librariesMap.outputUnit] = result; |
| 248 return result; | 224 return result; |
| 249 } | 225 } |
| 250 | 226 |
| 251 js.Statement _buildInvokeMain() { | 227 js.Statement _buildInvokeMain() { |
| 252 if (_compiler.isMockCompilation) return js.js.comment("Mock compilation"); | 228 if (_compiler.isMockCompilation) return js.js.comment("Mock compilation"); |
| 253 | 229 |
| 254 MainCallStubGenerator generator = | 230 MainCallStubGenerator generator = |
| 255 new MainCallStubGenerator(_compiler, backend, backend.emitter); | 231 new MainCallStubGenerator(_compiler, backend, backend.emitter); |
| 256 return generator.generateInvokeMain(); | 232 return generator.generateInvokeMain(); |
| 257 } | 233 } |
| 258 | 234 |
| 259 DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) { | 235 DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) { |
| 260 DeferredFragment result = new DeferredFragment( | 236 DeferredFragment result = new DeferredFragment( |
| 261 librariesMap.outputUnit, | 237 librariesMap.outputUnit, |
| 262 backend.deferredPartFileName(librariesMap.name, addExtension: false), | 238 backend.deferredPartFileName(librariesMap.name, addExtension: false), |
| 263 librariesMap.name, | 239 librariesMap.name, |
| 264 _buildLibraries(librariesMap), | 240 _buildLibraries(librariesMap), |
| 265 _buildStaticNonFinalFields(librariesMap), | 241 _buildStaticNonFinalFields(librariesMap), |
| 266 _buildStaticLazilyInitializedFields(librariesMap), | 242 _buildStaticLazilyInitializedFields(librariesMap), |
| 267 _buildConstants(librariesMap)); | 243 _buildConstants(librariesMap)); |
| 268 _outputs[librariesMap.outputUnit] = result; | 244 _outputs[librariesMap.outputUnit] = result; |
| 269 return result; | 245 return result; |
| 270 } | 246 } |
| 271 | 247 |
| 272 List<Constant> _buildConstants(LibrariesMap librariesMap) { | 248 List<Constant> _buildConstants(LibrariesMap librariesMap) { |
| 273 List<ConstantValue> constantValues = | 249 List<ConstantValue> constantValues = |
| 274 collector.outputConstantLists[librariesMap.outputUnit]; | 250 collector.outputConstantLists[librariesMap.outputUnit]; |
| 275 if (constantValues == null) return const <Constant>[]; | 251 if (constantValues == null) return const <Constant>[]; |
| 276 return constantValues.map((ConstantValue value) => _constants[value]) | 252 return constantValues |
| 253 .map((ConstantValue value) => _constants[value]) |
| 277 .toList(growable: false); | 254 .toList(growable: false); |
| 278 } | 255 } |
| 279 | 256 |
| 280 List<StaticField> _buildStaticNonFinalFields(LibrariesMap librariesMap) { | 257 List<StaticField> _buildStaticNonFinalFields(LibrariesMap librariesMap) { |
| 281 List<VariableElement> staticNonFinalFields = | 258 List<VariableElement> staticNonFinalFields = |
| 282 collector.outputStaticNonFinalFieldLists[librariesMap.outputUnit]; | 259 collector.outputStaticNonFinalFieldLists[librariesMap.outputUnit]; |
| 283 if (staticNonFinalFields == null) return const <StaticField>[]; | 260 if (staticNonFinalFields == null) return const <StaticField>[]; |
| 284 | 261 |
| 285 return staticNonFinalFields | 262 return staticNonFinalFields.map(_buildStaticField).toList(growable: false); |
| 286 .map(_buildStaticField) | |
| 287 .toList(growable: false); | |
| 288 } | 263 } |
| 289 | 264 |
| 290 StaticField _buildStaticField(Element element) { | 265 StaticField _buildStaticField(Element element) { |
| 291 JavaScriptConstantCompiler handler = backend.constants; | 266 JavaScriptConstantCompiler handler = backend.constants; |
| 292 ConstantValue initialValue = handler.getInitialValueFor(element); | 267 ConstantValue initialValue = handler.getInitialValueFor(element); |
| 293 // TODO(zarah): The holder should not be registered during building of | 268 // TODO(zarah): The holder should not be registered during building of |
| 294 // a static field. | 269 // a static field. |
| 295 _registry.registerHolder( | 270 _registry.registerHolder(namer.globalObjectForConstant(initialValue), |
| 296 namer.globalObjectForConstant(initialValue), isConstantsHolder: true); | 271 isConstantsHolder: true); |
| 297 js.Expression code = _task.emitter.constantReference(initialValue); | 272 js.Expression code = _task.emitter.constantReference(initialValue); |
| 298 js.Name name = namer.globalPropertyName(element); | 273 js.Name name = namer.globalPropertyName(element); |
| 299 bool isFinal = false; | 274 bool isFinal = false; |
| 300 bool isLazy = false; | 275 bool isLazy = false; |
| 301 | 276 |
| 302 // TODO(floitsch): we shouldn't update the registry in the middle of | 277 // TODO(floitsch): we shouldn't update the registry in the middle of |
| 303 // building a static field. (Note that the static-state holder was | 278 // building a static field. (Note that the static-state holder was |
| 304 // already registered earlier, and that we just call the register to get | 279 // already registered earlier, and that we just call the register to get |
| 305 // the holder-instance. | 280 // the holder-instance. |
| 306 return new StaticField(element, | 281 return new StaticField( |
| 307 name, _registerStaticStateHolder(), code, | 282 element, name, _registerStaticStateHolder(), code, isFinal, isLazy); |
| 308 isFinal, isLazy); | |
| 309 } | 283 } |
| 310 | 284 |
| 311 List<StaticField> _buildStaticLazilyInitializedFields( | 285 List<StaticField> _buildStaticLazilyInitializedFields( |
| 312 LibrariesMap librariesMap) { | 286 LibrariesMap librariesMap) { |
| 313 JavaScriptConstantCompiler handler = backend.constants; | 287 JavaScriptConstantCompiler handler = backend.constants; |
| 314 DeferredLoadTask loadTask = _compiler.deferredLoadTask; | 288 DeferredLoadTask loadTask = _compiler.deferredLoadTask; |
| 315 Iterable<VariableElement> lazyFields = handler | 289 Iterable<VariableElement> lazyFields = handler |
| 316 .getLazilyInitializedFieldsForEmission() | 290 .getLazilyInitializedFieldsForEmission() |
| 317 .where((element) => | 291 .where((element) => |
| 318 loadTask.outputUnitForElement(element) == librariesMap.outputUnit); | 292 loadTask.outputUnitForElement(element) == librariesMap.outputUnit); |
| 319 return Elements.sortedByPosition(lazyFields) | 293 return Elements |
| 294 .sortedByPosition(lazyFields) |
| 320 .map(_buildLazyField) | 295 .map(_buildLazyField) |
| 321 .where((field) => field != null) // Happens when the field was unused. | 296 .where((field) => field != null) // Happens when the field was unused. |
| 322 .toList(growable: false); | 297 .toList(growable: false); |
| 323 } | 298 } |
| 324 | 299 |
| 325 StaticField _buildLazyField(Element element) { | 300 StaticField _buildLazyField(Element element) { |
| 326 js.Expression code = backend.generatedCode[element]; | 301 js.Expression code = backend.generatedCode[element]; |
| 327 // The code is null if we ended up not needing the lazily | 302 // The code is null if we ended up not needing the lazily |
| 328 // initialized field after all because of constant folding | 303 // initialized field after all because of constant folding |
| 329 // before code generation. | 304 // before code generation. |
| 330 if (code == null) return null; | 305 if (code == null) return null; |
| 331 | 306 |
| 332 js.Name name = namer.globalPropertyName(element); | 307 js.Name name = namer.globalPropertyName(element); |
| 333 bool isFinal = element.isFinal; | 308 bool isFinal = element.isFinal; |
| 334 bool isLazy = true; | 309 bool isLazy = true; |
| 335 // TODO(floitsch): we shouldn't update the registry in the middle of | 310 // TODO(floitsch): we shouldn't update the registry in the middle of |
| 336 // building a static field. (Note that the static-state holder was | 311 // building a static field. (Note that the static-state holder was |
| 337 // already registered earlier, and that we just call the register to get | 312 // already registered earlier, and that we just call the register to get |
| 338 // the holder-instance. | 313 // the holder-instance. |
| 339 return new StaticField(element, | 314 return new StaticField( |
| 340 name, _registerStaticStateHolder(), code, | 315 element, name, _registerStaticStateHolder(), code, isFinal, isLazy); |
| 341 isFinal, isLazy); | |
| 342 } | 316 } |
| 343 | 317 |
| 344 List<Library> _buildLibraries(LibrariesMap librariesMap) { | 318 List<Library> _buildLibraries(LibrariesMap librariesMap) { |
| 345 List<Library> libraries = new List<Library>(librariesMap.length); | 319 List<Library> libraries = new List<Library>(librariesMap.length); |
| 346 int count = 0; | 320 int count = 0; |
| 347 librariesMap.forEach((LibraryElement library, List<Element> elements) { | 321 librariesMap.forEach((LibraryElement library, List<Element> elements) { |
| 348 libraries[count++] = _buildLibrary(library, elements); | 322 libraries[count++] = _buildLibrary(library, elements); |
| 349 }); | 323 }); |
| 350 return libraries; | 324 return libraries; |
| 351 } | 325 } |
| 352 | 326 |
| 353 void _addJsInteropStubs(LibrariesMap librariesMap) { | 327 void _addJsInteropStubs(LibrariesMap librariesMap) { |
| 354 if (_classes.containsKey(_compiler.coreClasses.objectClass)) { | 328 if (_classes.containsKey(_compiler.coreClasses.objectClass)) { |
| 355 var toStringInvocation = namer.invocationName(Selectors.toString_); | 329 var toStringInvocation = namer.invocationName(Selectors.toString_); |
| 356 // TODO(jacobr): register toString as used so that it is always accessible | 330 // TODO(jacobr): register toString as used so that it is always accessible |
| 357 // from JavaScript. | 331 // from JavaScript. |
| 358 _classes[_compiler.coreClasses.objectClass].callStubs.add( | 332 _classes[_compiler.coreClasses.objectClass].callStubs.add( |
| 359 _buildStubMethod( | 333 _buildStubMethod(new StringBackedName("toString"), |
| 360 new StringBackedName("toString"), | |
| 361 js.js('function() { return this.#(this) }', toStringInvocation))); | 334 js.js('function() { return this.#(this) }', toStringInvocation))); |
| 362 } | 335 } |
| 363 | 336 |
| 364 // We add all members from classes marked with isJsInterop to the base | 337 // We add all members from classes marked with isJsInterop to the base |
| 365 // Interceptor class with implementations that directly call the | 338 // Interceptor class with implementations that directly call the |
| 366 // corresponding JavaScript member. We do not attempt to bind this when | 339 // corresponding JavaScript member. We do not attempt to bind this when |
| 367 // tearing off JavaScript methods as we cannot distinguish between calling | 340 // tearing off JavaScript methods as we cannot distinguish between calling |
| 368 // a regular getter that returns a JavaScript function and tearing off | 341 // a regular getter that returns a JavaScript function and tearing off |
| 369 // a method in the case where there exist multiple JavaScript classes | 342 // a method in the case where there exist multiple JavaScript classes |
| 370 // that conflict on whether the member is a getter or a method. | 343 // that conflict on whether the member is a getter or a method. |
| 371 var interceptorClass = _classes[helpers.jsJavaScriptObjectClass]; | 344 var interceptorClass = _classes[helpers.jsJavaScriptObjectClass]; |
| 372 var stubNames = new Set<String>(); | 345 var stubNames = new Set<String>(); |
| 373 librariesMap.forEach((LibraryElement library, List<Element> elements) { | 346 librariesMap.forEach((LibraryElement library, List<Element> elements) { |
| 374 for (Element e in elements) { | 347 for (Element e in elements) { |
| 375 if (e is ClassElement && backend.isJsInterop(e)) { | 348 if (e is ClassElement && backend.isJsInterop(e)) { |
| 376 e.declaration.forEachMember((_, Element member) { | 349 e.declaration.forEachMember((_, Element member) { |
| 377 if (!member.isInstanceMember) return; | 350 if (!member.isInstanceMember) return; |
| 378 if (member.isGetter || member.isField || member.isFunction) { | 351 if (member.isGetter || member.isField || member.isFunction) { |
| 379 var selectors = | 352 var selectors = |
| 380 _compiler.codegenWorld.getterInvocationsByName(member.name); | 353 _compiler.codegenWorld.getterInvocationsByName(member.name); |
| 381 if (selectors != null && !selectors.isEmpty) { | 354 if (selectors != null && !selectors.isEmpty) { |
| 382 for (var selector in selectors.keys) { | 355 for (var selector in selectors.keys) { |
| 383 var stubName = namer.invocationName(selector); | 356 var stubName = namer.invocationName(selector); |
| 384 if (stubNames.add(stubName.key)) { | 357 if (stubNames.add(stubName.key)) { |
| 385 interceptorClass.callStubs.add(_buildStubMethod( | 358 interceptorClass.callStubs.add(_buildStubMethod(stubName, |
| 386 stubName, | 359 js.js('function(obj) { return obj.# }', [member.name]), |
| 387 js.js( | |
| 388 'function(obj) { return obj.# }', [member.name]), | |
| 389 element: member)); | 360 element: member)); |
| 390 } | 361 } |
| 391 } | 362 } |
| 392 } | 363 } |
| 393 } | 364 } |
| 394 | 365 |
| 395 if (member.isSetter || (member.isField && !member.isConst)) { | 366 if (member.isSetter || (member.isField && !member.isConst)) { |
| 396 var selectors = | 367 var selectors = |
| 397 _compiler.codegenWorld.setterInvocationsByName(member.name); | 368 _compiler.codegenWorld.setterInvocationsByName(member.name); |
| 398 if (selectors != null && !selectors.isEmpty) { | 369 if (selectors != null && !selectors.isEmpty) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 415 if (member.isFunction) { | 386 if (member.isFunction) { |
| 416 FunctionElement fn = member; | 387 FunctionElement fn = member; |
| 417 functionType = fn.type; | 388 functionType = fn.type; |
| 418 } else if (member.isGetter) { | 389 } else if (member.isGetter) { |
| 419 if (_compiler.options.trustTypeAnnotations) { | 390 if (_compiler.options.trustTypeAnnotations) { |
| 420 GetterElement getter = member; | 391 GetterElement getter = member; |
| 421 DartType returnType = getter.type.returnType; | 392 DartType returnType = getter.type.returnType; |
| 422 if (returnType.isFunctionType) { | 393 if (returnType.isFunctionType) { |
| 423 functionType = returnType; | 394 functionType = returnType; |
| 424 } else if (returnType.treatAsDynamic || | 395 } else if (returnType.treatAsDynamic || |
| 425 _compiler.types.isSubtype(returnType, | 396 _compiler.types.isSubtype( |
| 426 backend.coreTypes.functionType)) { | 397 returnType, backend.coreTypes.functionType)) { |
| 427 if (returnType.isTypedef) { | 398 if (returnType.isTypedef) { |
| 428 TypedefType typedef = returnType; | 399 TypedefType typedef = returnType; |
| 429 // TODO(jacobr): can we just use typdef.unaliased instead? | 400 // TODO(jacobr): can we just use typdef.unaliased instead? |
| 430 functionType = typedef.element.functionSignature.type; | 401 functionType = typedef.element.functionSignature.type; |
| 431 } else { | 402 } else { |
| 432 // Other misc function type such as coreTypes.Function. | 403 // Other misc function type such as coreTypes.Function. |
| 433 // Allow any number of arguments. | 404 // Allow any number of arguments. |
| 434 isFunctionLike = true; | 405 isFunctionLike = true; |
| 435 } | 406 } |
| 436 } | 407 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 457 if (selectors != null && !selectors.isEmpty) { | 428 if (selectors != null && !selectors.isEmpty) { |
| 458 for (var selector in selectors.keys) { | 429 for (var selector in selectors.keys) { |
| 459 // Check whether the arity matches this member. | 430 // Check whether the arity matches this member. |
| 460 var argumentCount = selector.argumentCount; | 431 var argumentCount = selector.argumentCount; |
| 461 // JS interop does not support named arguments. | 432 // JS interop does not support named arguments. |
| 462 if (selector.namedArgumentCount > 0) break; | 433 if (selector.namedArgumentCount > 0) break; |
| 463 if (argumentCount < minArgs) break; | 434 if (argumentCount < minArgs) break; |
| 464 if (argumentCount > maxArgs) break; | 435 if (argumentCount > maxArgs) break; |
| 465 var stubName = namer.invocationName(selector); | 436 var stubName = namer.invocationName(selector); |
| 466 if (!stubNames.add(stubName.key)) break; | 437 if (!stubNames.add(stubName.key)) break; |
| 467 var parameters = new List<String>.generate(argumentCount, | 438 var parameters = |
| 468 (i) => 'p$i'); | 439 new List<String>.generate(argumentCount, (i) => 'p$i'); |
| 469 | 440 |
| 470 // We intentionally generate the same stub method for direct | 441 // We intentionally generate the same stub method for direct |
| 471 // calls and call-throughs of getters so that calling a | 442 // calls and call-throughs of getters so that calling a |
| 472 // getter that returns a function behaves the same as calling | 443 // getter that returns a function behaves the same as calling |
| 473 // a method. This is helpful as many typed JavaScript APIs | 444 // a method. This is helpful as many typed JavaScript APIs |
| 474 // specify member functions with getters that return | 445 // specify member functions with getters that return |
| 475 // functions. The behavior of this solution matches JavaScript | 446 // functions. The behavior of this solution matches JavaScript |
| 476 // behavior implicitly binding this only when JavaScript | 447 // behavior implicitly binding this only when JavaScript |
| 477 // would. | 448 // would. |
| 478 interceptorClass.callStubs.add(_buildStubMethod( | 449 interceptorClass.callStubs.add(_buildStubMethod( |
| (...skipping 28 matching lines...) Expand all Loading... |
| 507 List<Class> classes = elements | 478 List<Class> classes = elements |
| 508 .where((e) => e is ClassElement) | 479 .where((e) => e is ClassElement) |
| 509 .map((ClassElement classElement) => _classes[classElement]) | 480 .map((ClassElement classElement) => _classes[classElement]) |
| 510 .where((Class cls) => | 481 .where((Class cls) => |
| 511 !cls.isNative || !_unneededNativeClasses.contains(cls)) | 482 !cls.isNative || !_unneededNativeClasses.contains(cls)) |
| 512 .toList(growable: false); | 483 .toList(growable: false); |
| 513 | 484 |
| 514 bool visitStatics = true; | 485 bool visitStatics = true; |
| 515 List<Field> staticFieldsForReflection = _buildFields(library, visitStatics); | 486 List<Field> staticFieldsForReflection = _buildFields(library, visitStatics); |
| 516 | 487 |
| 517 return new Library(library, uri, statics, classes, | 488 return new Library( |
| 518 staticFieldsForReflection); | 489 library, uri, statics, classes, staticFieldsForReflection); |
| 519 } | 490 } |
| 520 | 491 |
| 521 /// HACK for Incremental Compilation. | 492 /// HACK for Incremental Compilation. |
| 522 /// | 493 /// |
| 523 /// Returns a class that contains the fields of a class. | 494 /// Returns a class that contains the fields of a class. |
| 524 Class buildFieldsHackForIncrementalCompilation(ClassElement element) { | 495 Class buildFieldsHackForIncrementalCompilation(ClassElement element) { |
| 525 assert(_compiler.options.hasIncrementalSupport); | 496 assert(_compiler.options.hasIncrementalSupport); |
| 526 | 497 |
| 527 List<Field> instanceFields = _buildFields(element, false); | 498 List<Field> instanceFields = _buildFields(element, false); |
| 528 js.Name name = namer.className(element); | 499 js.Name name = namer.className(element); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 556 | 527 |
| 557 if (Elements.isNonAbstractInstanceMember(member)) { | 528 if (Elements.isNonAbstractInstanceMember(member)) { |
| 558 // TODO(herhut): Remove once _buildMethod can no longer return null. | 529 // TODO(herhut): Remove once _buildMethod can no longer return null. |
| 559 Method method = _buildMethod(member); | 530 Method method = _buildMethod(member); |
| 560 if (method != null) methods.add(method); | 531 if (method != null) methods.add(method); |
| 561 } | 532 } |
| 562 if (member.isGetter || member.isField) { | 533 if (member.isGetter || member.isField) { |
| 563 Map<Selector, SelectorConstraints> selectors = | 534 Map<Selector, SelectorConstraints> selectors = |
| 564 _compiler.codegenWorld.invocationsByName(member.name); | 535 _compiler.codegenWorld.invocationsByName(member.name); |
| 565 if (selectors != null && !selectors.isEmpty) { | 536 if (selectors != null && !selectors.isEmpty) { |
| 566 | |
| 567 Map<js.Name, js.Expression> callStubsForMember = | 537 Map<js.Name, js.Expression> callStubsForMember = |
| 568 classStubGenerator.generateCallStubsForGetter(member, selectors); | 538 classStubGenerator.generateCallStubsForGetter(member, selectors); |
| 569 callStubsForMember.forEach((js.Name name, js.Expression code) { | 539 callStubsForMember.forEach((js.Name name, js.Expression code) { |
| 570 callStubs.add(_buildStubMethod(name, code, element: member)); | 540 callStubs.add(_buildStubMethod(name, code, element: member)); |
| 571 }); | 541 }); |
| 572 } | 542 } |
| 573 } | 543 } |
| 574 } | 544 } |
| 575 | 545 |
| 576 List<StubMethod> typeVariableReaderStubs = | 546 List<StubMethod> typeVariableReaderStubs = |
| 577 runtimeTypeGenerator.generateTypeVariableReaderStubs(element); | 547 runtimeTypeGenerator.generateTypeVariableReaderStubs(element); |
| 578 | 548 |
| 579 List<StubMethod> noSuchMethodStubs = <StubMethod>[]; | 549 List<StubMethod> noSuchMethodStubs = <StubMethod>[]; |
| 580 | 550 |
| 581 if (backend.enabledNoSuchMethod && element.isObject) { | 551 if (backend.enabledNoSuchMethod && element.isObject) { |
| 582 Map<js.Name, Selector> selectors = | 552 Map<js.Name, Selector> selectors = |
| 583 classStubGenerator.computeSelectorsForNsmHandlers(); | 553 classStubGenerator.computeSelectorsForNsmHandlers(); |
| 584 selectors.forEach((js.Name name, Selector selector) { | 554 selectors.forEach((js.Name name, Selector selector) { |
| 585 // If the program contains `const Symbol` names we have to retain them. | 555 // If the program contains `const Symbol` names we have to retain them. |
| 586 String selectorName = selector.name; | 556 String selectorName = selector.name; |
| 587 if (selector.isSetter) selectorName = "$selectorName="; | 557 if (selector.isSetter) selectorName = "$selectorName="; |
| 588 if (backend.symbolsUsed.contains(selectorName)) { | 558 if (backend.symbolsUsed.contains(selectorName)) { |
| 589 _symbolsMap[name] = selectorName; | 559 _symbolsMap[name] = selectorName; |
| 590 } | 560 } |
| 591 noSuchMethodStubs | 561 noSuchMethodStubs.add( |
| 592 .add(classStubGenerator.generateStubForNoSuchMethod(name, | 562 classStubGenerator.generateStubForNoSuchMethod(name, selector)); |
| 593 selector)); | |
| 594 }); | 563 }); |
| 595 } | 564 } |
| 596 | 565 |
| 597 if (element == helpers.closureClass) { | 566 if (element == helpers.closureClass) { |
| 598 // We add a special getter here to allow for tearing off a closure from | 567 // We add a special getter here to allow for tearing off a closure from |
| 599 // itself. | 568 // itself. |
| 600 js.Name name = namer.getterForMember(Names.call); | 569 js.Name name = namer.getterForMember(Names.call); |
| 601 js.Fun function = js.js('function() { return this; }'); | 570 js.Fun function = js.js('function() { return this; }'); |
| 602 callStubs.add(_buildStubMethod(name, function)); | 571 callStubs.add(_buildStubMethod(name, function)); |
| 603 } | 572 } |
| 604 | 573 |
| 605 ClassElement implementation = element.implementation; | 574 ClassElement implementation = element.implementation; |
| 606 | 575 |
| 607 // MixinApplications run through the members of their mixin. Here, we are | 576 // MixinApplications run through the members of their mixin. Here, we are |
| 608 // only interested in direct members. | 577 // only interested in direct members. |
| 609 if (!onlyForRti && !element.isMixinApplication) { | 578 if (!onlyForRti && !element.isMixinApplication) { |
| 610 implementation.forEachMember(visitMember, includeBackendMembers: true); | 579 implementation.forEachMember(visitMember, includeBackendMembers: true); |
| 611 } | 580 } |
| 612 | 581 |
| 613 List<Field> instanceFields = | 582 List<Field> instanceFields = |
| 614 onlyForRti ? const <Field>[] : _buildFields(element, false); | 583 onlyForRti ? const <Field>[] : _buildFields(element, false); |
| 615 List<Field> staticFieldsForReflection = | 584 List<Field> staticFieldsForReflection = |
| 616 onlyForRti ? const <Field>[] : _buildFields(element, true); | 585 onlyForRti ? const <Field>[] : _buildFields(element, true); |
| 617 | 586 |
| 618 TypeTestProperties typeTests = | 587 TypeTestProperties typeTests = runtimeTypeGenerator.generateIsTests(element, |
| 619 runtimeTypeGenerator.generateIsTests( | 588 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); |
| 620 element, | |
| 621 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); | |
| 622 | 589 |
| 623 List<StubMethod> checkedSetters = <StubMethod>[]; | 590 List<StubMethod> checkedSetters = <StubMethod>[]; |
| 624 List<StubMethod> isChecks = <StubMethod>[]; | 591 List<StubMethod> isChecks = <StubMethod>[]; |
| 625 if (backend.isJsInterop(element)) { | 592 if (backend.isJsInterop(element)) { |
| 626 typeTests.properties.forEach((js.Name name, js.Node code) { | 593 typeTests.properties.forEach((js.Name name, js.Node code) { |
| 627 _classes[helpers.jsInterceptorClass].isChecks.add( | 594 _classes[helpers.jsInterceptorClass] |
| 628 _buildStubMethod(name, code)); | 595 .isChecks |
| 596 .add(_buildStubMethod(name, code)); |
| 629 }); | 597 }); |
| 630 } else { | 598 } else { |
| 631 for (Field field in instanceFields) { | 599 for (Field field in instanceFields) { |
| 632 if (field.needsCheckedSetter) { | 600 if (field.needsCheckedSetter) { |
| 633 assert(!field.needsUncheckedSetter); | 601 assert(!field.needsUncheckedSetter); |
| 634 Element element = field.element; | 602 Element element = field.element; |
| 635 js.Expression code = backend.generatedCode[element]; | 603 js.Expression code = backend.generatedCode[element]; |
| 636 assert(code != null); | 604 assert(code != null); |
| 637 js.Name name = namer.deriveSetterName(field.accessorName); | 605 js.Name name = namer.deriveSetterName(field.accessorName); |
| 638 checkedSetters.add(_buildStubMethod(name, code, element: element)); | 606 checkedSetters.add(_buildStubMethod(name, code, element: element)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 650 // building a class. | 618 // building a class. |
| 651 Holder holder = _registry.registerHolder(holderName); | 619 Holder holder = _registry.registerHolder(holderName); |
| 652 bool isInstantiated = !backend.isJsInterop(element) && | 620 bool isInstantiated = !backend.isJsInterop(element) && |
| 653 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); | 621 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element); |
| 654 | 622 |
| 655 Class result; | 623 Class result; |
| 656 if (element.isMixinApplication && !onlyForRti) { | 624 if (element.isMixinApplication && !onlyForRti) { |
| 657 assert(!backend.isNative(element)); | 625 assert(!backend.isNative(element)); |
| 658 assert(methods.isEmpty); | 626 assert(methods.isEmpty); |
| 659 | 627 |
| 660 result = new MixinApplication(element, | 628 result = new MixinApplication( |
| 661 name, holder, | 629 element, |
| 662 instanceFields, | 630 name, |
| 663 staticFieldsForReflection, | 631 holder, |
| 664 callStubs, | 632 instanceFields, |
| 665 typeVariableReaderStubs, | 633 staticFieldsForReflection, |
| 666 checkedSetters, | 634 callStubs, |
| 667 isChecks, | 635 typeVariableReaderStubs, |
| 668 typeTests.functionTypeIndex, | 636 checkedSetters, |
| 669 isDirectlyInstantiated: isInstantiated, | 637 isChecks, |
| 670 onlyForRti: onlyForRti); | 638 typeTests.functionTypeIndex, |
| 639 isDirectlyInstantiated: isInstantiated, |
| 640 onlyForRti: onlyForRti); |
| 671 } else { | 641 } else { |
| 672 result = new Class(element, | 642 result = new Class( |
| 673 name, holder, methods, instanceFields, | 643 element, |
| 674 staticFieldsForReflection, | 644 name, |
| 675 callStubs, | 645 holder, |
| 676 typeVariableReaderStubs, | 646 methods, |
| 677 noSuchMethodStubs, | 647 instanceFields, |
| 678 checkedSetters, | 648 staticFieldsForReflection, |
| 679 isChecks, | 649 callStubs, |
| 680 typeTests.functionTypeIndex, | 650 typeVariableReaderStubs, |
| 681 isDirectlyInstantiated: isInstantiated, | 651 noSuchMethodStubs, |
| 682 onlyForRti: onlyForRti, | 652 checkedSetters, |
| 683 isNative: backend.isNative(element)); | 653 isChecks, |
| 654 typeTests.functionTypeIndex, |
| 655 isDirectlyInstantiated: isInstantiated, |
| 656 onlyForRti: onlyForRti, |
| 657 isNative: backend.isNative(element)); |
| 684 } | 658 } |
| 685 _classes[element] = result; | 659 _classes[element] = result; |
| 686 return result; | 660 return result; |
| 687 } | 661 } |
| 688 | 662 |
| 689 bool _methodNeedsStubs(FunctionElement method) { | 663 bool _methodNeedsStubs(FunctionElement method) { |
| 690 return !method.functionSignature.optionalParameters.isEmpty; | 664 return !method.functionSignature.optionalParameters.isEmpty; |
| 691 } | 665 } |
| 692 | 666 |
| 693 bool _methodCanBeReflected(FunctionElement method) { | 667 bool _methodCanBeReflected(FunctionElement method) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 755 canTearOff = false; | 729 canTearOff = false; |
| 756 } else { | 730 } else { |
| 757 if (element.enclosingClass.isClosure) { | 731 if (element.enclosingClass.isClosure) { |
| 758 canTearOff = false; | 732 canTearOff = false; |
| 759 isClosureCallMethod = true; | 733 isClosureCallMethod = true; |
| 760 } else { | 734 } else { |
| 761 // Careful with operators. | 735 // Careful with operators. |
| 762 canTearOff = universe.hasInvokedGetter(element, _compiler.world) || | 736 canTearOff = universe.hasInvokedGetter(element, _compiler.world) || |
| 763 (canBeReflected && !element.isOperator); | 737 (canBeReflected && !element.isOperator); |
| 764 assert(canTearOff || | 738 assert(canTearOff || |
| 765 !universe.methodsNeedingSuperGetter.contains(element)); | 739 !universe.methodsNeedingSuperGetter.contains(element)); |
| 766 tearOffName = namer.getterForElement(element); | 740 tearOffName = namer.getterForElement(element); |
| 767 } | 741 } |
| 768 } | 742 } |
| 769 | 743 |
| 770 if (canTearOff) { | 744 if (canTearOff) { |
| 771 assert(invariant(element, !element.isGenerativeConstructor)); | 745 assert(invariant(element, !element.isGenerativeConstructor)); |
| 772 assert(invariant(element, !element.isGenerativeConstructorBody)); | 746 assert(invariant(element, !element.isGenerativeConstructorBody)); |
| 773 assert(invariant(element, !element.isConstructor)); | 747 assert(invariant(element, !element.isConstructor)); |
| 774 } | 748 } |
| 775 | 749 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 802 var /* List | Map */ optionalParameterDefaultValues; | 776 var /* List | Map */ optionalParameterDefaultValues; |
| 803 if (canBeApplied || canBeReflected) { | 777 if (canBeApplied || canBeReflected) { |
| 804 FunctionSignature signature = element.functionSignature; | 778 FunctionSignature signature = element.functionSignature; |
| 805 requiredParameterCount = signature.requiredParameterCount; | 779 requiredParameterCount = signature.requiredParameterCount; |
| 806 optionalParameterDefaultValues = | 780 optionalParameterDefaultValues = |
| 807 _computeParameterDefaultValues(signature); | 781 _computeParameterDefaultValues(signature); |
| 808 } | 782 } |
| 809 | 783 |
| 810 return new InstanceMethod(element, name, code, | 784 return new InstanceMethod(element, name, code, |
| 811 _generateParameterStubs(element, canTearOff), callName, | 785 _generateParameterStubs(element, canTearOff), callName, |
| 812 needsTearOff: canTearOff, tearOffName: tearOffName, | 786 needsTearOff: canTearOff, |
| 813 isClosureCallMethod: isClosureCallMethod, aliasName: aliasName, | 787 tearOffName: tearOffName, |
| 814 canBeApplied: canBeApplied, canBeReflected: canBeReflected, | 788 isClosureCallMethod: isClosureCallMethod, |
| 789 aliasName: aliasName, |
| 790 canBeApplied: canBeApplied, |
| 791 canBeReflected: canBeReflected, |
| 815 requiredParameterCount: requiredParameterCount, | 792 requiredParameterCount: requiredParameterCount, |
| 816 optionalParameterDefaultValues: optionalParameterDefaultValues, | 793 optionalParameterDefaultValues: optionalParameterDefaultValues, |
| 817 functionType: functionType); | 794 functionType: functionType); |
| 818 } | 795 } |
| 819 | 796 |
| 820 js.Expression _generateFunctionType(DartType type, OutputUnit outputUnit) { | 797 js.Expression _generateFunctionType(DartType type, OutputUnit outputUnit) { |
| 821 if (type.containsTypeVariables) { | 798 if (type.containsTypeVariables) { |
| 822 js.Expression thisAccess = js.js(r'this.$receiver'); | 799 js.Expression thisAccess = js.js(r'this.$receiver'); |
| 823 return backend.rtiEncoder.getSignatureEncoding(type, thisAccess); | 800 return backend.rtiEncoder.getSignatureEncoding(type, thisAccess); |
| 824 } else { | 801 } else { |
| 825 return backend.emitter.metadataCollector | 802 return backend.emitter.metadataCollector |
| 826 .reifyTypeForOutputUnit(type, outputUnit); | 803 .reifyTypeForOutputUnit(type, outputUnit); |
| 827 } | 804 } |
| 828 } | 805 } |
| 829 | 806 |
| 830 List<ParameterStubMethod> _generateParameterStubs(MethodElement element, | 807 List<ParameterStubMethod> _generateParameterStubs( |
| 831 bool canTearOff) { | 808 MethodElement element, bool canTearOff) { |
| 832 | |
| 833 if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[]; | 809 if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[]; |
| 834 | 810 |
| 835 ParameterStubGenerator generator = | 811 ParameterStubGenerator generator = |
| 836 new ParameterStubGenerator(_compiler, namer, backend); | 812 new ParameterStubGenerator(_compiler, namer, backend); |
| 837 return generator.generateParameterStubs(element, canTearOff: canTearOff); | 813 return generator.generateParameterStubs(element, canTearOff: canTearOff); |
| 838 } | 814 } |
| 839 | 815 |
| 840 /// Builds a stub method. | 816 /// Builds a stub method. |
| 841 /// | 817 /// |
| 842 /// Stub methods may have an element that can be used for code-size | 818 /// Stub methods may have an element that can be used for code-size |
| 843 /// attribution. | 819 /// attribution. |
| 844 Method _buildStubMethod(js.Name name, js.Expression code, | 820 Method _buildStubMethod(js.Name name, js.Expression code, {Element element}) { |
| 845 {Element element}) { | |
| 846 return new StubMethod(name, code, element: element); | 821 return new StubMethod(name, code, element: element); |
| 847 } | 822 } |
| 848 | 823 |
| 849 // The getInterceptor methods directly access the prototype of classes. | 824 // The getInterceptor methods directly access the prototype of classes. |
| 850 // We must evaluate these classes eagerly so that the prototype is | 825 // We must evaluate these classes eagerly so that the prototype is |
| 851 // accessible. | 826 // accessible. |
| 852 void _markEagerInterceptorClasses() { | 827 void _markEagerInterceptorClasses() { |
| 853 Map<js.Name, Set<ClassElement>> specializedGetInterceptors = | 828 Map<js.Name, Set<ClassElement>> specializedGetInterceptors = |
| 854 backend.specializedGetInterceptors; | 829 backend.specializedGetInterceptors; |
| 855 for (Set<ClassElement> classes in specializedGetInterceptors.values) { | 830 for (Set<ClassElement> classes in specializedGetInterceptors.values) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 874 List<js.Name> names = specializedGetInterceptors.keys.toList()..sort(); | 849 List<js.Name> names = specializedGetInterceptors.keys.toList()..sort(); |
| 875 return names.map((js.Name name) { | 850 return names.map((js.Name name) { |
| 876 Set<ClassElement> classes = specializedGetInterceptors[name]; | 851 Set<ClassElement> classes = specializedGetInterceptors[name]; |
| 877 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); | 852 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); |
| 878 return new StaticStubMethod(name, holder, code); | 853 return new StaticStubMethod(name, holder, code); |
| 879 }); | 854 }); |
| 880 } | 855 } |
| 881 | 856 |
| 882 List<Field> _buildFields(Element holder, bool visitStatics) { | 857 List<Field> _buildFields(Element holder, bool visitStatics) { |
| 883 List<Field> fields = <Field>[]; | 858 List<Field> fields = <Field>[]; |
| 884 new FieldVisitor(_compiler, namer).visitFields( | 859 new FieldVisitor(_compiler, namer).visitFields(holder, visitStatics, |
| 885 holder, visitStatics, (VariableElement field, | 860 (VariableElement field, js.Name name, js.Name accessorName, |
| 886 js.Name name, | 861 bool needsGetter, bool needsSetter, bool needsCheckedSetter) { |
| 887 js.Name accessorName, | |
| 888 bool needsGetter, | |
| 889 bool needsSetter, | |
| 890 bool needsCheckedSetter) { | |
| 891 assert(invariant(field, field.isDeclaration)); | 862 assert(invariant(field, field.isDeclaration)); |
| 892 | 863 |
| 893 int getterFlags = 0; | 864 int getterFlags = 0; |
| 894 if (needsGetter) { | 865 if (needsGetter) { |
| 895 if (visitStatics || !backend.fieldHasInterceptedGetter(field)) { | 866 if (visitStatics || !backend.fieldHasInterceptedGetter(field)) { |
| 896 getterFlags = 1; | 867 getterFlags = 1; |
| 897 } else { | 868 } else { |
| 898 getterFlags += 2; | 869 getterFlags += 2; |
| 899 // TODO(sra): 'isInterceptorClass' might not be the correct test | 870 // TODO(sra): 'isInterceptorClass' might not be the correct test |
| 900 // for methods forced to use the interceptor convention because | 871 // for methods forced to use the interceptor convention because |
| 901 // the method's class was elsewhere mixed-in to an interceptor. | 872 // the method's class was elsewhere mixed-in to an interceptor. |
| 902 if (!backend.isInterceptorClass(holder)) { | 873 if (!backend.isInterceptorClass(holder)) { |
| 903 getterFlags += 1; | 874 getterFlags += 1; |
| 904 } | 875 } |
| 905 } | 876 } |
| 906 } | 877 } |
| 907 | 878 |
| 908 int setterFlags = 0; | 879 int setterFlags = 0; |
| 909 if (needsSetter) { | 880 if (needsSetter) { |
| 910 if (visitStatics || !backend.fieldHasInterceptedSetter(field)) { | 881 if (visitStatics || !backend.fieldHasInterceptedSetter(field)) { |
| 911 setterFlags = 1; | 882 setterFlags = 1; |
| 912 } else { | 883 } else { |
| 913 setterFlags += 2; | 884 setterFlags += 2; |
| 914 if (!backend.isInterceptorClass(holder)) { | 885 if (!backend.isInterceptorClass(holder)) { |
| 915 setterFlags += 1; | 886 setterFlags += 1; |
| 916 } | 887 } |
| 917 } | 888 } |
| 918 } | 889 } |
| 919 | 890 |
| 920 fields.add(new Field(field, name, accessorName, | 891 fields.add(new Field(field, name, accessorName, getterFlags, setterFlags, |
| 921 getterFlags, setterFlags, | 892 needsCheckedSetter)); |
| 922 needsCheckedSetter)); | |
| 923 }); | 893 }); |
| 924 | 894 |
| 925 return fields; | 895 return fields; |
| 926 } | 896 } |
| 927 | 897 |
| 928 Iterable<StaticStubMethod> _generateOneShotInterceptors() { | 898 Iterable<StaticStubMethod> _generateOneShotInterceptors() { |
| 929 InterceptorStubGenerator stubGenerator = | 899 InterceptorStubGenerator stubGenerator = |
| 930 new InterceptorStubGenerator(_compiler, namer, backend); | 900 new InterceptorStubGenerator(_compiler, namer, backend); |
| 931 | 901 |
| 932 String holderName = namer.globalObjectFor(helpers.interceptorsLibrary); | 902 String holderName = namer.globalObjectFor(helpers.interceptorsLibrary); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 950 bool canBeApplied = _methodCanBeApplied(element); | 920 bool canBeApplied = _methodCanBeApplied(element); |
| 951 bool canBeReflected = _methodCanBeReflected(element); | 921 bool canBeReflected = _methodCanBeReflected(element); |
| 952 | 922 |
| 953 bool needsTearOff = isApplyTarget && | 923 bool needsTearOff = isApplyTarget && |
| 954 (canBeReflected || | 924 (canBeReflected || |
| 955 universe.staticFunctionsNeedingGetter.contains(element)); | 925 universe.staticFunctionsNeedingGetter.contains(element)); |
| 956 | 926 |
| 957 js.Name tearOffName = | 927 js.Name tearOffName = |
| 958 needsTearOff ? namer.staticClosureName(element) : null; | 928 needsTearOff ? namer.staticClosureName(element) : null; |
| 959 | 929 |
| 960 | |
| 961 js.Name callName = null; | 930 js.Name callName = null; |
| 962 if (needsTearOff) { | 931 if (needsTearOff) { |
| 963 Selector callSelector = | 932 Selector callSelector = |
| 964 new Selector.fromElement(element).toCallSelector(); | 933 new Selector.fromElement(element).toCallSelector(); |
| 965 callName = namer.invocationName(callSelector); | 934 callName = namer.invocationName(callSelector); |
| 966 } | 935 } |
| 967 js.Expression functionType; | 936 js.Expression functionType; |
| 968 DartType type = element.type; | 937 DartType type = element.type; |
| 969 if (needsTearOff || canBeReflected) { | 938 if (needsTearOff || canBeReflected) { |
| 970 OutputUnit outputUnit = | 939 OutputUnit outputUnit = |
| 971 _compiler.deferredLoadTask.outputUnitForElement(element); | 940 _compiler.deferredLoadTask.outputUnitForElement(element); |
| 972 functionType = _generateFunctionType(type, outputUnit); | 941 functionType = _generateFunctionType(type, outputUnit); |
| 973 } | 942 } |
| 974 | 943 |
| 975 int requiredParameterCount; | 944 int requiredParameterCount; |
| 976 var /* List | Map */ optionalParameterDefaultValues; | 945 var /* List | Map */ optionalParameterDefaultValues; |
| 977 if (canBeApplied || canBeReflected) { | 946 if (canBeApplied || canBeReflected) { |
| 978 FunctionSignature signature = element.functionSignature; | 947 FunctionSignature signature = element.functionSignature; |
| 979 requiredParameterCount = signature.requiredParameterCount; | 948 requiredParameterCount = signature.requiredParameterCount; |
| 980 optionalParameterDefaultValues = | 949 optionalParameterDefaultValues = |
| 981 _computeParameterDefaultValues(signature); | 950 _computeParameterDefaultValues(signature); |
| 982 } | 951 } |
| 983 | 952 |
| 984 // TODO(floitsch): we shouldn't update the registry in the middle of | 953 // TODO(floitsch): we shouldn't update the registry in the middle of |
| 985 // building a static method. | 954 // building a static method. |
| 986 return new StaticDartMethod(element, | 955 return new StaticDartMethod(element, name, _registry.registerHolder(holder), |
| 987 name, _registry.registerHolder(holder), code, | 956 code, _generateParameterStubs(element, needsTearOff), callName, |
| 988 _generateParameterStubs(element, needsTearOff), | 957 needsTearOff: needsTearOff, |
| 989 callName, | 958 tearOffName: tearOffName, |
| 990 needsTearOff: needsTearOff, | 959 canBeApplied: canBeApplied, |
| 991 tearOffName: tearOffName, | 960 canBeReflected: canBeReflected, |
| 992 canBeApplied: canBeApplied, | 961 requiredParameterCount: requiredParameterCount, |
| 993 canBeReflected: canBeReflected, | 962 optionalParameterDefaultValues: optionalParameterDefaultValues, |
| 994 requiredParameterCount: requiredParameterCount, | 963 functionType: functionType); |
| 995 optionalParameterDefaultValues: | |
| 996 optionalParameterDefaultValues, | |
| 997 functionType: functionType); | |
| 998 } | 964 } |
| 999 | 965 |
| 1000 void _registerConstants(OutputUnit outputUnit, | 966 void _registerConstants( |
| 1001 Iterable<ConstantValue> constantValues) { | 967 OutputUnit outputUnit, Iterable<ConstantValue> constantValues) { |
| 1002 // `constantValues` is null if an outputUnit doesn't contain any constants. | 968 // `constantValues` is null if an outputUnit doesn't contain any constants. |
| 1003 if (constantValues == null) return; | 969 if (constantValues == null) return; |
| 1004 for (ConstantValue constantValue in constantValues) { | 970 for (ConstantValue constantValue in constantValues) { |
| 1005 _registry.registerConstant(outputUnit, constantValue); | 971 _registry.registerConstant(outputUnit, constantValue); |
| 1006 assert(!_constants.containsKey(constantValue)); | 972 assert(!_constants.containsKey(constantValue)); |
| 1007 js.Name name = namer.constantName(constantValue); | 973 js.Name name = namer.constantName(constantValue); |
| 1008 String constantObject = namer.globalObjectForConstant(constantValue); | 974 String constantObject = namer.globalObjectForConstant(constantValue); |
| 1009 Holder holder = | 975 Holder holder = |
| 1010 _registry.registerHolder(constantObject, isConstantsHolder: true); | 976 _registry.registerHolder(constantObject, isConstantsHolder: true); |
| 1011 Constant constant = new Constant(name, holder, constantValue); | 977 Constant constant = new Constant(name, holder, constantValue); |
| 1012 _constants[constantValue] = constant; | 978 _constants[constantValue] = constant; |
| 1013 } | 979 } |
| 1014 } | 980 } |
| 1015 | 981 |
| 1016 Holder _registerStaticStateHolder() { | 982 Holder _registerStaticStateHolder() { |
| 1017 return _registry.registerHolder( | 983 return _registry.registerHolder(namer.staticStateHolder, |
| 1018 namer.staticStateHolder, isStaticStateHolder: true); | 984 isStaticStateHolder: true); |
| 1019 } | 985 } |
| 1020 } | 986 } |
| OLD | NEW |