OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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.ir_builder_task; | 5 library dart2js.ir_builder_task; |
6 | 6 |
7 import '../closure.dart' as closurelib; | 7 import '../closure.dart' as closurelib; |
8 import '../closure.dart' hide ClosureScope; | 8 import '../closure.dart' hide ClosureScope; |
9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
11 import '../dart2jslib.dart'; | 11 import '../dart2jslib.dart'; |
12 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
13 import '../elements/modelx.dart' show SynthesizedConstructorElementX, | 13 import '../elements/modelx.dart' show SynthesizedConstructorElementX, |
14 ConstructorBodyElementX, FunctionSignatureX; | 14 ConstructorBodyElementX, FunctionSignatureX; |
15 import '../io/source_information.dart'; | 15 import '../io/source_information.dart'; |
16 import '../js_backend/js_backend.dart' show JavaScriptBackend; | 16 import '../js_backend/js_backend.dart' show JavaScriptBackend; |
17 import '../resolution/semantic_visitor.dart'; | 17 import '../resolution/semantic_visitor.dart'; |
18 import '../resolution/operators.dart' as op; | 18 import '../resolution/operators.dart' as op; |
19 import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator; | 19 import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator; |
20 import '../tree/tree.dart' as ast; | 20 import '../tree/tree.dart' as ast; |
21 import '../universe/universe.dart' show SelectorKind, CallStructure; | 21 import '../universe/universe.dart' show SelectorKind, CallStructure; |
22 import 'cps_ir_nodes.dart' as ir; | 22 import 'cps_ir_nodes.dart' as ir; |
23 import 'cps_ir_builder.dart'; | 23 import 'cps_ir_builder.dart'; |
24 import '../native/native.dart' show NativeBehavior; | |
25 | |
26 // TODO(karlklose): remove. | |
27 import '../js/js.dart' as js show js, Template, Expression; | |
28 import '../ssa/ssa.dart' show TypeMaskFactory; | |
29 import '../types/types.dart' show TypeMask; | |
30 import '../util/util.dart'; | |
31 | |
32 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' | |
33 show JsBuiltin, JsGetName; | |
34 import '../constants/values.dart'; | |
24 | 35 |
25 typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode); | 36 typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode); |
26 | 37 |
27 /// This task provides the interface to build IR nodes from [ast.Node]s, which | 38 /// This task provides the interface to build IR nodes from [ast.Node]s, which |
28 /// is used from the [CpsFunctionCompiler] to generate code. | 39 /// is used from the [CpsFunctionCompiler] to generate code. |
29 /// | 40 /// |
30 /// This class is mainly there to correctly measure how long building the IR | 41 /// This class is mainly there to correctly measure how long building the IR |
31 /// takes. | 42 /// takes. |
32 class IrBuilderTask extends CompilerTask { | 43 class IrBuilderTask extends CompilerTask { |
33 final SourceInformationFactory sourceInformationFactory; | 44 final SourceInformationFactory sourceInformationFactory; |
(...skipping 953 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
987 callStructure, | 998 callStructure, |
988 translateDynamicArguments(arguments, callStructure)); | 999 translateDynamicArguments(arguments, callStructure)); |
989 } | 1000 } |
990 | 1001 |
991 @override | 1002 @override |
992 ir.Primitive handleStaticFunctionInvoke( | 1003 ir.Primitive handleStaticFunctionInvoke( |
993 ast.Send node, | 1004 ast.Send node, |
994 MethodElement function, | 1005 MethodElement function, |
995 ast.NodeList arguments, | 1006 ast.NodeList arguments, |
996 CallStructure callStructure, | 1007 CallStructure callStructure, |
997 _) { | 1008 _); |
998 // TODO(karlklose): support foreign functions. | |
999 if (compiler.backend.isForeign(function)) { | |
1000 return giveup(node, 'handleStaticFunctionInvoke: foreign: $function'); | |
1001 } | |
1002 return irBuilder.buildStaticFunctionInvocation(function, callStructure, | |
1003 translateStaticArguments(arguments, function, callStructure), | |
1004 sourceInformation: sourceInformationBuilder.buildCall(node)); | |
1005 } | |
1006 | 1009 |
1007 @override | 1010 @override |
1008 ir.Primitive handleStaticFunctionIncompatibleInvoke( | 1011 ir.Primitive handleStaticFunctionIncompatibleInvoke( |
1009 ast.Send node, | 1012 ast.Send node, |
1010 MethodElement function, | 1013 MethodElement function, |
1011 ast.NodeList arguments, | 1014 ast.NodeList arguments, |
1012 CallStructure callStructure, _) { | 1015 CallStructure callStructure, _) { |
1013 return buildStaticNoSuchMethod( | 1016 return buildStaticNoSuchMethod( |
1014 elements.getSelector(node), | 1017 elements.getSelector(node), |
1015 arguments.nodes.mapToList(visit)); | 1018 arguments.nodes.mapToList(visit)); |
(...skipping 838 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1854 try { | 1857 try { |
1855 return action(); | 1858 return action(); |
1856 } catch(e) { | 1859 } catch(e) { |
1857 if (e == ABORT_IRNODE_BUILDER) { | 1860 if (e == ABORT_IRNODE_BUILDER) { |
1858 return null; | 1861 return null; |
1859 } | 1862 } |
1860 rethrow; | 1863 rethrow; |
1861 } | 1864 } |
1862 } | 1865 } |
1863 | 1866 |
1864 void internalError(ast.Node node, String message) { | 1867 internalError(ast.Node node, String message) { |
1865 giveup(node, message); | 1868 giveup(node, message); |
1866 } | 1869 } |
1867 | 1870 |
1868 @override | 1871 @override |
1869 visitNode(ast.Node node) { | 1872 visitNode(ast.Node node) { |
1870 internalError(node, "Unhandled node"); | 1873 internalError(node, "Unhandled node"); |
1871 } | 1874 } |
1872 | 1875 |
1873 dynamic giveup(ast.Node node, [String reason]) { | 1876 dynamic giveup(ast.Node node, [String reason]) { |
1874 bailoutMessage = '($node): $reason'; | 1877 bailoutMessage = '($node): $reason'; |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2047 | 2050 |
2048 /// Returns [true], if the analysis could not determine that the type | 2051 /// Returns [true], if the analysis could not determine that the type |
2049 /// arguments for the class [cls] are never used in the program. | 2052 /// arguments for the class [cls] are never used in the program. |
2050 bool requiresRuntimeTypesFor(ClassElement cls) { | 2053 bool requiresRuntimeTypesFor(ClassElement cls) { |
2051 return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls); | 2054 return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls); |
2052 } | 2055 } |
2053 | 2056 |
2054 FunctionElement get throwTypeErrorHelper => _backend.getThrowTypeError(); | 2057 FunctionElement get throwTypeErrorHelper => _backend.getThrowTypeError(); |
2055 | 2058 |
2056 ClassElement get nullClass => _compiler.nullClass; | 2059 ClassElement get nullClass => _compiler.nullClass; |
2060 | |
2061 TypeMask getTypeMaskForForeign(NativeBehavior behavior) { | |
2062 return TypeMaskFactory.fromNativeBehavior(behavior, _compiler); | |
2063 } | |
2057 } | 2064 } |
2058 | 2065 |
2059 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder]. | 2066 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder]. |
2060 class JsIrBuilderVisitor extends IrBuilderVisitor { | 2067 class JsIrBuilderVisitor extends IrBuilderVisitor { |
2061 /// Promote the type of [irBuilder] to [JsIrBuilder]. | 2068 /// Promote the type of [irBuilder] to [JsIrBuilder]. |
2062 JsIrBuilder get irBuilder => super.irBuilder; | 2069 JsIrBuilder get irBuilder => super.irBuilder; |
2063 | 2070 |
2064 JavaScriptBackend get backend => compiler.backend; | 2071 JavaScriptBackend get backend => compiler.backend; |
2065 | 2072 |
2066 /// Result of closure conversion for the current body of code. | 2073 /// Result of closure conversion for the current body of code. |
(...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2798 ConstantExpression constant = | 2805 ConstantExpression constant = |
2799 backend.constants.getConstantForVariable(field); | 2806 backend.constants.getConstantForVariable(field); |
2800 if (constant != null && !field.isAssignable) { | 2807 if (constant != null && !field.isAssignable) { |
2801 return buildConstant(constant); | 2808 return buildConstant(constant); |
2802 } else if (backend.constants.lazyStatics.contains(field)) { | 2809 } else if (backend.constants.lazyStatics.contains(field)) { |
2803 return irBuilder.buildStaticFieldLazyGet(field, src); | 2810 return irBuilder.buildStaticFieldLazyGet(field, src); |
2804 } else { | 2811 } else { |
2805 return irBuilder.buildStaticFieldGet(field, src); | 2812 return irBuilder.buildStaticFieldGet(field, src); |
2806 } | 2813 } |
2807 } | 2814 } |
2815 | |
2816 /// Build code to handle foreign code, that is, native JavaScript code, or | |
2817 /// builtin values and operations of the backend. | |
2818 ir.Primitive handleForeignSend(ast.Send node, | |
2819 MethodElement function, | |
2820 Link<ast.Node> argumentNodes, | |
2821 CallStructure callStructure) { | |
2822 | |
2823 void validateArgumentCount({int minimum, int exactly}) { | |
2824 assert((minimum == null) != (exactly == null)); | |
2825 int count = 0; | |
2826 if (exactly != null) { | |
2827 minimum = exactly; | |
2828 } | |
2829 for (Link<ast.Node> arguments = argumentNodes; | |
Kevin Millikin (Google)
2015/06/16 11:23:10
I'd make argumentNodes a NodeList (to avoid exposi
karlklose
2015/06/18 09:38:14
Done.
| |
2830 !arguments.isEmpty; | |
2831 arguments = arguments.tail) { | |
2832 count++; | |
2833 if (exactly != null && count > exactly) { | |
2834 internalError(arguments.head, 'Additional argument.'); | |
2835 } | |
2836 } | |
2837 if (minimum != null && count < minimum) { | |
Kevin Millikin (Google)
2015/06/16 11:23:10
minimum should always be non-null.
karlklose
2015/06/18 09:38:14
Done.
| |
2838 internalError(node, 'Expected at least $minimum arguments.'); | |
2839 } | |
2840 } | |
2841 | |
2842 /// Call a helper method from the isolate library. The isolate library uses | |
2843 /// its own isolate structure, that encapsulates dart2js's isolate. | |
2844 ir.Primitive buildIsolateHelperInvocation(String helperName, | |
2845 CallStructure callStructure, | |
2846 Link<ast.Node> argumentNodes) { | |
Kevin Millikin (Google)
2015/06/16 11:23:10
argumentNodes is unused in this function.
karlklose
2015/06/18 09:38:14
Done.
| |
2847 Element element = backend.isolateHelperLibrary.find(helperName); | |
2848 if (element == null) { | |
2849 compiler.internalError(node, | |
2850 'Isolate library and compiler mismatch.'); | |
2851 } | |
2852 List<ir.Primitive> arguments = translateStaticArguments( | |
2853 node.argumentsNode, element, CallStructure.TWO_ARGS); | |
Kevin Millikin (Google)
2015/06/16 11:23:10
This uses the arguments NodeList off the Send. It
karlklose
2015/06/18 09:38:14
Done.
| |
2854 return irBuilder.buildStaticFunctionInvocation(element, | |
2855 CallStructure.TWO_ARGS, arguments, | |
2856 sourceInformation: sourceInformationBuilder.buildCall(node)); | |
2857 } | |
2858 | |
2859 /// Lookup the value of the enum described by [node]. | |
2860 getEnumValue(ast.Node node, EnumClassElement enumClass, List values) { | |
2861 Element element = elements[node]; | |
2862 if (element is! FieldElement || element.enclosingClass != enumClass) { | |
2863 internalError(node, 'expected a JsBuiltin enum value'); | |
2864 } | |
2865 | |
2866 int index = enumClass.enumValues.indexOf(element); | |
2867 return values[index]; | |
2868 } | |
2869 | |
2870 /// Returns the String the node evaluates to, or throws an error if the | |
2871 /// result is not a string constant. | |
2872 String expectStringConstant(ast.Node node) { | |
2873 ir.Primitive nameValue = visit(node); | |
2874 if (nameValue is ir.Constant && nameValue.value.isString) { | |
2875 StringConstantValue constantValue = nameValue.value; | |
2876 return constantValue.primitiveValue.slowToString(); | |
2877 } else { | |
2878 return internalError(node, 'expected a literal string'); | |
2879 } | |
2880 } | |
2881 | |
2882 NativeBehavior behavior = | |
2883 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | |
2884 switch (function.name) { | |
2885 case 'JS': | |
2886 validateArgumentCount(minimum: 2); | |
2887 // The first two arguments are the type and the foreign code template, | |
2888 // which already have been analyzed by the resolver and can be retrieved | |
2889 // using [NativeBehavior]. We can ignore these arguments in the backend. | |
2890 List<ir.Primitive> arguments = | |
2891 argumentNodes.skip(2).mapToList(visit, growable: false); | |
2892 return irBuilder.buildForeignCode(behavior.codeTemplate, arguments, | |
2893 behavior); | |
2894 | |
2895 case 'DART_CLOSURE_TO_JS': | |
2896 // TODO(ahe): This should probably take care to wrap the closure in | |
2897 // another closure that saves the current isolate. | |
2898 case 'RAW_DART_FUNCTION_REF': | |
2899 validateArgumentCount(exactly: 1); | |
2900 | |
2901 ast.Node argument = node.arguments.single; | |
2902 FunctionElement closure = elements[argument].implementation; | |
2903 if (!Elements.isStaticOrTopLevelFunction(closure)) { | |
2904 internalError(argument, | |
2905 'only static or toplevel function supported'); | |
2906 } | |
2907 if (closure.functionSignature.hasOptionalParameters) { | |
2908 internalError(argument, | |
2909 'closures with optional parameters not supported'); | |
2910 } | |
2911 return irBuilder.buildForeignCode( | |
2912 js.js.expressionTemplateYielding( | |
2913 backend.emitter.staticFunctionAccess(function)), | |
2914 <ir.Primitive>[], | |
2915 NativeBehavior.PURE, | |
2916 dependency: closure); | |
2917 | |
2918 case 'JS_BUILTIN': | |
2919 // The first argument is a description of the type and effect of the | |
2920 // builtin, which has already been analyzed in the frontend. The second | |
2921 // argument must be a [JsBuiltin] value. All other arguments are | |
2922 // values used by the JavaScript template that is associated with the | |
2923 // builtin. | |
2924 validateArgumentCount(minimum: 2); | |
2925 | |
2926 ast.Node builtin = argumentNodes.tail.head; | |
2927 JsBuiltin value = getEnumValue(argumentNodes.tail.head, | |
2928 backend.jsBuiltinEnum, JsBuiltin.values); | |
2929 js.Template template = backend.emitter.builtinTemplateFor(value); | |
2930 List<ir.Primitive> arguments = | |
2931 argumentNodes.skip(2).mapToList(visit, growable: false); | |
2932 return irBuilder.buildForeignCode(template, arguments, behavior); | |
2933 | |
2934 case 'JS_EMBEDDED_GLOBAL': | |
2935 validateArgumentCount(exactly: 2); | |
2936 | |
2937 String name = expectStringConstant(argumentNodes.tail.head); | |
2938 js.Expression access = | |
2939 backend.emitter.generateEmbeddedGlobalAccess(name); | |
2940 js.Template template = js.js.expressionTemplateYielding(access); | |
2941 return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior); | |
2942 | |
2943 case 'JS_INTERCEPTOR_CONSTANT': | |
2944 validateArgumentCount(exactly: 1); | |
2945 | |
2946 ast.Node argument = argumentNodes.head; | |
2947 ir.Primitive argumentValue = visit(argument); | |
2948 if (argumentValue is ir.Constant && argumentValue.value.isType) { | |
2949 TypeConstantValue constant = argumentValue.value; | |
2950 ConstantValue interceptorValue = | |
2951 new InterceptorConstantValue(constant.representedType); | |
2952 return irBuilder.buildConstant(argumentValue.expression, | |
2953 interceptorValue); | |
2954 } else { | |
2955 internalError(argument, 'expected Type as argument'); | |
2956 } | |
2957 break; | |
2958 | |
2959 case 'JS_EFFECT': | |
2960 return irBuilder.buildNullConstant(); | |
2961 | |
2962 case 'JS_GET_NAME': | |
2963 validateArgumentCount(exactly: 1); | |
2964 | |
2965 ast.Node argument = argumentNodes.head; | |
2966 JsGetName id = getEnumValue(argument, backend.jsGetNameEnum, | |
2967 JsGetName.values); | |
2968 String name = backend.namer.getNameForJsGetName(argument, id); | |
2969 return irBuilder.buildStringConstant(name); | |
2970 | |
2971 case 'JS_GET_FLAG': | |
2972 validateArgumentCount(exactly: 1); | |
2973 | |
2974 String name = expectStringConstant(argumentNodes.first); | |
2975 bool value = false; | |
2976 switch (name) { | |
2977 case 'MUST_RETAIN_METADATA': | |
2978 value = backend.mustRetainMetadata; | |
2979 break; | |
2980 case 'USE_CONTENT_SECURITY_POLICY': | |
2981 value = compiler.useContentSecurityPolicy; | |
2982 break; | |
2983 default: | |
2984 internalError(node, 'Unknown internal flag "$name".'); | |
2985 } | |
2986 return irBuilder.buildBooleanConstant(value); | |
2987 | |
2988 case 'JS_STRING_CONCAT': | |
2989 validateArgumentCount(exactly: 2); | |
2990 List<ir.Primitive> arguments = argumentNodes.mapToList(visit); | |
2991 return irBuilder.buildStringConcatenation(arguments); | |
2992 | |
2993 case 'JS_CURRENT_ISOLATE_CONTEXT': | |
2994 validateArgumentCount(exactly: 0); | |
2995 | |
2996 if (!compiler.hasIsolateSupport) { | |
2997 // If the isolate library is not used, we just generate code | |
2998 // to fetch the current isolate. | |
2999 String name = backend.namer.currentIsolate; | |
3000 return irBuilder.buildForeignCode(js.js.parseForeignJS(name), | |
3001 const <ir.Primitive>[], NativeBehavior.PURE); | |
3002 } else { | |
3003 return buildIsolateHelperInvocation('_currentIsolate', | |
3004 CallStructure.NO_ARGS, argumentNodes); | |
3005 } | |
3006 break; | |
3007 | |
3008 case 'JS_CALL_IN_ISOLATE': | |
3009 validateArgumentCount(exactly: 2); | |
3010 | |
3011 if (!compiler.hasIsolateSupport) { | |
3012 ir.Primitive closure = visit(argumentNodes.tail.head); | |
3013 return irBuilder.buildCallInvocation(closure, CallStructure.NO_ARGS, | |
3014 const <ir.Primitive>[]); | |
3015 } else { | |
3016 return buildIsolateHelperInvocation('_callInIsolate', | |
3017 CallStructure.TWO_ARGS, argumentNodes); | |
3018 } | |
3019 break; | |
3020 | |
3021 default: | |
3022 giveup(node, 'unplemented native construct: ${function.name}'); | |
3023 break; | |
3024 } | |
3025 } | |
3026 | |
3027 @override | |
3028 ir.Primitive handleStaticFunctionInvoke(ast.Send node, | |
3029 MethodElement function, | |
3030 ast.NodeList argumentList, | |
3031 CallStructure callStructure, | |
3032 _) { | |
3033 if (compiler.backend.isForeign(function)) { | |
3034 return handleForeignSend(node, function, argumentList.nodes, | |
Kevin Millikin (Google)
2015/06/16 11:23:10
"Send" seems weird here. handleForeignCode?
karlklose
2015/06/18 09:38:14
Done.
| |
3035 callStructure); | |
3036 } else { | |
3037 return irBuilder.buildStaticFunctionInvocation(function, callStructure, | |
3038 translateStaticArguments(argumentList, function, callStructure), | |
3039 sourceInformation: sourceInformationBuilder.buildCall(node)); | |
3040 } | |
3041 } | |
2808 } | 3042 } |
2809 | 3043 |
2810 /// Perform simple post-processing on the initial CPS-translated root term. | 3044 /// Perform simple post-processing on the initial CPS-translated root term. |
2811 /// | 3045 /// |
2812 /// This pass performs backend-independent post-processing on the translated | 3046 /// This pass performs backend-independent post-processing on the translated |
2813 /// term. It is implemented separately from the optimization passes because | 3047 /// term. It is implemented separately from the optimization passes because |
2814 /// it is required for correctness of the implementation. | 3048 /// it is required for correctness of the implementation. |
2815 /// | 3049 /// |
2816 /// It performs the following translations: | 3050 /// It performs the following translations: |
2817 /// - Replace [ir.LetPrim] binding a [ir.NonTailThrow] with a [ir.Throw] | 3051 /// - Replace [ir.LetPrim] binding a [ir.NonTailThrow] with a [ir.Throw] |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2857 } | 3091 } |
2858 | 3092 |
2859 processSetStatic(ir.SetStatic node) { | 3093 processSetStatic(ir.SetStatic node) { |
2860 node.body = replacementFor(node.body); | 3094 node.body = replacementFor(node.body); |
2861 } | 3095 } |
2862 | 3096 |
2863 processContinuation(ir.Continuation node) { | 3097 processContinuation(ir.Continuation node) { |
2864 node.body = replacementFor(node.body); | 3098 node.body = replacementFor(node.body); |
2865 } | 3099 } |
2866 } | 3100 } |
OLD | NEW |