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 '../../closure.dart' show ClosureFieldElement; | 7 import '../../closure.dart' show ClosureFieldElement; |
8 import '../../common.dart'; | 8 import '../../common.dart'; |
9 import '../../common/names.dart' show Names, Selectors; | 9 import '../../common/names.dart' show Names, Selectors; |
10 import '../../compiler.dart' show Compiler; | 10 import '../../compiler.dart' show Compiler; |
(...skipping 12 matching lines...) Expand all Loading... |
23 FunctionElement, | 23 FunctionElement, |
24 FunctionSignature, | 24 FunctionSignature, |
25 GetterElement, | 25 GetterElement, |
26 LibraryElement, | 26 LibraryElement, |
27 MemberElement, | 27 MemberElement, |
28 MethodElement, | 28 MethodElement, |
29 ParameterElement, | 29 ParameterElement, |
30 TypedefElement, | 30 TypedefElement, |
31 VariableElement; | 31 VariableElement; |
32 import '../../elements/entities.dart'; | 32 import '../../elements/entities.dart'; |
| 33 import '../../elements/resolution_types.dart' show Types; |
33 import '../../elements/types.dart' show DartType; | 34 import '../../elements/types.dart' show DartType; |
34 import '../../js/js.dart' as js; | 35 import '../../js/js.dart' as js; |
35 import '../../js_backend/js_backend.dart' | 36 import '../../js_backend/backend.dart' |
36 show Namer, JavaScriptBackend, JavaScriptConstantCompiler, StringBackedName; | 37 show |
| 38 JavaScriptBackend, |
| 39 RuntimeTypesEncoder, |
| 40 RuntimeTypesNeed, |
| 41 SuperMemberData; |
| 42 import '../../js_backend/backend_usage.dart'; |
| 43 import '../../js_backend/constant_handler_javascript.dart' |
| 44 show JavaScriptConstantCompiler; |
| 45 import '../../js_backend/namer.dart' show Namer, StringBackedName; |
| 46 import '../../js_backend/native_data.dart'; |
| 47 import '../../js_backend/interceptor_data.dart'; |
| 48 import '../../js_backend/mirrors_data.dart'; |
| 49 import '../../native/enqueue.dart' show NativeCodegenEnqueuer; |
| 50 import '../../options.dart'; |
37 import '../../universe/selector.dart' show Selector; | 51 import '../../universe/selector.dart' show Selector; |
38 import '../../universe/world_builder.dart' | 52 import '../../universe/world_builder.dart' |
39 show CodegenWorldBuilder, SelectorConstraints; | 53 show CodegenWorldBuilder, SelectorConstraints; |
40 import '../../world.dart' show ClosedWorld; | 54 import '../../world.dart' show ClosedWorld; |
41 import '../js_emitter.dart' | 55 import '../js_emitter.dart' |
42 show | 56 show |
43 ClassStubGenerator, | 57 ClassStubGenerator, |
44 CodeEmitterTask, | 58 CodeEmitterTask, |
45 computeMixinClass, | 59 computeMixinClass, |
46 Emitter, | 60 Emitter, |
(...skipping 30 matching lines...) Expand all Loading... |
77 | 91 |
78 ProgramBuilder(Compiler compiler, Namer namer, this._task, Emitter emitter, | 92 ProgramBuilder(Compiler compiler, Namer namer, this._task, Emitter emitter, |
79 ClosedWorld closedWorld, Set<ClassElement> rtiNeededClasses) | 93 ClosedWorld closedWorld, Set<ClassElement> rtiNeededClasses) |
80 : this._compiler = compiler, | 94 : this._compiler = compiler, |
81 this.namer = namer, | 95 this.namer = namer, |
82 this.closedWorld = closedWorld, | 96 this.closedWorld = closedWorld, |
83 this.collector = new Collector( | 97 this.collector = new Collector( |
84 compiler, namer, closedWorld, rtiNeededClasses, emitter), | 98 compiler, namer, closedWorld, rtiNeededClasses, emitter), |
85 this._registry = new Registry(compiler); | 99 this._registry = new Registry(compiler); |
86 | 100 |
87 JavaScriptBackend get backend => _compiler.backend; | 101 JavaScriptBackend get _backend => _compiler.backend; |
88 CodegenWorldBuilder get worldBuilder => _compiler.codegenWorldBuilder; | 102 CodegenWorldBuilder get _worldBuilder => _compiler.codegenWorldBuilder; |
| 103 DeferredLoadTask get _deferredLoadTask => _compiler.deferredLoadTask; |
| 104 Types get _types => _compiler.types; |
| 105 CommonElements get _commonElements => _compiler.commonElements; |
| 106 CompilerOptions get _options => _compiler.options; |
| 107 NativeCodegenEnqueuer get _nativeCodegenEnqueuer => |
| 108 _backend.nativeCodegenEnqueuer; |
| 109 Namer get _namer => _backend.namer; |
| 110 BackendUsage get _backendUsage => _backend.backendUsage; |
| 111 CodeEmitterTask get _emitter => _backend.emitter; |
| 112 JavaScriptConstantCompiler get _constantHandler => _backend.constants; |
| 113 NativeData get _nativeData => _backend.nativeData; |
| 114 RuntimeTypesNeed get _rtiNeed => _backend.rtiNeed; |
| 115 MirrorsData get _mirrorsData => _backend.mirrorsData; |
| 116 InterceptorData get _interceptorData => _backend.interceptorData; |
| 117 SuperMemberData get _superMemberData => _backend.superMemberData; |
| 118 RuntimeTypesEncoder get _rtiEncoder => _backend.rtiEncoder; |
| 119 OneShotInterceptorData get _oneShotInterceptorData => |
| 120 _backend.oneShotInterceptorData; |
89 | 121 |
90 /// Mapping from [ClassElement] to constructed [Class]. We need this to | 122 /// Mapping from [ClassElement] to constructed [Class]. We need this to |
91 /// update the superclass in the [Class]. | 123 /// update the superclass in the [Class]. |
92 final Map<ClassElement, Class> _classes = <ClassElement, Class>{}; | 124 final Map<ClassElement, Class> _classes = <ClassElement, Class>{}; |
93 | 125 |
94 /// Mapping from [OutputUnit] to constructed [Fragment]. We need this to | 126 /// Mapping from [OutputUnit] to constructed [Fragment]. We need this to |
95 /// generate the deferredLoadingMap (to know which hunks to load). | 127 /// generate the deferredLoadingMap (to know which hunks to load). |
96 final Map<OutputUnit, Fragment> _outputs = <OutputUnit, Fragment>{}; | 128 final Map<OutputUnit, Fragment> _outputs = <OutputUnit, Fragment>{}; |
97 | 129 |
98 /// Mapping from [ConstantValue] to constructed [Constant]. We need this to | 130 /// Mapping from [ConstantValue] to constructed [Constant]. We need this to |
99 /// update field-initializers to point to the ConstantModel. | 131 /// update field-initializers to point to the ConstantModel. |
100 final Map<ConstantValue, Constant> _constants = <ConstantValue, Constant>{}; | 132 final Map<ConstantValue, Constant> _constants = <ConstantValue, Constant>{}; |
101 | 133 |
102 /// Mapping from names to strings. | 134 /// Mapping from names to strings. |
103 /// | 135 /// |
104 /// This mapping is used to support `const Symbol` expressions. | 136 /// This mapping is used to support `const Symbol` expressions. |
105 /// | 137 /// |
106 /// This map is filled when building classes. | 138 /// This map is filled when building classes. |
107 final Map<js.Name, String> _symbolsMap = <js.Name, String>{}; | 139 final Map<js.Name, String> _symbolsMap = <js.Name, String>{}; |
108 | 140 |
109 Set<Class> _unneededNativeClasses; | 141 Set<Class> _unneededNativeClasses; |
110 | 142 |
111 Program buildProgram({bool storeFunctionTypesInMetadata: false}) { | 143 Program buildProgram({bool storeFunctionTypesInMetadata: false}) { |
112 collector.collect(); | 144 collector.collect(); |
113 | 145 |
114 this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata; | 146 this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata; |
115 // Note: In rare cases (mostly tests) output units can be empty. This | 147 // Note: In rare cases (mostly tests) output units can be empty. This |
116 // happens when the deferred code is dead-code eliminated but we still need | 148 // happens when the deferred code is dead-code eliminated but we still need |
117 // to check that the library has been loaded. | 149 // to check that the library has been loaded. |
118 _compiler.deferredLoadTask.allOutputUnits | 150 _deferredLoadTask.allOutputUnits.forEach(_registry.registerOutputUnit); |
119 .forEach(_registry.registerOutputUnit); | |
120 collector.outputClassLists.forEach(_registry.registerElements); | 151 collector.outputClassLists.forEach(_registry.registerElements); |
121 collector.outputStaticLists.forEach(_registry.registerElements); | 152 collector.outputStaticLists.forEach(_registry.registerElements); |
122 collector.outputConstantLists.forEach(_registerConstants); | 153 collector.outputConstantLists.forEach(_registerConstants); |
123 collector.outputStaticNonFinalFieldLists | 154 collector.outputStaticNonFinalFieldLists |
124 .forEach(_registry.registerElements); | 155 .forEach(_registry.registerElements); |
125 | 156 |
126 // We always add the current isolate holder. | 157 // We always add the current isolate holder. |
127 _registerStaticStateHolder(); | 158 _registerStaticStateHolder(); |
128 | 159 |
129 // We need to run the native-preparation before we build the output. The | 160 // We need to run the native-preparation before we build the output. The |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 | 199 |
169 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount); | 200 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount); |
170 fragments[0] = mainFragment; | 201 fragments[0] = mainFragment; |
171 fragments.setAll(1, deferredFragments); | 202 fragments.setAll(1, deferredFragments); |
172 | 203 |
173 _markEagerClasses(); | 204 _markEagerClasses(); |
174 | 205 |
175 List<Holder> holders = _registry.holders.toList(growable: false); | 206 List<Holder> holders = _registry.holders.toList(growable: false); |
176 | 207 |
177 bool needsNativeSupport = | 208 bool needsNativeSupport = |
178 backend.nativeCodegenEnqueuer.hasInstantiatedNativeClasses; | 209 _nativeCodegenEnqueuer.hasInstantiatedNativeClasses; |
179 | 210 |
180 assert(!needsNativeSupport || nativeClasses.isNotEmpty); | 211 assert(!needsNativeSupport || nativeClasses.isNotEmpty); |
181 | 212 |
182 List<js.TokenFinalizer> finalizers = [_task.metadataCollector]; | 213 List<js.TokenFinalizer> finalizers = [_task.metadataCollector]; |
183 if (backend.namer is js.TokenFinalizer) { | 214 if (_namer is js.TokenFinalizer) { |
184 var namingFinalizer = backend.namer; | 215 var namingFinalizer = _namer; |
185 finalizers.add(namingFinalizer as js.TokenFinalizer); | 216 finalizers.add(namingFinalizer as js.TokenFinalizer); |
186 } | 217 } |
187 | 218 |
188 return new Program(fragments, holders, _buildLoadMap(), _symbolsMap, | 219 return new Program(fragments, holders, _buildLoadMap(), _symbolsMap, |
189 _buildTypeToInterceptorMap(), _task.metadataCollector, finalizers, | 220 _buildTypeToInterceptorMap(), _task.metadataCollector, finalizers, |
190 needsNativeSupport: needsNativeSupport, | 221 needsNativeSupport: needsNativeSupport, |
191 outputContainsConstantList: collector.outputContainsConstantList, | 222 outputContainsConstantList: collector.outputContainsConstantList, |
192 hasIsolateSupport: backend.backendUsage.isIsolateInUse); | 223 hasIsolateSupport: _backendUsage.isIsolateInUse); |
193 } | 224 } |
194 | 225 |
195 void _markEagerClasses() { | 226 void _markEagerClasses() { |
196 _markEagerInterceptorClasses(); | 227 _markEagerInterceptorClasses(); |
197 } | 228 } |
198 | 229 |
199 /// Builds a map from loadId to outputs-to-load. | 230 /// Builds a map from loadId to outputs-to-load. |
200 Map<String, List<Fragment>> _buildLoadMap() { | 231 Map<String, List<Fragment>> _buildLoadMap() { |
201 Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{}; | 232 Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{}; |
202 _compiler.deferredLoadTask.hunksToLoad | 233 _deferredLoadTask.hunksToLoad |
203 .forEach((String loadId, List<OutputUnit> outputUnits) { | 234 .forEach((String loadId, List<OutputUnit> outputUnits) { |
204 loadMap[loadId] = outputUnits | 235 loadMap[loadId] = outputUnits |
205 .map((OutputUnit unit) => _outputs[unit]) | 236 .map((OutputUnit unit) => _outputs[unit]) |
206 .toList(growable: false); | 237 .toList(growable: false); |
207 }); | 238 }); |
208 return loadMap; | 239 return loadMap; |
209 } | 240 } |
210 | 241 |
211 js.Expression _buildTypeToInterceptorMap() { | 242 js.Expression _buildTypeToInterceptorMap() { |
212 InterceptorStubGenerator stubGenerator = | 243 InterceptorStubGenerator stubGenerator = |
213 new InterceptorStubGenerator(_compiler, namer, backend, closedWorld); | 244 new InterceptorStubGenerator(_compiler, namer, _backend, closedWorld); |
214 return stubGenerator.generateTypeToInterceptorMap(); | 245 return stubGenerator.generateTypeToInterceptorMap(); |
215 } | 246 } |
216 | 247 |
217 MainFragment _buildMainFragment(LibrariesMap librariesMap) { | 248 MainFragment _buildMainFragment(LibrariesMap librariesMap) { |
218 // Construct the main output from the libraries and the registered holders. | 249 // Construct the main output from the libraries and the registered holders. |
219 MainFragment result = new MainFragment( | 250 MainFragment result = new MainFragment( |
220 librariesMap.outputUnit, | 251 librariesMap.outputUnit, |
221 "", // The empty string is the name for the main output file. | 252 "", // The empty string is the name for the main output file. |
222 _buildInvokeMain(), | 253 _buildInvokeMain(), |
223 _buildLibraries(librariesMap), | 254 _buildLibraries(librariesMap), |
224 _buildStaticNonFinalFields(librariesMap), | 255 _buildStaticNonFinalFields(librariesMap), |
225 _buildStaticLazilyInitializedFields(librariesMap), | 256 _buildStaticLazilyInitializedFields(librariesMap), |
226 _buildConstants(librariesMap)); | 257 _buildConstants(librariesMap)); |
227 _outputs[librariesMap.outputUnit] = result; | 258 _outputs[librariesMap.outputUnit] = result; |
228 return result; | 259 return result; |
229 } | 260 } |
230 | 261 |
231 js.Statement _buildInvokeMain() { | 262 js.Statement _buildInvokeMain() { |
232 if (_compiler.isMockCompilation) return js.js.comment("Mock compilation"); | 263 if (_compiler.isMockCompilation) return js.js.comment("Mock compilation"); |
233 | 264 |
234 MainCallStubGenerator generator = | 265 MainCallStubGenerator generator = |
235 new MainCallStubGenerator(backend, backend.emitter); | 266 new MainCallStubGenerator(_backend, _emitter); |
236 return generator.generateInvokeMain(_compiler.mainFunction); | 267 return generator.generateInvokeMain(_compiler.mainFunction); |
237 } | 268 } |
238 | 269 |
239 DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) { | 270 DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) { |
240 DeferredFragment result = new DeferredFragment( | 271 DeferredFragment result = new DeferredFragment( |
241 librariesMap.outputUnit, | 272 librariesMap.outputUnit, |
242 backend.deferredPartFileName(librariesMap.name, addExtension: false), | 273 _backend.deferredPartFileName(librariesMap.name, addExtension: false), |
243 librariesMap.name, | 274 librariesMap.name, |
244 _buildLibraries(librariesMap), | 275 _buildLibraries(librariesMap), |
245 _buildStaticNonFinalFields(librariesMap), | 276 _buildStaticNonFinalFields(librariesMap), |
246 _buildStaticLazilyInitializedFields(librariesMap), | 277 _buildStaticLazilyInitializedFields(librariesMap), |
247 _buildConstants(librariesMap)); | 278 _buildConstants(librariesMap)); |
248 _outputs[librariesMap.outputUnit] = result; | 279 _outputs[librariesMap.outputUnit] = result; |
249 return result; | 280 return result; |
250 } | 281 } |
251 | 282 |
252 List<Constant> _buildConstants(LibrariesMap librariesMap) { | 283 List<Constant> _buildConstants(LibrariesMap librariesMap) { |
253 List<ConstantValue> constantValues = | 284 List<ConstantValue> constantValues = |
254 collector.outputConstantLists[librariesMap.outputUnit]; | 285 collector.outputConstantLists[librariesMap.outputUnit]; |
255 if (constantValues == null) return const <Constant>[]; | 286 if (constantValues == null) return const <Constant>[]; |
256 return constantValues | 287 return constantValues |
257 .map((ConstantValue value) => _constants[value]) | 288 .map((ConstantValue value) => _constants[value]) |
258 .toList(growable: false); | 289 .toList(growable: false); |
259 } | 290 } |
260 | 291 |
261 List<StaticField> _buildStaticNonFinalFields(LibrariesMap librariesMap) { | 292 List<StaticField> _buildStaticNonFinalFields(LibrariesMap librariesMap) { |
262 List<VariableElement> staticNonFinalFields = | 293 List<VariableElement> staticNonFinalFields = |
263 collector.outputStaticNonFinalFieldLists[librariesMap.outputUnit]; | 294 collector.outputStaticNonFinalFieldLists[librariesMap.outputUnit]; |
264 if (staticNonFinalFields == null) return const <StaticField>[]; | 295 if (staticNonFinalFields == null) return const <StaticField>[]; |
265 | 296 |
266 return staticNonFinalFields.map(_buildStaticField).toList(growable: false); | 297 return staticNonFinalFields.map(_buildStaticField).toList(growable: false); |
267 } | 298 } |
268 | 299 |
269 StaticField _buildStaticField(FieldElement element) { | 300 StaticField _buildStaticField(FieldElement element) { |
270 JavaScriptConstantCompiler handler = backend.constants; | 301 ConstantValue initialValue = |
271 ConstantValue initialValue = handler.getConstantValue(element.constant); | 302 _constantHandler.getConstantValue(element.constant); |
272 // TODO(zarah): The holder should not be registered during building of | 303 // TODO(zarah): The holder should not be registered during building of |
273 // a static field. | 304 // a static field. |
274 _registry.registerHolder(namer.globalObjectForConstant(initialValue), | 305 _registry.registerHolder(namer.globalObjectForConstant(initialValue), |
275 isConstantsHolder: true); | 306 isConstantsHolder: true); |
276 js.Expression code = _task.emitter.constantReference(initialValue); | 307 js.Expression code = _task.emitter.constantReference(initialValue); |
277 js.Name name = namer.globalPropertyName(element); | 308 js.Name name = namer.globalPropertyName(element); |
278 bool isFinal = false; | 309 bool isFinal = false; |
279 bool isLazy = false; | 310 bool isLazy = false; |
280 | 311 |
281 // TODO(floitsch): we shouldn't update the registry in the middle of | 312 // TODO(floitsch): we shouldn't update the registry in the middle of |
282 // building a static field. (Note that the static-state holder was | 313 // building a static field. (Note that the static-state holder was |
283 // already registered earlier, and that we just call the register to get | 314 // already registered earlier, and that we just call the register to get |
284 // the holder-instance. | 315 // the holder-instance. |
285 return new StaticField( | 316 return new StaticField( |
286 element, name, _registerStaticStateHolder(), code, isFinal, isLazy); | 317 element, name, _registerStaticStateHolder(), code, isFinal, isLazy); |
287 } | 318 } |
288 | 319 |
289 List<StaticField> _buildStaticLazilyInitializedFields( | 320 List<StaticField> _buildStaticLazilyInitializedFields( |
290 LibrariesMap librariesMap) { | 321 LibrariesMap librariesMap) { |
291 JavaScriptConstantCompiler handler = backend.constants; | 322 Iterable<FieldElement> lazyFields = _constantHandler |
292 DeferredLoadTask loadTask = _compiler.deferredLoadTask; | |
293 Iterable<FieldElement> lazyFields = handler | |
294 .getLazilyInitializedFieldsForEmission() | 323 .getLazilyInitializedFieldsForEmission() |
295 .where((element) => | 324 .where((element) => |
296 loadTask.outputUnitForElement(element) == librariesMap.outputUnit); | 325 _deferredLoadTask.outputUnitForElement(element) == |
| 326 librariesMap.outputUnit); |
297 return Elements | 327 return Elements |
298 .sortedByPosition(lazyFields) | 328 .sortedByPosition(lazyFields) |
299 .map(_buildLazyField) | 329 .map(_buildLazyField) |
300 .where((field) => field != null) // Happens when the field was unused. | 330 .where((field) => field != null) // Happens when the field was unused. |
301 .toList(growable: false); | 331 .toList(growable: false); |
302 } | 332 } |
303 | 333 |
304 StaticField _buildLazyField(FieldElement element) { | 334 StaticField _buildLazyField(FieldElement element) { |
305 js.Expression code = backend.generatedCode[element]; | 335 js.Expression code = _backend.generatedCode[element]; |
306 // The code is null if we ended up not needing the lazily | 336 // The code is null if we ended up not needing the lazily |
307 // initialized field after all because of constant folding | 337 // initialized field after all because of constant folding |
308 // before code generation. | 338 // before code generation. |
309 if (code == null) return null; | 339 if (code == null) return null; |
310 | 340 |
311 js.Name name = namer.globalPropertyName(element); | 341 js.Name name = namer.globalPropertyName(element); |
312 bool isFinal = element.isFinal; | 342 bool isFinal = element.isFinal; |
313 bool isLazy = true; | 343 bool isLazy = true; |
314 // TODO(floitsch): we shouldn't update the registry in the middle of | 344 // TODO(floitsch): we shouldn't update the registry in the middle of |
315 // building a static field. (Note that the static-state holder was | 345 // building a static field. (Note that the static-state holder was |
316 // already registered earlier, and that we just call the register to get | 346 // already registered earlier, and that we just call the register to get |
317 // the holder-instance. | 347 // the holder-instance. |
318 return new StaticField( | 348 return new StaticField( |
319 element, name, _registerStaticStateHolder(), code, isFinal, isLazy); | 349 element, name, _registerStaticStateHolder(), code, isFinal, isLazy); |
320 } | 350 } |
321 | 351 |
322 List<Library> _buildLibraries(LibrariesMap librariesMap) { | 352 List<Library> _buildLibraries(LibrariesMap librariesMap) { |
323 List<Library> libraries = new List<Library>(librariesMap.length); | 353 List<Library> libraries = new List<Library>(librariesMap.length); |
324 int count = 0; | 354 int count = 0; |
325 librariesMap.forEach((LibraryElement library, List<Element> elements) { | 355 librariesMap.forEach((LibraryElement library, List<Element> elements) { |
326 libraries[count++] = _buildLibrary(library, elements); | 356 libraries[count++] = _buildLibrary(library, elements); |
327 }); | 357 }); |
328 return libraries; | 358 return libraries; |
329 } | 359 } |
330 | 360 |
331 void _addJsInteropStubs(LibrariesMap librariesMap) { | 361 void _addJsInteropStubs(LibrariesMap librariesMap) { |
332 if (_classes.containsKey(_compiler.commonElements.objectClass)) { | 362 if (_classes.containsKey(_commonElements.objectClass)) { |
333 var toStringInvocation = namer.invocationName(Selectors.toString_); | 363 var toStringInvocation = namer.invocationName(Selectors.toString_); |
334 // TODO(jacobr): register toString as used so that it is always accessible | 364 // TODO(jacobr): register toString as used so that it is always accessible |
335 // from JavaScript. | 365 // from JavaScript. |
336 _classes[_compiler.commonElements.objectClass].callStubs.add( | 366 _classes[_commonElements.objectClass].callStubs.add(_buildStubMethod( |
337 _buildStubMethod(new StringBackedName("toString"), | 367 new StringBackedName("toString"), |
338 js.js('function() { return this.#(this) }', toStringInvocation))); | 368 js.js('function() { return this.#(this) }', toStringInvocation))); |
339 } | 369 } |
340 | 370 |
341 // We add all members from classes marked with isJsInterop to the base | 371 // We add all members from classes marked with isJsInterop to the base |
342 // Interceptor class with implementations that directly call the | 372 // Interceptor class with implementations that directly call the |
343 // corresponding JavaScript member. We do not attempt to bind this when | 373 // corresponding JavaScript member. We do not attempt to bind this when |
344 // tearing off JavaScript methods as we cannot distinguish between calling | 374 // tearing off JavaScript methods as we cannot distinguish between calling |
345 // a regular getter that returns a JavaScript function and tearing off | 375 // a regular getter that returns a JavaScript function and tearing off |
346 // a method in the case where there exist multiple JavaScript classes | 376 // a method in the case where there exist multiple JavaScript classes |
347 // that conflict on whether the member is a getter or a method. | 377 // that conflict on whether the member is a getter or a method. |
348 var interceptorClass = | 378 var interceptorClass = _classes[_commonElements.jsJavaScriptObjectClass]; |
349 _classes[_compiler.commonElements.jsJavaScriptObjectClass]; | |
350 var stubNames = new Set<String>(); | 379 var stubNames = new Set<String>(); |
351 librariesMap.forEach((LibraryElement library, List<Element> elements) { | 380 librariesMap.forEach((LibraryElement library, List<Element> elements) { |
352 for (Element e in elements) { | 381 for (Element e in elements) { |
353 if (e is ClassElement && backend.nativeData.isJsInteropClass(e)) { | 382 if (e is ClassElement && _nativeData.isJsInteropClass(e)) { |
354 e.declaration.forEachMember((_, Element member) { | 383 e.declaration.forEachMember((_, Element member) { |
355 var jsName = | 384 var jsName = _nativeData.computeUnescapedJSInteropName(member.name); |
356 backend.nativeData.computeUnescapedJSInteropName(member.name); | |
357 if (!member.isInstanceMember) return; | 385 if (!member.isInstanceMember) return; |
358 if (member.isGetter || member.isField || member.isFunction) { | 386 if (member.isGetter || member.isField || member.isFunction) { |
359 var selectors = worldBuilder.getterInvocationsByName(member.name); | 387 var selectors = |
| 388 _worldBuilder.getterInvocationsByName(member.name); |
360 if (selectors != null && !selectors.isEmpty) { | 389 if (selectors != null && !selectors.isEmpty) { |
361 for (var selector in selectors.keys) { | 390 for (var selector in selectors.keys) { |
362 var stubName = namer.invocationName(selector); | 391 var stubName = namer.invocationName(selector); |
363 if (stubNames.add(stubName.key)) { | 392 if (stubNames.add(stubName.key)) { |
364 interceptorClass.callStubs.add(_buildStubMethod(stubName, | 393 interceptorClass.callStubs.add(_buildStubMethod(stubName, |
365 js.js('function(obj) { return obj.# }', [jsName]), | 394 js.js('function(obj) { return obj.# }', [jsName]), |
366 element: member)); | 395 element: member)); |
367 } | 396 } |
368 } | 397 } |
369 } | 398 } |
370 } | 399 } |
371 | 400 |
372 if (member.isSetter || (member.isField && !member.isConst)) { | 401 if (member.isSetter || (member.isField && !member.isConst)) { |
373 var selectors = worldBuilder.setterInvocationsByName(member.name); | 402 var selectors = |
| 403 _worldBuilder.setterInvocationsByName(member.name); |
374 if (selectors != null && !selectors.isEmpty) { | 404 if (selectors != null && !selectors.isEmpty) { |
375 var stubName = namer.setterForElement(member); | 405 var stubName = namer.setterForElement(member); |
376 if (stubNames.add(stubName.key)) { | 406 if (stubNames.add(stubName.key)) { |
377 interceptorClass.callStubs.add(_buildStubMethod(stubName, | 407 interceptorClass.callStubs.add(_buildStubMethod(stubName, |
378 js.js('function(obj, v) { return obj.# = v }', [jsName]), | 408 js.js('function(obj, v) { return obj.# = v }', [jsName]), |
379 element: member)); | 409 element: member)); |
380 } | 410 } |
381 } | 411 } |
382 } | 412 } |
383 | 413 |
384 // Generating stubs for direct calls and stubs for call-through | 414 // Generating stubs for direct calls and stubs for call-through |
385 // of getters that happen to be functions. | 415 // of getters that happen to be functions. |
386 bool isFunctionLike = false; | 416 bool isFunctionLike = false; |
387 ResolutionFunctionType functionType = null; | 417 ResolutionFunctionType functionType = null; |
388 | 418 |
389 if (member.isFunction) { | 419 if (member.isFunction) { |
390 FunctionElement fn = member; | 420 FunctionElement fn = member; |
391 functionType = fn.type; | 421 functionType = fn.type; |
392 } else if (member.isGetter) { | 422 } else if (member.isGetter) { |
393 if (_compiler.options.trustTypeAnnotations) { | 423 if (_options.trustTypeAnnotations) { |
394 GetterElement getter = member; | 424 GetterElement getter = member; |
395 ResolutionDartType returnType = getter.type.returnType; | 425 ResolutionDartType returnType = getter.type.returnType; |
396 if (returnType.isFunctionType) { | 426 if (returnType.isFunctionType) { |
397 functionType = returnType; | 427 functionType = returnType; |
398 } else if (returnType.treatAsDynamic || | 428 } else if (returnType.treatAsDynamic || |
399 _compiler.types.isSubtype( | 429 _types.isSubtype( |
400 returnType, | 430 returnType, |
401 // ignore: UNNECESSARY_CAST | 431 // ignore: UNNECESSARY_CAST |
402 backend.commonElements.functionType as DartType)) { | 432 _commonElements.functionType as DartType)) { |
403 if (returnType.isTypedef) { | 433 if (returnType.isTypedef) { |
404 ResolutionTypedefType typedef = returnType; | 434 ResolutionTypedefType typedef = returnType; |
405 // TODO(jacobr): can we just use typdef.unaliased instead? | 435 // TODO(jacobr): can we just use typdef.unaliased instead? |
406 functionType = typedef.element.functionSignature.type; | 436 functionType = typedef.element.functionSignature.type; |
407 } else { | 437 } else { |
408 // Other misc function type such as commonElements.Function. | 438 // Other misc function type such as commonElements.Function. |
409 // Allow any number of arguments. | 439 // Allow any number of arguments. |
410 isFunctionLike = true; | 440 isFunctionLike = true; |
411 } | 441 } |
412 } | 442 } |
413 } else { | 443 } else { |
414 isFunctionLike = true; | 444 isFunctionLike = true; |
415 } | 445 } |
416 } // TODO(jacobr): handle field elements. | 446 } // TODO(jacobr): handle field elements. |
417 | 447 |
418 if (isFunctionLike || functionType != null) { | 448 if (isFunctionLike || functionType != null) { |
419 int minArgs; | 449 int minArgs; |
420 int maxArgs; | 450 int maxArgs; |
421 if (functionType != null) { | 451 if (functionType != null) { |
422 minArgs = functionType.parameterTypes.length; | 452 minArgs = functionType.parameterTypes.length; |
423 maxArgs = minArgs + functionType.optionalParameterTypes.length; | 453 maxArgs = minArgs + functionType.optionalParameterTypes.length; |
424 } else { | 454 } else { |
425 minArgs = 0; | 455 minArgs = 0; |
426 maxArgs = 32767; | 456 maxArgs = 32767; |
427 } | 457 } |
428 var selectors = worldBuilder.invocationsByName(member.name); | 458 var selectors = _worldBuilder.invocationsByName(member.name); |
429 // Named arguments are not yet supported. In the future we | 459 // Named arguments are not yet supported. In the future we |
430 // may want to map named arguments to an object literal containing | 460 // may want to map named arguments to an object literal containing |
431 // all named arguments. | 461 // all named arguments. |
432 if (selectors != null && !selectors.isEmpty) { | 462 if (selectors != null && !selectors.isEmpty) { |
433 for (var selector in selectors.keys) { | 463 for (var selector in selectors.keys) { |
434 // Check whether the arity matches this member. | 464 // Check whether the arity matches this member. |
435 var argumentCount = selector.argumentCount; | 465 var argumentCount = selector.argumentCount; |
436 // JS interop does not support named arguments. | 466 // JS interop does not support named arguments. |
437 if (selector.namedArgumentCount > 0) continue; | 467 if (selector.namedArgumentCount > 0) continue; |
438 if (argumentCount < minArgs) continue; | 468 if (argumentCount < minArgs) continue; |
(...skipping 28 matching lines...) Expand all Loading... |
467 // Note that a library-element may have multiple [Library]s, if it is split | 497 // Note that a library-element may have multiple [Library]s, if it is split |
468 // into multiple output units. | 498 // into multiple output units. |
469 Library _buildLibrary(LibraryElement library, List<Element> elements) { | 499 Library _buildLibrary(LibraryElement library, List<Element> elements) { |
470 String uri = library.canonicalUri.toString(); | 500 String uri = library.canonicalUri.toString(); |
471 | 501 |
472 List<StaticMethod> statics = elements | 502 List<StaticMethod> statics = elements |
473 .where((e) => e is FunctionElement) | 503 .where((e) => e is FunctionElement) |
474 .map(_buildStaticMethod) | 504 .map(_buildStaticMethod) |
475 .toList(); | 505 .toList(); |
476 | 506 |
477 if (library == _compiler.commonElements.interceptorsLibrary) { | 507 if (library == _commonElements.interceptorsLibrary) { |
478 statics.addAll(_generateGetInterceptorMethods()); | 508 statics.addAll(_generateGetInterceptorMethods()); |
479 statics.addAll(_generateOneShotInterceptors()); | 509 statics.addAll(_generateOneShotInterceptors()); |
480 } | 510 } |
481 | 511 |
482 List<Class> classes = elements | 512 List<Class> classes = elements |
483 .where((e) => e is ClassElement) | 513 .where((e) => e is ClassElement) |
484 .map((ClassElement classElement) => _classes[classElement]) | 514 .map((ClassElement classElement) => _classes[classElement]) |
485 .where((Class cls) => | 515 .where((Class cls) => |
486 !cls.isNative || !_unneededNativeClasses.contains(cls)) | 516 !cls.isNative || !_unneededNativeClasses.contains(cls)) |
487 .toList(growable: false); | 517 .toList(growable: false); |
488 | 518 |
489 bool visitStatics = true; | 519 bool visitStatics = true; |
490 List<Field> staticFieldsForReflection = | 520 List<Field> staticFieldsForReflection = |
491 _buildFields(library, visitStatics: visitStatics); | 521 _buildFields(library, visitStatics: visitStatics); |
492 | 522 |
493 return new Library( | 523 return new Library( |
494 library, uri, statics, classes, staticFieldsForReflection); | 524 library, uri, statics, classes, staticFieldsForReflection); |
495 } | 525 } |
496 | 526 |
497 Class _buildClass(ClassElement element) { | 527 Class _buildClass(ClassElement element) { |
498 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); | 528 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); |
499 bool hasRtiField = backend.rtiNeed.classNeedsRtiField(element); | 529 bool hasRtiField = _rtiNeed.classNeedsRtiField(element); |
500 if (backend.nativeData.isJsInteropClass(element)) { | 530 if (_nativeData.isJsInteropClass(element)) { |
501 // TODO(jacobr): check whether the class has any active static fields | 531 // TODO(jacobr): check whether the class has any active static fields |
502 // if it does not we can suppress it completely. | 532 // if it does not we can suppress it completely. |
503 onlyForRti = true; | 533 onlyForRti = true; |
504 } | 534 } |
505 | 535 |
506 List<Method> methods = []; | 536 List<Method> methods = []; |
507 List<StubMethod> callStubs = <StubMethod>[]; | 537 List<StubMethod> callStubs = <StubMethod>[]; |
508 | 538 |
509 ClassStubGenerator classStubGenerator = new ClassStubGenerator( | 539 ClassStubGenerator classStubGenerator = new ClassStubGenerator( |
510 namer, backend, worldBuilder, closedWorld, | 540 namer, _backend, _worldBuilder, closedWorld, |
511 enableMinification: _compiler.options.enableMinification); | 541 enableMinification: _options.enableMinification); |
512 RuntimeTypeGenerator runtimeTypeGenerator = | 542 RuntimeTypeGenerator runtimeTypeGenerator = |
513 new RuntimeTypeGenerator(_compiler, _task, namer); | 543 new RuntimeTypeGenerator(_compiler, _task, namer); |
514 | 544 |
515 void visitMember(ClassElement enclosing, MemberElement member) { | 545 void visitMember(ClassElement enclosing, MemberElement member) { |
516 assert(invariant(element, member.isDeclaration)); | 546 assert(invariant(element, member.isDeclaration)); |
517 assert(invariant(element, element == enclosing)); | 547 assert(invariant(element, element == enclosing)); |
518 | 548 |
519 if (Elements.isNonAbstractInstanceMember(member)) { | 549 if (Elements.isNonAbstractInstanceMember(member)) { |
520 // TODO(herhut): Remove once _buildMethod can no longer return null. | 550 // TODO(herhut): Remove once _buildMethod can no longer return null. |
521 Method method = _buildMethod(member); | 551 Method method = _buildMethod(member); |
522 if (method != null) methods.add(method); | 552 if (method != null) methods.add(method); |
523 } | 553 } |
524 if (member.isGetter || member.isField) { | 554 if (member.isGetter || member.isField) { |
525 Map<Selector, SelectorConstraints> selectors = | 555 Map<Selector, SelectorConstraints> selectors = |
526 worldBuilder.invocationsByName(member.name); | 556 _worldBuilder.invocationsByName(member.name); |
527 if (selectors != null && !selectors.isEmpty) { | 557 if (selectors != null && !selectors.isEmpty) { |
528 Map<js.Name, js.Expression> callStubsForMember = | 558 Map<js.Name, js.Expression> callStubsForMember = |
529 classStubGenerator.generateCallStubsForGetter(member, selectors); | 559 classStubGenerator.generateCallStubsForGetter(member, selectors); |
530 callStubsForMember.forEach((js.Name name, js.Expression code) { | 560 callStubsForMember.forEach((js.Name name, js.Expression code) { |
531 callStubs.add(_buildStubMethod(name, code, element: member)); | 561 callStubs.add(_buildStubMethod(name, code, element: member)); |
532 }); | 562 }); |
533 } | 563 } |
534 } | 564 } |
535 } | 565 } |
536 | 566 |
537 List<StubMethod> noSuchMethodStubs = <StubMethod>[]; | 567 List<StubMethod> noSuchMethodStubs = <StubMethod>[]; |
538 | 568 |
539 if (backend.backendUsage.isNoSuchMethodUsed && element.isObject) { | 569 if (_backendUsage.isNoSuchMethodUsed && element.isObject) { |
540 Map<js.Name, Selector> selectors = | 570 Map<js.Name, Selector> selectors = |
541 classStubGenerator.computeSelectorsForNsmHandlers(); | 571 classStubGenerator.computeSelectorsForNsmHandlers(); |
542 selectors.forEach((js.Name name, Selector selector) { | 572 selectors.forEach((js.Name name, Selector selector) { |
543 // If the program contains `const Symbol` names we have to retain them. | 573 // If the program contains `const Symbol` names we have to retain them. |
544 String selectorName = selector.name; | 574 String selectorName = selector.name; |
545 if (selector.isSetter) selectorName = "$selectorName="; | 575 if (selector.isSetter) selectorName = "$selectorName="; |
546 if (backend.mirrorsData.symbolsUsed.contains(selectorName)) { | 576 if (_mirrorsData.symbolsUsed.contains(selectorName)) { |
547 _symbolsMap[name] = selectorName; | 577 _symbolsMap[name] = selectorName; |
548 } | 578 } |
549 noSuchMethodStubs.add( | 579 noSuchMethodStubs.add( |
550 classStubGenerator.generateStubForNoSuchMethod(name, selector)); | 580 classStubGenerator.generateStubForNoSuchMethod(name, selector)); |
551 }); | 581 }); |
552 } | 582 } |
553 | 583 |
554 if (element == _compiler.commonElements.closureClass) { | 584 if (element == _commonElements.closureClass) { |
555 // We add a special getter here to allow for tearing off a closure from | 585 // We add a special getter here to allow for tearing off a closure from |
556 // itself. | 586 // itself. |
557 js.Name name = namer.getterForMember(Names.call); | 587 js.Name name = namer.getterForMember(Names.call); |
558 js.Fun function = js.js('function() { return this; }'); | 588 js.Fun function = js.js('function() { return this; }'); |
559 callStubs.add(_buildStubMethod(name, function)); | 589 callStubs.add(_buildStubMethod(name, function)); |
560 } | 590 } |
561 | 591 |
562 ClassElement implementation = element.implementation; | 592 ClassElement implementation = element.implementation; |
563 | 593 |
564 // MixinApplications run through the members of their mixin. Here, we are | 594 // MixinApplications run through the members of their mixin. Here, we are |
565 // only interested in direct members. | 595 // only interested in direct members. |
566 if (!onlyForRti && !element.isMixinApplication) { | 596 if (!onlyForRti && !element.isMixinApplication) { |
567 implementation.forEachMember(visitMember, includeBackendMembers: true); | 597 implementation.forEachMember(visitMember, includeBackendMembers: true); |
568 } | 598 } |
569 bool isInterceptedClass = | 599 bool isInterceptedClass = _interceptorData.isInterceptedClass(element); |
570 backend.interceptorData.isInterceptedClass(element); | |
571 List<Field> instanceFields = onlyForRti | 600 List<Field> instanceFields = onlyForRti |
572 ? const <Field>[] | 601 ? const <Field>[] |
573 : _buildFields(element, | 602 : _buildFields(element, |
574 visitStatics: false, isHolderInterceptedClass: isInterceptedClass); | 603 visitStatics: false, isHolderInterceptedClass: isInterceptedClass); |
575 List<Field> staticFieldsForReflection = onlyForRti | 604 List<Field> staticFieldsForReflection = onlyForRti |
576 ? const <Field>[] | 605 ? const <Field>[] |
577 : _buildFields(element, | 606 : _buildFields(element, |
578 visitStatics: true, isHolderInterceptedClass: isInterceptedClass); | 607 visitStatics: true, isHolderInterceptedClass: isInterceptedClass); |
579 | 608 |
580 TypeTestProperties typeTests = runtimeTypeGenerator.generateIsTests(element, | 609 TypeTestProperties typeTests = runtimeTypeGenerator.generateIsTests(element, |
581 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); | 610 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata); |
582 | 611 |
583 List<StubMethod> checkedSetters = <StubMethod>[]; | 612 List<StubMethod> checkedSetters = <StubMethod>[]; |
584 List<StubMethod> isChecks = <StubMethod>[]; | 613 List<StubMethod> isChecks = <StubMethod>[]; |
585 if (backend.nativeData.isJsInteropClass(element)) { | 614 if (_nativeData.isJsInteropClass(element)) { |
586 typeTests.properties.forEach((js.Name name, js.Node code) { | 615 typeTests.properties.forEach((js.Name name, js.Node code) { |
587 _classes[_compiler.commonElements.jsInterceptorClass] | 616 _classes[_commonElements.jsInterceptorClass] |
588 .isChecks | 617 .isChecks |
589 .add(_buildStubMethod(name, code)); | 618 .add(_buildStubMethod(name, code)); |
590 }); | 619 }); |
591 } else { | 620 } else { |
592 for (Field field in instanceFields) { | 621 for (Field field in instanceFields) { |
593 if (field.needsCheckedSetter) { | 622 if (field.needsCheckedSetter) { |
594 assert(!field.needsUncheckedSetter); | 623 assert(!field.needsUncheckedSetter); |
595 FieldElement element = field.element; | 624 FieldElement element = field.element; |
596 js.Expression code = backend.generatedCode[element]; | 625 js.Expression code = _backend.generatedCode[element]; |
597 assert(code != null); | 626 assert(code != null); |
598 js.Name name = namer.deriveSetterName(field.accessorName); | 627 js.Name name = namer.deriveSetterName(field.accessorName); |
599 checkedSetters.add(_buildStubMethod(name, code, element: element)); | 628 checkedSetters.add(_buildStubMethod(name, code, element: element)); |
600 } | 629 } |
601 } | 630 } |
602 | 631 |
603 typeTests.properties.forEach((js.Name name, js.Node code) { | 632 typeTests.properties.forEach((js.Name name, js.Node code) { |
604 isChecks.add(_buildStubMethod(name, code)); | 633 isChecks.add(_buildStubMethod(name, code)); |
605 }); | 634 }); |
606 } | 635 } |
607 | 636 |
608 js.Name name = namer.className(element); | 637 js.Name name = namer.className(element); |
609 String holderName = namer.globalObjectFor(element); | 638 String holderName = namer.globalObjectFor(element); |
610 // TODO(floitsch): we shouldn't update the registry in the middle of | 639 // TODO(floitsch): we shouldn't update the registry in the middle of |
611 // building a class. | 640 // building a class. |
612 Holder holder = _registry.registerHolder(holderName); | 641 Holder holder = _registry.registerHolder(holderName); |
613 bool isInstantiated = !backend.nativeData.isJsInteropClass(element) && | 642 bool isInstantiated = !_nativeData.isJsInteropClass(element) && |
614 worldBuilder.directlyInstantiatedClasses.contains(element); | 643 _worldBuilder.directlyInstantiatedClasses.contains(element); |
615 | 644 |
616 Class result; | 645 Class result; |
617 if (element.isMixinApplication && !onlyForRti) { | 646 if (element.isMixinApplication && !onlyForRti) { |
618 assert(!backend.nativeData.isNativeClass(element)); | 647 assert(!_nativeData.isNativeClass(element)); |
619 assert(methods.isEmpty); | 648 assert(methods.isEmpty); |
620 | 649 |
621 result = new MixinApplication( | 650 result = new MixinApplication( |
622 element, | 651 element, |
623 name, | 652 name, |
624 holder, | 653 holder, |
625 instanceFields, | 654 instanceFields, |
626 staticFieldsForReflection, | 655 staticFieldsForReflection, |
627 callStubs, | 656 callStubs, |
628 checkedSetters, | 657 checkedSetters, |
(...skipping 11 matching lines...) Expand all Loading... |
640 instanceFields, | 669 instanceFields, |
641 staticFieldsForReflection, | 670 staticFieldsForReflection, |
642 callStubs, | 671 callStubs, |
643 noSuchMethodStubs, | 672 noSuchMethodStubs, |
644 checkedSetters, | 673 checkedSetters, |
645 isChecks, | 674 isChecks, |
646 typeTests.functionTypeIndex, | 675 typeTests.functionTypeIndex, |
647 isDirectlyInstantiated: isInstantiated, | 676 isDirectlyInstantiated: isInstantiated, |
648 hasRtiField: hasRtiField, | 677 hasRtiField: hasRtiField, |
649 onlyForRti: onlyForRti, | 678 onlyForRti: onlyForRti, |
650 isNative: backend.nativeData.isNativeClass(element)); | 679 isNative: _nativeData.isNativeClass(element)); |
651 } | 680 } |
652 _classes[element] = result; | 681 _classes[element] = result; |
653 return result; | 682 return result; |
654 } | 683 } |
655 | 684 |
656 bool _methodNeedsStubs(FunctionElement method) { | 685 bool _methodNeedsStubs(FunctionElement method) { |
657 return !method.functionSignature.optionalParameters.isEmpty; | 686 return !method.functionSignature.optionalParameters.isEmpty; |
658 } | 687 } |
659 | 688 |
660 bool _methodCanBeReflected(MethodElement method) { | 689 bool _methodCanBeReflected(MethodElement method) { |
661 return backend.mirrorsData.isMemberAccessibleByReflection(method); | 690 return _mirrorsData.isMemberAccessibleByReflection(method); |
662 } | 691 } |
663 | 692 |
664 bool _methodCanBeApplied(FunctionElement method) { | 693 bool _methodCanBeApplied(FunctionElement method) { |
665 return backend.backendUsage.isFunctionApplyUsed && | 694 return _backendUsage.isFunctionApplyUsed && |
666 closedWorld.getMightBePassedToApply(method); | 695 closedWorld.getMightBePassedToApply(method); |
667 } | 696 } |
668 | 697 |
669 /* Map | List */ _computeParameterDefaultValues(FunctionSignature signature) { | 698 /* Map | List */ _computeParameterDefaultValues(FunctionSignature signature) { |
670 var /* Map | List */ optionalParameterDefaultValues; | 699 var /* Map | List */ optionalParameterDefaultValues; |
671 if (signature.optionalParametersAreNamed) { | 700 if (signature.optionalParametersAreNamed) { |
672 optionalParameterDefaultValues = new Map<String, ConstantValue>(); | 701 optionalParameterDefaultValues = new Map<String, ConstantValue>(); |
673 signature.forEachOptionalParameter((ParameterElement parameter) { | 702 signature.forEachOptionalParameter((ParameterElement parameter) { |
674 ConstantValue def = | 703 ConstantValue def = |
675 backend.constants.getConstantValue(parameter.constant); | 704 _constantHandler.getConstantValue(parameter.constant); |
676 optionalParameterDefaultValues[parameter.name] = def; | 705 optionalParameterDefaultValues[parameter.name] = def; |
677 }); | 706 }); |
678 } else { | 707 } else { |
679 optionalParameterDefaultValues = <ConstantValue>[]; | 708 optionalParameterDefaultValues = <ConstantValue>[]; |
680 signature.forEachOptionalParameter((ParameterElement parameter) { | 709 signature.forEachOptionalParameter((ParameterElement parameter) { |
681 ConstantValue def = | 710 ConstantValue def = |
682 backend.constants.getConstantValue(parameter.constant); | 711 _constantHandler.getConstantValue(parameter.constant); |
683 optionalParameterDefaultValues.add(def); | 712 optionalParameterDefaultValues.add(def); |
684 }); | 713 }); |
685 } | 714 } |
686 return optionalParameterDefaultValues; | 715 return optionalParameterDefaultValues; |
687 } | 716 } |
688 | 717 |
689 DartMethod _buildMethod(MethodElement element) { | 718 DartMethod _buildMethod(MethodElement element) { |
690 assert(element.isDeclaration); | 719 assert(element.isDeclaration); |
691 js.Name name = namer.methodPropertyName(element); | 720 js.Name name = namer.methodPropertyName(element); |
692 js.Expression code = backend.generatedCode[element]; | 721 js.Expression code = _backend.generatedCode[element]; |
693 | 722 |
694 // TODO(kasperl): Figure out under which conditions code is null. | 723 // TODO(kasperl): Figure out under which conditions code is null. |
695 if (code == null) return null; | 724 if (code == null) return null; |
696 | 725 |
697 bool canTearOff = false; | 726 bool canTearOff = false; |
698 js.Name tearOffName; | 727 js.Name tearOffName; |
699 bool isClosureCallMethod = false; | 728 bool isClosureCallMethod = false; |
700 bool isNotApplyTarget = !element.isFunction || element.isAccessor; | 729 bool isNotApplyTarget = !element.isFunction || element.isAccessor; |
701 | 730 |
702 bool canBeReflected = _methodCanBeReflected(element); | 731 bool canBeReflected = _methodCanBeReflected(element); |
703 bool canBeApplied = _methodCanBeApplied(element); | 732 bool canBeApplied = _methodCanBeApplied(element); |
704 | 733 |
705 js.Name aliasName = backend.superMemberData.isAliasedSuperMember(element) | 734 js.Name aliasName = _superMemberData.isAliasedSuperMember(element) |
706 ? namer.aliasedSuperMemberPropertyName(element) | 735 ? namer.aliasedSuperMemberPropertyName(element) |
707 : null; | 736 : null; |
708 | 737 |
709 if (isNotApplyTarget) { | 738 if (isNotApplyTarget) { |
710 canTearOff = false; | 739 canTearOff = false; |
711 } else { | 740 } else { |
712 if (element.enclosingClass.isClosure) { | 741 if (element.enclosingClass.isClosure) { |
713 canTearOff = false; | 742 canTearOff = false; |
714 isClosureCallMethod = true; | 743 isClosureCallMethod = true; |
715 } else { | 744 } else { |
716 // Careful with operators. | 745 // Careful with operators. |
717 canTearOff = worldBuilder.hasInvokedGetter(element, closedWorld) || | 746 canTearOff = _worldBuilder.hasInvokedGetter(element, closedWorld) || |
718 (canBeReflected && !element.isOperator); | 747 (canBeReflected && !element.isOperator); |
719 assert(canTearOff || | 748 assert(canTearOff || |
720 !worldBuilder.methodsNeedingSuperGetter.contains(element)); | 749 !_worldBuilder.methodsNeedingSuperGetter.contains(element)); |
721 tearOffName = namer.getterForElement(element); | 750 tearOffName = namer.getterForElement(element); |
722 } | 751 } |
723 } | 752 } |
724 | 753 |
725 if (canTearOff) { | 754 if (canTearOff) { |
726 assert(invariant(element, !element.isGenerativeConstructor)); | 755 assert(invariant(element, !element.isGenerativeConstructor)); |
727 assert(invariant(element, !element.isGenerativeConstructorBody)); | 756 assert(invariant(element, !element.isGenerativeConstructorBody)); |
728 assert(invariant(element, !element.isConstructor)); | 757 assert(invariant(element, !element.isConstructor)); |
729 } | 758 } |
730 | 759 |
(...skipping 10 matching lines...) Expand all Loading... |
741 // this information anyway as they cannot be torn off or | 770 // this information anyway as they cannot be torn off or |
742 // reflected. | 771 // reflected. |
743 var body = element; | 772 var body = element; |
744 memberType = body.constructor.type; | 773 memberType = body.constructor.type; |
745 } else { | 774 } else { |
746 memberType = element.type; | 775 memberType = element.type; |
747 } | 776 } |
748 | 777 |
749 js.Expression functionType; | 778 js.Expression functionType; |
750 if (canTearOff || canBeReflected) { | 779 if (canTearOff || canBeReflected) { |
751 OutputUnit outputUnit = | 780 OutputUnit outputUnit = _deferredLoadTask.outputUnitForElement(element); |
752 _compiler.deferredLoadTask.outputUnitForElement(element); | |
753 functionType = _generateFunctionType(memberType, outputUnit); | 781 functionType = _generateFunctionType(memberType, outputUnit); |
754 } | 782 } |
755 | 783 |
756 int requiredParameterCount; | 784 int requiredParameterCount; |
757 var /* List | Map */ optionalParameterDefaultValues; | 785 var /* List | Map */ optionalParameterDefaultValues; |
758 if (canBeApplied || canBeReflected) { | 786 if (canBeApplied || canBeReflected) { |
759 FunctionSignature signature = element.functionSignature; | 787 FunctionSignature signature = element.functionSignature; |
760 requiredParameterCount = signature.requiredParameterCount; | 788 requiredParameterCount = signature.requiredParameterCount; |
761 optionalParameterDefaultValues = | 789 optionalParameterDefaultValues = |
762 _computeParameterDefaultValues(signature); | 790 _computeParameterDefaultValues(signature); |
763 } | 791 } |
764 | 792 |
765 return new InstanceMethod(element, name, code, | 793 return new InstanceMethod(element, name, code, |
766 _generateParameterStubs(element, canTearOff), callName, | 794 _generateParameterStubs(element, canTearOff), callName, |
767 needsTearOff: canTearOff, | 795 needsTearOff: canTearOff, |
768 tearOffName: tearOffName, | 796 tearOffName: tearOffName, |
769 isClosureCallMethod: isClosureCallMethod, | 797 isClosureCallMethod: isClosureCallMethod, |
770 aliasName: aliasName, | 798 aliasName: aliasName, |
771 canBeApplied: canBeApplied, | 799 canBeApplied: canBeApplied, |
772 canBeReflected: canBeReflected, | 800 canBeReflected: canBeReflected, |
773 requiredParameterCount: requiredParameterCount, | 801 requiredParameterCount: requiredParameterCount, |
774 optionalParameterDefaultValues: optionalParameterDefaultValues, | 802 optionalParameterDefaultValues: optionalParameterDefaultValues, |
775 functionType: functionType); | 803 functionType: functionType); |
776 } | 804 } |
777 | 805 |
778 js.Expression _generateFunctionType( | 806 js.Expression _generateFunctionType( |
779 ResolutionDartType type, OutputUnit outputUnit) { | 807 ResolutionDartType type, OutputUnit outputUnit) { |
780 if (type.containsTypeVariables) { | 808 if (type.containsTypeVariables) { |
781 js.Expression thisAccess = js.js(r'this.$receiver'); | 809 js.Expression thisAccess = js.js(r'this.$receiver'); |
782 return backend.rtiEncoder | 810 return _rtiEncoder.getSignatureEncoding( |
783 .getSignatureEncoding(backend.emitter.emitter, type, thisAccess); | 811 _emitter.emitter, type, thisAccess); |
784 } else { | 812 } else { |
785 return backend.emitter.metadataCollector | 813 return _emitter.metadataCollector |
786 .reifyTypeForOutputUnit(type, outputUnit); | 814 .reifyTypeForOutputUnit(type, outputUnit); |
787 } | 815 } |
788 } | 816 } |
789 | 817 |
790 List<ParameterStubMethod> _generateParameterStubs( | 818 List<ParameterStubMethod> _generateParameterStubs( |
791 MethodElement element, bool canTearOff) { | 819 MethodElement element, bool canTearOff) { |
792 if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[]; | 820 if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[]; |
793 | 821 |
794 ParameterStubGenerator generator = | 822 ParameterStubGenerator generator = |
795 new ParameterStubGenerator(_compiler, namer, backend, closedWorld); | 823 new ParameterStubGenerator(_compiler, namer, _backend, closedWorld); |
796 return generator.generateParameterStubs(element, canTearOff: canTearOff); | 824 return generator.generateParameterStubs(element, canTearOff: canTearOff); |
797 } | 825 } |
798 | 826 |
799 /// Builds a stub method. | 827 /// Builds a stub method. |
800 /// | 828 /// |
801 /// Stub methods may have an element that can be used for code-size | 829 /// Stub methods may have an element that can be used for code-size |
802 /// attribution. | 830 /// attribution. |
803 Method _buildStubMethod(js.Name name, js.Expression code, | 831 Method _buildStubMethod(js.Name name, js.Expression code, |
804 {MemberElement element}) { | 832 {MemberElement element}) { |
805 return new StubMethod(name, code, element: element); | 833 return new StubMethod(name, code, element: element); |
806 } | 834 } |
807 | 835 |
808 // The getInterceptor methods directly access the prototype of classes. | 836 // The getInterceptor methods directly access the prototype of classes. |
809 // We must evaluate these classes eagerly so that the prototype is | 837 // We must evaluate these classes eagerly so that the prototype is |
810 // accessible. | 838 // accessible. |
811 void _markEagerInterceptorClasses() { | 839 void _markEagerInterceptorClasses() { |
812 Iterable<js.Name> names = | 840 Iterable<js.Name> names = |
813 backend.oneShotInterceptorData.specializedGetInterceptorNames; | 841 _oneShotInterceptorData.specializedGetInterceptorNames; |
814 for (js.Name name in names) { | 842 for (js.Name name in names) { |
815 for (ClassElement element in backend.oneShotInterceptorData | 843 for (ClassElement element |
816 .getSpecializedGetInterceptorsFor(name)) { | 844 in _oneShotInterceptorData.getSpecializedGetInterceptorsFor(name)) { |
817 Class cls = _classes[element]; | 845 Class cls = _classes[element]; |
818 if (cls != null) cls.isEager = true; | 846 if (cls != null) cls.isEager = true; |
819 } | 847 } |
820 } | 848 } |
821 } | 849 } |
822 | 850 |
823 Iterable<StaticStubMethod> _generateGetInterceptorMethods() { | 851 Iterable<StaticStubMethod> _generateGetInterceptorMethods() { |
824 InterceptorStubGenerator stubGenerator = | 852 InterceptorStubGenerator stubGenerator = |
825 new InterceptorStubGenerator(_compiler, namer, backend, closedWorld); | 853 new InterceptorStubGenerator(_compiler, namer, _backend, closedWorld); |
826 | 854 |
827 String holderName = namer | 855 String holderName = |
828 .globalObjectForLibrary(_compiler.commonElements.interceptorsLibrary); | 856 namer.globalObjectForLibrary(_commonElements.interceptorsLibrary); |
829 // TODO(floitsch): we shouldn't update the registry in the middle of | 857 // TODO(floitsch): we shouldn't update the registry in the middle of |
830 // generating the interceptor methods. | 858 // generating the interceptor methods. |
831 Holder holder = _registry.registerHolder(holderName); | 859 Holder holder = _registry.registerHolder(holderName); |
832 | 860 |
833 Iterable<js.Name> names = | 861 Iterable<js.Name> names = |
834 backend.oneShotInterceptorData.specializedGetInterceptorNames; | 862 _oneShotInterceptorData.specializedGetInterceptorNames; |
835 return names.map((js.Name name) { | 863 return names.map((js.Name name) { |
836 Set<ClassEntity> classes = | 864 Set<ClassEntity> classes = |
837 backend.oneShotInterceptorData.getSpecializedGetInterceptorsFor(name); | 865 _oneShotInterceptorData.getSpecializedGetInterceptorsFor(name); |
838 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); | 866 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); |
839 return new StaticStubMethod(name, holder, code); | 867 return new StaticStubMethod(name, holder, code); |
840 }); | 868 }); |
841 } | 869 } |
842 | 870 |
843 List<Field> _buildFields(Element holder, | 871 List<Field> _buildFields(Element holder, |
844 {bool visitStatics, bool isHolderInterceptedClass: false}) { | 872 {bool visitStatics, bool isHolderInterceptedClass: false}) { |
845 List<Field> fields = <Field>[]; | 873 List<Field> fields = <Field>[]; |
846 new FieldVisitor(_compiler, namer, closedWorld) | 874 new FieldVisitor(_compiler, namer, closedWorld) |
847 .visitFields(holder, visitStatics, (FieldElement field, | 875 .visitFields(holder, visitStatics, (FieldElement field, |
848 js.Name name, | 876 js.Name name, |
849 js.Name accessorName, | 877 js.Name accessorName, |
850 bool needsGetter, | 878 bool needsGetter, |
851 bool needsSetter, | 879 bool needsSetter, |
852 bool needsCheckedSetter) { | 880 bool needsCheckedSetter) { |
853 assert(invariant(field, field.isDeclaration)); | 881 assert(invariant(field, field.isDeclaration)); |
854 | 882 |
855 int getterFlags = 0; | 883 int getterFlags = 0; |
856 if (needsGetter) { | 884 if (needsGetter) { |
857 if (visitStatics || | 885 if (visitStatics || |
858 !backend.interceptorData.fieldHasInterceptedGetter(field)) { | 886 !_interceptorData.fieldHasInterceptedGetter(field)) { |
859 getterFlags = 1; | 887 getterFlags = 1; |
860 } else { | 888 } else { |
861 getterFlags += 2; | 889 getterFlags += 2; |
862 // TODO(sra): 'isInterceptedClass' might not be the correct test | 890 // TODO(sra): 'isInterceptedClass' might not be the correct test |
863 // for methods forced to use the interceptor convention because | 891 // for methods forced to use the interceptor convention because |
864 // the method's class was elsewhere mixed-in to an interceptor. | 892 // the method's class was elsewhere mixed-in to an interceptor. |
865 if (!isHolderInterceptedClass) { | 893 if (!isHolderInterceptedClass) { |
866 getterFlags += 1; | 894 getterFlags += 1; |
867 } | 895 } |
868 } | 896 } |
869 } | 897 } |
870 | 898 |
871 int setterFlags = 0; | 899 int setterFlags = 0; |
872 if (needsSetter) { | 900 if (needsSetter) { |
873 if (visitStatics || | 901 if (visitStatics || |
874 !backend.interceptorData.fieldHasInterceptedSetter(field)) { | 902 !_interceptorData.fieldHasInterceptedSetter(field)) { |
875 setterFlags = 1; | 903 setterFlags = 1; |
876 } else { | 904 } else { |
877 setterFlags += 2; | 905 setterFlags += 2; |
878 if (!isHolderInterceptedClass) { | 906 if (!isHolderInterceptedClass) { |
879 setterFlags += 1; | 907 setterFlags += 1; |
880 } | 908 } |
881 } | 909 } |
882 } | 910 } |
883 | 911 |
884 fields.add(new Field(field, name, accessorName, getterFlags, setterFlags, | 912 fields.add(new Field(field, name, accessorName, getterFlags, setterFlags, |
885 needsCheckedSetter)); | 913 needsCheckedSetter)); |
886 }); | 914 }); |
887 | 915 |
888 return fields; | 916 return fields; |
889 } | 917 } |
890 | 918 |
891 Iterable<StaticStubMethod> _generateOneShotInterceptors() { | 919 Iterable<StaticStubMethod> _generateOneShotInterceptors() { |
892 InterceptorStubGenerator stubGenerator = | 920 InterceptorStubGenerator stubGenerator = |
893 new InterceptorStubGenerator(_compiler, namer, backend, closedWorld); | 921 new InterceptorStubGenerator(_compiler, namer, _backend, closedWorld); |
894 | 922 |
895 String holderName = namer | 923 String holderName = |
896 .globalObjectForLibrary(_compiler.commonElements.interceptorsLibrary); | 924 namer.globalObjectForLibrary(_commonElements.interceptorsLibrary); |
897 // TODO(floitsch): we shouldn't update the registry in the middle of | 925 // TODO(floitsch): we shouldn't update the registry in the middle of |
898 // generating the interceptor methods. | 926 // generating the interceptor methods. |
899 Holder holder = _registry.registerHolder(holderName); | 927 Holder holder = _registry.registerHolder(holderName); |
900 | 928 |
901 List<js.Name> names = | 929 List<js.Name> names = _oneShotInterceptorData.oneShotInterceptorNames; |
902 backend.oneShotInterceptorData.oneShotInterceptorNames; | |
903 return names.map((js.Name name) { | 930 return names.map((js.Name name) { |
904 js.Expression code = stubGenerator.generateOneShotInterceptor(name); | 931 js.Expression code = stubGenerator.generateOneShotInterceptor(name); |
905 return new StaticStubMethod(name, holder, code); | 932 return new StaticStubMethod(name, holder, code); |
906 }); | 933 }); |
907 } | 934 } |
908 | 935 |
909 StaticDartMethod _buildStaticMethod(MethodElement element) { | 936 StaticDartMethod _buildStaticMethod(MethodElement element) { |
910 js.Name name = namer.methodPropertyName(element); | 937 js.Name name = namer.methodPropertyName(element); |
911 String holder = namer.globalObjectFor(element); | 938 String holder = namer.globalObjectFor(element); |
912 js.Expression code = backend.generatedCode[element]; | 939 js.Expression code = _backend.generatedCode[element]; |
913 | 940 |
914 bool isApplyTarget = !element.isConstructor && !element.isAccessor; | 941 bool isApplyTarget = !element.isConstructor && !element.isAccessor; |
915 bool canBeApplied = _methodCanBeApplied(element); | 942 bool canBeApplied = _methodCanBeApplied(element); |
916 bool canBeReflected = _methodCanBeReflected(element); | 943 bool canBeReflected = _methodCanBeReflected(element); |
917 | 944 |
918 bool needsTearOff = isApplyTarget && | 945 bool needsTearOff = isApplyTarget && |
919 (canBeReflected || | 946 (canBeReflected || |
920 worldBuilder.staticFunctionsNeedingGetter.contains(element)); | 947 _worldBuilder.staticFunctionsNeedingGetter.contains(element)); |
921 | 948 |
922 js.Name tearOffName = | 949 js.Name tearOffName = |
923 needsTearOff ? namer.staticClosureName(element) : null; | 950 needsTearOff ? namer.staticClosureName(element) : null; |
924 | 951 |
925 js.Name callName = null; | 952 js.Name callName = null; |
926 if (needsTearOff) { | 953 if (needsTearOff) { |
927 Selector callSelector = | 954 Selector callSelector = |
928 new Selector.fromElement(element).toCallSelector(); | 955 new Selector.fromElement(element).toCallSelector(); |
929 callName = namer.invocationName(callSelector); | 956 callName = namer.invocationName(callSelector); |
930 } | 957 } |
931 js.Expression functionType; | 958 js.Expression functionType; |
932 ResolutionDartType type = element.type; | 959 ResolutionDartType type = element.type; |
933 if (needsTearOff || canBeReflected) { | 960 if (needsTearOff || canBeReflected) { |
934 OutputUnit outputUnit = | 961 OutputUnit outputUnit = _deferredLoadTask.outputUnitForElement(element); |
935 _compiler.deferredLoadTask.outputUnitForElement(element); | |
936 functionType = _generateFunctionType(type, outputUnit); | 962 functionType = _generateFunctionType(type, outputUnit); |
937 } | 963 } |
938 | 964 |
939 int requiredParameterCount; | 965 int requiredParameterCount; |
940 var /* List | Map */ optionalParameterDefaultValues; | 966 var /* List | Map */ optionalParameterDefaultValues; |
941 if (canBeApplied || canBeReflected) { | 967 if (canBeApplied || canBeReflected) { |
942 FunctionSignature signature = element.functionSignature; | 968 FunctionSignature signature = element.functionSignature; |
943 requiredParameterCount = signature.requiredParameterCount; | 969 requiredParameterCount = signature.requiredParameterCount; |
944 optionalParameterDefaultValues = | 970 optionalParameterDefaultValues = |
945 _computeParameterDefaultValues(signature); | 971 _computeParameterDefaultValues(signature); |
(...skipping 26 matching lines...) Expand all Loading... |
972 Constant constant = new Constant(name, holder, constantValue); | 998 Constant constant = new Constant(name, holder, constantValue); |
973 _constants[constantValue] = constant; | 999 _constants[constantValue] = constant; |
974 } | 1000 } |
975 } | 1001 } |
976 | 1002 |
977 Holder _registerStaticStateHolder() { | 1003 Holder _registerStaticStateHolder() { |
978 return _registry.registerHolder(namer.staticStateHolder, | 1004 return _registry.registerHolder(namer.staticStateHolder, |
979 isStaticStateHolder: true); | 1005 isStaticStateHolder: true); |
980 } | 1006 } |
981 } | 1007 } |
OLD | NEW |