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 '../types/types.dart' show TypeMask; | 20 import '../types/types.dart' show TypeMask; |
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'; | |
35 | 24 |
36 typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode); | 25 typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode); |
37 | 26 |
38 /// This task provides the interface to build IR nodes from [ast.Node]s, which | 27 /// This task provides the interface to build IR nodes from [ast.Node]s, which |
39 /// is used from the [CpsFunctionCompiler] to generate code. | 28 /// is used from the [CpsFunctionCompiler] to generate code. |
40 /// | 29 /// |
41 /// This class is mainly there to correctly measure how long building the IR | 30 /// This class is mainly there to correctly measure how long building the IR |
42 /// takes. | 31 /// takes. |
43 class IrBuilderTask extends CompilerTask { | 32 class IrBuilderTask extends CompilerTask { |
44 final SourceInformationFactory sourceInformationFactory; | 33 final SourceInformationFactory sourceInformationFactory; |
(...skipping 943 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
988 callStructure, | 977 callStructure, |
989 translateDynamicArguments(arguments, callStructure)); | 978 translateDynamicArguments(arguments, callStructure)); |
990 } | 979 } |
991 | 980 |
992 @override | 981 @override |
993 ir.Primitive handleStaticFunctionInvoke( | 982 ir.Primitive handleStaticFunctionInvoke( |
994 ast.Send node, | 983 ast.Send node, |
995 MethodElement function, | 984 MethodElement function, |
996 ast.NodeList arguments, | 985 ast.NodeList arguments, |
997 CallStructure callStructure, | 986 CallStructure callStructure, |
998 _); | 987 _) { |
| 988 // TODO(karlklose): support foreign functions. |
| 989 if (compiler.backend.isForeign(function)) { |
| 990 return giveup(node, 'handleStaticFunctionInvoke: foreign: $function'); |
| 991 } |
| 992 return irBuilder.buildStaticFunctionInvocation(function, callStructure, |
| 993 translateStaticArguments(arguments, function, callStructure), |
| 994 sourceInformation: sourceInformationBuilder.buildCall(node)); |
| 995 } |
999 | 996 |
1000 @override | 997 @override |
1001 ir.Primitive handleStaticFunctionIncompatibleInvoke( | 998 ir.Primitive handleStaticFunctionIncompatibleInvoke( |
1002 ast.Send node, | 999 ast.Send node, |
1003 MethodElement function, | 1000 MethodElement function, |
1004 ast.NodeList arguments, | 1001 ast.NodeList arguments, |
1005 CallStructure callStructure, _) { | 1002 CallStructure callStructure, _) { |
1006 return buildStaticNoSuchMethod( | 1003 return buildStaticNoSuchMethod( |
1007 elements.getSelector(node), | 1004 elements.getSelector(node), |
1008 arguments.nodes.mapToList(visit)); | 1005 arguments.nodes.mapToList(visit)); |
(...skipping 870 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1879 try { | 1876 try { |
1880 return action(); | 1877 return action(); |
1881 } catch(e) { | 1878 } catch(e) { |
1882 if (e == ABORT_IRNODE_BUILDER) { | 1879 if (e == ABORT_IRNODE_BUILDER) { |
1883 return null; | 1880 return null; |
1884 } | 1881 } |
1885 rethrow; | 1882 rethrow; |
1886 } | 1883 } |
1887 } | 1884 } |
1888 | 1885 |
1889 internalError(ast.Node node, String message) { | 1886 void internalError(ast.Node node, String message) { |
1890 giveup(node, message); | 1887 giveup(node, message); |
1891 } | 1888 } |
1892 | 1889 |
1893 @override | 1890 @override |
1894 visitNode(ast.Node node) { | 1891 visitNode(ast.Node node) { |
1895 internalError(node, "Unhandled node"); | 1892 internalError(node, "Unhandled node"); |
1896 } | 1893 } |
1897 | 1894 |
1898 dynamic giveup(ast.Node node, [String reason]) { | 1895 dynamic giveup(ast.Node node, [String reason]) { |
1899 bailoutMessage = '($node): $reason'; | 1896 bailoutMessage = '($node): $reason'; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2074 /// arguments for the class [cls] are never used in the program. | 2071 /// arguments for the class [cls] are never used in the program. |
2075 bool requiresRuntimeTypesFor(ClassElement cls) { | 2072 bool requiresRuntimeTypesFor(ClassElement cls) { |
2076 return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls); | 2073 return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls); |
2077 } | 2074 } |
2078 | 2075 |
2079 FunctionElement get throwTypeErrorHelper => _backend.getThrowTypeError(); | 2076 FunctionElement get throwTypeErrorHelper => _backend.getThrowTypeError(); |
2080 | 2077 |
2081 ClassElement get nullClass => _compiler.nullClass; | 2078 ClassElement get nullClass => _compiler.nullClass; |
2082 | 2079 |
2083 DartType unaliasType(DartType type) => type.unalias(_compiler); | 2080 DartType unaliasType(DartType type) => type.unalias(_compiler); |
2084 | |
2085 TypeMask getTypeMaskForForeign(NativeBehavior behavior) { | |
2086 return TypeMaskFactory.fromNativeBehavior(behavior, _compiler); | |
2087 } | |
2088 } | 2081 } |
2089 | 2082 |
2090 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder]. | 2083 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder]. |
2091 class JsIrBuilderVisitor extends IrBuilderVisitor { | 2084 class JsIrBuilderVisitor extends IrBuilderVisitor { |
2092 /// Promote the type of [irBuilder] to [JsIrBuilder]. | 2085 /// Promote the type of [irBuilder] to [JsIrBuilder]. |
2093 JsIrBuilder get irBuilder => super.irBuilder; | 2086 JsIrBuilder get irBuilder => super.irBuilder; |
2094 | 2087 |
2095 JavaScriptBackend get backend => compiler.backend; | 2088 JavaScriptBackend get backend => compiler.backend; |
2096 | 2089 |
2097 /// Result of closure conversion for the current body of code. | 2090 /// Result of closure conversion for the current body of code. |
(...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2831 ConstantExpression constant = | 2824 ConstantExpression constant = |
2832 backend.constants.getConstantForVariable(field); | 2825 backend.constants.getConstantForVariable(field); |
2833 if (constant != null && !field.isAssignable) { | 2826 if (constant != null && !field.isAssignable) { |
2834 return buildConstant(constant); | 2827 return buildConstant(constant); |
2835 } else if (backend.constants.lazyStatics.contains(field)) { | 2828 } else if (backend.constants.lazyStatics.contains(field)) { |
2836 return irBuilder.buildStaticFieldLazyGet(field, src); | 2829 return irBuilder.buildStaticFieldLazyGet(field, src); |
2837 } else { | 2830 } else { |
2838 return irBuilder.buildStaticFieldGet(field, src); | 2831 return irBuilder.buildStaticFieldGet(field, src); |
2839 } | 2832 } |
2840 } | 2833 } |
2841 | |
2842 /// Build code to handle foreign code, that is, native JavaScript code, or | |
2843 /// builtin values and operations of the backend. | |
2844 ir.Primitive handleForeignCode(ast.Send node, | |
2845 MethodElement function, | |
2846 ast.NodeList argumentList, | |
2847 CallStructure callStructure) { | |
2848 | |
2849 void validateArgumentCount({int minimum, int exactly}) { | |
2850 assert((minimum == null) != (exactly == null)); | |
2851 int count = 0; | |
2852 int maximum; | |
2853 if (exactly != null) { | |
2854 minimum = exactly; | |
2855 maximum = exactly; | |
2856 } | |
2857 for (ast.Node argument in argumentList) { | |
2858 count++; | |
2859 if (maximum != null && count > maximum) { | |
2860 internalError(argument, 'Additional argument.'); | |
2861 } | |
2862 } | |
2863 if (count < minimum) { | |
2864 internalError(node, 'Expected at least $minimum arguments.'); | |
2865 } | |
2866 } | |
2867 | |
2868 /// Call a helper method from the isolate library. The isolate library uses | |
2869 /// its own isolate structure, that encapsulates dart2js's isolate. | |
2870 ir.Primitive buildIsolateHelperInvocation(String helperName, | |
2871 CallStructure callStructure) { | |
2872 Element element = backend.isolateHelperLibrary.find(helperName); | |
2873 if (element == null) { | |
2874 compiler.internalError(node, | |
2875 'Isolate library and compiler mismatch.'); | |
2876 } | |
2877 List<ir.Primitive> arguments = translateStaticArguments(argumentList, | |
2878 element, CallStructure.TWO_ARGS); | |
2879 return irBuilder.buildStaticFunctionInvocation(element, | |
2880 CallStructure.TWO_ARGS, arguments, | |
2881 sourceInformation: sourceInformationBuilder.buildCall(node)); | |
2882 } | |
2883 | |
2884 /// Lookup the value of the enum described by [node]. | |
2885 getEnumValue(ast.Node node, EnumClassElement enumClass, List values) { | |
2886 Element element = elements[node]; | |
2887 if (element is! FieldElement || element.enclosingClass != enumClass) { | |
2888 internalError(node, 'expected a JsBuiltin enum value'); | |
2889 } | |
2890 | |
2891 int index = enumClass.enumValues.indexOf(element); | |
2892 return values[index]; | |
2893 } | |
2894 | |
2895 /// Returns the String the node evaluates to, or throws an error if the | |
2896 /// result is not a string constant. | |
2897 String expectStringConstant(ast.Node node) { | |
2898 ir.Primitive nameValue = visit(node); | |
2899 if (nameValue is ir.Constant && nameValue.value.isString) { | |
2900 StringConstantValue constantValue = nameValue.value; | |
2901 return constantValue.primitiveValue.slowToString(); | |
2902 } else { | |
2903 return internalError(node, 'expected a literal string'); | |
2904 } | |
2905 } | |
2906 | |
2907 Link<ast.Node> argumentNodes = argumentList.nodes; | |
2908 NativeBehavior behavior = | |
2909 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | |
2910 switch (function.name) { | |
2911 case 'JS': | |
2912 validateArgumentCount(minimum: 2); | |
2913 // The first two arguments are the type and the foreign code template, | |
2914 // which already have been analyzed by the resolver and can be retrieved | |
2915 // using [NativeBehavior]. We can ignore these arguments in the backend. | |
2916 List<ir.Primitive> arguments = | |
2917 argumentNodes.skip(2).mapToList(visit, growable: false); | |
2918 return irBuilder.buildForeignCode(behavior.codeTemplate, arguments, | |
2919 behavior); | |
2920 | |
2921 case 'DART_CLOSURE_TO_JS': | |
2922 // TODO(ahe): This should probably take care to wrap the closure in | |
2923 // another closure that saves the current isolate. | |
2924 case 'RAW_DART_FUNCTION_REF': | |
2925 validateArgumentCount(exactly: 1); | |
2926 | |
2927 ast.Node argument = node.arguments.single; | |
2928 FunctionElement closure = elements[argument].implementation; | |
2929 if (!Elements.isStaticOrTopLevelFunction(closure)) { | |
2930 internalError(argument, | |
2931 'only static or toplevel function supported'); | |
2932 } | |
2933 if (closure.functionSignature.hasOptionalParameters) { | |
2934 internalError(argument, | |
2935 'closures with optional parameters not supported'); | |
2936 } | |
2937 return irBuilder.buildForeignCode( | |
2938 js.js.expressionTemplateYielding( | |
2939 backend.emitter.staticFunctionAccess(function)), | |
2940 <ir.Primitive>[], | |
2941 NativeBehavior.PURE, | |
2942 dependency: closure); | |
2943 | |
2944 case 'JS_BUILTIN': | |
2945 // The first argument is a description of the type and effect of the | |
2946 // builtin, which has already been analyzed in the frontend. The second | |
2947 // argument must be a [JsBuiltin] value. All other arguments are | |
2948 // values used by the JavaScript template that is associated with the | |
2949 // builtin. | |
2950 validateArgumentCount(minimum: 2); | |
2951 | |
2952 ast.Node builtin = argumentNodes.tail.head; | |
2953 JsBuiltin value = getEnumValue(argumentNodes.tail.head, | |
2954 backend.jsBuiltinEnum, JsBuiltin.values); | |
2955 js.Template template = backend.emitter.builtinTemplateFor(value); | |
2956 List<ir.Primitive> arguments = | |
2957 argumentNodes.skip(2).mapToList(visit, growable: false); | |
2958 return irBuilder.buildForeignCode(template, arguments, behavior); | |
2959 | |
2960 case 'JS_EMBEDDED_GLOBAL': | |
2961 validateArgumentCount(exactly: 2); | |
2962 | |
2963 String name = expectStringConstant(argumentNodes.tail.head); | |
2964 js.Expression access = | |
2965 backend.emitter.generateEmbeddedGlobalAccess(name); | |
2966 js.Template template = js.js.expressionTemplateYielding(access); | |
2967 return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior); | |
2968 | |
2969 case 'JS_INTERCEPTOR_CONSTANT': | |
2970 validateArgumentCount(exactly: 1); | |
2971 | |
2972 ast.Node argument = argumentNodes.head; | |
2973 ir.Primitive argumentValue = visit(argument); | |
2974 if (argumentValue is ir.Constant && argumentValue.value.isType) { | |
2975 TypeConstantValue constant = argumentValue.value; | |
2976 ConstantValue interceptorValue = | |
2977 new InterceptorConstantValue(constant.representedType); | |
2978 return irBuilder.buildConstant(argumentValue.expression, | |
2979 interceptorValue); | |
2980 } else { | |
2981 internalError(argument, 'expected Type as argument'); | |
2982 } | |
2983 break; | |
2984 | |
2985 case 'JS_EFFECT': | |
2986 return irBuilder.buildNullConstant(); | |
2987 | |
2988 case 'JS_GET_NAME': | |
2989 validateArgumentCount(exactly: 1); | |
2990 | |
2991 ast.Node argument = argumentNodes.head; | |
2992 JsGetName id = getEnumValue(argument, backend.jsGetNameEnum, | |
2993 JsGetName.values); | |
2994 String name = backend.namer.getNameForJsGetName(argument, id); | |
2995 return irBuilder.buildStringConstant(name); | |
2996 | |
2997 case 'JS_GET_FLAG': | |
2998 validateArgumentCount(exactly: 1); | |
2999 | |
3000 String name = expectStringConstant(argumentNodes.first); | |
3001 bool value = false; | |
3002 switch (name) { | |
3003 case 'MUST_RETAIN_METADATA': | |
3004 value = backend.mustRetainMetadata; | |
3005 break; | |
3006 case 'USE_CONTENT_SECURITY_POLICY': | |
3007 value = compiler.useContentSecurityPolicy; | |
3008 break; | |
3009 default: | |
3010 internalError(node, 'Unknown internal flag "$name".'); | |
3011 } | |
3012 return irBuilder.buildBooleanConstant(value); | |
3013 | |
3014 case 'JS_STRING_CONCAT': | |
3015 validateArgumentCount(exactly: 2); | |
3016 List<ir.Primitive> arguments = argumentNodes.mapToList(visit); | |
3017 return irBuilder.buildStringConcatenation(arguments); | |
3018 | |
3019 case 'JS_CURRENT_ISOLATE_CONTEXT': | |
3020 validateArgumentCount(exactly: 0); | |
3021 | |
3022 if (!compiler.hasIsolateSupport) { | |
3023 // If the isolate library is not used, we just generate code | |
3024 // to fetch the current isolate. | |
3025 String name = backend.namer.currentIsolate; | |
3026 return irBuilder.buildForeignCode(js.js.parseForeignJS(name), | |
3027 const <ir.Primitive>[], NativeBehavior.PURE); | |
3028 } else { | |
3029 return buildIsolateHelperInvocation('_currentIsolate', | |
3030 CallStructure.NO_ARGS); | |
3031 } | |
3032 break; | |
3033 | |
3034 case 'JS_CALL_IN_ISOLATE': | |
3035 validateArgumentCount(exactly: 2); | |
3036 | |
3037 if (!compiler.hasIsolateSupport) { | |
3038 ir.Primitive closure = visit(argumentNodes.tail.head); | |
3039 return irBuilder.buildCallInvocation(closure, CallStructure.NO_ARGS, | |
3040 const <ir.Primitive>[]); | |
3041 } else { | |
3042 return buildIsolateHelperInvocation('_callInIsolate', | |
3043 CallStructure.TWO_ARGS); | |
3044 } | |
3045 break; | |
3046 | |
3047 default: | |
3048 giveup(node, 'unplemented native construct: ${function.name}'); | |
3049 break; | |
3050 } | |
3051 } | |
3052 | |
3053 @override | |
3054 ir.Primitive handleStaticFunctionInvoke(ast.Send node, | |
3055 MethodElement function, | |
3056 ast.NodeList argumentList, | |
3057 CallStructure callStructure, | |
3058 _) { | |
3059 if (compiler.backend.isForeign(function)) { | |
3060 return handleForeignCode(node, function, argumentList, callStructure); | |
3061 } else { | |
3062 return irBuilder.buildStaticFunctionInvocation(function, callStructure, | |
3063 translateStaticArguments(argumentList, function, callStructure), | |
3064 sourceInformation: sourceInformationBuilder.buildCall(node)); | |
3065 } | |
3066 } | |
3067 } | 2834 } |
3068 | 2835 |
3069 /// Perform simple post-processing on the initial CPS-translated root term. | 2836 /// Perform simple post-processing on the initial CPS-translated root term. |
3070 /// | 2837 /// |
3071 /// This pass performs backend-independent post-processing on the translated | 2838 /// This pass performs backend-independent post-processing on the translated |
3072 /// term. It is implemented separately from the optimization passes because | 2839 /// term. It is implemented separately from the optimization passes because |
3073 /// it is required for correctness of the implementation. | 2840 /// it is required for correctness of the implementation. |
3074 /// | 2841 /// |
3075 /// It performs the following translations: | 2842 /// It performs the following translations: |
3076 /// - Replace [ir.LetPrim] binding a [ir.NonTailThrow] with a [ir.Throw] | 2843 /// - Replace [ir.LetPrim] binding a [ir.NonTailThrow] with a [ir.Throw] |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3116 } | 2883 } |
3117 | 2884 |
3118 processSetStatic(ir.SetStatic node) { | 2885 processSetStatic(ir.SetStatic node) { |
3119 node.body = replacementFor(node.body); | 2886 node.body = replacementFor(node.body); |
3120 } | 2887 } |
3121 | 2888 |
3122 processContinuation(ir.Continuation node) { | 2889 processContinuation(ir.Continuation node) { |
3123 node.body = replacementFor(node.body); | 2890 node.body = replacementFor(node.body); |
3124 } | 2891 } |
3125 } | 2892 } |
OLD | NEW |