| 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 |