Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 6 | 6 |
| 7 import '../constants/expressions.dart'; | |
| 7 import '../common.dart'; | 8 import '../common.dart'; |
| 8 import '../common/names.dart'; | 9 import '../common/names.dart'; |
| 9 import '../compiler.dart'; | 10 import '../compiler.dart'; |
| 10 import '../constants/values.dart'; | 11 import '../constants/values.dart'; |
| 11 import '../dart_types.dart'; | 12 import '../dart_types.dart'; |
| 12 import '../elements/elements.dart'; | 13 import '../elements/elements.dart'; |
| 13 import '../js_backend/backend_helpers.dart'; | 14 import '../js_backend/backend_helpers.dart'; |
| 14 import '../js_backend/js_backend.dart'; | 15 import '../js_backend/js_backend.dart'; |
| 15 import '../kernel/kernel.dart'; | 16 import '../kernel/kernel.dart'; |
| 16 import '../kernel/kernel_debug.dart'; | 17 import '../kernel/kernel_debug.dart'; |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 .inferredReturnTypeForElement(_backend.helpers.assertThrow, _compiler); | 279 .inferredReturnTypeForElement(_backend.helpers.assertThrow, _compiler); |
| 279 | 280 |
| 280 DartType getDartType(ir.DartType type) { | 281 DartType getDartType(ir.DartType type) { |
| 281 return type.accept(_typeConverter); | 282 return type.accept(_typeConverter); |
| 282 } | 283 } |
| 283 | 284 |
| 284 List<DartType> getDartTypes(List<ir.DartType> types) { | 285 List<DartType> getDartTypes(List<ir.DartType> types) { |
| 285 return types.map(getDartType).toList(); | 286 return types.map(getDartType).toList(); |
| 286 } | 287 } |
| 287 | 288 |
| 289 /// Computes the function type corresponding the signature of [node]. | |
| 290 FunctionType getFunctionType(ir.FunctionNode node) { | |
| 291 DartType returnType = getDartType(node.returnType); | |
| 292 List<DartType> parameterTypes = <DartType>[]; | |
| 293 List<DartType> optionalParameterTypes = <DartType>[]; | |
| 294 for (ir.VariableDeclaration variable in node.positionalParameters) { | |
| 295 if (parameterTypes.length == node.requiredParameterCount) { | |
| 296 optionalParameterTypes.add(getDartType(variable.type)); | |
| 297 } else { | |
| 298 parameterTypes.add(getDartType(variable.type)); | |
| 299 } | |
| 300 } | |
| 301 List<String> namedParameters = <String>[]; | |
| 302 List<DartType> namedParameterTypes = <DartType>[]; | |
| 303 List<ir.VariableDeclaration> sortedNamedParameters = | |
| 304 node.namedParameters.toList()..sort((a, b) => a.name.compareTo(b.name)); | |
| 305 for (ir.VariableDeclaration variable in sortedNamedParameters) { | |
| 306 namedParameters.add(variable.name); | |
| 307 namedParameterTypes.add(getDartType(variable.type)); | |
| 308 } | |
| 309 return new FunctionType.synthesized(returnType, parameterTypes, | |
| 310 optionalParameterTypes, namedParameters, namedParameterTypes); | |
| 311 } | |
| 312 | |
| 313 /// Converts [annotations] into a list of [ConstantExpression]s. | |
| 314 List<ConstantExpression> getMetadata(List<ir.Expression> annotations) { | |
| 315 List<ConstantExpression> metadata = <ConstantExpression>[]; | |
| 316 annotations.forEach((ir.Expression node) { | |
| 317 ConstantExpression constant = node.accept(new Constantifier(this)); | |
| 318 if (constant == null) { | |
| 319 throw new UnsupportedError( | |
| 320 'No constant for ${DebugPrinter.prettyPrint(node)}'); | |
| 321 } | |
| 322 metadata.add(constant); | |
| 323 }); | |
| 324 return metadata; | |
| 325 } | |
| 326 | |
| 327 /// Compute the kind of foreign helper function called by [node], if any. | |
| 288 @override | 328 @override |
| 289 ForeignKind getForeignKind(ir.StaticInvocation node) { | 329 ForeignKind getForeignKind(ir.StaticInvocation node) { |
| 290 if (isForeignLibrary(node.target.enclosingLibrary)) { | 330 if (isForeignLibrary(node.target.enclosingLibrary)) { |
| 291 switch (node.target.name.name) { | 331 switch (node.target.name.name) { |
| 292 case BackendHelpers.JS: | 332 case BackendHelpers.JS: |
| 293 return ForeignKind.JS; | 333 return ForeignKind.JS; |
| 294 case BackendHelpers.JS_BUILTIN: | 334 case BackendHelpers.JS_BUILTIN: |
| 295 return ForeignKind.JS_BUILTIN; | 335 return ForeignKind.JS_BUILTIN; |
| 296 case BackendHelpers.JS_EMBEDDED_GLOBAL: | 336 case BackendHelpers.JS_EMBEDDED_GLOBAL: |
| 297 return ForeignKind.JS_EMBEDDED_GLOBAL; | 337 return ForeignKind.JS_EMBEDDED_GLOBAL; |
| 298 case BackendHelpers.JS_INTERCEPTOR_CONSTANT: | 338 case BackendHelpers.JS_INTERCEPTOR_CONSTANT: |
| 299 return ForeignKind.JS_INTERCEPTOR_CONSTANT; | 339 return ForeignKind.JS_INTERCEPTOR_CONSTANT; |
| 300 } | 340 } |
| 301 } | 341 } |
| 302 return ForeignKind.NONE; | 342 return ForeignKind.NONE; |
| 303 } | 343 } |
| 304 | 344 |
| 345 /// Return `true` if [node] is the `dart:_foregin_helper` library. | |
|
Harry Terkelsen
2016/11/01 17:26:27
foreign_helper
Johnni Winther
2016/11/02 15:16:27
Done.
| |
| 305 bool isForeignLibrary(ir.Library node) { | 346 bool isForeignLibrary(ir.Library node) { |
| 306 return node.importUri == BackendHelpers.DART_FOREIGN_HELPER; | 347 return node.importUri == BackendHelpers.DART_FOREIGN_HELPER; |
| 307 } | 348 } |
| 308 | 349 |
| 350 /// Looks up [typeName] for use in the spec-string of a `JS` called. | |
| 351 // TODO(johnniwinther): Use this in [NativeBehavior] instead of calling the | |
| 352 // `ForeignResolver`. | |
| 353 // TODO(johnniwinther): Cache the result to avoid redundany lookups? | |
|
Harry Terkelsen
2016/11/01 17:26:27
redundant
Johnni Winther
2016/11/02 15:16:27
Done.
| |
| 309 DartType _typeLookup(String typeName) { | 354 DartType _typeLookup(String typeName) { |
| 310 DartType findIn(Uri uri) { | 355 DartType findIn(Uri uri) { |
| 311 LibraryElement library = _compiler.libraryLoader.lookupLibrary(uri); | 356 LibraryElement library = _compiler.libraryLoader.lookupLibrary(uri); |
| 312 if (library != null) { | 357 if (library != null) { |
| 313 Element element = library.find(typeName); | 358 Element element = library.find(typeName); |
| 314 if (element != null && element.isClass) { | 359 if (element != null && element.isClass) { |
| 315 ClassElement cls = element; | 360 ClassElement cls = element; |
| 316 return cls.rawType; | 361 return cls.rawType; |
| 317 } | 362 } |
| 318 } | 363 } |
| 319 return null; | 364 return null; |
| 320 } | 365 } |
| 321 | 366 |
| 322 DartType type = findIn(Uris.dart_core); | 367 DartType type = findIn(Uris.dart_core); |
| 323 type ??= findIn(BackendHelpers.DART_JS_HELPER); | 368 type ??= findIn(BackendHelpers.DART_JS_HELPER); |
| 324 type ??= findIn(BackendHelpers.DART_INTERCEPTORS); | 369 type ??= findIn(BackendHelpers.DART_INTERCEPTORS); |
| 325 type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER); | 370 type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER); |
| 326 type ??= findIn(Uris.dart_collection); | 371 type ??= findIn(Uris.dart_collection); |
| 327 type ??= findIn(Uris.dart_html); | 372 type ??= findIn(Uris.dart_html); |
| 328 return type; | 373 return type; |
| 329 } | 374 } |
| 330 | 375 |
| 376 /// Computes the [NativeBehavior] for a call to the [JS] function. | |
| 377 // TODO(johnniwinther): Cache this for later use. | |
| 331 NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) { | 378 NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) { |
| 332 if (node.arguments.positional.length < 2 || | 379 if (node.arguments.positional.length < 2 || |
| 333 node.arguments.named.isNotEmpty) { | 380 node.arguments.named.isNotEmpty) { |
| 334 reporter.reportErrorMessage( | 381 reporter.reportErrorMessage( |
| 335 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS); | 382 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS); |
| 336 return new NativeBehavior(); | 383 return new NativeBehavior(); |
| 337 } | 384 } |
| 338 String specString = node.arguments.positional[0].accept(new Stringifier()); | 385 String specString = node.arguments.positional[0].accept(new Stringifier()); |
| 339 if (specString == null) { | 386 if (specString == null) { |
| 340 reporter.reportErrorMessage( | 387 reporter.reportErrorMessage( |
| 341 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST); | 388 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST); |
| 342 return new NativeBehavior(); | 389 return new NativeBehavior(); |
| 343 } | 390 } |
| 344 | 391 |
| 345 String codeString = node.arguments.positional[1].accept(new Stringifier()); | 392 String codeString = node.arguments.positional[1].accept(new Stringifier()); |
| 346 if (codeString == null) { | 393 if (codeString == null) { |
| 347 reporter.reportErrorMessage( | 394 reporter.reportErrorMessage( |
| 348 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND); | 395 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND); |
| 349 return new NativeBehavior(); | 396 return new NativeBehavior(); |
| 350 } | 397 } |
| 351 | 398 |
| 352 return NativeBehavior.ofJsCall(specString, codeString, _typeLookup, | 399 return NativeBehavior.ofJsCall(specString, codeString, _typeLookup, |
| 353 CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes); | 400 CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes); |
| 354 } | 401 } |
| 355 | 402 |
| 403 /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN] function. | |
| 404 // TODO(johnniwinther): Cache this for later use. | |
| 356 NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) { | 405 NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) { |
| 357 if (node.arguments.positional.length < 1) { | 406 if (node.arguments.positional.length < 1) { |
| 358 reporter.internalError( | 407 reporter.internalError( |
| 359 CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type."); | 408 CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type."); |
| 360 return new NativeBehavior(); | 409 return new NativeBehavior(); |
| 361 } | 410 } |
| 362 if (node.arguments.positional.length < 2) { | 411 if (node.arguments.positional.length < 2) { |
| 363 reporter.internalError( | 412 reporter.internalError( |
| 364 CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name."); | 413 CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name."); |
| 365 return new NativeBehavior(); | 414 return new NativeBehavior(); |
| 366 } | 415 } |
| 367 String specString = node.arguments.positional[0].accept(new Stringifier()); | 416 String specString = node.arguments.positional[0].accept(new Stringifier()); |
| 368 if (specString == null) { | 417 if (specString == null) { |
| 369 reporter.internalError( | 418 reporter.internalError( |
| 370 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); | 419 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); |
| 371 return new NativeBehavior(); | 420 return new NativeBehavior(); |
| 372 } | 421 } |
| 373 return NativeBehavior.ofJsBuiltinCall(specString, _typeLookup, | 422 return NativeBehavior.ofJsBuiltinCall(specString, _typeLookup, |
| 374 CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes); | 423 CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes); |
| 375 } | 424 } |
| 376 | 425 |
| 426 /// Computes the [NativeBehavior] for a call to the [JS_EMBEDDED_GLOBAL] | |
| 427 /// function. | |
| 428 // TODO(johnniwinther): Cache this for later use. | |
| 377 NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall( | 429 NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall( |
| 378 ir.StaticInvocation node) { | 430 ir.StaticInvocation node) { |
| 379 if (node.arguments.positional.length < 1) { | 431 if (node.arguments.positional.length < 1) { |
| 380 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | 432 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
| 381 "JS embedded global expression has no type."); | 433 "JS embedded global expression has no type."); |
| 382 return new NativeBehavior(); | 434 return new NativeBehavior(); |
| 383 } | 435 } |
| 384 if (node.arguments.positional.length < 2) { | 436 if (node.arguments.positional.length < 2) { |
| 385 reporter.internalError( | 437 reporter.internalError( |
| 386 CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name."); | 438 CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name."); |
| 387 return new NativeBehavior(); | 439 return new NativeBehavior(); |
| 388 } | 440 } |
| 389 if (node.arguments.positional.length > 2 || | 441 if (node.arguments.positional.length > 2 || |
| 390 node.arguments.named.isNotEmpty) { | 442 node.arguments.named.isNotEmpty) { |
| 391 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | 443 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
| 392 "JS embedded global has more than 2 arguments."); | 444 "JS embedded global has more than 2 arguments."); |
| 393 return new NativeBehavior(); | 445 return new NativeBehavior(); |
| 394 } | 446 } |
| 395 String specString = node.arguments.positional[0].accept(new Stringifier()); | 447 String specString = node.arguments.positional[0].accept(new Stringifier()); |
| 396 if (specString == null) { | 448 if (specString == null) { |
| 397 reporter.internalError( | 449 reporter.internalError( |
| 398 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); | 450 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); |
| 399 return new NativeBehavior(); | 451 return new NativeBehavior(); |
| 400 } | 452 } |
| 401 return NativeBehavior.ofJsEmbeddedGlobalCall(specString, _typeLookup, | 453 return NativeBehavior.ofJsEmbeddedGlobalCall(specString, _typeLookup, |
| 402 CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes); | 454 CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes); |
| 403 } | 455 } |
| 456 | |
| 457 /// Returns `true` is [node] has a `@Native(...)` annotation. | |
| 458 // TODO(johnniwinther): Cache this for later use. | |
| 459 bool isNative(ir.Class node) { | |
| 460 for (ir.Expression annotation in node.annotations) { | |
| 461 if (annotation is ir.ConstructorInvocation) { | |
| 462 ConstructorElement target = getElement(annotation.target).declaration; | |
| 463 if (target.enclosingClass == | |
| 464 _compiler.commonElements.nativeAnnotationClass) { | |
| 465 return true; | |
| 466 } | |
| 467 } | |
| 468 } | |
| 469 return false; | |
| 470 } | |
| 471 | |
| 472 /// Computes the native behavior for reading the native [field]. | |
| 473 // TODO(johnniwinther): Cache this for later use. | |
| 474 NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) { | |
| 475 DartType type = getDartType(field.type); | |
| 476 List<ConstantExpression> metadata = getMetadata(field.annotations); | |
| 477 return NativeBehavior.ofFieldLoad( | |
| 478 CURRENT_ELEMENT_SPANNABLE, type, metadata, _typeLookup, _compiler, | |
| 479 isJsInterop: false); | |
| 480 } | |
| 481 | |
| 482 /// Computes the native behavior for writing to the native [field]. | |
| 483 // TODO(johnniwinther): Cache this for later use. | |
| 484 NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) { | |
| 485 DartType type = getDartType(field.type); | |
| 486 return NativeBehavior.ofFieldStore(type, _compiler.resolution); | |
| 487 } | |
| 488 | |
| 489 /// Computes the native behavior for calling [procedure]. | |
| 490 // TODO(johnniwinther): Cache this for later use. | |
| 491 NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) { | |
| 492 DartType type = getFunctionType(procedure.function); | |
| 493 List<ConstantExpression> metadata = getMetadata(procedure.annotations); | |
| 494 return NativeBehavior.ofMethod( | |
| 495 CURRENT_ELEMENT_SPANNABLE, type, metadata, _typeLookup, _compiler, | |
| 496 isJsInterop: false); | |
| 497 } | |
| 404 } | 498 } |
| 405 | 499 |
| 500 /// Kinds of foreign functions. | |
| 406 enum ForeignKind { | 501 enum ForeignKind { |
| 407 JS, | 502 JS, |
| 408 JS_BUILTIN, | 503 JS_BUILTIN, |
| 409 JS_EMBEDDED_GLOBAL, | 504 JS_EMBEDDED_GLOBAL, |
| 410 JS_INTERCEPTOR_CONSTANT, | 505 JS_INTERCEPTOR_CONSTANT, |
| 411 NONE, | 506 NONE, |
| 412 } | 507 } |
| 413 | 508 |
| 509 /// Visitor that converts kernel dart types into [DartType]. | |
| 414 class DartTypeConverter extends ir.DartTypeVisitor<DartType> { | 510 class DartTypeConverter extends ir.DartTypeVisitor<DartType> { |
| 415 final KernelAstAdapter astAdapter; | 511 final KernelAstAdapter astAdapter; |
| 416 | 512 |
| 417 DartTypeConverter(this.astAdapter); | 513 DartTypeConverter(this.astAdapter); |
| 418 | 514 |
| 419 DartType visitType(ir.DartType type) => type.accept(this); | 515 DartType visitType(ir.DartType type) => type.accept(this); |
| 420 | 516 |
| 421 List<DartType> visitTypes(List<ir.DartType> types) { | 517 List<DartType> visitTypes(List<ir.DartType> types) { |
| 422 return new List.generate( | 518 return new List.generate( |
| 423 types.length, (int index) => types[index].accept(this)); | 519 types.length, (int index) => types[index].accept(this)); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 486 String visitStringConcatenation(ir.StringConcatenation node) { | 582 String visitStringConcatenation(ir.StringConcatenation node) { |
| 487 StringBuffer sb = new StringBuffer(); | 583 StringBuffer sb = new StringBuffer(); |
| 488 for (ir.Expression expression in node.expressions) { | 584 for (ir.Expression expression in node.expressions) { |
| 489 String value = expression.accept(this); | 585 String value = expression.accept(this); |
| 490 if (value == null) return null; | 586 if (value == null) return null; |
| 491 sb.write(value); | 587 sb.write(value); |
| 492 } | 588 } |
| 493 return sb.toString(); | 589 return sb.toString(); |
| 494 } | 590 } |
| 495 } | 591 } |
| 592 | |
| 593 /// Visitor that converts a kernel constant expression into a | |
| 594 /// [ConstantExpression]. | |
| 595 class Constantifier extends ir.ExpressionVisitor<ConstantExpression> { | |
| 596 final KernelAstAdapter astAdapter; | |
| 597 | |
| 598 Constantifier(this.astAdapter); | |
| 599 | |
| 600 @override | |
| 601 ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) { | |
| 602 ConstructorElement constructor = | |
| 603 astAdapter.getElement(node.target).declaration; | |
|
Harry Terkelsen
2016/11/01 17:26:27
it seems like 'getElement(...).declaration' is com
Johnni Winther
2016/11/02 15:16:27
Agree. In progress in https://codereview.chromium.
| |
| 604 List<DartType> typeArguments = <DartType>[]; | |
| 605 for (ir.DartType type in node.arguments.types) { | |
| 606 typeArguments.add(astAdapter.getDartType(type)); | |
| 607 } | |
| 608 List<ConstantExpression> arguments = <ConstantExpression>[]; | |
| 609 List<String> argumentNames = <String>[]; | |
| 610 for (ir.Expression argument in node.arguments.positional) { | |
| 611 ConstantExpression constant = argument.accept(this); | |
| 612 if (constant == null) return null; | |
| 613 arguments.add(constant); | |
| 614 } | |
| 615 for (ir.NamedExpression argument in node.arguments.named) { | |
| 616 argumentNames.add(argument.name); | |
| 617 ConstantExpression constant = argument.value.accept(this); | |
| 618 if (constant == null) return null; | |
| 619 arguments.add(constant); | |
| 620 } | |
| 621 return new ConstructedConstantExpression( | |
| 622 constructor.enclosingClass.thisType.createInstantiation(typeArguments), | |
| 623 constructor, | |
| 624 new CallStructure( | |
| 625 node.arguments.positional.length + argumentNames.length, | |
| 626 argumentNames), | |
| 627 arguments); | |
| 628 } | |
| 629 | |
| 630 @override | |
| 631 ConstantExpression visitStringLiteral(ir.StringLiteral node) { | |
| 632 return new StringConstantExpression(node.value); | |
| 633 } | |
| 634 } | |
| OLD | NEW |