| 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 |