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 part of js_backend; | 5 part of js_backend; |
6 | 6 |
7 const VERBOSE_OPTIMIZER_HINTS = false; | 7 const VERBOSE_OPTIMIZER_HINTS = false; |
8 | 8 |
9 class JavaScriptItemCompilationContext extends ItemCompilationContext { | 9 class JavaScriptItemCompilationContext extends ItemCompilationContext { |
10 final Set<HInstruction> boundsChecked = new Set<HInstruction>(); | 10 final Set<HInstruction> boundsChecked = new Set<HInstruction>(); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 // it outside a loop either. | 46 // it outside a loop either. |
47 canBeInlined[element] = false; | 47 canBeInlined[element] = false; |
48 canBeInlinedInsideLoop[element] = false; | 48 canBeInlinedInsideLoop[element] = false; |
49 } else { | 49 } else { |
50 canBeInlined[element] = false; | 50 canBeInlined[element] = false; |
51 } | 51 } |
52 } | 52 } |
53 } | 53 } |
54 | 54 |
55 class JavaScriptBackend extends Backend { | 55 class JavaScriptBackend extends Backend { |
| 56 static final Uri DART_JS_MIRRORS = |
| 57 new Uri(scheme: 'dart', path: '_js_mirrors'); |
| 58 static final Uri DART_JS_NAMES = |
| 59 new Uri(scheme: 'dart', path: '_js_names'); |
| 60 |
56 SsaBuilderTask builder; | 61 SsaBuilderTask builder; |
57 SsaOptimizerTask optimizer; | 62 SsaOptimizerTask optimizer; |
58 SsaCodeGeneratorTask generator; | 63 SsaCodeGeneratorTask generator; |
59 CodeEmitterTask emitter; | 64 CodeEmitterTask emitter; |
60 | 65 |
61 /** | 66 /** |
62 * The generated code as a js AST for compiled methods. | 67 * The generated code as a js AST for compiled methods. |
63 */ | 68 */ |
64 Map<Element, jsAst.Expression> get generatedCode { | 69 Map<Element, jsAst.Expression> get generatedCode { |
65 return compiler.enqueuer.codegen.generatedCode; | 70 return compiler.enqueuer.codegen.generatedCode; |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 } | 467 } |
463 } | 468 } |
464 return result; | 469 return result; |
465 } | 470 } |
466 | 471 |
467 bool operatorEqHandlesNullArgument(FunctionElement operatorEqfunction) { | 472 bool operatorEqHandlesNullArgument(FunctionElement operatorEqfunction) { |
468 return specialOperatorEqClasses.contains( | 473 return specialOperatorEqClasses.contains( |
469 operatorEqfunction.enclosingClass); | 474 operatorEqfunction.enclosingClass); |
470 } | 475 } |
471 | 476 |
472 void initializeHelperClasses() { | |
473 getInterceptorMethod = compiler.findInterceptor('getInterceptor'); | |
474 interceptedNames = compiler.findInterceptor('interceptedNames'); | |
475 mapTypeToInterceptor = compiler.findInterceptor('mapTypeToInterceptor'); | |
476 getNativeInterceptorMethod = | |
477 compiler.findInterceptor('getNativeInterceptor'); | |
478 | |
479 // These methods are overwritten with generated versions. | |
480 inlineCache.markAsNonInlinable(getInterceptorMethod, insideLoop: true); | |
481 | |
482 List<ClassElement> classes = [ | |
483 jsInterceptorClass = | |
484 compiler.findInterceptor('Interceptor'), | |
485 jsStringClass = compiler.findInterceptor('JSString'), | |
486 jsArrayClass = compiler.findInterceptor('JSArray'), | |
487 // The int class must be before the double class, because the | |
488 // emitter relies on this list for the order of type checks. | |
489 jsIntClass = compiler.findInterceptor('JSInt'), | |
490 jsPositiveIntClass = compiler.findInterceptor('JSPositiveInt'), | |
491 jsUInt32Class = compiler.findInterceptor('JSUInt32'), | |
492 jsUInt31Class = compiler.findInterceptor('JSUInt31'), | |
493 jsDoubleClass = compiler.findInterceptor('JSDouble'), | |
494 jsNumberClass = compiler.findInterceptor('JSNumber'), | |
495 jsNullClass = compiler.findInterceptor('JSNull'), | |
496 jsBoolClass = compiler.findInterceptor('JSBool'), | |
497 jsMutableArrayClass = compiler.findInterceptor('JSMutableArray'), | |
498 jsFixedArrayClass = compiler.findInterceptor('JSFixedArray'), | |
499 jsExtendableArrayClass = compiler.findInterceptor('JSExtendableArray'), | |
500 jsPlainJavaScriptObjectClass = | |
501 compiler.findInterceptor('PlainJavaScriptObject'), | |
502 jsUnknownJavaScriptObjectClass = | |
503 compiler.findInterceptor('UnknownJavaScriptObject'), | |
504 ]; | |
505 | |
506 implementationClasses = <ClassElement, ClassElement>{}; | |
507 implementationClasses[compiler.intClass] = jsIntClass; | |
508 implementationClasses[compiler.boolClass] = jsBoolClass; | |
509 implementationClasses[compiler.numClass] = jsNumberClass; | |
510 implementationClasses[compiler.doubleClass] = jsDoubleClass; | |
511 implementationClasses[compiler.stringClass] = jsStringClass; | |
512 implementationClasses[compiler.listClass] = jsArrayClass; | |
513 implementationClasses[compiler.nullClass] = jsNullClass; | |
514 | |
515 jsIndexableClass = compiler.findInterceptor('JSIndexable'); | |
516 jsMutableIndexableClass = compiler.findInterceptor('JSMutableIndexable'); | |
517 | |
518 // TODO(kasperl): Some tests do not define the special JSArray | |
519 // subclasses, so we check to see if they are defined before | |
520 // trying to resolve them. | |
521 if (jsFixedArrayClass != null) { | |
522 jsFixedArrayClass.ensureResolved(compiler); | |
523 } | |
524 if (jsExtendableArrayClass != null) { | |
525 jsExtendableArrayClass.ensureResolved(compiler); | |
526 } | |
527 | |
528 jsIndexableClass.ensureResolved(compiler); | |
529 jsIndexableLength = compiler.lookupElementIn( | |
530 jsIndexableClass, 'length'); | |
531 if (jsIndexableLength != null && jsIndexableLength.isAbstractField) { | |
532 AbstractFieldElement element = jsIndexableLength; | |
533 jsIndexableLength = element.getter; | |
534 } | |
535 | |
536 jsArrayClass.ensureResolved(compiler); | |
537 jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed'); | |
538 jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast'); | |
539 jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add'); | |
540 | |
541 jsStringClass.ensureResolved(compiler); | |
542 jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split'); | |
543 jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+'); | |
544 jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString'); | |
545 | |
546 typeLiteralClass = compiler.findHelper('TypeImpl'); | |
547 mapLiteralClass = compiler.coreLibrary.find('LinkedHashMap'); | |
548 constMapLiteralClass = compiler.findHelper('ConstantMap'); | |
549 | |
550 objectEquals = compiler.lookupElementIn(compiler.objectClass, '=='); | |
551 | |
552 jsIndexingBehaviorInterface = | |
553 compiler.findHelper('JavaScriptIndexingBehavior'); | |
554 | |
555 specialOperatorEqClasses | |
556 ..add(compiler.objectClass) | |
557 ..add(jsInterceptorClass) | |
558 ..add(jsNullClass); | |
559 | |
560 validateInterceptorImplementsAllObjectMethods(jsInterceptorClass); | |
561 // The null-interceptor must also implement *all* methods. | |
562 validateInterceptorImplementsAllObjectMethods(jsNullClass); | |
563 | |
564 typeVariableClass = compiler.findHelper('TypeVariable'); | |
565 | |
566 indexablePrimitiveType = new TypeMask.nonNullSubtype(jsIndexableClass); | |
567 readableArrayType = new TypeMask.nonNullSubclass(jsArrayClass); | |
568 mutableArrayType = new TypeMask.nonNullSubclass(jsMutableArrayClass); | |
569 fixedArrayType = new TypeMask.nonNullExact(jsFixedArrayClass); | |
570 extendableArrayType = new TypeMask.nonNullExact(jsExtendableArrayClass); | |
571 nonNullType = compiler.typesTask.dynamicType.nonNullable(); | |
572 | |
573 noSideEffectsClass = compiler.findHelper('NoSideEffects'); | |
574 noThrowsClass = compiler.findHelper('NoThrows'); | |
575 noInlineClass = compiler.findHelper('NoInline'); | |
576 irRepresentationClass = compiler.findHelper('IrRepresentation'); | |
577 } | |
578 | |
579 void validateInterceptorImplementsAllObjectMethods( | 477 void validateInterceptorImplementsAllObjectMethods( |
580 ClassElement interceptorClass) { | 478 ClassElement interceptorClass) { |
581 if (interceptorClass == null) return; | 479 if (interceptorClass == null) return; |
582 interceptorClass.ensureResolved(compiler); | 480 interceptorClass.ensureResolved(compiler); |
583 compiler.objectClass.forEachMember((_, Element member) { | 481 compiler.objectClass.forEachMember((_, Element member) { |
584 if (member.isGenerativeConstructor) return; | 482 if (member.isGenerativeConstructor) return; |
585 Element interceptorMember = interceptorClass.lookupMember(member.name); | 483 Element interceptorMember = interceptorClass.lookupMember(member.name); |
586 // Interceptors must override all Object methods due to calling convention | 484 // Interceptors must override all Object methods due to calling convention |
587 // differences. | 485 // differences. |
588 assert(interceptorMember.enclosingClass == interceptorClass); | 486 assert(interceptorMember.enclosingClass == interceptorClass); |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 enqueueClass(enqueuer, jsPlainJavaScriptObjectClass, registry); | 739 enqueueClass(enqueuer, jsPlainJavaScriptObjectClass, registry); |
842 needToInitializeIsolateAffinityTag = true; | 740 needToInitializeIsolateAffinityTag = true; |
843 needToInitializeDispatchProperty = true; | 741 needToInitializeDispatchProperty = true; |
844 } | 742 } |
845 | 743 |
846 JavaScriptItemCompilationContext createItemCompilationContext() { | 744 JavaScriptItemCompilationContext createItemCompilationContext() { |
847 return new JavaScriptItemCompilationContext(); | 745 return new JavaScriptItemCompilationContext(); |
848 } | 746 } |
849 | 747 |
850 void enqueueHelpers(ResolutionEnqueuer world, Registry registry) { | 748 void enqueueHelpers(ResolutionEnqueuer world, Registry registry) { |
| 749 assert(compiler.interceptorsLibrary != null); |
851 // TODO(ngeoffray): Not enqueuing those two classes currently make | 750 // TODO(ngeoffray): Not enqueuing those two classes currently make |
852 // the compiler potentially crash. However, any reasonable program | 751 // the compiler potentially crash. However, any reasonable program |
853 // will instantiate those two classes. | 752 // will instantiate those two classes. |
854 addInterceptors(jsBoolClass, world, registry); | 753 addInterceptors(jsBoolClass, world, registry); |
855 addInterceptors(jsNullClass, world, registry); | 754 addInterceptors(jsNullClass, world, registry); |
856 if (compiler.enableTypeAssertions) { | 755 if (compiler.enableTypeAssertions) { |
857 // Unconditionally register the helper that checks if the | 756 // Unconditionally register the helper that checks if the |
858 // expression in an if/while/for is a boolean. | 757 // expression in an if/while/for is a boolean. |
859 // TODO(ngeoffray): Should we have the resolver register those instead? | 758 // TODO(ngeoffray): Should we have the resolver register those instead? |
860 Element e = | 759 Element e = |
(...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1684 for (MetadataAnnotation metadata in element.metadata) { | 1583 for (MetadataAnnotation metadata in element.metadata) { |
1685 metadata.ensureResolved(compiler); | 1584 metadata.ensureResolved(compiler); |
1686 Constant constant = constants.getConstantForMetadata(metadata); | 1585 Constant constant = constants.getConstantForMetadata(metadata); |
1687 constants.addCompileTimeConstantForEmission(constant); | 1586 constants.addCompileTimeConstantForEmission(constant); |
1688 } | 1587 } |
1689 return true; | 1588 return true; |
1690 } | 1589 } |
1691 return false; | 1590 return false; |
1692 } | 1591 } |
1693 | 1592 |
1694 Future onLibraryLoaded(LibraryElement library, Uri uri) { | 1593 void onLibraryScanned(LibraryElement library) { |
1695 if (uri == Uri.parse('dart:_js_mirrors')) { | 1594 Uri uri = library.canonicalUri; |
1696 disableTreeShakingMarker = | 1595 |
1697 library.find('disableTreeShaking'); | 1596 // TODO(johnniwinther): Assert that the elements are found. |
1698 preserveMetadataMarker = | 1597 VariableElement findVariable(String name) { |
1699 library.find('preserveMetadata'); | 1598 return library.find(name); |
1700 } else if (uri == Uri.parse('dart:_js_names')) { | |
1701 preserveNamesMarker = | |
1702 library.find('preserveNames'); | |
1703 } else if (uri == Uri.parse('dart:_js_helper')) { | |
1704 getIsolateAffinityTagMarker = | |
1705 library.find('getIsolateAffinityTag'); | |
1706 } | 1599 } |
| 1600 |
| 1601 FunctionElement findMethod(String name) { |
| 1602 return library.find(name); |
| 1603 } |
| 1604 |
| 1605 ClassElement findClass(String name) { |
| 1606 return library.find(name); |
| 1607 } |
| 1608 |
| 1609 if (uri == Compiler.DART_INTERCEPTORS) { |
| 1610 getInterceptorMethod = findMethod('getInterceptor'); |
| 1611 interceptedNames = findVariable('interceptedNames'); |
| 1612 mapTypeToInterceptor = findVariable('mapTypeToInterceptor'); |
| 1613 getNativeInterceptorMethod = findMethod('getNativeInterceptor'); |
| 1614 |
| 1615 List<ClassElement> classes = [ |
| 1616 jsInterceptorClass = findClass('Interceptor'), |
| 1617 jsStringClass = findClass('JSString'), |
| 1618 jsArrayClass = findClass('JSArray'), |
| 1619 // The int class must be before the double class, because the |
| 1620 // emitter relies on this list for the order of type checks. |
| 1621 jsIntClass = findClass('JSInt'), |
| 1622 jsPositiveIntClass = findClass('JSPositiveInt'), |
| 1623 jsUInt32Class = findClass('JSUInt32'), |
| 1624 jsUInt31Class = findClass('JSUInt31'), |
| 1625 jsDoubleClass = findClass('JSDouble'), |
| 1626 jsNumberClass = findClass('JSNumber'), |
| 1627 jsNullClass = findClass('JSNull'), |
| 1628 jsBoolClass = findClass('JSBool'), |
| 1629 jsMutableArrayClass = findClass('JSMutableArray'), |
| 1630 jsFixedArrayClass = findClass('JSFixedArray'), |
| 1631 jsExtendableArrayClass = findClass('JSExtendableArray'), |
| 1632 jsPlainJavaScriptObjectClass = findClass('PlainJavaScriptObject'), |
| 1633 jsUnknownJavaScriptObjectClass = findClass('UnknownJavaScriptObject'), |
| 1634 ]; |
| 1635 |
| 1636 jsIndexableClass = findClass('JSIndexable'); |
| 1637 jsMutableIndexableClass = findClass('JSMutableIndexable'); |
| 1638 } else if (uri == Compiler.DART_JS_HELPER) { |
| 1639 typeLiteralClass = findClass('TypeImpl'); |
| 1640 constMapLiteralClass = findClass('ConstantMap'); |
| 1641 typeVariableClass = findClass('TypeVariable'); |
| 1642 |
| 1643 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior'); |
| 1644 |
| 1645 noSideEffectsClass = findClass('NoSideEffects'); |
| 1646 noThrowsClass = findClass('NoThrows'); |
| 1647 noInlineClass = findClass('NoInline'); |
| 1648 irRepresentationClass = findClass('IrRepresentation'); |
| 1649 } else if (uri == DART_JS_MIRRORS) { |
| 1650 disableTreeShakingMarker = library.find('disableTreeShaking'); |
| 1651 preserveMetadataMarker = library.find('preserveMetadata'); |
| 1652 } else if (uri == DART_JS_NAMES) { |
| 1653 preserveNamesMarker = library.find('preserveNames'); |
| 1654 } else if (uri == Compiler.DART_JS_HELPER) { |
| 1655 getIsolateAffinityTagMarker = library.find('getIsolateAffinityTag'); |
| 1656 } |
| 1657 } |
| 1658 |
| 1659 Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) { |
| 1660 if (!loadedLibraries.containsKey(Compiler.DART_CORE)) { |
| 1661 return new Future.value(); |
| 1662 } |
| 1663 assert(loadedLibraries.containsKey(Compiler.DART_CORE)); |
| 1664 assert(loadedLibraries.containsKey(Compiler.DART_INTERCEPTORS)); |
| 1665 assert(loadedLibraries.containsKey(Compiler.DART_JS_HELPER)); |
| 1666 |
| 1667 // [LinkedHashMap] is reexported from dart:collection and can therefore not |
| 1668 // be loaded from dart:core in [onLibraryScanned]. |
| 1669 mapLiteralClass = compiler.coreLibrary.find('LinkedHashMap'); |
| 1670 |
| 1671 implementationClasses = <ClassElement, ClassElement>{}; |
| 1672 implementationClasses[compiler.intClass] = jsIntClass; |
| 1673 implementationClasses[compiler.boolClass] = jsBoolClass; |
| 1674 implementationClasses[compiler.numClass] = jsNumberClass; |
| 1675 implementationClasses[compiler.doubleClass] = jsDoubleClass; |
| 1676 implementationClasses[compiler.stringClass] = jsStringClass; |
| 1677 implementationClasses[compiler.listClass] = jsArrayClass; |
| 1678 implementationClasses[compiler.nullClass] = jsNullClass; |
| 1679 |
| 1680 // These methods are overwritten with generated versions. |
| 1681 inlineCache.markAsNonInlinable(getInterceptorMethod, insideLoop: true); |
| 1682 |
| 1683 // TODO(kasperl): Some tests do not define the special JSArray |
| 1684 // subclasses, so we check to see if they are defined before |
| 1685 // trying to resolve them. |
| 1686 if (jsFixedArrayClass != null) { |
| 1687 jsFixedArrayClass.ensureResolved(compiler); |
| 1688 } |
| 1689 if (jsExtendableArrayClass != null) { |
| 1690 jsExtendableArrayClass.ensureResolved(compiler); |
| 1691 } |
| 1692 |
| 1693 jsIndexableClass.ensureResolved(compiler); |
| 1694 jsIndexableLength = compiler.lookupElementIn( |
| 1695 jsIndexableClass, 'length'); |
| 1696 if (jsIndexableLength != null && jsIndexableLength.isAbstractField) { |
| 1697 AbstractFieldElement element = jsIndexableLength; |
| 1698 jsIndexableLength = element.getter; |
| 1699 } |
| 1700 |
| 1701 jsArrayClass.ensureResolved(compiler); |
| 1702 jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed'); |
| 1703 jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast'); |
| 1704 jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add'); |
| 1705 |
| 1706 jsStringClass.ensureResolved(compiler); |
| 1707 jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split'); |
| 1708 jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+'); |
| 1709 jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString'); |
| 1710 |
| 1711 objectEquals = compiler.lookupElementIn(compiler.objectClass, '=='); |
| 1712 |
| 1713 specialOperatorEqClasses |
| 1714 ..add(compiler.objectClass) |
| 1715 ..add(jsInterceptorClass) |
| 1716 ..add(jsNullClass); |
| 1717 |
| 1718 indexablePrimitiveType = new TypeMask.nonNullSubtype(jsIndexableClass); |
| 1719 readableArrayType = new TypeMask.nonNullSubclass(jsArrayClass); |
| 1720 mutableArrayType = new TypeMask.nonNullSubclass(jsMutableArrayClass); |
| 1721 fixedArrayType = new TypeMask.nonNullExact(jsFixedArrayClass); |
| 1722 extendableArrayType = new TypeMask.nonNullExact(jsExtendableArrayClass); |
| 1723 nonNullType = compiler.typesTask.dynamicType.nonNullable(); |
| 1724 |
| 1725 validateInterceptorImplementsAllObjectMethods(jsInterceptorClass); |
| 1726 // The null-interceptor must also implement *all* methods. |
| 1727 validateInterceptorImplementsAllObjectMethods(jsNullClass); |
1707 return new Future.value(); | 1728 return new Future.value(); |
1708 } | 1729 } |
1709 | 1730 |
1710 void registerMirrorUsage(Set<String> symbols, | 1731 void registerMirrorUsage(Set<String> symbols, |
1711 Set<Element> targets, | 1732 Set<Element> targets, |
1712 Set<Element> metaTargets) { | 1733 Set<Element> metaTargets) { |
1713 if (symbols == null && targets == null && metaTargets == null) { | 1734 if (symbols == null && targets == null && metaTargets == null) { |
1714 // The user didn't specify anything, or there are imports of | 1735 // The user didn't specify anything, or there are imports of |
1715 // 'dart:mirrors' without @MirrorsUsed. | 1736 // 'dart:mirrors' without @MirrorsUsed. |
1716 hasInsufficientMirrorsUsed = true; | 1737 hasInsufficientMirrorsUsed = true; |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1955 } | 1976 } |
1956 | 1977 |
1957 /// Records that [constant] is used by the element behind [registry]. | 1978 /// Records that [constant] is used by the element behind [registry]. |
1958 class Dependency { | 1979 class Dependency { |
1959 final Constant constant; | 1980 final Constant constant; |
1960 // TODO(johnniwinther): Change to [Element] when dependency nodes are added. | 1981 // TODO(johnniwinther): Change to [Element] when dependency nodes are added. |
1961 final Registry registry; | 1982 final Registry registry; |
1962 | 1983 |
1963 const Dependency(this.constant, this.registry); | 1984 const Dependency(this.constant, this.registry); |
1964 } | 1985 } |
OLD | NEW |