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