| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library js_backend.backend; | 5 library js_backend.backend; |
| 6 | 6 |
| 7 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; | 7 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; |
| 8 | 8 |
| 9 import '../common.dart'; | 9 import '../common.dart'; |
| 10 import '../common/backend_api.dart' | 10 import '../common/backend_api.dart' |
| 11 show BackendClasses, ForeignResolver, NativeRegistry, ImpactTransformer; | 11 show ForeignResolver, NativeRegistry, ImpactTransformer; |
| 12 import '../common/codegen.dart' show CodegenImpact, CodegenWorkItem; | 12 import '../common/codegen.dart' show CodegenImpact, CodegenWorkItem; |
| 13 import '../common/names.dart' show Uris; | 13 import '../common/names.dart' show Uris; |
| 14 import '../common/resolution.dart' | 14 import '../common/resolution.dart' |
| 15 show Frontend, Resolution, ResolutionImpact, Target; | 15 show Frontend, Resolution, ResolutionImpact, Target; |
| 16 import '../common/tasks.dart' show CompilerTask; | 16 import '../common/tasks.dart' show CompilerTask; |
| 17 import '../compiler.dart' show Compiler; | 17 import '../compiler.dart' show Compiler; |
| 18 import '../constants/constant_system.dart'; | 18 import '../constants/constant_system.dart'; |
| 19 import '../constants/expressions.dart'; | 19 import '../constants/expressions.dart'; |
| 20 import '../constants/values.dart'; | 20 import '../constants/values.dart'; |
| 21 import '../common_elements.dart' show CommonElements, ElementEnvironment; | 21 import '../common_elements.dart' show CommonElements; |
| 22 import '../deferred_load.dart' show DeferredLoadTask; | 22 import '../deferred_load.dart' show DeferredLoadTask; |
| 23 import '../dump_info.dart' show DumpInfoTask; | 23 import '../dump_info.dart' show DumpInfoTask; |
| 24 import '../elements/elements.dart'; | 24 import '../elements/elements.dart'; |
| 25 import '../elements/entities.dart'; | 25 import '../elements/entities.dart'; |
| 26 import '../elements/resolution_types.dart'; | 26 import '../elements/resolution_types.dart'; |
| 27 import '../elements/types.dart'; | 27 import '../elements/types.dart'; |
| 28 import '../enqueue.dart' | 28 import '../enqueue.dart' |
| 29 show | 29 show |
| 30 DirectEnqueuerStrategy, | 30 DirectEnqueuerStrategy, |
| 31 Enqueuer, | 31 Enqueuer, |
| (...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 MirrorsDataImpl _mirrorsData; | 443 MirrorsDataImpl _mirrorsData; |
| 444 CheckedModeHelpers _checkedModeHelpers; | 444 CheckedModeHelpers _checkedModeHelpers; |
| 445 | 445 |
| 446 final SuperMemberData superMemberData = new SuperMemberData(); | 446 final SuperMemberData superMemberData = new SuperMemberData(); |
| 447 | 447 |
| 448 native.NativeResolutionEnqueuer _nativeResolutionEnqueuer; | 448 native.NativeResolutionEnqueuer _nativeResolutionEnqueuer; |
| 449 native.NativeCodegenEnqueuer _nativeCodegenEnqueuer; | 449 native.NativeCodegenEnqueuer _nativeCodegenEnqueuer; |
| 450 | 450 |
| 451 BackendImpacts impacts; | 451 BackendImpacts impacts; |
| 452 | 452 |
| 453 /// Common classes used by the backend. | |
| 454 BackendClasses _backendClasses; | |
| 455 | |
| 456 /// Backend access to the front-end. | 453 /// Backend access to the front-end. |
| 457 final JSFrontendAccess frontend; | 454 final JSFrontendAccess frontend; |
| 458 | 455 |
| 459 Target _target; | 456 Target _target; |
| 460 | 457 |
| 461 Tracer tracer; | 458 Tracer tracer; |
| 462 | 459 |
| 463 static SourceInformationStrategy createSourceInformationStrategy( | 460 static SourceInformationStrategy createSourceInformationStrategy( |
| 464 {bool generateSourceMap: false, | 461 {bool generateSourceMap: false, |
| 465 bool useMultiSourceInfo: false, | 462 bool useMultiSourceInfo: false, |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 548 | 545 |
| 549 /// Codegen support for generating table of interceptors and | 546 /// Codegen support for generating table of interceptors and |
| 550 /// constructors for custom elements. | 547 /// constructors for custom elements. |
| 551 CustomElementsCodegenAnalysis get customElementsCodegenAnalysis { | 548 CustomElementsCodegenAnalysis get customElementsCodegenAnalysis { |
| 552 assert(invariant( | 549 assert(invariant( |
| 553 NO_LOCATION_SPANNABLE, _customElementsCodegenAnalysis != null, | 550 NO_LOCATION_SPANNABLE, _customElementsCodegenAnalysis != null, |
| 554 message: "CustomElementsCodegenAnalysis has not been created yet.")); | 551 message: "CustomElementsCodegenAnalysis has not been created yet.")); |
| 555 return _customElementsCodegenAnalysis; | 552 return _customElementsCodegenAnalysis; |
| 556 } | 553 } |
| 557 | 554 |
| 558 /// Common classes used by the backend. | |
| 559 BackendClasses get backendClasses { | |
| 560 assert(invariant(NO_LOCATION_SPANNABLE, _backendClasses != null, | |
| 561 message: "BackendClasses has not been created yet.")); | |
| 562 return _backendClasses; | |
| 563 } | |
| 564 | |
| 565 NativeBasicData get nativeBasicData { | 555 NativeBasicData get nativeBasicData { |
| 566 assert(invariant(NO_LOCATION_SPANNABLE, _nativeBasicData != null, | 556 assert(invariant(NO_LOCATION_SPANNABLE, _nativeBasicData != null, |
| 567 message: "NativeBasicData has not been computed yet.")); | 557 message: "NativeBasicData has not been computed yet.")); |
| 568 return _nativeBasicData; | 558 return _nativeBasicData; |
| 569 } | 559 } |
| 570 | 560 |
| 571 NativeBasicDataBuilder get nativeBasicDataBuilder => _nativeBasicDataBuilder; | 561 NativeBasicDataBuilder get nativeBasicDataBuilder => _nativeBasicDataBuilder; |
| 572 | 562 |
| 573 /// Resolution analysis for tracking reflective access to type variables. | 563 /// Resolution analysis for tracking reflective access to type variables. |
| 574 TypeVariableResolutionAnalysis get typeVariableResolutionAnalysis { | 564 TypeVariableResolutionAnalysis get typeVariableResolutionAnalysis { |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 node, MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | 827 node, MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |
| 838 } | 828 } |
| 839 // No native behavior for this call. | 829 // No native behavior for this call. |
| 840 return null; | 830 return null; |
| 841 } | 831 } |
| 842 | 832 |
| 843 ResolutionEnqueuer createResolutionEnqueuer( | 833 ResolutionEnqueuer createResolutionEnqueuer( |
| 844 CompilerTask task, Compiler compiler) { | 834 CompilerTask task, Compiler compiler) { |
| 845 _nativeBasicData = | 835 _nativeBasicData = |
| 846 nativeBasicDataBuilder.close(compiler.elementEnvironment); | 836 nativeBasicDataBuilder.close(compiler.elementEnvironment); |
| 847 _backendClasses = new JavaScriptBackendClasses( | |
| 848 compiler.elementEnvironment, commonElements, nativeBasicData); | |
| 849 _nativeResolutionEnqueuer = new native.NativeResolutionEnqueuer( | 837 _nativeResolutionEnqueuer = new native.NativeResolutionEnqueuer( |
| 850 compiler.options, | 838 compiler.options, |
| 851 compiler.elementEnvironment, | 839 compiler.elementEnvironment, |
| 852 commonElements, | 840 commonElements, |
| 853 backendClasses, | |
| 854 backendUsageBuilder, | 841 backendUsageBuilder, |
| 855 new NativeClassResolverImpl( | 842 new NativeClassResolverImpl( |
| 856 compiler.resolution, reporter, commonElements, nativeBasicData)); | 843 compiler.resolution, reporter, commonElements, nativeBasicData)); |
| 857 _nativeData = new NativeDataImpl(nativeBasicData); | 844 _nativeData = new NativeDataImpl(nativeBasicData); |
| 858 _customElementsResolutionAnalysis = new CustomElementsResolutionAnalysis( | 845 _customElementsResolutionAnalysis = new CustomElementsResolutionAnalysis( |
| 859 compiler.resolution, | 846 compiler.resolution, |
| 860 constantSystem, | 847 constantSystem, |
| 861 commonElements, | 848 commonElements, |
| 862 backendClasses, | |
| 863 nativeBasicData, | 849 nativeBasicData, |
| 864 backendUsageBuilder); | 850 backendUsageBuilder); |
| 865 impactTransformer = new JavaScriptImpactTransformer( | 851 impactTransformer = new JavaScriptImpactTransformer( |
| 866 compiler.options, | 852 compiler.options, |
| 867 compiler.elementEnvironment, | 853 compiler.elementEnvironment, |
| 868 commonElements, | 854 commonElements, |
| 869 impacts, | 855 impacts, |
| 870 nativeBasicData, | 856 nativeBasicData, |
| 871 _nativeResolutionEnqueuer, | 857 _nativeResolutionEnqueuer, |
| 872 backendUsageBuilder, | 858 backendUsageBuilder, |
| 873 mirrorsDataBuilder, | 859 mirrorsDataBuilder, |
| 874 customElementsResolutionAnalysis, | 860 customElementsResolutionAnalysis, |
| 875 rtiNeedBuilder); | 861 rtiNeedBuilder); |
| 876 _interceptorDataBuilder = new InterceptorDataBuilderImpl( | 862 _interceptorDataBuilder = new InterceptorDataBuilderImpl( |
| 877 nativeBasicData, compiler.elementEnvironment, commonElements); | 863 nativeBasicData, compiler.elementEnvironment, commonElements); |
| 878 return new ResolutionEnqueuer( | 864 return new ResolutionEnqueuer( |
| 879 task, | 865 task, |
| 880 compiler.options, | 866 compiler.options, |
| 881 compiler.reporter, | 867 compiler.reporter, |
| 882 compiler.options.analyzeOnly && compiler.options.analyzeMain | 868 compiler.options.analyzeOnly && compiler.options.analyzeMain |
| 883 ? const DirectEnqueuerStrategy() | 869 ? const DirectEnqueuerStrategy() |
| 884 : const TreeShakingEnqueuerStrategy(), | 870 : const TreeShakingEnqueuerStrategy(), |
| 885 new ResolutionEnqueuerListener( | 871 new ResolutionEnqueuerListener( |
| 886 compiler.options, | 872 compiler.options, |
| 887 compiler.elementEnvironment, | 873 compiler.elementEnvironment, |
| 888 commonElements, | 874 commonElements, |
| 889 impacts, | 875 impacts, |
| 890 backendClasses, | |
| 891 nativeBasicData, | 876 nativeBasicData, |
| 892 interceptorDataBuilder, | 877 interceptorDataBuilder, |
| 893 backendUsageBuilder, | 878 backendUsageBuilder, |
| 894 rtiNeedBuilder, | 879 rtiNeedBuilder, |
| 895 mirrorsDataBuilder, | 880 mirrorsDataBuilder, |
| 896 noSuchMethodRegistry, | 881 noSuchMethodRegistry, |
| 897 customElementsResolutionAnalysis, | 882 customElementsResolutionAnalysis, |
| 898 lookupMapResolutionAnalysis, | 883 lookupMapResolutionAnalysis, |
| 899 mirrorsResolutionAnalysis, | 884 mirrorsResolutionAnalysis, |
| 900 typeVariableResolutionAnalysis, | 885 typeVariableResolutionAnalysis, |
| 901 _nativeResolutionEnqueuer, | 886 _nativeResolutionEnqueuer, |
| 902 compiler.deferredLoadTask, | 887 compiler.deferredLoadTask, |
| 903 kernelTask), | 888 kernelTask), |
| 904 new ElementResolutionWorldBuilder( | 889 new ElementResolutionWorldBuilder( |
| 905 this, compiler.resolution, const OpenWorldStrategy()), | 890 this, compiler.resolution, const OpenWorldStrategy()), |
| 906 new ResolutionWorkItemBuilder(compiler.resolution)); | 891 new ResolutionWorkItemBuilder(compiler.resolution)); |
| 907 } | 892 } |
| 908 | 893 |
| 909 /// Creates an [Enqueuer] for code generation specific to this backend. | 894 /// Creates an [Enqueuer] for code generation specific to this backend. |
| 910 CodegenEnqueuer createCodegenEnqueuer( | 895 CodegenEnqueuer createCodegenEnqueuer( |
| 911 CompilerTask task, Compiler compiler, ClosedWorld closedWorld) { | 896 CompilerTask task, Compiler compiler, ClosedWorld closedWorld) { |
| 912 _typeVariableCodegenAnalysis = new TypeVariableCodegenAnalysis( | 897 _typeVariableCodegenAnalysis = new TypeVariableCodegenAnalysis( |
| 913 compiler.elementEnvironment, this, commonElements, mirrorsData); | 898 compiler.elementEnvironment, this, commonElements, mirrorsData); |
| 914 _lookupMapAnalysis = new LookupMapAnalysis( | 899 _lookupMapAnalysis = new LookupMapAnalysis( |
| 915 reporter, | 900 reporter, |
| 916 constantSystem, | 901 constantSystem, |
| 917 constants, | 902 constants, |
| 918 compiler.elementEnvironment, | 903 compiler.elementEnvironment, |
| 919 commonElements, | 904 commonElements, |
| 920 backendClasses, | |
| 921 lookupMapResolutionAnalysis); | 905 lookupMapResolutionAnalysis); |
| 922 _mirrorsCodegenAnalysis = mirrorsResolutionAnalysis.close(); | 906 _mirrorsCodegenAnalysis = mirrorsResolutionAnalysis.close(); |
| 923 _customElementsCodegenAnalysis = new CustomElementsCodegenAnalysis( | 907 _customElementsCodegenAnalysis = new CustomElementsCodegenAnalysis( |
| 924 compiler.resolution, | 908 compiler.resolution, constantSystem, commonElements, nativeBasicData); |
| 925 constantSystem, | |
| 926 commonElements, | |
| 927 backendClasses, | |
| 928 nativeBasicData); | |
| 929 _nativeCodegenEnqueuer = new native.NativeCodegenEnqueuer( | 909 _nativeCodegenEnqueuer = new native.NativeCodegenEnqueuer( |
| 930 compiler.options, | 910 compiler.options, |
| 931 compiler.elementEnvironment, | 911 compiler.elementEnvironment, |
| 932 commonElements, | 912 commonElements, |
| 933 backendClasses, | |
| 934 emitter, | 913 emitter, |
| 935 _nativeResolutionEnqueuer, | 914 _nativeResolutionEnqueuer, |
| 936 nativeData); | 915 nativeData); |
| 937 return new CodegenEnqueuer( | 916 return new CodegenEnqueuer( |
| 938 task, | 917 task, |
| 939 compiler.options, | 918 compiler.options, |
| 940 const TreeShakingEnqueuerStrategy(), | 919 const TreeShakingEnqueuerStrategy(), |
| 941 new CodegenWorldBuilderImpl( | 920 new CodegenWorldBuilderImpl( |
| 942 nativeBasicData, closedWorld, constants, const TypeMaskStrategy()), | 921 nativeBasicData, closedWorld, constants, const TypeMaskStrategy()), |
| 943 new CodegenWorkItemBuilder(this, compiler.options), | 922 new CodegenWorkItemBuilder(this, compiler.options), |
| 944 new CodegenEnqueuerListener( | 923 new CodegenEnqueuerListener( |
| 945 compiler.elementEnvironment, | 924 compiler.elementEnvironment, |
| 946 commonElements, | 925 commonElements, |
| 947 impacts, | 926 impacts, |
| 948 backendClasses, | |
| 949 backendUsage, | 927 backendUsage, |
| 950 rtiNeed, | 928 rtiNeed, |
| 951 customElementsCodegenAnalysis, | 929 customElementsCodegenAnalysis, |
| 952 typeVariableCodegenAnalysis, | 930 typeVariableCodegenAnalysis, |
| 953 lookupMapAnalysis, | 931 lookupMapAnalysis, |
| 954 mirrorsCodegenAnalysis, | 932 mirrorsCodegenAnalysis, |
| 955 nativeCodegenEnqueuer)); | 933 nativeCodegenEnqueuer)); |
| 956 } | 934 } |
| 957 | 935 |
| 958 WorldImpact codegen(CodegenWorkItem work) { | 936 WorldImpact codegen(CodegenWorkItem work) { |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1466 @override | 1444 @override |
| 1467 void onImpactUsed(ImpactUseCase impactUse) { | 1445 void onImpactUsed(ImpactUseCase impactUse) { |
| 1468 if (impactUse == DeferredLoadTask.IMPACT_USE && !supportSerialization) { | 1446 if (impactUse == DeferredLoadTask.IMPACT_USE && !supportSerialization) { |
| 1469 // TODO(johnniwinther): Allow emptying when serialization has been | 1447 // TODO(johnniwinther): Allow emptying when serialization has been |
| 1470 // performed. | 1448 // performed. |
| 1471 resolution.emptyCache(); | 1449 resolution.emptyCache(); |
| 1472 } | 1450 } |
| 1473 } | 1451 } |
| 1474 } | 1452 } |
| 1475 | 1453 |
| 1476 // TODO(efortuna): Merge with commonElements. | |
| 1477 class JavaScriptBackendClasses implements BackendClasses { | |
| 1478 final ElementEnvironment _env; | |
| 1479 final CommonElements _commonElements; | |
| 1480 final NativeBasicData _nativeData; | |
| 1481 | |
| 1482 JavaScriptBackendClasses(this._env, this._commonElements, this._nativeData); | |
| 1483 | |
| 1484 ClassEntity get intClass => _commonElements.jsIntClass; | |
| 1485 ClassEntity get uint32Class => _commonElements.jsUInt32Class; | |
| 1486 ClassEntity get uint31Class => _commonElements.jsUInt31Class; | |
| 1487 ClassEntity get positiveIntClass => _commonElements.jsPositiveIntClass; | |
| 1488 ClassEntity get doubleClass => _commonElements.jsDoubleClass; | |
| 1489 ClassEntity get numClass => _commonElements.jsNumberClass; | |
| 1490 ClassEntity get stringClass => _commonElements.jsStringClass; | |
| 1491 ClassEntity get listClass => _commonElements.jsArrayClass; | |
| 1492 ClassEntity get mutableListClass => _commonElements.jsMutableArrayClass; | |
| 1493 ClassEntity get constListClass => _commonElements.jsUnmodifiableArrayClass; | |
| 1494 ClassEntity get fixedListClass => _commonElements.jsFixedArrayClass; | |
| 1495 ClassEntity get growableListClass => _commonElements.jsExtendableArrayClass; | |
| 1496 ClassEntity get mapClass => _commonElements.mapLiteralClass; | |
| 1497 ClassEntity get constMapClass => _commonElements.constMapLiteralClass; | |
| 1498 ClassEntity get typeClass => _commonElements.typeLiteralClass; | |
| 1499 InterfaceType get typeType => _env.getRawType(typeClass); | |
| 1500 | |
| 1501 ClassEntity get boolClass => _commonElements.jsBoolClass; | |
| 1502 ClassEntity get nullClass => _commonElements.jsNullClass; | |
| 1503 ClassEntity get syncStarIterableClass => _commonElements.syncStarIterable; | |
| 1504 ClassEntity get asyncFutureClass => _commonElements.futureImplementation; | |
| 1505 ClassEntity get asyncStarStreamClass => _commonElements.controllerStream; | |
| 1506 ClassEntity get functionClass => _commonElements.functionClass; | |
| 1507 ClassEntity get indexableClass => _commonElements.jsIndexableClass; | |
| 1508 ClassEntity get mutableIndexableClass => | |
| 1509 _commonElements.jsMutableIndexableClass; | |
| 1510 ClassEntity get indexingBehaviorClass => | |
| 1511 _commonElements.jsIndexingBehaviorInterface; | |
| 1512 ClassEntity get interceptorClass => _commonElements.jsInterceptorClass; | |
| 1513 | |
| 1514 bool isDefaultEqualityImplementation(MemberEntity element) { | |
| 1515 assert(element.name == '=='); | |
| 1516 ClassEntity classElement = element.enclosingClass; | |
| 1517 return classElement == _commonElements.objectClass || | |
| 1518 classElement == _commonElements.jsInterceptorClass || | |
| 1519 classElement == _commonElements.jsNullClass; | |
| 1520 } | |
| 1521 | |
| 1522 @override | |
| 1523 bool isNativeClass(ClassEntity element) { | |
| 1524 return _nativeData.isNativeClass(element); | |
| 1525 } | |
| 1526 | |
| 1527 InterfaceType getConstantMapTypeFor(InterfaceType sourceType, | |
| 1528 {bool hasProtoKey: false, bool onlyStringKeys: false}) { | |
| 1529 ClassEntity classElement = onlyStringKeys | |
| 1530 ? (hasProtoKey | |
| 1531 ? _commonElements.constantProtoMapClass | |
| 1532 : _commonElements.constantStringMapClass) | |
| 1533 : _commonElements.generalConstantMapClass; | |
| 1534 List<DartType> typeArgument = sourceType.typeArguments; | |
| 1535 if (sourceType.treatAsRaw) { | |
| 1536 return _env.getRawType(classElement); | |
| 1537 } else { | |
| 1538 return _env.createInterfaceType(classElement, typeArgument); | |
| 1539 } | |
| 1540 } | |
| 1541 | |
| 1542 @override | |
| 1543 FieldEntity get symbolField => _commonElements.symbolImplementationField; | |
| 1544 | |
| 1545 @override | |
| 1546 InterfaceType get symbolType { | |
| 1547 return _env.getRawType(_commonElements.symbolImplementationClass); | |
| 1548 } | |
| 1549 } | |
| 1550 | |
| 1551 class JavaScriptBackendTarget extends Target { | 1454 class JavaScriptBackendTarget extends Target { |
| 1552 final JavaScriptBackend _backend; | 1455 final JavaScriptBackend _backend; |
| 1553 | 1456 |
| 1554 JavaScriptBackendTarget(this._backend); | 1457 JavaScriptBackendTarget(this._backend); |
| 1555 | 1458 |
| 1556 @override | 1459 @override |
| 1557 bool isTargetSpecificLibrary(LibraryElement element) { | 1460 bool isTargetSpecificLibrary(LibraryElement element) { |
| 1558 return _backend.isTargetSpecificLibrary(element); | 1461 return _backend.isTargetSpecificLibrary(element); |
| 1559 } | 1462 } |
| 1560 | 1463 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1609 | 1512 |
| 1610 bool canUseAliasedSuperMember(MemberEntity member, Selector selector) { | 1513 bool canUseAliasedSuperMember(MemberEntity member, Selector selector) { |
| 1611 return !selector.isGetter; | 1514 return !selector.isGetter; |
| 1612 } | 1515 } |
| 1613 | 1516 |
| 1614 /// Returns `true` if [member] is called from a subclass via `super`. | 1517 /// Returns `true` if [member] is called from a subclass via `super`. |
| 1615 bool isAliasedSuperMember(MemberEntity member) { | 1518 bool isAliasedSuperMember(MemberEntity member) { |
| 1616 return _aliasedSuperMembers.contains(member); | 1519 return _aliasedSuperMembers.contains(member); |
| 1617 } | 1520 } |
| 1618 } | 1521 } |
| OLD | NEW |