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 import '../common.dart'; | 5 import '../common.dart'; |
6 import '../common/backend_api.dart' show | 6 import '../common/backend_api.dart' show ForeignResolver; |
7 ForeignResolver; | 7 import '../common/resolution.dart' show Parsing, Resolution; |
8 import '../common/resolution.dart' show | 8 import '../compiler.dart' show Compiler; |
9 Parsing, | |
10 Resolution; | |
11 import '../compiler.dart' show | |
12 Compiler; | |
13 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
14 import '../core_types.dart' show | 10 import '../core_types.dart' show CoreTypes; |
15 CoreTypes; | |
16 import '../dart_types.dart'; | 11 import '../dart_types.dart'; |
17 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
18 import '../js/js.dart' as js; | 13 import '../js/js.dart' as js; |
19 import '../js_backend/js_backend.dart'; | 14 import '../js_backend/js_backend.dart'; |
20 import '../tree/tree.dart'; | 15 import '../tree/tree.dart'; |
21 import '../universe/side_effects.dart' show | 16 import '../universe/side_effects.dart' show SideEffects; |
22 SideEffects; | |
23 import '../util/util.dart'; | 17 import '../util/util.dart'; |
24 | 18 |
25 import 'enqueue.dart'; | 19 import 'enqueue.dart'; |
26 import 'js.dart'; | 20 import 'js.dart'; |
27 | 21 |
28 /// This class is a temporary work-around until we get a more powerful DartType. | 22 /// This class is a temporary work-around until we get a more powerful DartType. |
29 class SpecialType { | 23 class SpecialType { |
30 final String name; | 24 final String name; |
31 const SpecialType._(this.name); | 25 const SpecialType._(this.name); |
32 | 26 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 * If there is one or more `@Returns` annotations, the union of the named types | 96 * If there is one or more `@Returns` annotations, the union of the named types |
103 * replaces the declared return type. | 97 * replaces the declared return type. |
104 * | 98 * |
105 * @Returns('IDBRequest') | 99 * @Returns('IDBRequest') |
106 * IDBRequest openCursor(); | 100 * IDBRequest openCursor(); |
107 * | 101 * |
108 * Types in annotations are non-nullable, so include `@Returns('Null')` if | 102 * Types in annotations are non-nullable, so include `@Returns('Null')` if |
109 * `null` may be returned. | 103 * `null` may be returned. |
110 */ | 104 */ |
111 class NativeBehavior { | 105 class NativeBehavior { |
112 | |
113 /// [DartType]s or [SpecialType]s returned or yielded by the native element. | 106 /// [DartType]s or [SpecialType]s returned or yielded by the native element. |
114 final List typesReturned = []; | 107 final List typesReturned = []; |
115 | 108 |
116 /// [DartType]s or [SpecialType]s instantiated by the native element. | 109 /// [DartType]s or [SpecialType]s instantiated by the native element. |
117 final List typesInstantiated = []; | 110 final List typesInstantiated = []; |
118 | 111 |
119 // If this behavior is for a JS expression, [codeTemplate] contains the | 112 // If this behavior is for a JS expression, [codeTemplate] contains the |
120 // parsed tree. | 113 // parsed tree. |
121 js.Template codeTemplate; | 114 js.Template codeTemplate; |
122 | 115 |
123 final SideEffects sideEffects = new SideEffects.empty(); | 116 final SideEffects sideEffects = new SideEffects.empty(); |
124 | 117 |
125 NativeThrowBehavior throwBehavior = NativeThrowBehavior.MAY; | 118 NativeThrowBehavior throwBehavior = NativeThrowBehavior.MAY; |
126 | 119 |
127 bool isAllocation = false; | 120 bool isAllocation = false; |
128 bool useGvn = false; | 121 bool useGvn = false; |
129 | 122 |
130 // TODO(sra): Make NativeBehavior immutable so PURE and PURE_ALLOCATION can be | 123 // TODO(sra): Make NativeBehavior immutable so PURE and PURE_ALLOCATION can be |
131 // final constant-like objects. | 124 // final constant-like objects. |
132 static NativeBehavior get PURE => NativeBehavior._makePure(); | 125 static NativeBehavior get PURE => NativeBehavior._makePure(); |
133 static NativeBehavior get PURE_ALLOCATION => | 126 static NativeBehavior get PURE_ALLOCATION => |
134 NativeBehavior._makePure(isAllocation: true); | 127 NativeBehavior._makePure(isAllocation: true); |
135 static NativeBehavior get CHANGES_OTHER => NativeBehavior._makeChangesOther(); | 128 static NativeBehavior get CHANGES_OTHER => NativeBehavior._makeChangesOther(); |
136 static NativeBehavior get DEPENDS_OTHER => NativeBehavior._makeDependsOther(); | 129 static NativeBehavior get DEPENDS_OTHER => NativeBehavior._makeDependsOther(); |
137 | 130 |
138 | |
139 String toString() { | 131 String toString() { |
140 return 'NativeBehavior(' | 132 return 'NativeBehavior(' |
141 'returns: ${typesReturned}' | 133 'returns: ${typesReturned}' |
142 ', creates: ${typesInstantiated}' | 134 ', creates: ${typesInstantiated}' |
143 ', sideEffects: ${sideEffects}' | 135 ', sideEffects: ${sideEffects}' |
144 ', throws: ${throwBehavior}' | 136 ', throws: ${throwBehavior}' |
145 '${isAllocation ? ", isAllocation" : ""}' | 137 '${isAllocation ? ", isAllocation" : ""}' |
146 '${useGvn ? ", useGvn" : ""}' | 138 '${useGvn ? ", useGvn" : ""}' |
147 ')'; | 139 ')'; |
148 } | 140 } |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 /// Each tag kind (including the 'type-tag's) can only occur once in the | 223 /// Each tag kind (including the 'type-tag's) can only occur once in the |
232 /// sequence. | 224 /// sequence. |
233 /// | 225 /// |
234 /// [specString] is the specification string, [resolveType] resolves named | 226 /// [specString] is the specification string, [resolveType] resolves named |
235 /// types into type values, [typesReturned] and [typesInstantiated] collects | 227 /// types into type values, [typesReturned] and [typesInstantiated] collects |
236 /// the types defined by the specification string, and [objectType] and | 228 /// the types defined by the specification string, and [objectType] and |
237 /// [nullType] define the types for `Object` and `Null`, respectively. The | 229 /// [nullType] define the types for `Object` and `Null`, respectively. The |
238 /// latter is used for the type strings of the form '' and 'var'. | 230 /// latter is used for the type strings of the form '' and 'var'. |
239 /// [validTags] can be used to restrict which tags are accepted. | 231 /// [validTags] can be used to restrict which tags are accepted. |
240 static void processSpecString( | 232 static void processSpecString( |
241 DiagnosticReporter reporter, | 233 DiagnosticReporter reporter, Spannable spannable, String specString, |
242 Spannable spannable, | |
243 String specString, | |
244 {Iterable<String> validTags, | 234 {Iterable<String> validTags, |
245 void setSideEffects(SideEffects newEffects), | 235 void setSideEffects(SideEffects newEffects), |
246 void setThrows(NativeThrowBehavior throwKind), | 236 void setThrows(NativeThrowBehavior throwKind), |
247 void setIsAllocation(bool isAllocation), | 237 void setIsAllocation(bool isAllocation), |
248 void setUseGvn(bool useGvn), | 238 void setUseGvn(bool useGvn), |
249 dynamic resolveType(String typeString), | 239 dynamic resolveType(String typeString), |
250 List typesReturned, | 240 List typesReturned, |
251 List typesInstantiated, | 241 List typesInstantiated, |
252 objectType, nullType}) { | 242 objectType, |
253 | 243 nullType}) { |
254 | |
255 bool seenError = false; | 244 bool seenError = false; |
256 | 245 |
257 void reportError(String message) { | 246 void reportError(String message) { |
258 seenError = true; | 247 seenError = true; |
259 reporter.reportErrorMessage( | 248 reporter.reportErrorMessage( |
260 spannable, MessageKind.GENERIC, {'text': message}); | 249 spannable, MessageKind.GENERIC, {'text': message}); |
261 } | 250 } |
262 | 251 |
263 const List<String> knownTags = const [ | 252 const List<String> knownTags = const [ |
264 'creates', 'returns', 'depends', 'effects', | 253 'creates', |
265 'throws', 'gvn', 'new']; | 254 'returns', |
| 255 'depends', |
| 256 'effects', |
| 257 'throws', |
| 258 'gvn', |
| 259 'new' |
| 260 ]; |
266 | 261 |
267 /// Resolve a type string of one of the three forms: | 262 /// Resolve a type string of one of the three forms: |
268 /// * 'void' - in which case [onVoid] is called, | 263 /// * 'void' - in which case [onVoid] is called, |
269 /// * '' or 'var' - in which case [onVar] is called, | 264 /// * '' or 'var' - in which case [onVar] is called, |
270 /// * 'T1|...|Tn' - in which case [onType] is called for each resolved Ti. | 265 /// * 'T1|...|Tn' - in which case [onType] is called for each resolved Ti. |
271 void resolveTypesString(String typesString, | 266 void resolveTypesString(String typesString, |
272 {onVoid(), onVar(), onType(type)}) { | 267 {onVoid(), onVar(), onType(type)}) { |
273 // Various things that are not in fact types. | 268 // Various things that are not in fact types. |
274 if (typesString == 'void') { | 269 if (typesString == 'void') { |
275 if (onVoid != null) { | 270 if (onVoid != null) { |
276 onVoid(); | 271 onVoid(); |
277 } | 272 } |
278 return; | 273 return; |
279 } | 274 } |
280 if (typesString == '' || typesString == 'var') { | 275 if (typesString == '' || typesString == 'var') { |
281 if (onVar != null) { | 276 if (onVar != null) { |
282 onVar(); | 277 onVar(); |
(...skipping 10 matching lines...) Expand all Loading... |
293 resolveTypesString(specString.trim(), onVar: () { | 288 resolveTypesString(specString.trim(), onVar: () { |
294 typesReturned.add(objectType); | 289 typesReturned.add(objectType); |
295 typesReturned.add(nullType); | 290 typesReturned.add(nullType); |
296 }, onType: (type) { | 291 }, onType: (type) { |
297 typesInstantiated.add(type); | 292 typesInstantiated.add(type); |
298 typesReturned.add(type); | 293 typesReturned.add(type); |
299 }); | 294 }); |
300 return; | 295 return; |
301 } | 296 } |
302 | 297 |
303 List<String> specs = specString.split(';') | 298 List<String> specs = specString.split(';').map((s) => s.trim()).toList(); |
304 .map((s) => s.trim()) | 299 if (specs.last == "") specs.removeLast(); // Allow separator to terminate. |
305 .toList(); | |
306 if (specs.last == "") specs.removeLast(); // Allow separator to terminate. | |
307 | 300 |
308 assert(validTags == null || | 301 assert( |
309 (validTags.toSet()..removeAll(validTags)).isEmpty); | 302 validTags == null || (validTags.toSet()..removeAll(validTags)).isEmpty); |
310 if (validTags == null) validTags = knownTags; | 303 if (validTags == null) validTags = knownTags; |
311 | 304 |
312 Map<String, String> values = <String, String>{}; | 305 Map<String, String> values = <String, String>{}; |
313 | 306 |
314 for (String spec in specs) { | 307 for (String spec in specs) { |
315 List<String> tagAndValue = spec.split(':'); | 308 List<String> tagAndValue = spec.split(':'); |
316 if (tagAndValue.length != 2) { | 309 if (tagAndValue.length != 2) { |
317 reportError("Invalid <tag>:<value> pair '$spec'."); | 310 reportError("Invalid <tag>:<value> pair '$spec'."); |
318 continue; | 311 continue; |
319 } | 312 } |
(...skipping 24 matching lines...) Expand all Loading... |
344 if (tagString == null) return null; | 337 if (tagString == null) return null; |
345 var value = map[tagString]; | 338 var value = map[tagString]; |
346 if (value == null) { | 339 if (value == null) { |
347 reportError("Unknown '$tag' specification: '$tagString'."); | 340 reportError("Unknown '$tag' specification: '$tagString'."); |
348 } | 341 } |
349 return value; | 342 return value; |
350 } | 343 } |
351 | 344 |
352 String returns = values['returns']; | 345 String returns = values['returns']; |
353 if (returns != null) { | 346 if (returns != null) { |
354 resolveTypesString(returns, | 347 resolveTypesString(returns, onVar: () { |
355 onVar: () { | 348 typesReturned.add(objectType); |
356 typesReturned.add(objectType); | 349 typesReturned.add(nullType); |
357 typesReturned.add(nullType); | 350 }, onType: (type) { |
358 }, | 351 typesReturned.add(type); |
359 onType: (type) { | 352 }); |
360 typesReturned.add(type); | |
361 }); | |
362 } | 353 } |
363 | 354 |
364 String creates = values['creates']; | 355 String creates = values['creates']; |
365 if (creates != null) { | 356 if (creates != null) { |
366 resolveTypesString(creates, | 357 resolveTypesString(creates, onVoid: () { |
367 onVoid: () { | 358 reportError("Invalid type string 'creates:$creates'"); |
368 reportError("Invalid type string 'creates:$creates'"); | 359 }, onType: (type) { |
369 }, | 360 typesInstantiated.add(type); |
370 onType: (type) { | 361 }); |
371 typesInstantiated.add(type); | |
372 }); | |
373 } else if (returns != null) { | 362 } else if (returns != null) { |
374 resolveTypesString(returns, | 363 resolveTypesString(returns, onType: (type) { |
375 onType: (type) { | 364 typesInstantiated.add(type); |
376 typesInstantiated.add(type); | 365 }); |
377 }); | |
378 } | 366 } |
379 | 367 |
380 const throwsOption = const <String, NativeThrowBehavior>{ | 368 const throwsOption = const <String, NativeThrowBehavior>{ |
381 'never': NativeThrowBehavior.NEVER, | 369 'never': NativeThrowBehavior.NEVER, |
382 'null(1)': NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS, | 370 'null(1)': NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS, |
383 'may': NativeThrowBehavior.MAY, | 371 'may': NativeThrowBehavior.MAY, |
384 'must': NativeThrowBehavior.MUST }; | 372 'must': NativeThrowBehavior.MUST |
| 373 }; |
385 | 374 |
386 const boolOptions = const<String, bool>{'true': true, 'false': false}; | 375 const boolOptions = const <String, bool>{'true': true, 'false': false}; |
387 | 376 |
388 SideEffects sideEffects = processEffects(reportError, | 377 SideEffects sideEffects = |
389 values['effects'], values['depends']); | 378 processEffects(reportError, values['effects'], values['depends']); |
390 NativeThrowBehavior throwsKind = tagValueLookup('throws', throwsOption); | 379 NativeThrowBehavior throwsKind = tagValueLookup('throws', throwsOption); |
391 bool isAllocation = tagValueLookup('new', boolOptions); | 380 bool isAllocation = tagValueLookup('new', boolOptions); |
392 bool useGvn = tagValueLookup('gvn', boolOptions); | 381 bool useGvn = tagValueLookup('gvn', boolOptions); |
393 | 382 |
394 if (isAllocation == true && useGvn == true) { | 383 if (isAllocation == true && useGvn == true) { |
395 reportError("'new' and 'gvn' are incompatible"); | 384 reportError("'new' and 'gvn' are incompatible"); |
396 } | 385 } |
397 | 386 |
398 if (seenError) return; // Avoid callbacks. | 387 if (seenError) return; // Avoid callbacks. |
399 | 388 |
400 // TODO(sra): Simplify [throwBehavior] using [sideEffects]. | 389 // TODO(sra): Simplify [throwBehavior] using [sideEffects]. |
401 | 390 |
402 if (sideEffects != null) setSideEffects(sideEffects); | 391 if (sideEffects != null) setSideEffects(sideEffects); |
403 if (throwsKind != null) setThrows(throwsKind); | 392 if (throwsKind != null) setThrows(throwsKind); |
404 if (isAllocation != null) setIsAllocation(isAllocation); | 393 if (isAllocation != null) setIsAllocation(isAllocation); |
405 if (useGvn != null) setUseGvn(useGvn); | 394 if (useGvn != null) setUseGvn(useGvn); |
406 } | 395 } |
407 | 396 |
408 static SideEffects processEffects( | 397 static SideEffects processEffects( |
409 void reportError(String message), | 398 void reportError(String message), String effects, String depends) { |
410 String effects, | |
411 String depends) { | |
412 | |
413 if (effects == null && depends == null) return null; | 399 if (effects == null && depends == null) return null; |
414 | 400 |
415 if (effects == null || depends == null) { | 401 if (effects == null || depends == null) { |
416 reportError("'effects' and 'depends' must occur together."); | 402 reportError("'effects' and 'depends' must occur together."); |
417 return null; | 403 return null; |
418 } | 404 } |
419 | 405 |
420 SideEffects sideEffects = new SideEffects(); | 406 SideEffects sideEffects = new SideEffects(); |
421 if (effects == "none") { | 407 if (effects == "none") { |
422 sideEffects.clearAllSideEffects(); | 408 sideEffects.clearAllSideEffects(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
466 break; | 452 break; |
467 default: | 453 default: |
468 reportError("Unrecognized side-effect flag: '$dependency'."); | 454 reportError("Unrecognized side-effect flag: '$dependency'."); |
469 } | 455 } |
470 } | 456 } |
471 } | 457 } |
472 | 458 |
473 return sideEffects; | 459 return sideEffects; |
474 } | 460 } |
475 | 461 |
476 static NativeBehavior ofJsCall( | 462 static NativeBehavior ofJsCall(Send jsCall, DiagnosticReporter reporter, |
477 Send jsCall, | 463 Parsing parsing, CoreTypes coreTypes, ForeignResolver resolver) { |
478 DiagnosticReporter reporter, | |
479 Parsing parsing, | |
480 CoreTypes coreTypes, | |
481 ForeignResolver resolver) { | |
482 // The first argument of a JS-call is a string encoding various attributes | 464 // The first argument of a JS-call is a string encoding various attributes |
483 // of the code. | 465 // of the code. |
484 // | 466 // |
485 // 'Type1|Type2'. A union type. | 467 // 'Type1|Type2'. A union type. |
486 // '=Object'. A JavaScript Object, no subtype. | 468 // '=Object'. A JavaScript Object, no subtype. |
487 | 469 |
488 NativeBehavior behavior = new NativeBehavior(); | 470 NativeBehavior behavior = new NativeBehavior(); |
489 | 471 |
490 var argNodes = jsCall.arguments; | 472 var argNodes = jsCall.arguments; |
491 if (argNodes.isEmpty || argNodes.tail.isEmpty) { | 473 if (argNodes.isEmpty || argNodes.tail.isEmpty) { |
492 reporter.reportErrorMessage( | 474 reporter.reportErrorMessage(jsCall, MessageKind.GENERIC, |
493 jsCall, | |
494 MessageKind.GENERIC, | |
495 {'text': "JS expression takes two or more arguments."}); | 475 {'text': "JS expression takes two or more arguments."}); |
496 return behavior; | 476 return behavior; |
497 } | 477 } |
498 | 478 |
499 var specArgument = argNodes.head; | 479 var specArgument = argNodes.head; |
500 if (specArgument is !StringNode || specArgument.isInterpolation) { | 480 if (specArgument is! StringNode || specArgument.isInterpolation) { |
501 reporter.reportErrorMessage( | 481 reporter.reportErrorMessage(specArgument, MessageKind.GENERIC, |
502 specArgument, MessageKind.GENERIC, | |
503 {'text': "JS first argument must be a string literal."}); | 482 {'text': "JS first argument must be a string literal."}); |
504 return behavior; | 483 return behavior; |
505 } | 484 } |
506 | 485 |
507 var codeArgument = argNodes.tail.head; | 486 var codeArgument = argNodes.tail.head; |
508 if (codeArgument is !StringNode || codeArgument.isInterpolation) { | 487 if (codeArgument is! StringNode || codeArgument.isInterpolation) { |
509 reporter.reportErrorMessage( | 488 reporter.reportErrorMessage(codeArgument, MessageKind.GENERIC, |
510 codeArgument, MessageKind.GENERIC, | |
511 {'text': "JS second argument must be a string literal."}); | 489 {'text': "JS second argument must be a string literal."}); |
512 return behavior; | 490 return behavior; |
513 } | 491 } |
514 | 492 |
515 behavior.codeTemplate = | 493 behavior.codeTemplate = |
516 js.js.parseForeignJS(codeArgument.dartString.slowToString()); | 494 js.js.parseForeignJS(codeArgument.dartString.slowToString()); |
517 | 495 |
518 String specString = specArgument.dartString.slowToString(); | 496 String specString = specArgument.dartString.slowToString(); |
519 | 497 |
520 dynamic resolveType(String typeString) { | 498 dynamic resolveType(String typeString) { |
(...skipping 18 matching lines...) Expand all Loading... |
539 } | 517 } |
540 | 518 |
541 void setIsAllocation(bool isAllocation) { | 519 void setIsAllocation(bool isAllocation) { |
542 behavior.isAllocation = isAllocation; | 520 behavior.isAllocation = isAllocation; |
543 } | 521 } |
544 | 522 |
545 void setUseGvn(bool useGvn) { | 523 void setUseGvn(bool useGvn) { |
546 behavior.useGvn = useGvn; | 524 behavior.useGvn = useGvn; |
547 } | 525 } |
548 | 526 |
549 processSpecString( | 527 processSpecString(reporter, specArgument, specString, |
550 reporter, | |
551 specArgument, | |
552 specString, | |
553 setSideEffects: setSideEffects, | 528 setSideEffects: setSideEffects, |
554 setThrows: setThrows, | 529 setThrows: setThrows, |
555 setIsAllocation: setIsAllocation, | 530 setIsAllocation: setIsAllocation, |
556 setUseGvn: setUseGvn, | 531 setUseGvn: setUseGvn, |
557 resolveType: resolveType, | 532 resolveType: resolveType, |
558 typesReturned: behavior.typesReturned, | 533 typesReturned: behavior.typesReturned, |
559 typesInstantiated: behavior.typesInstantiated, | 534 typesInstantiated: behavior.typesInstantiated, |
560 objectType: coreTypes.objectType, | 535 objectType: coreTypes.objectType, |
561 nullType: coreTypes.nullType); | 536 nullType: coreTypes.nullType); |
562 | 537 |
(...skipping 10 matching lines...) Expand all Loading... |
573 } | 548 } |
574 | 549 |
575 static void _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( | 550 static void _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( |
576 NativeBehavior behavior, | 551 NativeBehavior behavior, |
577 Send jsBuiltinOrEmbeddedGlobalCall, | 552 Send jsBuiltinOrEmbeddedGlobalCall, |
578 DiagnosticReporter reporter, | 553 DiagnosticReporter reporter, |
579 Parsing parsing, | 554 Parsing parsing, |
580 CoreTypes coreTypes, | 555 CoreTypes coreTypes, |
581 ForeignResolver resolver, | 556 ForeignResolver resolver, |
582 {bool isBuiltin, | 557 {bool isBuiltin, |
583 List<String> validTags}) { | 558 List<String> validTags}) { |
584 // The first argument of a JS-embedded global call is a string encoding | 559 // The first argument of a JS-embedded global call is a string encoding |
585 // the type of the code. | 560 // the type of the code. |
586 // | 561 // |
587 // 'Type1|Type2'. A union type. | 562 // 'Type1|Type2'. A union type. |
588 // '=Object'. A JavaScript Object, no subtype. | 563 // '=Object'. A JavaScript Object, no subtype. |
589 | 564 |
590 String builtinOrGlobal = isBuiltin ? "builtin" : "embedded global"; | 565 String builtinOrGlobal = isBuiltin ? "builtin" : "embedded global"; |
591 | 566 |
592 Link<Node> argNodes = jsBuiltinOrEmbeddedGlobalCall.arguments; | 567 Link<Node> argNodes = jsBuiltinOrEmbeddedGlobalCall.arguments; |
593 if (argNodes.isEmpty) { | 568 if (argNodes.isEmpty) { |
(...skipping 30 matching lines...) Expand all Loading... |
624 typeString, | 599 typeString, |
625 parsing, | 600 parsing, |
626 (name) => resolver.resolveTypeFromString(specLiteral, name), | 601 (name) => resolver.resolveTypeFromString(specLiteral, name), |
627 jsBuiltinOrEmbeddedGlobalCall); | 602 jsBuiltinOrEmbeddedGlobalCall); |
628 } | 603 } |
629 | 604 |
630 void setSideEffects(SideEffects newEffects) { | 605 void setSideEffects(SideEffects newEffects) { |
631 behavior.sideEffects.setTo(newEffects); | 606 behavior.sideEffects.setTo(newEffects); |
632 } | 607 } |
633 | 608 |
634 processSpecString( | 609 processSpecString(reporter, jsBuiltinOrEmbeddedGlobalCall, specString, |
635 reporter, | |
636 jsBuiltinOrEmbeddedGlobalCall, | |
637 specString, | |
638 validTags: validTags, | 610 validTags: validTags, |
639 resolveType: resolveType, | 611 resolveType: resolveType, |
640 setSideEffects: setSideEffects, | 612 setSideEffects: setSideEffects, |
641 typesReturned: behavior.typesReturned, | 613 typesReturned: behavior.typesReturned, |
642 typesInstantiated: behavior.typesInstantiated, | 614 typesInstantiated: behavior.typesInstantiated, |
643 objectType: coreTypes.objectType, | 615 objectType: coreTypes.objectType, |
644 nullType: coreTypes.nullType); | 616 nullType: coreTypes.nullType); |
645 } | 617 } |
646 | 618 |
647 static NativeBehavior ofJsBuiltinCall( | 619 static NativeBehavior ofJsBuiltinCall( |
648 Send jsBuiltinCall, | 620 Send jsBuiltinCall, |
649 DiagnosticReporter reporter, | 621 DiagnosticReporter reporter, |
650 Parsing parsing, | 622 Parsing parsing, |
651 CoreTypes coreTypes, | 623 CoreTypes coreTypes, |
652 ForeignResolver resolver) { | 624 ForeignResolver resolver) { |
653 NativeBehavior behavior = new NativeBehavior(); | 625 NativeBehavior behavior = new NativeBehavior(); |
654 behavior.sideEffects.setTo(new SideEffects()); | 626 behavior.sideEffects.setTo(new SideEffects()); |
655 | 627 |
656 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( | 628 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( |
657 behavior, | 629 behavior, jsBuiltinCall, reporter, parsing, coreTypes, resolver, |
658 jsBuiltinCall, | |
659 reporter, | |
660 parsing, | |
661 coreTypes, | |
662 resolver, | |
663 isBuiltin: true); | 630 isBuiltin: true); |
664 | 631 |
665 return behavior; | 632 return behavior; |
666 } | 633 } |
667 | 634 |
668 static NativeBehavior ofJsEmbeddedGlobalCall( | 635 static NativeBehavior ofJsEmbeddedGlobalCall( |
669 Send jsEmbeddedGlobalCall, | 636 Send jsEmbeddedGlobalCall, |
670 DiagnosticReporter reporter, | 637 DiagnosticReporter reporter, |
671 Parsing parsing, | 638 Parsing parsing, |
672 CoreTypes coreTypes, | 639 CoreTypes coreTypes, |
673 ForeignResolver resolver) { | 640 ForeignResolver resolver) { |
674 NativeBehavior behavior = new NativeBehavior(); | 641 NativeBehavior behavior = new NativeBehavior(); |
675 // TODO(sra): Allow the use site to override these defaults. | 642 // TODO(sra): Allow the use site to override these defaults. |
676 // Embedded globals are usually pre-computed data structures or JavaScript | 643 // Embedded globals are usually pre-computed data structures or JavaScript |
677 // functions that never change. | 644 // functions that never change. |
678 behavior.sideEffects.setTo(new SideEffects.empty()); | 645 behavior.sideEffects.setTo(new SideEffects.empty()); |
679 behavior.throwBehavior = NativeThrowBehavior.NEVER; | 646 behavior.throwBehavior = NativeThrowBehavior.NEVER; |
680 | 647 |
681 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( | 648 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( |
682 behavior, | 649 behavior, jsEmbeddedGlobalCall, reporter, parsing, coreTypes, resolver, |
683 jsEmbeddedGlobalCall, | 650 isBuiltin: false, validTags: const ['returns', 'creates']); |
684 reporter, | |
685 parsing, | |
686 coreTypes, | |
687 resolver, | |
688 isBuiltin: false, | |
689 validTags: const ['returns', 'creates']); | |
690 | 651 |
691 return behavior; | 652 return behavior; |
692 } | 653 } |
693 | 654 |
694 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { | 655 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { |
695 FunctionType type = method.computeType(compiler.resolution); | 656 FunctionType type = method.computeType(compiler.resolution); |
696 var behavior = new NativeBehavior(); | 657 var behavior = new NativeBehavior(); |
697 var returnType = type.returnType; | 658 var returnType = type.returnType; |
698 bool isInterop = compiler.backend.isJsInterop(method); | 659 bool isInterop = compiler.backend.isJsInterop(method); |
699 // Note: For dart:html and other internal libraries we maintain, we can | 660 // Note: For dart:html and other internal libraries we maintain, we can |
700 // trust the return type and use it to limit what we enqueue. We have to | 661 // trust the return type and use it to limit what we enqueue. We have to |
701 // be more conservative about JS interop types and assume they can return | 662 // be more conservative about JS interop types and assume they can return |
702 // anything (unless the user provides the experimental flag to trust the | 663 // anything (unless the user provides the experimental flag to trust the |
703 // type of js-interop APIs). We do restrict the allocation effects and say | 664 // type of js-interop APIs). We do restrict the allocation effects and say |
704 // that interop calls create only interop types (which may be unsound if | 665 // that interop calls create only interop types (which may be unsound if |
705 // an interop call returns a DOM type and declares a dynamic return type, | 666 // an interop call returns a DOM type and declares a dynamic return type, |
706 // but otherwise we would include a lot of code by default). | 667 // but otherwise we would include a lot of code by default). |
707 // TODO(sigmund,sra): consider doing something better for numeric types. | 668 // TODO(sigmund,sra): consider doing something better for numeric types. |
708 behavior.typesReturned.add( | 669 behavior.typesReturned.add( |
709 !isInterop || compiler.options.trustJSInteropTypeAnnotations | 670 !isInterop || compiler.options.trustJSInteropTypeAnnotations |
710 ? returnType : const DynamicType()); | 671 ? returnType |
| 672 : const DynamicType()); |
711 if (!type.returnType.isVoid) { | 673 if (!type.returnType.isVoid) { |
712 // Declared types are nullable. | 674 // Declared types are nullable. |
713 behavior.typesReturned.add(compiler.coreTypes.nullType); | 675 behavior.typesReturned.add(compiler.coreTypes.nullType); |
714 } | 676 } |
715 behavior._capture(type, compiler.resolution, | 677 behavior._capture(type, compiler.resolution, |
716 isInterop: isInterop, compiler: compiler); | 678 isInterop: isInterop, compiler: compiler); |
717 | 679 |
718 // TODO(sra): Optional arguments are currently missing from the | 680 // TODO(sra): Optional arguments are currently missing from the |
719 // DartType. This should be fixed so the following work-around can be | 681 // DartType. This should be fixed so the following work-around can be |
720 // removed. | 682 // removed. |
721 method.functionSignature.forEachOptionalParameter( | 683 method.functionSignature |
722 (ParameterElement parameter) { | 684 .forEachOptionalParameter((ParameterElement parameter) { |
723 behavior._escape(parameter.type, compiler.resolution); | 685 behavior._escape(parameter.type, compiler.resolution); |
724 }); | 686 }); |
725 | 687 |
726 behavior._overrideWithAnnotations(method, compiler); | 688 behavior._overrideWithAnnotations(method, compiler); |
727 return behavior; | 689 return behavior; |
728 } | 690 } |
729 | 691 |
730 static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) { | 692 static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) { |
731 Resolution resolution = compiler.resolution; | 693 Resolution resolution = compiler.resolution; |
732 DartType type = field.computeType(resolution); | 694 DartType type = field.computeType(resolution); |
733 var behavior = new NativeBehavior(); | 695 var behavior = new NativeBehavior(); |
734 bool isInterop = compiler.backend.isJsInterop(field); | 696 bool isInterop = compiler.backend.isJsInterop(field); |
735 // TODO(sigmund,sra): consider doing something better for numeric types. | 697 // TODO(sigmund,sra): consider doing something better for numeric types. |
736 behavior.typesReturned.add( | 698 behavior.typesReturned.add( |
737 !isInterop || compiler.options.trustJSInteropTypeAnnotations | 699 !isInterop || compiler.options.trustJSInteropTypeAnnotations |
738 ? type : const DynamicType()); | 700 ? type |
| 701 : const DynamicType()); |
739 // Declared types are nullable. | 702 // Declared types are nullable. |
740 behavior.typesReturned.add(resolution.coreTypes.nullType); | 703 behavior.typesReturned.add(resolution.coreTypes.nullType); |
741 behavior._capture(type, resolution, | 704 behavior._capture(type, resolution, |
742 isInterop: isInterop, compiler: compiler); | 705 isInterop: isInterop, compiler: compiler); |
743 behavior._overrideWithAnnotations(field, compiler); | 706 behavior._overrideWithAnnotations(field, compiler); |
744 return behavior; | 707 return behavior; |
745 } | 708 } |
746 | 709 |
747 static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) { | 710 static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) { |
748 Resolution resolution = compiler.resolution; | 711 Resolution resolution = compiler.resolution; |
(...skipping 11 matching lines...) Expand all Loading... |
760 DartType lookup(String name) { | 723 DartType lookup(String name) { |
761 Element e = element.buildScope().lookup(name); | 724 Element e = element.buildScope().lookup(name); |
762 if (e == null) return null; | 725 if (e == null) return null; |
763 if (e is! ClassElement) return null; | 726 if (e is! ClassElement) return null; |
764 ClassElement cls = e; | 727 ClassElement cls = e; |
765 cls.ensureResolved(compiler.resolution); | 728 cls.ensureResolved(compiler.resolution); |
766 return cls.thisType; | 729 return cls.thisType; |
767 } | 730 } |
768 | 731 |
769 NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; | 732 NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; |
770 var creates = _collect(element, compiler, enqueuer.annotationCreatesClass, | 733 var creates = |
771 lookup); | 734 _collect(element, compiler, enqueuer.annotationCreatesClass, lookup); |
772 var returns = _collect(element, compiler, enqueuer.annotationReturnsClass, | 735 var returns = |
773 lookup); | 736 _collect(element, compiler, enqueuer.annotationReturnsClass, lookup); |
774 | 737 |
775 if (creates != null) { | 738 if (creates != null) { |
776 typesInstantiated..clear()..addAll(creates); | 739 typesInstantiated |
| 740 ..clear() |
| 741 ..addAll(creates); |
777 } | 742 } |
778 if (returns != null) { | 743 if (returns != null) { |
779 typesReturned..clear()..addAll(returns); | 744 typesReturned |
| 745 ..clear() |
| 746 ..addAll(returns); |
780 } | 747 } |
781 } | 748 } |
782 | 749 |
783 /** | 750 /** |
784 * Returns a list of type constraints from the annotations of | 751 * Returns a list of type constraints from the annotations of |
785 * [annotationClass]. | 752 * [annotationClass]. |
786 * Returns `null` if no constraints. | 753 * Returns `null` if no constraints. |
787 */ | 754 */ |
788 static _collect(Element element, Compiler compiler, Element annotationClass, | 755 static _collect(Element element, Compiler compiler, Element annotationClass, |
789 lookup(str)) { | 756 lookup(str)) { |
790 DiagnosticReporter reporter = compiler.reporter; | 757 DiagnosticReporter reporter = compiler.reporter; |
791 var types = null; | 758 var types = null; |
792 for (MetadataAnnotation annotation in element.implementation.metadata) { | 759 for (MetadataAnnotation annotation in element.implementation.metadata) { |
793 annotation.ensureResolved(compiler.resolution); | 760 annotation.ensureResolved(compiler.resolution); |
794 ConstantValue value = | 761 ConstantValue value = |
795 compiler.constants.getConstantValue(annotation.constant); | 762 compiler.constants.getConstantValue(annotation.constant); |
796 if (!value.isConstructedObject) continue; | 763 if (!value.isConstructedObject) continue; |
797 ConstructedConstantValue constructedObject = value; | 764 ConstructedConstantValue constructedObject = value; |
798 if (constructedObject.type.element != annotationClass) continue; | 765 if (constructedObject.type.element != annotationClass) continue; |
799 | 766 |
800 Iterable<ConstantValue> fields = constructedObject.fields.values; | 767 Iterable<ConstantValue> fields = constructedObject.fields.values; |
801 // TODO(sra): Better validation of the constant. | 768 // TODO(sra): Better validation of the constant. |
802 if (fields.length != 1 || !fields.single.isString) { | 769 if (fields.length != 1 || !fields.single.isString) { |
803 reporter.internalError(annotation, | 770 reporter.internalError( |
804 'Annotations needs one string: ${annotation.node}'); | 771 annotation, 'Annotations needs one string: ${annotation.node}'); |
805 } | 772 } |
806 StringConstantValue specStringConstant = fields.single; | 773 StringConstantValue specStringConstant = fields.single; |
807 String specString = specStringConstant.toDartString().slowToString(); | 774 String specString = specStringConstant.toDartString().slowToString(); |
808 for (final typeString in specString.split('|')) { | 775 for (final typeString in specString.split('|')) { |
809 var type = _parseType(typeString, compiler.parsing, lookup, annotation); | 776 var type = _parseType(typeString, compiler.parsing, lookup, annotation); |
810 if (types == null) types = []; | 777 if (types == null) types = []; |
811 types.add(type); | 778 types.add(type); |
812 } | 779 } |
813 } | 780 } |
814 return types; | 781 return types; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
853 if (!isInterop) { | 820 if (!isInterop) { |
854 typesInstantiated.add(type); | 821 typesInstantiated.add(type); |
855 } else { | 822 } else { |
856 if (type.element != null && backend.isNative(type.element)) { | 823 if (type.element != null && backend.isNative(type.element)) { |
857 // Any declared native or interop type (isNative implies isJsInterop) | 824 // Any declared native or interop type (isNative implies isJsInterop) |
858 // is assumed to be allocated. | 825 // is assumed to be allocated. |
859 typesInstantiated.add(type); | 826 typesInstantiated.add(type); |
860 } | 827 } |
861 | 828 |
862 if (!compiler.options.trustJSInteropTypeAnnotations || | 829 if (!compiler.options.trustJSInteropTypeAnnotations || |
863 type.isDynamic || type.isObject) { | 830 type.isDynamic || |
| 831 type.isObject) { |
864 // By saying that only JS-interop types can be created, we prevent | 832 // By saying that only JS-interop types can be created, we prevent |
865 // pulling in every other native type (e.g. all of dart:html) when a | 833 // pulling in every other native type (e.g. all of dart:html) when a |
866 // JS interop API returns dynamic or when we don't trust the type | 834 // JS interop API returns dynamic or when we don't trust the type |
867 // annotations. This means that to some degree we still use the return | 835 // annotations. This means that to some degree we still use the return |
868 // type to decide whether to include native types, even if we don't | 836 // type to decide whether to include native types, even if we don't |
869 // trust the type annotation. | 837 // trust the type annotation. |
870 ClassElement cls = backend.helpers.jsJavaScriptObjectClass; | 838 ClassElement cls = backend.helpers.jsJavaScriptObjectClass; |
871 cls.ensureResolved(resolution); | 839 cls.ensureResolved(resolution); |
872 typesInstantiated.add(cls.thisType); | 840 typesInstantiated.add(cls.thisType); |
873 } else { | 841 } else { |
874 // Otherwise, when the declared type is a Dart type, we do not | 842 // Otherwise, when the declared type is a Dart type, we do not |
875 // register an allocation because we assume it cannot be instantiated | 843 // register an allocation because we assume it cannot be instantiated |
876 // from within the JS-interop code. It must have escaped from another | 844 // from within the JS-interop code. It must have escaped from another |
877 // API. | 845 // API. |
878 } | 846 } |
879 } | 847 } |
880 } | 848 } |
881 } | 849 } |
882 | 850 |
883 static dynamic _parseType( | 851 static dynamic _parseType( |
884 String typeString, | 852 String typeString, Parsing parsing, lookup(name), locationNodeOrElement) { |
885 Parsing parsing, | |
886 lookup(name), | |
887 locationNodeOrElement) { | |
888 DiagnosticReporter reporter = parsing.reporter; | 853 DiagnosticReporter reporter = parsing.reporter; |
889 if (typeString == '=Object') return SpecialType.JsObject; | 854 if (typeString == '=Object') return SpecialType.JsObject; |
890 if (typeString == 'dynamic') { | 855 if (typeString == 'dynamic') { |
891 return const DynamicType(); | 856 return const DynamicType(); |
892 } | 857 } |
893 var type = lookup(typeString); | 858 var type = lookup(typeString); |
894 if (type != null) return type; | 859 if (type != null) return type; |
895 | 860 |
896 int index = typeString.indexOf('<'); | 861 int index = typeString.indexOf('<'); |
897 if (index < 1) { | 862 if (index < 1) { |
898 reporter.reportErrorMessage( | 863 reporter.reportErrorMessage(_errorNode(locationNodeOrElement, parsing), |
899 _errorNode(locationNodeOrElement, parsing), | 864 MessageKind.GENERIC, {'text': "Type '$typeString' not found."}); |
900 MessageKind.GENERIC, | |
901 {'text': "Type '$typeString' not found."}); | |
902 return const DynamicType(); | 865 return const DynamicType(); |
903 } | 866 } |
904 type = lookup(typeString.substring(0, index)); | 867 type = lookup(typeString.substring(0, index)); |
905 if (type != null) { | 868 if (type != null) { |
906 // TODO(sra): Parse type parameters. | 869 // TODO(sra): Parse type parameters. |
907 return type; | 870 return type; |
908 } | 871 } |
909 reporter.reportErrorMessage( | 872 reporter.reportErrorMessage(_errorNode(locationNodeOrElement, parsing), |
910 _errorNode(locationNodeOrElement, parsing), | 873 MessageKind.GENERIC, {'text': "Type '$typeString' not found."}); |
911 MessageKind.GENERIC, | |
912 {'text': "Type '$typeString' not found."}); | |
913 return const DynamicType(); | 874 return const DynamicType(); |
914 } | 875 } |
915 | 876 |
916 static _errorNode(locationNodeOrElement, Parsing parsing) { | 877 static _errorNode(locationNodeOrElement, Parsing parsing) { |
917 if (locationNodeOrElement is Node) return locationNodeOrElement; | 878 if (locationNodeOrElement is Node) return locationNodeOrElement; |
918 return locationNodeOrElement.parseNode(parsing); | 879 return locationNodeOrElement.parseNode(parsing); |
919 } | 880 } |
920 } | 881 } |
OLD | NEW |