Chromium Code Reviews| 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 |