| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../common/names.dart'; | 8 import '../common/names.dart'; |
| 9 import '../constants/constructors.dart'; |
| 9 import '../constants/expressions.dart'; | 10 import '../constants/expressions.dart'; |
| 10 import '../core_types.dart'; | 11 import '../core_types.dart'; |
| 11 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
| 12 import '../elements/entities.dart'; | 13 import '../elements/entities.dart'; |
| 13 import '../elements/types.dart'; | 14 import '../elements/types.dart'; |
| 14 import '../js_backend/backend_helpers.dart'; | 15 import '../js_backend/backend_helpers.dart'; |
| 15 import '../native/native.dart' as native; | 16 import '../native/native.dart' as native; |
| 16 import '../universe/call_structure.dart'; | 17 import '../universe/call_structure.dart'; |
| 17 import '../universe/selector.dart'; | 18 import '../universe/selector.dart'; |
| 18 import 'kernel_debug.dart'; | 19 import 'kernel_debug.dart'; |
| 19 | 20 |
| 20 /// Interface that translates between Kernel IR nodes and entities. | 21 /// Interface that translates between Kernel IR nodes and entities. |
| 21 abstract class KernelElementAdapter { | 22 abstract class KernelElementAdapter { |
| 22 /// Access to the commonly used elements and types. | 23 /// Access to the commonly used elements and types. |
| 23 CommonElements get commonElements; | 24 CommonElements get commonElements; |
| 24 | 25 |
| 26 /// [ElementEnvironment] for library, class and member lookup. |
| 27 ElementEnvironment get elementEnvironment; |
| 28 |
| 25 /// Returns the [DartType] corresponding to [type]. | 29 /// Returns the [DartType] corresponding to [type]. |
| 26 DartType getDartType(ir.DartType type); | 30 DartType getDartType(ir.DartType type); |
| 27 | 31 |
| 28 /// Returns the list of [DartType]s corresponding to [types]. | 32 /// Returns the list of [DartType]s corresponding to [types]. |
| 29 List<DartType> getDartTypes(List<ir.DartType> types); | 33 List<DartType> getDartTypes(List<ir.DartType> types); |
| 30 | 34 |
| 31 /// Returns the [InterfaceType] corresponding to [type]. | 35 /// Returns the [InterfaceType] corresponding to [type]. |
| 32 InterfaceType getInterfaceType(ir.InterfaceType type); | 36 InterfaceType getInterfaceType(ir.InterfaceType type); |
| 33 | 37 |
| 34 /// Return the [InterfaceType] corresponding to the [cls] with the given | 38 /// Return the [InterfaceType] corresponding to the [cls] with the given |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 enum ForeignKind { | 113 enum ForeignKind { |
| 110 JS, | 114 JS, |
| 111 JS_BUILTIN, | 115 JS_BUILTIN, |
| 112 JS_EMBEDDED_GLOBAL, | 116 JS_EMBEDDED_GLOBAL, |
| 113 JS_INTERCEPTOR_CONSTANT, | 117 JS_INTERCEPTOR_CONSTANT, |
| 114 NONE, | 118 NONE, |
| 115 } | 119 } |
| 116 | 120 |
| 117 abstract class KernelElementAdapterMixin implements KernelElementAdapter { | 121 abstract class KernelElementAdapterMixin implements KernelElementAdapter { |
| 118 DiagnosticReporter get reporter; | 122 DiagnosticReporter get reporter; |
| 119 CommonElements get commonElements; | 123 FunctionType getFunctionType(ir.FunctionNode node); |
| 120 | 124 native.BehaviorBuilder get nativeBehaviorBuilder; |
| 121 LibraryEntity lookupLibrary(Uri uri); | |
| 122 ClassEntity lookupClass(LibraryEntity library, String name); | |
| 123 InterfaceType getRawType(ClassEntity cls); | |
| 124 InterfaceType getThisType(ClassEntity cls); | |
| 125 | 125 |
| 126 @override | 126 @override |
| 127 Name getName(ir.Name name) { | 127 Name getName(ir.Name name) { |
| 128 return new Name( | 128 return new Name( |
| 129 name.name, name.isPrivate ? getLibrary(name.library) : null); | 129 name.name, name.isPrivate ? getLibrary(name.library) : null); |
| 130 } | 130 } |
| 131 | 131 |
| 132 @override | 132 @override |
| 133 CallStructure getCallStructure(ir.Arguments arguments) { | 133 CallStructure getCallStructure(ir.Arguments arguments) { |
| 134 int argumentCount = arguments.positional.length + arguments.named.length; | 134 int argumentCount = arguments.positional.length + arguments.named.length; |
| 135 List<String> namedArguments = arguments.named.map((e) => e.name).toList(); | 135 List<String> namedArguments = arguments.named.map((e) => e.name).toList(); |
| 136 return new CallStructure(argumentCount, namedArguments); | 136 return new CallStructure(argumentCount, namedArguments); |
| 137 } | 137 } |
| 138 | 138 |
| 139 @override | 139 @override |
| 140 Selector getSelector(ir.Expression node) { | 140 Selector getSelector(ir.Expression node) { |
| 141 // TODO(efortuna): This is screaming for a common interface between | 141 // TODO(efortuna): This is screaming for a common interface between |
| 142 // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel | 142 // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel |
| 143 // folks. | 143 // folks. |
| 144 if (node is ir.PropertyGet) { | 144 if (node is ir.PropertyGet) { |
| 145 return getGetterSelector((node as ir.PropertyGet).name); | 145 return getGetterSelector(node.name); |
| 146 } | 146 } |
| 147 if (node is ir.SuperPropertyGet) { | 147 if (node is ir.SuperPropertyGet) { |
| 148 return getGetterSelector((node as ir.SuperPropertyGet).name); | 148 return getGetterSelector(node.name); |
| 149 } | 149 } |
| 150 if (node is ir.PropertySet) { | 150 if (node is ir.PropertySet) { |
| 151 return getSetterSelector((node as ir.PropertySet).name); | 151 return getSetterSelector(node.name); |
| 152 } | 152 } |
| 153 if (node is ir.SuperPropertySet) { | 153 if (node is ir.SuperPropertySet) { |
| 154 return getSetterSelector((node as ir.SuperPropertySet).name); | 154 return getSetterSelector(node.name); |
| 155 } | 155 } |
| 156 if (node is ir.InvocationExpression) return getInvocationSelector(node); | 156 if (node is ir.InvocationExpression) { |
| 157 return getInvocationSelector(node); |
| 158 } |
| 157 throw new SpannableAssertionFailure( | 159 throw new SpannableAssertionFailure( |
| 158 CURRENT_ELEMENT_SPANNABLE, | 160 CURRENT_ELEMENT_SPANNABLE, |
| 159 "Can only get the selector for a property get or an invocation: " | 161 "Can only get the selector for a property get or an invocation: " |
| 160 "${node}"); | 162 "${node}"); |
| 161 } | 163 } |
| 162 | 164 |
| 163 Selector getInvocationSelector(ir.InvocationExpression invocation) { | 165 Selector getInvocationSelector(ir.InvocationExpression invocation) { |
| 164 Name name = getName(invocation.name); | 166 Name name = getName(invocation.name); |
| 165 SelectorKind kind; | 167 SelectorKind kind; |
| 166 if (Elements.isOperatorName(invocation.name.name)) { | 168 if (Elements.isOperatorName(invocation.name.name)) { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 return node.importUri == BackendHelpers.DART_FOREIGN_HELPER; | 241 return node.importUri == BackendHelpers.DART_FOREIGN_HELPER; |
| 240 } | 242 } |
| 241 | 243 |
| 242 /// Looks up [typeName] for use in the spec-string of a `JS` called. | 244 /// Looks up [typeName] for use in the spec-string of a `JS` called. |
| 243 // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling | 245 // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling |
| 244 // the `ForeignResolver`. | 246 // the `ForeignResolver`. |
| 245 // TODO(johnniwinther): Cache the result to avoid redundant lookups? | 247 // TODO(johnniwinther): Cache the result to avoid redundant lookups? |
| 246 native.TypeLookup typeLookup({bool resolveAsRaw: true}) { | 248 native.TypeLookup typeLookup({bool resolveAsRaw: true}) { |
| 247 return (String typeName) { | 249 return (String typeName) { |
| 248 DartType findIn(Uri uri) { | 250 DartType findIn(Uri uri) { |
| 249 LibraryEntity library = lookupLibrary(uri); | 251 LibraryEntity library = elementEnvironment.lookupLibrary(uri); |
| 250 if (library != null) { | 252 if (library != null) { |
| 251 ClassEntity cls = lookupClass(library, typeName); | 253 ClassEntity cls = elementEnvironment.lookupClass(library, typeName); |
| 252 if (cls != null) { | 254 if (cls != null) { |
| 253 // TODO(johnniwinther): Align semantics. | 255 // TODO(johnniwinther): Align semantics. |
| 254 return resolveAsRaw ? getRawType(cls) : getThisType(cls); | 256 return resolveAsRaw |
| 257 ? elementEnvironment.getRawType(cls) |
| 258 : elementEnvironment.getThisType(cls); |
| 255 } | 259 } |
| 256 } | 260 } |
| 257 return null; | 261 return null; |
| 258 } | 262 } |
| 259 | 263 |
| 260 DartType type = findIn(Uris.dart_core); | 264 DartType type = findIn(Uris.dart_core); |
| 261 type ??= findIn(BackendHelpers.DART_JS_HELPER); | 265 type ??= findIn(BackendHelpers.DART_JS_HELPER); |
| 262 type ??= findIn(BackendHelpers.DART_INTERCEPTORS); | 266 type ??= findIn(BackendHelpers.DART_INTERCEPTORS); |
| 263 type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER); | 267 type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER); |
| 264 type ??= findIn(Uris.dart_collection); | 268 type ??= findIn(Uris.dart_collection); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 node.arguments.named.isNotEmpty) { | 381 node.arguments.named.isNotEmpty) { |
| 378 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE, | 382 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE, |
| 379 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | 383 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |
| 380 } | 384 } |
| 381 ir.Node argument = node.arguments.positional.first; | 385 ir.Node argument = node.arguments.positional.first; |
| 382 if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) { | 386 if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) { |
| 383 return getInterfaceType(argument.type); | 387 return getInterfaceType(argument.type); |
| 384 } | 388 } |
| 385 return null; | 389 return null; |
| 386 } | 390 } |
| 391 |
| 392 /// Computes the native behavior for reading the native [field]. |
| 393 // TODO(johnniwinther): Cache this for later use. |
| 394 native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) { |
| 395 DartType type = getDartType(field.type); |
| 396 List<ConstantExpression> metadata = getMetadata(field.annotations); |
| 397 // TODO(johnniwinther): Provide the correct value for [isJsInterop]. |
| 398 return nativeBehaviorBuilder.buildFieldLoadBehavior( |
| 399 type, metadata, typeLookup(resolveAsRaw: false), |
| 400 isJsInterop: false); |
| 401 } |
| 402 |
| 403 /// Computes the native behavior for writing to the native [field]. |
| 404 // TODO(johnniwinther): Cache this for later use. |
| 405 native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) { |
| 406 DartType type = getDartType(field.type); |
| 407 return nativeBehaviorBuilder.buildFieldStoreBehavior(type); |
| 408 } |
| 409 |
| 410 /// Computes the native behavior for calling [procedure]. |
| 411 // TODO(johnniwinther): Cache this for later use. |
| 412 native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) { |
| 413 DartType type = getFunctionType(procedure.function); |
| 414 List<ConstantExpression> metadata = getMetadata(procedure.annotations); |
| 415 // TODO(johnniwinther): Provide the correct value for [isJsInterop]. |
| 416 return nativeBehaviorBuilder.buildMethodBehavior( |
| 417 type, metadata, typeLookup(resolveAsRaw: false), |
| 418 isJsInterop: false); |
| 419 } |
| 387 } | 420 } |
| 388 | 421 |
| 389 /// Visitor that converts string literals and concatenations of string literals | 422 /// Visitor that converts string literals and concatenations of string literals |
| 390 /// into the string value. | 423 /// into the string value. |
| 391 class Stringifier extends ir.ExpressionVisitor<String> { | 424 class Stringifier extends ir.ExpressionVisitor<String> { |
| 392 @override | 425 @override |
| 393 String visitStringLiteral(ir.StringLiteral node) => node.value; | 426 String visitStringLiteral(ir.StringLiteral node) => node.value; |
| 394 | 427 |
| 395 @override | 428 @override |
| 396 String visitStringConcatenation(ir.StringConcatenation node) { | 429 String visitStringConcatenation(ir.StringConcatenation node) { |
| 397 StringBuffer sb = new StringBuffer(); | 430 StringBuffer sb = new StringBuffer(); |
| 398 for (ir.Expression expression in node.expressions) { | 431 for (ir.Expression expression in node.expressions) { |
| 399 String value = expression.accept(this); | 432 String value = expression.accept(this); |
| 400 if (value == null) return null; | 433 if (value == null) return null; |
| 401 sb.write(value); | 434 sb.write(value); |
| 402 } | 435 } |
| 403 return sb.toString(); | 436 return sb.toString(); |
| 404 } | 437 } |
| 405 } | 438 } |
| 406 | 439 |
| 407 /// Visitor that converts a kernel constant expression into a | 440 /// Visitor that converts a kernel constant expression into a |
| 408 /// [ConstantExpression]. | 441 /// [ConstantExpression]. |
| 409 class Constantifier extends ir.ExpressionVisitor<ConstantExpression> { | 442 class Constantifier extends ir.ExpressionVisitor<ConstantExpression> { |
| 410 final KernelElementAdapter elementAdapter; | 443 final KernelElementAdapter elementAdapter; |
| 411 | 444 |
| 412 Constantifier(this.elementAdapter); | 445 Constantifier(this.elementAdapter); |
| 413 | 446 |
| 414 @override | 447 ConstantExpression defaultExpression(ir.Expression node) { |
| 415 ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) { | 448 throw new UnimplementedError( |
| 449 'Unimplemented constant expression $node (${node.runtimeType})'); |
| 450 } |
| 451 |
| 452 List<ConstantExpression> _computeArguments(ir.Arguments node) { |
| 416 List<ConstantExpression> arguments = <ConstantExpression>[]; | 453 List<ConstantExpression> arguments = <ConstantExpression>[]; |
| 417 List<String> argumentNames = <String>[]; | 454 for (ir.Expression argument in node.positional) { |
| 418 for (ir.Expression argument in node.arguments.positional) { | |
| 419 ConstantExpression constant = argument.accept(this); | 455 ConstantExpression constant = argument.accept(this); |
| 420 if (constant == null) return null; | 456 if (constant == null) return null; |
| 421 arguments.add(constant); | 457 arguments.add(constant); |
| 422 } | 458 } |
| 423 for (ir.NamedExpression argument in node.arguments.named) { | 459 for (ir.NamedExpression argument in node.named) { |
| 424 argumentNames.add(argument.name); | |
| 425 ConstantExpression constant = argument.value.accept(this); | 460 ConstantExpression constant = argument.value.accept(this); |
| 426 if (constant == null) return null; | 461 if (constant == null) return null; |
| 427 arguments.add(constant); | 462 arguments.add(constant); |
| 428 } | 463 } |
| 464 return arguments; |
| 465 } |
| 466 |
| 467 ConstructedConstantExpression _computeConstructorInvocation( |
| 468 ir.Constructor target, ir.Arguments arguments) { |
| 429 return new ConstructedConstantExpression( | 469 return new ConstructedConstantExpression( |
| 430 elementAdapter.createInterfaceType( | 470 elementAdapter.createInterfaceType( |
| 431 node.target.enclosingClass, node.arguments.types), | 471 target.enclosingClass, arguments.types), |
| 432 elementAdapter.getConstructor(node.target), | 472 elementAdapter.getConstructor(target), |
| 433 new CallStructure( | 473 elementAdapter.getCallStructure(arguments), |
| 434 node.arguments.positional.length + argumentNames.length, | 474 _computeArguments(arguments)); |
| 435 argumentNames), | |
| 436 arguments); | |
| 437 } | 475 } |
| 438 | 476 |
| 439 @override | 477 @override |
| 478 ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) { |
| 479 return _computeConstructorInvocation(node.target, node.arguments); |
| 480 } |
| 481 |
| 482 @override |
| 483 ConstantExpression visitVariableGet(ir.VariableGet node) { |
| 484 if (node.variable.parent is ir.FunctionNode) { |
| 485 ir.FunctionNode function = node.variable.parent; |
| 486 int index = function.positionalParameters.indexOf(node.variable); |
| 487 if (index != -1) { |
| 488 return new PositionalArgumentReference(index); |
| 489 } else { |
| 490 assert(function.namedParameters.contains(node.variable)); |
| 491 return new NamedArgumentReference(node.variable.name); |
| 492 } |
| 493 } |
| 494 throw new UnimplementedError( |
| 495 'Unimplemented constant expression $node (${node.runtimeType})'); |
| 496 } |
| 497 |
| 498 @override |
| 440 ConstantExpression visitStaticGet(ir.StaticGet node) { | 499 ConstantExpression visitStaticGet(ir.StaticGet node) { |
| 441 return new FieldConstantExpression(elementAdapter.getField(node.target)); | 500 return new FieldConstantExpression(elementAdapter.getField(node.target)); |
| 442 } | 501 } |
| 443 | 502 |
| 444 @override | 503 @override |
| 445 ConstantExpression visitStringLiteral(ir.StringLiteral node) { | 504 ConstantExpression visitStringLiteral(ir.StringLiteral node) { |
| 446 return new StringConstantExpression(node.value); | 505 return new StringConstantExpression(node.value); |
| 447 } | 506 } |
| 507 |
| 508 /// Compute the [ConstantConstructor] corresponding to the const constructor |
| 509 /// [node]. |
| 510 ConstantConstructor computeConstantConstructor(ir.Constructor node) { |
| 511 assert(node.isConst); |
| 512 ir.Class cls = node.enclosingClass; |
| 513 InterfaceType type = elementAdapter.elementEnvironment |
| 514 .getThisType(elementAdapter.getClass(cls)); |
| 515 |
| 516 Map<dynamic, ConstantExpression> defaultValues = |
| 517 <dynamic, ConstantExpression>{}; |
| 518 int parameterIndex = 0; |
| 519 node.function.positionalParameters |
| 520 .forEach((ir.VariableDeclaration parameter) { |
| 521 if (parameter.initializer != null) { |
| 522 defaultValues[parameterIndex] = parameter.initializer.accept(this); |
| 523 } |
| 524 parameterIndex++; |
| 525 }); |
| 526 node.function.namedParameters.forEach((ir.VariableDeclaration parameter) { |
| 527 defaultValues[parameter.name] = parameter.initializer.accept(this); |
| 528 }); |
| 529 |
| 530 bool isRedirecting = node.initializers.length == 1 && |
| 531 node.initializers.single is ir.RedirectingInitializer; |
| 532 |
| 533 Map<FieldEntity, ConstantExpression> fieldMap = |
| 534 <FieldEntity, ConstantExpression>{}; |
| 535 |
| 536 void registerField(ir.Field field, ConstantExpression constant) { |
| 537 fieldMap[elementAdapter.getField(field)] = constant; |
| 538 } |
| 539 |
| 540 if (!isRedirecting) { |
| 541 for (ir.Field field in cls.fields) { |
| 542 if (field.initializer != null) { |
| 543 registerField(field, field.initializer.accept(this)); |
| 544 } |
| 545 } |
| 546 } |
| 547 |
| 548 ConstructedConstantExpression superConstructorInvocation; |
| 549 for (ir.Initializer initializer in node.initializers) { |
| 550 if (initializer is ir.FieldInitializer) { |
| 551 registerField(initializer.field, initializer.value.accept(this)); |
| 552 } else if (initializer is ir.SuperInitializer) { |
| 553 superConstructorInvocation = _computeConstructorInvocation( |
| 554 initializer.target, initializer.arguments); |
| 555 } else if (initializer is ir.RedirectingInitializer) { |
| 556 superConstructorInvocation = _computeConstructorInvocation( |
| 557 initializer.target, initializer.arguments); |
| 558 } else { |
| 559 throw new UnsupportedError( |
| 560 'Unexpected initializer $node (${node.runtimeType})'); |
| 561 } |
| 562 } |
| 563 if (isRedirecting) { |
| 564 return new RedirectingGenerativeConstantConstructor( |
| 565 defaultValues, superConstructorInvocation); |
| 566 } else { |
| 567 return new GenerativeConstantConstructor( |
| 568 type, defaultValues, fieldMap, superConstructorInvocation); |
| 569 } |
| 570 } |
| 448 } | 571 } |
| OLD | NEW |