OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
6 | 6 |
7 /// Represents an entry's position in one of the global metadata arrays. | 7 /// Represents an entry's position in one of the global metadata arrays. |
8 /// | 8 /// |
9 /// [_rc] is used to count the number of references of the token in the | 9 /// [_rc] is used to count the number of references of the token in the |
10 /// ast for a program. | 10 /// ast for a program. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 | 56 |
57 class _ForwardingMetadataEntry extends _MetadataEntry implements Placeholder { | 57 class _ForwardingMetadataEntry extends _MetadataEntry implements Placeholder { |
58 _MetadataEntry _forwardTo; | 58 _MetadataEntry _forwardTo; |
59 var debug; | 59 var debug; |
60 | 60 |
61 bool get isBound => _forwardTo != null; | 61 bool get isBound => _forwardTo != null; |
62 | 62 |
63 _ForwardingMetadataEntry([this.debug]); | 63 _ForwardingMetadataEntry([this.debug]); |
64 | 64 |
65 _MetadataEntry get forwardTo { | 65 _MetadataEntry get forwardTo { |
66 assert(isBound); | 66 assert(isBound); |
67 return _forwardTo; | 67 return _forwardTo; |
68 } | 68 } |
69 | 69 |
70 jsAst.Expression get entry { | 70 jsAst.Expression get entry { |
71 assert(isBound); | 71 assert(isBound); |
72 return forwardTo.entry; | 72 return forwardTo.entry; |
73 } | 73 } |
74 | 74 |
75 int get value { | 75 int get value { |
76 assert(isBound); | 76 assert(isBound); |
77 return forwardTo.value; | 77 return forwardTo.value; |
78 } | 78 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 for (MetadataAnnotation annotation in element.metadata) { | 165 for (MetadataAnnotation annotation in element.metadata) { |
166 ConstantValue constant = | 166 ConstantValue constant = |
167 _backend.constants.getConstantValueForMetadata(annotation); | 167 _backend.constants.getConstantValueForMetadata(annotation); |
168 if (constant == null) { | 168 if (constant == null) { |
169 reporter.internalError(annotation, 'Annotation value is null.'); | 169 reporter.internalError(annotation, 'Annotation value is null.'); |
170 } else { | 170 } else { |
171 metadata.add(_emitter.constantReference(constant)); | 171 metadata.add(_emitter.constantReference(constant)); |
172 } | 172 } |
173 } | 173 } |
174 if (metadata.isEmpty) return null; | 174 if (metadata.isEmpty) return null; |
175 return js('function() { return # }', | 175 return js( |
176 new jsAst.ArrayInitializer(metadata)); | 176 'function() { return # }', new jsAst.ArrayInitializer(metadata)); |
177 }); | 177 }); |
178 } | 178 } |
179 | 179 |
180 List<jsAst.DeferredNumber> reifyDefaultArguments(FunctionElement function) { | 180 List<jsAst.DeferredNumber> reifyDefaultArguments(FunctionElement function) { |
181 function = function.implementation; | 181 function = function.implementation; |
182 FunctionSignature signature = function.functionSignature; | 182 FunctionSignature signature = function.functionSignature; |
183 if (signature.optionalParameterCount == 0) return const []; | 183 if (signature.optionalParameterCount == 0) return const []; |
184 | 184 |
185 // Optional parameters of redirecting factory constructors take their | 185 // Optional parameters of redirecting factory constructors take their |
186 // defaults from the corresponding parameters of the redirection target. | 186 // defaults from the corresponding parameters of the redirection target. |
187 Map<ParameterElement, ParameterElement> targetParameterMap; | 187 Map<ParameterElement, ParameterElement> targetParameterMap; |
188 if (function is ConstructorElement) { | 188 if (function is ConstructorElement) { |
189 // TODO(sra): dart2js generates a redirecting factory constructor body | 189 // TODO(sra): dart2js generates a redirecting factory constructor body |
190 // that has the signature of the redirecting constructor that calls the | 190 // that has the signature of the redirecting constructor that calls the |
191 // redirection target. This is wrong - it should have the signature of the | 191 // redirection target. This is wrong - it should have the signature of the |
192 // target. This would make the reified default arguments trivial. | 192 // target. This would make the reified default arguments trivial. |
193 | 193 |
194 ConstructorElement constructor = function; | 194 ConstructorElement constructor = function; |
195 while (constructor.isRedirectingFactory && | 195 while (constructor.isRedirectingFactory && |
196 !constructor.isCyclicRedirection) { | 196 !constructor.isCyclicRedirection) { |
197 // TODO(sra): Remove the loop once effectiveTarget forwards to patches. | 197 // TODO(sra): Remove the loop once effectiveTarget forwards to patches. |
198 constructor = constructor.effectiveTarget.implementation; | 198 constructor = constructor.effectiveTarget.implementation; |
199 } | 199 } |
200 | 200 |
201 if (constructor != function) { | 201 if (constructor != function) { |
202 if (signature.hasOptionalParameters) { | 202 if (signature.hasOptionalParameters) { |
203 targetParameterMap = | 203 targetParameterMap = |
204 mapRedirectingFactoryConstructorOptionalParameters( | 204 mapRedirectingFactoryConstructorOptionalParameters( |
205 signature, constructor.functionSignature); | 205 signature, constructor.functionSignature); |
206 } | 206 } |
207 } | 207 } |
208 } | 208 } |
209 | 209 |
210 List<jsAst.DeferredNumber> defaultValues = <jsAst.DeferredNumber>[]; | 210 List<jsAst.DeferredNumber> defaultValues = <jsAst.DeferredNumber>[]; |
211 for (ParameterElement element in signature.optionalParameters) { | 211 for (ParameterElement element in signature.optionalParameters) { |
212 ParameterElement parameter = | 212 ParameterElement parameter = |
213 (targetParameterMap == null) ? element : targetParameterMap[element]; | 213 (targetParameterMap == null) ? element : targetParameterMap[element]; |
214 ConstantValue constant = (parameter == null) | 214 ConstantValue constant = (parameter == null) |
215 ? null | 215 ? null |
216 : _backend.constants.getConstantValueForVariable(parameter); | 216 : _backend.constants.getConstantValueForVariable(parameter); |
217 jsAst.Expression expression = (constant == null) | 217 jsAst.Expression expression = (constant == null) |
218 ? new jsAst.LiteralNull() | 218 ? new jsAst.LiteralNull() |
219 : _emitter.constantReference(constant); | 219 : _emitter.constantReference(constant); |
220 defaultValues.add(_addGlobalMetadata(expression)); | 220 defaultValues.add(_addGlobalMetadata(expression)); |
221 } | 221 } |
222 return defaultValues; | 222 return defaultValues; |
223 } | 223 } |
224 | 224 |
225 Map<ParameterElement, ParameterElement> | 225 Map<ParameterElement, ParameterElement> mapRedirectingFactoryConstructorOption
alParameters( |
226 mapRedirectingFactoryConstructorOptionalParameters( | |
227 FunctionSignature source, FunctionSignature target) { | 226 FunctionSignature source, FunctionSignature target) { |
228 var map = <ParameterElement, ParameterElement>{}; | 227 var map = <ParameterElement, ParameterElement>{}; |
229 | 228 |
230 if (source.optionalParametersAreNamed != | 229 if (source.optionalParametersAreNamed != |
231 target.optionalParametersAreNamed) { | 230 target.optionalParametersAreNamed) { |
232 // No legal optional arguments due to mismatch between named vs positional | 231 // No legal optional arguments due to mismatch between named vs positional |
233 // optional arguments. | 232 // optional arguments. |
234 return map; | 233 return map; |
235 } | 234 } |
236 | 235 |
237 if (source.optionalParametersAreNamed) { | 236 if (source.optionalParametersAreNamed) { |
238 for (ParameterElement element in source.optionalParameters) { | 237 for (ParameterElement element in source.optionalParameters) { |
239 for (ParameterElement redirectedElement in target.optionalParameters) { | 238 for (ParameterElement redirectedElement in target.optionalParameters) { |
240 if (element.name == redirectedElement.name) { | 239 if (element.name == redirectedElement.name) { |
241 map[element] = redirectedElement; | 240 map[element] = redirectedElement; |
242 break; | 241 break; |
243 } | 242 } |
244 } | 243 } |
245 } | 244 } |
246 } else { | 245 } else { |
247 int i = source.requiredParameterCount; | 246 int i = source.requiredParameterCount; |
248 for (ParameterElement element in source.orderedOptionalParameters) { | 247 for (ParameterElement element in source.orderedOptionalParameters) { |
249 if (i >= target.requiredParameterCount && i < target.parameterCount) { | 248 if (i >= target.requiredParameterCount && i < target.parameterCount) { |
250 map[element] = | 249 map[element] = target.orderedOptionalParameters[ |
251 target.orderedOptionalParameters[i - target.requiredParameterCount
]; | 250 i - target.requiredParameterCount]; |
252 } | 251 } |
253 ++i; | 252 ++i; |
254 } | 253 } |
255 } | 254 } |
256 return map; | 255 return map; |
257 } | 256 } |
258 | 257 |
259 jsAst.Expression reifyMetadata(MetadataAnnotation annotation) { | 258 jsAst.Expression reifyMetadata(MetadataAnnotation annotation) { |
260 ConstantValue constant = | 259 ConstantValue constant = |
261 _backend.constants.getConstantValueForMetadata(annotation); | 260 _backend.constants.getConstantValueForMetadata(annotation); |
262 if (constant == null) { | 261 if (constant == null) { |
263 reporter.internalError(annotation, 'Annotation value is null.'); | 262 reporter.internalError(annotation, 'Annotation value is null.'); |
264 return null; | 263 return null; |
265 } | 264 } |
266 return _addGlobalMetadata(_emitter.constantReference(constant)); | 265 return _addGlobalMetadata(_emitter.constantReference(constant)); |
267 } | 266 } |
268 | 267 |
269 jsAst.Expression reifyType(DartType type, {ignoreTypeVariables: false}) { | 268 jsAst.Expression reifyType(DartType type, {ignoreTypeVariables: false}) { |
270 return reifyTypeForOutputUnit(type, | 269 return reifyTypeForOutputUnit( |
271 _compiler.deferredLoadTask.mainOutputUnit, | 270 type, _compiler.deferredLoadTask.mainOutputUnit, |
272 ignoreTypeVariables: ignoreTypeVariables); | 271 ignoreTypeVariables: ignoreTypeVariables); |
273 } | 272 } |
274 | 273 |
275 jsAst.Expression reifyTypeForOutputUnit(DartType type, | 274 jsAst.Expression reifyTypeForOutputUnit(DartType type, OutputUnit outputUnit, |
276 OutputUnit outputUnit, | 275 {ignoreTypeVariables: false}) { |
277 {ignoreTypeVariables: false}) { | |
278 return addTypeInOutputUnit(type, outputUnit, | 276 return addTypeInOutputUnit(type, outputUnit, |
279 ignoreTypeVariables: ignoreTypeVariables); | 277 ignoreTypeVariables: ignoreTypeVariables); |
280 } | 278 } |
281 | 279 |
282 jsAst.Expression reifyName(String name) { | 280 jsAst.Expression reifyName(String name) { |
283 return _addGlobalMetadata(js.string(name)); | 281 return _addGlobalMetadata(js.string(name)); |
284 } | 282 } |
285 | 283 |
286 jsAst.Expression reifyExpression(jsAst.Expression expression) { | 284 jsAst.Expression reifyExpression(jsAst.Expression expression) { |
287 return _addGlobalMetadata(expression); | 285 return _addGlobalMetadata(expression); |
288 } | 286 } |
289 | 287 |
290 Placeholder getMetadataPlaceholder([debug]) { | 288 Placeholder getMetadataPlaceholder([debug]) { |
291 return new _ForwardingMetadataEntry(debug); | 289 return new _ForwardingMetadataEntry(debug); |
292 } | 290 } |
293 | 291 |
294 _MetadataEntry _addGlobalMetadata(jsAst.Node node) { | 292 _MetadataEntry _addGlobalMetadata(jsAst.Node node) { |
295 String nameToKey(jsAst.Name name) => "${name.key}"; | 293 String nameToKey(jsAst.Name name) => "${name.key}"; |
296 String printed = jsAst.prettyPrint( | 294 String printed = |
297 node, _compiler, renamerForNames: nameToKey); | 295 jsAst.prettyPrint(node, _compiler, renamerForNames: nameToKey); |
298 return _globalMetadataMap.putIfAbsent(printed, () { | 296 return _globalMetadataMap.putIfAbsent(printed, () { |
299 _BoundMetadataEntry result = new _BoundMetadataEntry(node); | 297 _BoundMetadataEntry result = new _BoundMetadataEntry(node); |
300 if (_compiler.options.hasIncrementalSupport) { | 298 if (_compiler.options.hasIncrementalSupport) { |
301 result.finalize(_globalMetadataCounter++); | 299 result.finalize(_globalMetadataCounter++); |
302 } | 300 } |
303 return result; | 301 return result; |
304 }); | 302 }); |
305 } | 303 } |
306 | 304 |
307 jsAst.Expression _computeTypeRepresentation(DartType type, | 305 jsAst.Expression _computeTypeRepresentation(DartType type, |
308 {ignoreTypeVariables: false}) { | 306 {ignoreTypeVariables: false}) { |
309 jsAst.Expression representation = _backend.rtiEncoder.getTypeRepresentation( | 307 jsAst.Expression representation = |
310 type, | 308 _backend.rtiEncoder.getTypeRepresentation(type, (variable) { |
311 (variable) { | 309 if (ignoreTypeVariables) return new jsAst.LiteralNull(); |
312 if (ignoreTypeVariables) return new jsAst.LiteralNull(); | 310 return _typeVariableHandler.reifyTypeVariable(variable.element); |
313 return _typeVariableHandler.reifyTypeVariable(variable.element); | 311 }, (TypedefType typedef) { |
314 }, | 312 return _backend.isAccessibleByReflection(typedef.element); |
315 (TypedefType typedef) { | 313 }); |
316 return _backend.isAccessibleByReflection(typedef.element); | |
317 }); | |
318 | 314 |
319 if (representation is jsAst.LiteralString) { | 315 if (representation is jsAst.LiteralString) { |
320 // We don't want the representation to be a string, since we use | 316 // We don't want the representation to be a string, since we use |
321 // strings as indicator for non-initialized types in the lazy emitter. | 317 // strings as indicator for non-initialized types in the lazy emitter. |
322 reporter.internalError( | 318 reporter.internalError( |
323 NO_LOCATION_SPANNABLE, 'reified types should not be strings.'); | 319 NO_LOCATION_SPANNABLE, 'reified types should not be strings.'); |
324 } | 320 } |
325 | 321 |
326 return representation; | 322 return representation; |
327 | |
328 } | 323 } |
329 | 324 |
330 jsAst.Expression addTypeInOutputUnit(DartType type, | 325 jsAst.Expression addTypeInOutputUnit(DartType type, OutputUnit outputUnit, |
331 OutputUnit outputUnit, | 326 {ignoreTypeVariables: false}) { |
332 {ignoreTypeVariables: false}) { | |
333 if (_typesMap[outputUnit] == null) { | 327 if (_typesMap[outputUnit] == null) { |
334 _typesMap[outputUnit] = new Map<DartType, _BoundMetadataEntry>(); | 328 _typesMap[outputUnit] = new Map<DartType, _BoundMetadataEntry>(); |
335 } | 329 } |
336 return _typesMap[outputUnit].putIfAbsent(type, () { | 330 return _typesMap[outputUnit].putIfAbsent(type, () { |
337 _BoundMetadataEntry result = new _BoundMetadataEntry( | 331 _BoundMetadataEntry result = new _BoundMetadataEntry( |
338 _computeTypeRepresentation(type, | 332 _computeTypeRepresentation(type, |
339 ignoreTypeVariables: ignoreTypeVariables)); | 333 ignoreTypeVariables: ignoreTypeVariables)); |
340 if (_compiler.options.hasIncrementalSupport) { | 334 if (_compiler.options.hasIncrementalSupport) { |
341 result.finalize(_globalTypesCounter++); | 335 result.finalize(_globalTypesCounter++); |
342 } | 336 } |
343 return result; | 337 return result; |
344 }); | 338 }); |
345 } | 339 } |
346 | 340 |
347 List<jsAst.DeferredNumber> computeMetadata(FunctionElement element) { | 341 List<jsAst.DeferredNumber> computeMetadata(FunctionElement element) { |
348 return reporter.withCurrentElement(element, () { | 342 return reporter.withCurrentElement(element, () { |
349 if (!_mustEmitMetadataFor(element)) return const <jsAst.DeferredNumber>[]; | 343 if (!_mustEmitMetadataFor(element)) return const <jsAst.DeferredNumber>[]; |
(...skipping 12 matching lines...) Expand all Loading... |
362 for (_BoundMetadataEntry entry in entries) { | 356 for (_BoundMetadataEntry entry in entries) { |
363 if (!entry.isUsed) continue; | 357 if (!entry.isUsed) continue; |
364 if (debugger.findUnboundPlaceholders(entry.entry)) { | 358 if (debugger.findUnboundPlaceholders(entry.entry)) { |
365 return false; | 359 return false; |
366 } | 360 } |
367 } | 361 } |
368 return true; | 362 return true; |
369 } | 363 } |
370 void countTokensInTypes(Iterable<_BoundMetadataEntry> entries) { | 364 void countTokensInTypes(Iterable<_BoundMetadataEntry> entries) { |
371 jsAst.TokenCounter counter = new jsAst.TokenCounter(); | 365 jsAst.TokenCounter counter = new jsAst.TokenCounter(); |
372 entries.where((_BoundMetadataEntry e) => e._rc > 0) | 366 entries |
373 .map((_BoundMetadataEntry e) => e.entry) | 367 .where((_BoundMetadataEntry e) => e._rc > 0) |
374 .forEach(counter.countTokens); | 368 .map((_BoundMetadataEntry e) => e.entry) |
| 369 .forEach(counter.countTokens); |
375 } | 370 } |
376 | 371 |
377 jsAst.ArrayInitializer finalizeMap(Map<dynamic, _BoundMetadataEntry> map) { | 372 jsAst.ArrayInitializer finalizeMap(Map<dynamic, _BoundMetadataEntry> map) { |
378 // When in incremental mode, we allocate entries eagerly. | 373 // When in incremental mode, we allocate entries eagerly. |
379 if (_compiler.options.hasIncrementalSupport) { | 374 if (_compiler.options.hasIncrementalSupport) { |
380 return new jsAst.ArrayInitializer(map.values.toList()); | 375 return new jsAst.ArrayInitializer(map.values.toList()); |
381 } | 376 } |
382 | 377 |
383 bool isUsed(_BoundMetadataEntry entry) => entry.isUsed; | 378 bool isUsed(_BoundMetadataEntry entry) => entry.isUsed; |
384 List<_BoundMetadataEntry> entries = map.values.where(isUsed).toList(); | 379 List<_BoundMetadataEntry> entries = map.values.where(isUsed).toList(); |
385 entries.sort(); | 380 entries.sort(); |
386 | 381 |
387 // TODO(herhut): Bucket entries by index length and use a stable | 382 // TODO(herhut): Bucket entries by index length and use a stable |
388 // distribution within buckets. | 383 // distribution within buckets. |
389 int count = 0; | 384 int count = 0; |
390 for (_BoundMetadataEntry entry in entries) { | 385 for (_BoundMetadataEntry entry in entries) { |
391 entry.finalize(count++); | 386 entry.finalize(count++); |
392 } | 387 } |
393 | 388 |
394 List<jsAst.Node> values = | 389 List<jsAst.Node> values = |
395 entries.map((_BoundMetadataEntry e) => e.entry).toList(); | 390 entries.map((_BoundMetadataEntry e) => e.entry).toList(); |
396 | 391 |
397 return new jsAst.ArrayInitializer(values); | 392 return new jsAst.ArrayInitializer(values); |
398 } | 393 } |
399 | 394 |
400 _globalMetadata.setExpression(finalizeMap(_globalMetadataMap)); | 395 _globalMetadata.setExpression(finalizeMap(_globalMetadataMap)); |
401 | 396 |
402 _typesTokens.forEach((OutputUnit outputUnit, _MetadataList token) { | 397 _typesTokens.forEach((OutputUnit outputUnit, _MetadataList token) { |
403 Map typesMap = _typesMap[outputUnit]; | 398 Map typesMap = _typesMap[outputUnit]; |
404 if (typesMap != null) { | 399 if (typesMap != null) { |
405 assert(checkTokensInTypes(outputUnit, typesMap.values)); | 400 assert(checkTokensInTypes(outputUnit, typesMap.values)); |
406 countTokensInTypes(typesMap.values); | 401 countTokensInTypes(typesMap.values); |
407 token.setExpression(finalizeMap(typesMap)); | 402 token.setExpression(finalizeMap(typesMap)); |
(...skipping 15 matching lines...) Expand all Loading... |
423 if (token is _ForwardingMetadataEntry && !token.isBound) { | 418 if (token is _ForwardingMetadataEntry && !token.isBound) { |
424 _foundUnboundToken = true; | 419 _foundUnboundToken = true; |
425 } | 420 } |
426 } | 421 } |
427 | 422 |
428 bool findUnboundPlaceholders(jsAst.Node node) { | 423 bool findUnboundPlaceholders(jsAst.Node node) { |
429 node.accept(this); | 424 node.accept(this); |
430 return _foundUnboundToken; | 425 return _foundUnboundToken; |
431 } | 426 } |
432 } | 427 } |
OLD | NEW |