| 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 library dart2js.js_emitter.program_builder; | 5 library dart2js.js_emitter.program_builder; |
| 6 | 6 |
| 7 import '../../closure.dart' show ClosureFieldElement; | 7 import '../../closure.dart' show ClosureFieldElement; |
| 8 import '../../common.dart'; | 8 import '../../common.dart'; |
| 9 import '../../common/names.dart' show Names, Selectors; | 9 import '../../common/names.dart' show Names, Selectors; |
| 10 import '../../compiler.dart' show Compiler; | 10 import '../../compiler.dart' show Compiler; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 ParameterElement, | 27 ParameterElement, |
| 28 TypedefElement, | 28 TypedefElement, |
| 29 VariableElement; | 29 VariableElement; |
| 30 import '../../js/js.dart' as js; | 30 import '../../js/js.dart' as js; |
| 31 import '../../js_backend/backend_helpers.dart' show BackendHelpers; | 31 import '../../js_backend/backend_helpers.dart' show BackendHelpers; |
| 32 import '../../js_backend/js_backend.dart' | 32 import '../../js_backend/js_backend.dart' |
| 33 show Namer, JavaScriptBackend, JavaScriptConstantCompiler, StringBackedName; | 33 show Namer, JavaScriptBackend, JavaScriptConstantCompiler, StringBackedName; |
| 34 import '../../universe/selector.dart' show Selector; | 34 import '../../universe/selector.dart' show Selector; |
| 35 import '../../universe/world_builder.dart' | 35 import '../../universe/world_builder.dart' |
| 36 show CodegenWorldBuilder, SelectorConstraints; | 36 show CodegenWorldBuilder, SelectorConstraints; |
| 37 import '../../world.dart' show ClosedWorld; |
| 37 import '../js_emitter.dart' | 38 import '../js_emitter.dart' |
| 38 show | 39 show |
| 39 ClassStubGenerator, | 40 ClassStubGenerator, |
| 40 CodeEmitterTask, | 41 CodeEmitterTask, |
| 41 computeMixinClass, | 42 computeMixinClass, |
| 42 Emitter, | 43 Emitter, |
| 43 InterceptorStubGenerator, | 44 InterceptorStubGenerator, |
| 44 MainCallStubGenerator, | 45 MainCallStubGenerator, |
| 45 ParameterStubGenerator, | 46 ParameterStubGenerator, |
| 46 RuntimeTypeGenerator, | 47 RuntimeTypeGenerator, |
| 47 TypeTestProperties; | 48 TypeTestProperties; |
| 48 import '../model.dart'; | 49 import '../model.dart'; |
| 49 | 50 |
| 50 part 'collector.dart'; | 51 part 'collector.dart'; |
| 51 part 'field_visitor.dart'; | 52 part 'field_visitor.dart'; |
| 52 part 'registry.dart'; | 53 part 'registry.dart'; |
| 53 | 54 |
| 54 /// Builds a self-contained representation of the program that can then be | 55 /// Builds a self-contained representation of the program that can then be |
| 55 /// emitted more easily by the individual emitters. | 56 /// emitted more easily by the individual emitters. |
| 56 class ProgramBuilder { | 57 class ProgramBuilder { |
| 57 final Compiler _compiler; | 58 final Compiler _compiler; |
| 58 final Namer namer; | 59 final Namer namer; |
| 59 final CodeEmitterTask _task; | 60 final CodeEmitterTask _task; |
| 61 final ClosedWorld closedWorld; |
| 60 | 62 |
| 61 /// Contains the collected information the program builder used to build | 63 /// Contains the collected information the program builder used to build |
| 62 /// the model. | 64 /// the model. |
| 63 // The collector will be filled on the first call to `buildProgram`. | 65 // The collector will be filled on the first call to `buildProgram`. |
| 64 // It is stored and publicly exposed for backwards compatibility. New code | 66 // It is stored and publicly exposed for backwards compatibility. New code |
| 65 // (and in particular new emitters) should not use it. | 67 // (and in particular new emitters) should not use it. |
| 66 final Collector collector; | 68 final Collector collector; |
| 67 | 69 |
| 68 final Registry _registry; | 70 final Registry _registry; |
| 69 | 71 |
| 70 /// True if the program should store function types in the metadata. | 72 /// True if the program should store function types in the metadata. |
| 71 bool _storeFunctionTypesInMetadata = false; | 73 bool _storeFunctionTypesInMetadata = false; |
| 72 | 74 |
| 73 ProgramBuilder(Compiler compiler, Namer namer, this._task, Emitter emitter, | 75 ProgramBuilder(Compiler compiler, Namer namer, this._task, Emitter emitter, |
| 74 Set<ClassElement> rtiNeededClasses) | 76 ClosedWorld closedWorld, Set<ClassElement> rtiNeededClasses) |
| 75 : this._compiler = compiler, | 77 : this._compiler = compiler, |
| 76 this.namer = namer, | 78 this.namer = namer, |
| 77 this.collector = | 79 this.closedWorld = closedWorld, |
| 78 new Collector(compiler, namer, rtiNeededClasses, emitter), | 80 this.collector = new Collector( |
| 81 compiler, namer, closedWorld, rtiNeededClasses, emitter), |
| 79 this._registry = new Registry(compiler); | 82 this._registry = new Registry(compiler); |
| 80 | 83 |
| 81 JavaScriptBackend get backend => _compiler.backend; | 84 JavaScriptBackend get backend => _compiler.backend; |
| 82 BackendHelpers get helpers => backend.helpers; | 85 BackendHelpers get helpers => backend.helpers; |
| 83 CodegenWorldBuilder get universe => _compiler.codegenWorld; | 86 CodegenWorldBuilder get universe => _compiler.codegenWorld; |
| 84 | 87 |
| 85 /// Mapping from [ClassElement] to constructed [Class]. We need this to | 88 /// Mapping from [ClassElement] to constructed [Class]. We need this to |
| 86 /// update the superclass in the [Class]. | 89 /// update the superclass in the [Class]. |
| 87 final Map<ClassElement, Class> _classes = <ClassElement, Class>{}; | 90 final Map<ClassElement, Class> _classes = <ClassElement, Class>{}; |
| 88 | 91 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 .forEach((String loadId, List<OutputUnit> outputUnits) { | 201 .forEach((String loadId, List<OutputUnit> outputUnits) { |
| 199 loadMap[loadId] = outputUnits | 202 loadMap[loadId] = outputUnits |
| 200 .map((OutputUnit unit) => _outputs[unit]) | 203 .map((OutputUnit unit) => _outputs[unit]) |
| 201 .toList(growable: false); | 204 .toList(growable: false); |
| 202 }); | 205 }); |
| 203 return loadMap; | 206 return loadMap; |
| 204 } | 207 } |
| 205 | 208 |
| 206 js.Expression _buildTypeToInterceptorMap() { | 209 js.Expression _buildTypeToInterceptorMap() { |
| 207 InterceptorStubGenerator stubGenerator = | 210 InterceptorStubGenerator stubGenerator = |
| 208 new InterceptorStubGenerator(_compiler, namer, backend); | 211 new InterceptorStubGenerator(_compiler, namer, backend, closedWorld); |
| 209 return stubGenerator.generateTypeToInterceptorMap(); | 212 return stubGenerator.generateTypeToInterceptorMap(); |
| 210 } | 213 } |
| 211 | 214 |
| 212 MainFragment _buildMainFragment(LibrariesMap librariesMap) { | 215 MainFragment _buildMainFragment(LibrariesMap librariesMap) { |
| 213 // Construct the main output from the libraries and the registered holders. | 216 // Construct the main output from the libraries and the registered holders. |
| 214 MainFragment result = new MainFragment( | 217 MainFragment result = new MainFragment( |
| 215 librariesMap.outputUnit, | 218 librariesMap.outputUnit, |
| 216 "", // The empty string is the name for the main output file. | 219 "", // The empty string is the name for the main output file. |
| 217 _buildInvokeMain(), | 220 _buildInvokeMain(), |
| 218 _buildLibraries(librariesMap), | 221 _buildLibraries(librariesMap), |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 bool hasRtiField = backend.classNeedsRtiField(element); | 513 bool hasRtiField = backend.classNeedsRtiField(element); |
| 511 if (backend.isJsInterop(element)) { | 514 if (backend.isJsInterop(element)) { |
| 512 // TODO(jacobr): check whether the class has any active static fields | 515 // TODO(jacobr): check whether the class has any active static fields |
| 513 // if it does not we can suppress it completely. | 516 // if it does not we can suppress it completely. |
| 514 onlyForRti = true; | 517 onlyForRti = true; |
| 515 } | 518 } |
| 516 | 519 |
| 517 List<Method> methods = []; | 520 List<Method> methods = []; |
| 518 List<StubMethod> callStubs = <StubMethod>[]; | 521 List<StubMethod> callStubs = <StubMethod>[]; |
| 519 | 522 |
| 520 ClassStubGenerator classStubGenerator = | 523 ClassStubGenerator classStubGenerator = new ClassStubGenerator( |
| 521 new ClassStubGenerator(_compiler, namer, backend); | 524 namer, backend, universe, closedWorld, |
| 525 enableMinification: _compiler.options.enableMinification); |
| 522 RuntimeTypeGenerator runtimeTypeGenerator = | 526 RuntimeTypeGenerator runtimeTypeGenerator = |
| 523 new RuntimeTypeGenerator(_compiler, _task, namer); | 527 new RuntimeTypeGenerator(_compiler, _task, namer); |
| 524 | 528 |
| 525 void visitMember(ClassElement enclosing, Element member) { | 529 void visitMember(ClassElement enclosing, Element member) { |
| 526 assert(invariant(element, member.isDeclaration)); | 530 assert(invariant(element, member.isDeclaration)); |
| 527 assert(invariant(element, element == enclosing)); | 531 assert(invariant(element, element == enclosing)); |
| 528 | 532 |
| 529 if (Elements.isNonAbstractInstanceMember(member)) { | 533 if (Elements.isNonAbstractInstanceMember(member)) { |
| 530 // TODO(herhut): Remove once _buildMethod can no longer return null. | 534 // TODO(herhut): Remove once _buildMethod can no longer return null. |
| 531 Method method = _buildMethod(member); | 535 Method method = _buildMethod(member); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 | 673 |
| 670 bool _methodCanBeReflected(FunctionElement method) { | 674 bool _methodCanBeReflected(FunctionElement method) { |
| 671 return backend.isAccessibleByReflection(method) || | 675 return backend.isAccessibleByReflection(method) || |
| 672 // During incremental compilation, we have to assume that reflection | 676 // During incremental compilation, we have to assume that reflection |
| 673 // *might* get enabled. | 677 // *might* get enabled. |
| 674 _compiler.options.hasIncrementalSupport; | 678 _compiler.options.hasIncrementalSupport; |
| 675 } | 679 } |
| 676 | 680 |
| 677 bool _methodCanBeApplied(FunctionElement method) { | 681 bool _methodCanBeApplied(FunctionElement method) { |
| 678 return backend.hasFunctionApplySupport && | 682 return backend.hasFunctionApplySupport && |
| 679 _compiler.closedWorld.getMightBePassedToApply(method); | 683 closedWorld.getMightBePassedToApply(method); |
| 680 } | 684 } |
| 681 | 685 |
| 682 // TODO(herhut): Refactor incremental compilation and remove method. | 686 // TODO(herhut): Refactor incremental compilation and remove method. |
| 683 Method buildMethodHackForIncrementalCompilation(FunctionElement element) { | 687 Method buildMethodHackForIncrementalCompilation(FunctionElement element) { |
| 684 assert(_compiler.options.hasIncrementalSupport); | 688 assert(_compiler.options.hasIncrementalSupport); |
| 685 if (element.isInstanceMember) { | 689 if (element.isInstanceMember) { |
| 686 return _buildMethod(element); | 690 return _buildMethod(element); |
| 687 } else { | 691 } else { |
| 688 return _buildStaticMethod(element); | 692 return _buildStaticMethod(element); |
| 689 } | 693 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 : null; | 733 : null; |
| 730 | 734 |
| 731 if (isNotApplyTarget) { | 735 if (isNotApplyTarget) { |
| 732 canTearOff = false; | 736 canTearOff = false; |
| 733 } else { | 737 } else { |
| 734 if (element.enclosingClass.isClosure) { | 738 if (element.enclosingClass.isClosure) { |
| 735 canTearOff = false; | 739 canTearOff = false; |
| 736 isClosureCallMethod = true; | 740 isClosureCallMethod = true; |
| 737 } else { | 741 } else { |
| 738 // Careful with operators. | 742 // Careful with operators. |
| 739 canTearOff = | 743 canTearOff = universe.hasInvokedGetter(element, closedWorld) || |
| 740 universe.hasInvokedGetter(element, _compiler.closedWorld) || | 744 (canBeReflected && !element.isOperator); |
| 741 (canBeReflected && !element.isOperator); | |
| 742 assert(canTearOff || | 745 assert(canTearOff || |
| 743 !universe.methodsNeedingSuperGetter.contains(element)); | 746 !universe.methodsNeedingSuperGetter.contains(element)); |
| 744 tearOffName = namer.getterForElement(element); | 747 tearOffName = namer.getterForElement(element); |
| 745 } | 748 } |
| 746 } | 749 } |
| 747 | 750 |
| 748 if (canTearOff) { | 751 if (canTearOff) { |
| 749 assert(invariant(element, !element.isGenerativeConstructor)); | 752 assert(invariant(element, !element.isGenerativeConstructor)); |
| 750 assert(invariant(element, !element.isGenerativeConstructorBody)); | 753 assert(invariant(element, !element.isGenerativeConstructorBody)); |
| 751 assert(invariant(element, !element.isConstructor)); | 754 assert(invariant(element, !element.isConstructor)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 806 return backend.emitter.metadataCollector | 809 return backend.emitter.metadataCollector |
| 807 .reifyTypeForOutputUnit(type, outputUnit); | 810 .reifyTypeForOutputUnit(type, outputUnit); |
| 808 } | 811 } |
| 809 } | 812 } |
| 810 | 813 |
| 811 List<ParameterStubMethod> _generateParameterStubs( | 814 List<ParameterStubMethod> _generateParameterStubs( |
| 812 MethodElement element, bool canTearOff) { | 815 MethodElement element, bool canTearOff) { |
| 813 if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[]; | 816 if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[]; |
| 814 | 817 |
| 815 ParameterStubGenerator generator = | 818 ParameterStubGenerator generator = |
| 816 new ParameterStubGenerator(_compiler, namer, backend); | 819 new ParameterStubGenerator(_compiler, namer, backend, closedWorld); |
| 817 return generator.generateParameterStubs(element, canTearOff: canTearOff); | 820 return generator.generateParameterStubs(element, canTearOff: canTearOff); |
| 818 } | 821 } |
| 819 | 822 |
| 820 /// Builds a stub method. | 823 /// Builds a stub method. |
| 821 /// | 824 /// |
| 822 /// Stub methods may have an element that can be used for code-size | 825 /// Stub methods may have an element that can be used for code-size |
| 823 /// attribution. | 826 /// attribution. |
| 824 Method _buildStubMethod(js.Name name, js.Expression code, {Element element}) { | 827 Method _buildStubMethod(js.Name name, js.Expression code, {Element element}) { |
| 825 return new StubMethod(name, code, element: element); | 828 return new StubMethod(name, code, element: element); |
| 826 } | 829 } |
| 827 | 830 |
| 828 // The getInterceptor methods directly access the prototype of classes. | 831 // The getInterceptor methods directly access the prototype of classes. |
| 829 // We must evaluate these classes eagerly so that the prototype is | 832 // We must evaluate these classes eagerly so that the prototype is |
| 830 // accessible. | 833 // accessible. |
| 831 void _markEagerInterceptorClasses() { | 834 void _markEagerInterceptorClasses() { |
| 832 Map<js.Name, Set<ClassElement>> specializedGetInterceptors = | 835 Map<js.Name, Set<ClassElement>> specializedGetInterceptors = |
| 833 backend.specializedGetInterceptors; | 836 backend.specializedGetInterceptors; |
| 834 for (Set<ClassElement> classes in specializedGetInterceptors.values) { | 837 for (Set<ClassElement> classes in specializedGetInterceptors.values) { |
| 835 for (ClassElement element in classes) { | 838 for (ClassElement element in classes) { |
| 836 Class cls = _classes[element]; | 839 Class cls = _classes[element]; |
| 837 if (cls != null) cls.isEager = true; | 840 if (cls != null) cls.isEager = true; |
| 838 } | 841 } |
| 839 } | 842 } |
| 840 } | 843 } |
| 841 | 844 |
| 842 Iterable<StaticStubMethod> _generateGetInterceptorMethods() { | 845 Iterable<StaticStubMethod> _generateGetInterceptorMethods() { |
| 843 InterceptorStubGenerator stubGenerator = | 846 InterceptorStubGenerator stubGenerator = |
| 844 new InterceptorStubGenerator(_compiler, namer, backend); | 847 new InterceptorStubGenerator(_compiler, namer, backend, closedWorld); |
| 845 | 848 |
| 846 String holderName = namer.globalObjectFor(helpers.interceptorsLibrary); | 849 String holderName = namer.globalObjectFor(helpers.interceptorsLibrary); |
| 847 // TODO(floitsch): we shouldn't update the registry in the middle of | 850 // TODO(floitsch): we shouldn't update the registry in the middle of |
| 848 // generating the interceptor methods. | 851 // generating the interceptor methods. |
| 849 Holder holder = _registry.registerHolder(holderName); | 852 Holder holder = _registry.registerHolder(holderName); |
| 850 | 853 |
| 851 Map<js.Name, Set<ClassElement>> specializedGetInterceptors = | 854 Map<js.Name, Set<ClassElement>> specializedGetInterceptors = |
| 852 backend.specializedGetInterceptors; | 855 backend.specializedGetInterceptors; |
| 853 List<js.Name> names = specializedGetInterceptors.keys.toList()..sort(); | 856 List<js.Name> names = specializedGetInterceptors.keys.toList()..sort(); |
| 854 return names.map((js.Name name) { | 857 return names.map((js.Name name) { |
| 855 Set<ClassElement> classes = specializedGetInterceptors[name]; | 858 Set<ClassElement> classes = specializedGetInterceptors[name]; |
| 856 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); | 859 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes); |
| 857 return new StaticStubMethod(name, holder, code); | 860 return new StaticStubMethod(name, holder, code); |
| 858 }); | 861 }); |
| 859 } | 862 } |
| 860 | 863 |
| 861 List<Field> _buildFields(Element holder, bool visitStatics) { | 864 List<Field> _buildFields(Element holder, bool visitStatics) { |
| 862 List<Field> fields = <Field>[]; | 865 List<Field> fields = <Field>[]; |
| 863 new FieldVisitor(_compiler, namer).visitFields(holder, visitStatics, | 866 new FieldVisitor(_compiler, namer, closedWorld) |
| 864 (VariableElement field, js.Name name, js.Name accessorName, | 867 .visitFields(holder, visitStatics, (VariableElement field, |
| 865 bool needsGetter, bool needsSetter, bool needsCheckedSetter) { | 868 js.Name name, |
| 869 js.Name accessorName, |
| 870 bool needsGetter, |
| 871 bool needsSetter, |
| 872 bool needsCheckedSetter) { |
| 866 assert(invariant(field, field.isDeclaration)); | 873 assert(invariant(field, field.isDeclaration)); |
| 867 | 874 |
| 868 int getterFlags = 0; | 875 int getterFlags = 0; |
| 869 if (needsGetter) { | 876 if (needsGetter) { |
| 870 if (visitStatics || !backend.fieldHasInterceptedGetter(field)) { | 877 if (visitStatics || !backend.fieldHasInterceptedGetter(field)) { |
| 871 getterFlags = 1; | 878 getterFlags = 1; |
| 872 } else { | 879 } else { |
| 873 getterFlags += 2; | 880 getterFlags += 2; |
| 874 // TODO(sra): 'isInterceptorClass' might not be the correct test | 881 // TODO(sra): 'isInterceptorClass' might not be the correct test |
| 875 // for methods forced to use the interceptor convention because | 882 // for methods forced to use the interceptor convention because |
| (...skipping 18 matching lines...) Expand all Loading... |
| 894 | 901 |
| 895 fields.add(new Field(field, name, accessorName, getterFlags, setterFlags, | 902 fields.add(new Field(field, name, accessorName, getterFlags, setterFlags, |
| 896 needsCheckedSetter)); | 903 needsCheckedSetter)); |
| 897 }); | 904 }); |
| 898 | 905 |
| 899 return fields; | 906 return fields; |
| 900 } | 907 } |
| 901 | 908 |
| 902 Iterable<StaticStubMethod> _generateOneShotInterceptors() { | 909 Iterable<StaticStubMethod> _generateOneShotInterceptors() { |
| 903 InterceptorStubGenerator stubGenerator = | 910 InterceptorStubGenerator stubGenerator = |
| 904 new InterceptorStubGenerator(_compiler, namer, backend); | 911 new InterceptorStubGenerator(_compiler, namer, backend, closedWorld); |
| 905 | 912 |
| 906 String holderName = namer.globalObjectFor(helpers.interceptorsLibrary); | 913 String holderName = namer.globalObjectFor(helpers.interceptorsLibrary); |
| 907 // TODO(floitsch): we shouldn't update the registry in the middle of | 914 // TODO(floitsch): we shouldn't update the registry in the middle of |
| 908 // generating the interceptor methods. | 915 // generating the interceptor methods. |
| 909 Holder holder = _registry.registerHolder(holderName); | 916 Holder holder = _registry.registerHolder(holderName); |
| 910 | 917 |
| 911 List<js.Name> names = backend.oneShotInterceptors.keys.toList()..sort(); | 918 List<js.Name> names = backend.oneShotInterceptors.keys.toList()..sort(); |
| 912 return names.map((js.Name name) { | 919 return names.map((js.Name name) { |
| 913 js.Expression code = stubGenerator.generateOneShotInterceptor(name); | 920 js.Expression code = stubGenerator.generateOneShotInterceptor(name); |
| 914 return new StaticStubMethod(name, holder, code); | 921 return new StaticStubMethod(name, holder, code); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 981 Constant constant = new Constant(name, holder, constantValue); | 988 Constant constant = new Constant(name, holder, constantValue); |
| 982 _constants[constantValue] = constant; | 989 _constants[constantValue] = constant; |
| 983 } | 990 } |
| 984 } | 991 } |
| 985 | 992 |
| 986 Holder _registerStaticStateHolder() { | 993 Holder _registerStaticStateHolder() { |
| 987 return _registry.registerHolder(namer.staticStateHolder, | 994 return _registry.registerHolder(namer.staticStateHolder, |
| 988 isStaticStateHolder: true); | 995 isStaticStateHolder: true); |
| 989 } | 996 } |
| 990 } | 997 } |
| OLD | NEW |