| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 class SsaCodeGeneratorTask extends CompilerTask { | 5 class SsaCodeGeneratorTask extends CompilerTask { |
| 6 final JavaScriptBackend backend; | 6 final JavaScriptBackend backend; |
| 7 SsaCodeGeneratorTask(JavaScriptBackend backend) | 7 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 8 : this.backend = backend, | 8 : this.backend = backend, |
| 9 super(backend.compiler); | 9 super(backend.compiler); |
| 10 String get name() => 'SSA code generator'; | 10 String get name() => 'SSA code generator'; |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 Compiler get compiler() => backend.compiler; | 205 Compiler get compiler() => backend.compiler; |
| 206 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; | 206 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; |
| 207 Enqueuer get world() => backend.compiler.enqueuer.codegen; | 207 Enqueuer get world() => backend.compiler.enqueuer.codegen; |
| 208 | 208 |
| 209 bool isGenerateAtUseSite(HInstruction instruction) { | 209 bool isGenerateAtUseSite(HInstruction instruction) { |
| 210 return generateAtUseSite.contains(instruction); | 210 return generateAtUseSite.contains(instruction); |
| 211 } | 211 } |
| 212 | 212 |
| 213 bool isNonNegativeInt32Constant(HInstruction instruction) { | 213 bool isNonNegativeInt32Constant(HInstruction instruction) { |
| 214 if (instruction.isConstantInteger()) { | 214 if (instruction.isConstantInteger()) { |
| 215 int value = instruction.constant.value; | 215 int value = |
| 216 ((instruction as HConstant).constant as PrimitiveConstant).value; |
| 216 if (value >= 0 && value < (1 << 31)) { | 217 if (value >= 0 && value < (1 << 31)) { |
| 217 return true; | 218 return true; |
| 218 } | 219 } |
| 219 } | 220 } |
| 220 return false; | 221 return false; |
| 221 } | 222 } |
| 222 | 223 |
| 223 bool hasNonBitOpUser(HInstruction instruction, Set<HPhi> phiSet) { | 224 bool hasNonBitOpUser(HInstruction instruction, Set<HPhi> phiSet) { |
| 224 for (HInstruction use in instruction.usedBy) { | 225 for (HInstruction use in instruction.usedBy) { |
| 225 if (use is HPhi) { | 226 if (use is HPhi) { |
| 226 if (!phiSet.contains(use)) { | 227 if (!phiSet.contains(use)) { |
| 227 phiSet.add(use); | 228 phiSet.add(use); |
| 228 if (hasNonBitOpUser(use, phiSet)) return true; | 229 if (hasNonBitOpUser(use, phiSet)) return true; |
| 229 } | 230 } |
| 230 } else if (use is! HBitNot && use is! HBinaryBitOp) { | 231 } else if (use is! HBitNot && use is! HBinaryBitOp) { |
| 231 return true; | 232 return true; |
| 232 } | 233 } |
| 233 } | 234 } |
| 234 return false; | 235 return false; |
| 235 } | 236 } |
| 236 | 237 |
| 237 // We want the outcome of bit-operations to be positive. However, if | 238 // We want the outcome of bit-operations to be positive. However, if |
| 238 // the result of a bit-operation is only used by other bit | 239 // the result of a bit-operation is only used by other bit |
| 239 // operations we do not have to convert to an unsigned | 240 // operations we do not have to convert to an unsigned |
| 240 // integer. Also, if we are using & with a positive constant we know | 241 // integer. Also, if we are using & with a positive constant we know |
| 241 // that the result is positive already and need no conversion. | 242 // that the result is positive already and need no conversion. |
| 242 bool requiresUintConversion(HInstruction instruction) { | 243 bool requiresUintConversion(HInstruction instruction) { |
| 243 if (instruction is HBitAnd && | 244 if (instruction is HBitAnd && |
| 244 (isNonNegativeInt32Constant(instruction.left) || | 245 (isNonNegativeInt32Constant((instruction as HBitAnd).left) || |
| 245 isNonNegativeInt32Constant(instruction.right))) { | 246 isNonNegativeInt32Constant((instruction as HBitAnd).right))) { |
| 246 return false; | 247 return false; |
| 247 } | 248 } |
| 248 return hasNonBitOpUser(instruction, new Set<HPhi>()); | 249 return hasNonBitOpUser(instruction, new Set<HPhi>()); |
| 249 } | 250 } |
| 250 | 251 |
| 251 SsaCodeGenerator(this.backend, | 252 SsaCodeGenerator(this.backend, |
| 252 this.work, | 253 this.work, |
| 253 this.parameters, | 254 this.parameters, |
| 254 this.parameterNames) | 255 this.parameterNames) |
| 255 : declaredVariables = new Set<String>(), | 256 : declaredVariables = new Set<String>(), |
| 256 delayedVariableDeclarations = new Set<String>(), | 257 delayedVariableDeclarations = new Set<String>(), |
| 257 buffer = new CodeBuffer(), | 258 buffer = new CodeBuffer(), |
| 258 generateAtUseSite = new Set<HInstruction>(), | 259 generateAtUseSite = new Set<HInstruction>(), |
| 259 controlFlowOperators = new Set<HInstruction>(), | 260 controlFlowOperators = new Set<HInstruction>(), |
| 260 breakAction = new Map<Element, ElementAction>(), | 261 breakAction = new Map<Element, ElementAction>(), |
| 261 continueAction = new Map<Element, ElementAction>(), | 262 continueAction = new Map<Element, ElementAction>(), |
| 262 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { | 263 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { |
| 263 } | 264 } |
| 264 | 265 |
| 265 abstract visitTypeGuard(HTypeGuard node); | 266 abstract visitTypeGuard(HTypeGuard node); |
| 267 abstract visitBailoutTarget(HBailoutTarget node); |
| 266 | 268 |
| 267 abstract beginGraph(HGraph graph); | 269 abstract beginGraph(HGraph graph); |
| 268 abstract endGraph(HGraph graph); | 270 abstract endGraph(HGraph graph); |
| 269 | 271 |
| 270 abstract beginLoop(HBasicBlock block); | 272 abstract beginLoop(HBasicBlock block); |
| 271 abstract endLoop(HBasicBlock block); | 273 abstract endLoop(HBasicBlock block); |
| 272 abstract handleLoopCondition(HLoopBranch node); | 274 abstract handleLoopCondition(HLoopBranch node); |
| 273 | 275 |
| 274 abstract preLabeledBlock(HLabeledBlockInformation labeledBlockInfo); | 276 abstract preLabeledBlock(HLabeledBlockInformation labeledBlockInfo); |
| 275 abstract startLabeledBlock(HLabeledBlockInformation labeledBlockInfo); | 277 abstract startLabeledBlock(HLabeledBlockInformation labeledBlockInfo); |
| (...skipping 884 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 } | 1162 } |
| 1161 if (!isGeneratingExpression()) { | 1163 if (!isGeneratingExpression()) { |
| 1162 buffer.add(';\n'); | 1164 buffer.add(';\n'); |
| 1163 } | 1165 } |
| 1164 } | 1166 } |
| 1165 } | 1167 } |
| 1166 | 1168 |
| 1167 void iterateBasicBlock(HBasicBlock node) { | 1169 void iterateBasicBlock(HBasicBlock node) { |
| 1168 HInstruction instruction = node.first; | 1170 HInstruction instruction = node.first; |
| 1169 while (instruction !== node.last) { | 1171 while (instruction !== node.last) { |
| 1170 if (instruction is HTypeGuard) { | 1172 if (instruction is HTypeGuard || instruction is HBailoutTarget) { |
| 1171 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 1173 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 1172 } else if (!isGenerateAtUseSite(instruction)) { | 1174 } else if (!isGenerateAtUseSite(instruction)) { |
| 1173 expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; | 1175 expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; |
| 1174 define(instruction); | 1176 define(instruction); |
| 1175 } | 1177 } |
| 1176 instruction = instruction.next; | 1178 instruction = instruction.next; |
| 1177 } | 1179 } |
| 1178 assignPhisOfSuccessors(node); | 1180 assignPhisOfSuccessors(node); |
| 1179 if (instruction is HLoopBranch && isGeneratingExpression()) { | 1181 if (instruction is HLoopBranch && isGeneratingExpression()) { |
| 1180 addExpressionSeparator(); | 1182 addExpressionSeparator(); |
| (...skipping 1523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2704 | 2706 |
| 2705 int maxBailoutParameters; | 2707 int maxBailoutParameters; |
| 2706 | 2708 |
| 2707 HBasicBlock beginGraph(HGraph graph) => graph.entry; | 2709 HBasicBlock beginGraph(HGraph graph) => graph.entry; |
| 2708 void endGraph(HGraph graph) {} | 2710 void endGraph(HGraph graph) {} |
| 2709 | 2711 |
| 2710 void bailout(HTypeGuard guard, String reason) { | 2712 void bailout(HTypeGuard guard, String reason) { |
| 2711 if (maxBailoutParameters === null) { | 2713 if (maxBailoutParameters === null) { |
| 2712 maxBailoutParameters = 0; | 2714 maxBailoutParameters = 0; |
| 2713 work.guards.forEach((HTypeGuard workGuard) { | 2715 work.guards.forEach((HTypeGuard workGuard) { |
| 2714 int inputLength = workGuard.inputs.length; | 2716 HBailoutTarget target = workGuard.bailoutTarget; |
| 2717 int inputLength = target.inputs.length; |
| 2715 if (inputLength > maxBailoutParameters) { | 2718 if (inputLength > maxBailoutParameters) { |
| 2716 maxBailoutParameters = inputLength; | 2719 maxBailoutParameters = inputLength; |
| 2717 } | 2720 } |
| 2718 }); | 2721 }); |
| 2719 } | 2722 } |
| 2720 HInstruction input = guard.guarded; | 2723 HInstruction input = guard.guarded; |
| 2724 HBailoutTarget target = guard.bailoutTarget; |
| 2721 Namer namer = compiler.namer; | 2725 Namer namer = compiler.namer; |
| 2722 Element element = work.element; | 2726 Element element = work.element; |
| 2723 buffer.add('return '); | 2727 buffer.add('return '); |
| 2724 if (element.isInstanceMember()) { | 2728 if (element.isInstanceMember()) { |
| 2725 // TODO(ngeoffray): This does not work in case we come from a | 2729 // TODO(ngeoffray): This does not work in case we come from a |
| 2726 // super call. We must make bailout names unique. | 2730 // super call. We must make bailout names unique. |
| 2727 buffer.add('this.${namer.getBailoutName(element)}'); | 2731 buffer.add('this.${namer.getBailoutName(element)}'); |
| 2728 } else { | 2732 } else { |
| 2729 buffer.add(namer.isolateBailoutAccess(element)); | 2733 buffer.add(namer.isolateBailoutAccess(element)); |
| 2730 } | 2734 } |
| 2731 buffer.add('(${guard.state}'); | 2735 buffer.add('(${guard.state}'); |
| 2732 // TODO(ngeoffray): try to put a variable at a deterministic | 2736 // TODO(ngeoffray): try to put a variable at a deterministic |
| 2733 // location, so that multiple bailout calls put the variable at | 2737 // location, so that multiple bailout calls put the variable at |
| 2734 // the same parameter index. | 2738 // the same parameter index. |
| 2735 int i = 0; | 2739 int i = 0; |
| 2736 for (; i < guard.inputs.length; i++) { | 2740 for (; i < target.inputs.length; i++) { |
| 2741 assert(guard.inputs.indexOf(target.inputs[i]) >= 0); |
| 2737 buffer.add(', '); | 2742 buffer.add(', '); |
| 2738 use(guard.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2743 use(target.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2739 } | 2744 } |
| 2740 // Make sure we call the bailout method with the number of | 2745 // Make sure we call the bailout method with the number of |
| 2741 // arguments it expects. This avoids having the underlying | 2746 // arguments it expects. This avoids having the underlying |
| 2742 // JS engine fill them in for us. | 2747 // JS engine fill them in for us. |
| 2743 for (; i < maxBailoutParameters; i++) { | 2748 for (; i < maxBailoutParameters; i++) { |
| 2744 buffer.add(', 0'); | 2749 buffer.add(', 0'); |
| 2745 } | 2750 } |
| 2746 buffer.add(')'); | 2751 buffer.add(')'); |
| 2747 } | 2752 } |
| 2748 | 2753 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2822 buffer.add(' && '); | 2827 buffer.add(' && '); |
| 2823 checkType(input, indexingBehavior, negative: true); | 2828 checkType(input, indexingBehavior, negative: true); |
| 2824 buffer.add('))) '); | 2829 buffer.add('))) '); |
| 2825 bailout(node, 'Not a string or array'); | 2830 bailout(node, 'Not a string or array'); |
| 2826 } else { | 2831 } else { |
| 2827 compiler.internalError('Unexpected type guard', instruction: input); | 2832 compiler.internalError('Unexpected type guard', instruction: input); |
| 2828 } | 2833 } |
| 2829 buffer.add(';\n'); | 2834 buffer.add(';\n'); |
| 2830 } | 2835 } |
| 2831 | 2836 |
| 2837 void visitBailoutTarget(HBailoutTarget target) { |
| 2838 // Do nothing. Bailout targets are only used in the non-optimized version. |
| 2839 } |
| 2840 |
| 2832 void beginLoop(HBasicBlock block) { | 2841 void beginLoop(HBasicBlock block) { |
| 2833 addIndentation(); | 2842 addIndentation(); |
| 2834 HLoopInformation info = block.loopInformation; | 2843 HLoopInformation info = block.loopInformation; |
| 2835 for (LabelElement label in info.labels) { | 2844 for (LabelElement label in info.labels) { |
| 2836 writeLabel(label); | 2845 writeLabel(label); |
| 2837 buffer.add(":"); | 2846 buffer.add(":"); |
| 2838 } | 2847 } |
| 2839 buffer.add('while (true) {\n'); | 2848 buffer.add('while (true) {\n'); |
| 2840 indent++; | 2849 indent++; |
| 2841 } | 2850 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2899 return labels.last(); | 2908 return labels.last(); |
| 2900 } | 2909 } |
| 2901 | 2910 |
| 2902 HBasicBlock beginGraph(HGraph graph) { | 2911 HBasicBlock beginGraph(HGraph graph) { |
| 2903 propagator = new SsaBailoutPropagator(compiler, generateAtUseSite); | 2912 propagator = new SsaBailoutPropagator(compiler, generateAtUseSite); |
| 2904 propagator.visitGraph(graph); | 2913 propagator.visitGraph(graph); |
| 2905 // TODO(ngeoffray): We could avoid generating the state at the | 2914 // TODO(ngeoffray): We could avoid generating the state at the |
| 2906 // call site for non-complex bailout methods. | 2915 // call site for non-complex bailout methods. |
| 2907 newParameters.add('state'); | 2916 newParameters.add('state'); |
| 2908 | 2917 |
| 2909 if (propagator.hasComplexTypeGuards) { | 2918 if (propagator.hasComplexBailoutTargets) { |
| 2910 // Use generic parameters that will be assigned to | 2919 // Use generic parameters that will be assigned to |
| 2911 // the right variables in the setup phase. | 2920 // the right variables in the setup phase. |
| 2912 for (int i = 0; i < propagator.maxBailoutParameters; i++) { | 2921 for (int i = 0; i < propagator.maxBailoutParameters; i++) { |
| 2913 String name = 'env$i'; | 2922 String name = 'env$i'; |
| 2914 declaredVariables.add(name); | 2923 declaredVariables.add(name); |
| 2915 newParameters.add(', $name'); | 2924 newParameters.add(', $name'); |
| 2916 } | 2925 } |
| 2917 | 2926 |
| 2918 startBailoutSwitch(); | 2927 startBailoutSwitch(); |
| 2919 | 2928 |
| 2920 // The setup phase of a bailout function sets up the environment for | 2929 // The setup phase of a bailout function sets up the environment for |
| 2921 // each bailout target. Each bailout target will populate this | 2930 // each bailout target. Each bailout target will populate this |
| 2922 // setup phase. It is put at the beginning of the function. | 2931 // setup phase. It is put at the beginning of the function. |
| 2923 setup.add(' switch (state) {\n'); | 2932 setup.add(' switch (state) {\n'); |
| 2924 return graph.entry; | 2933 return graph.entry; |
| 2925 } else { | 2934 } else { |
| 2926 // We have a simple type guard, so we can reuse the names that | 2935 // We have a simple bailout target, so we can reuse the names that |
| 2927 // the type guard expects. | 2936 // the bailout target expects. |
| 2928 for (HInstruction input in propagator.firstTypeGuard.inputs) { | 2937 for (HInstruction input in propagator.firstBailoutTarget.inputs) { |
| 2929 input = unwrap(input); | 2938 input = unwrap(input); |
| 2930 String name = variableNames.getName(input); | 2939 String name = variableNames.getName(input); |
| 2931 declaredVariables.add(name); | 2940 declaredVariables.add(name); |
| 2932 newParameters.add(', $name'); | 2941 newParameters.add(', $name'); |
| 2933 } | 2942 } |
| 2934 | 2943 |
| 2935 // We change the first instruction of the first guard to be the | 2944 // We change the first instruction of the first guard to be the |
| 2936 // guard. We will change it back in the call to [endGraph]. | 2945 // bailout target. We will change it back in the call to [endGraph]. |
| 2937 HBasicBlock block = propagator.firstTypeGuard.block; | 2946 HBasicBlock block = propagator.firstBailoutTarget.block; |
| 2938 savedFirstInstruction = block.first; | 2947 savedFirstInstruction = block.first; |
| 2939 block.first = propagator.firstTypeGuard; | 2948 block.first = propagator.firstBailoutTarget; |
| 2940 return block; | 2949 return block; |
| 2941 } | 2950 } |
| 2942 } | 2951 } |
| 2943 | 2952 |
| 2944 // If argument is a [HCheck] and it does not have a name, we try to | 2953 // If argument is a [HCheck] and it does not have a name, we try to |
| 2945 // find the name of its checked input. Note that there must be a | 2954 // find the name of its checked input. Note that there must be a |
| 2946 // name, otherwise the instruction would not be in the live | 2955 // name, otherwise the instruction would not be in the live |
| 2947 // environment. | 2956 // environment. |
| 2948 HInstruction unwrap(HInstruction argument) { | 2957 HInstruction unwrap(HInstruction argument) { |
| 2949 while (argument is HCheck && !variableNames.hasName(argument)) { | 2958 while (argument is HCheck && !variableNames.hasName(argument)) { |
| 2950 argument = argument.checkedInput; | 2959 argument = argument.checkedInput; |
| 2951 } | 2960 } |
| 2952 assert(variableNames.hasName(argument)); | 2961 assert(variableNames.hasName(argument)); |
| 2953 return argument; | 2962 return argument; |
| 2954 } | 2963 } |
| 2955 | 2964 |
| 2956 void endGraph(HGraph graph) { | 2965 void endGraph(HGraph graph) { |
| 2957 if (propagator.hasComplexTypeGuards) { | 2966 if (propagator.hasComplexBailoutTargets) { |
| 2958 indent--; // Close original case. | 2967 indent--; // Close original case. |
| 2959 indent--; | 2968 indent--; |
| 2960 addIndented('}\n'); // Close 'switch'. | 2969 addIndented('}\n'); // Close 'switch'. |
| 2961 setup.add(' }\n'); | 2970 setup.add(' }\n'); |
| 2962 } else { | 2971 } else { |
| 2963 // Put back the original first instruction of the block. | 2972 // Put back the original first instruction of the block. |
| 2964 propagator.firstTypeGuard.block.first = savedFirstInstruction; | 2973 propagator.firstBailoutTarget.block.first = savedFirstInstruction; |
| 2965 } | 2974 } |
| 2966 } | 2975 } |
| 2967 | 2976 |
| 2968 bool visitAndOrInfo(HAndOrBlockInformation info) => false; | 2977 bool visitAndOrInfo(HAndOrBlockInformation info) => false; |
| 2969 | 2978 |
| 2970 bool visitIfInfo(HIfBlockInformation info) { | 2979 bool visitIfInfo(HIfBlockInformation info) { |
| 2971 if (info.thenGraph.start.hasGuards()) return false; | 2980 if (info.thenGraph.start.hasBailoutTargets()) return false; |
| 2972 if (info.elseGraph.start.hasGuards()) return false; | 2981 if (info.elseGraph.start.hasBailoutTargets()) return false; |
| 2973 return super.visitIfInfo(info); | 2982 return super.visitIfInfo(info); |
| 2974 } | 2983 } |
| 2975 | 2984 |
| 2976 bool visitLoopInfo(HLoopBlockInformation info) { | 2985 bool visitLoopInfo(HLoopBlockInformation info) { |
| 2977 if (info.start.hasGuards()) return false; | 2986 if (info.start.hasBailoutTargets()) return false; |
| 2978 if (info.loopHeader.hasGuards()) return false; | 2987 if (info.loopHeader.hasBailoutTargets()) return false; |
| 2979 return super.visitLoopInfo(info); | 2988 return super.visitLoopInfo(info); |
| 2980 } | 2989 } |
| 2981 | 2990 |
| 2982 bool visitTryInfo(HTryBlockInformation info) => false; | 2991 bool visitTryInfo(HTryBlockInformation info) => false; |
| 2983 bool visitSequenceInfo(HStatementSequenceInformation info) => false; | 2992 bool visitSequenceInfo(HStatementSequenceInformation info) => false; |
| 2984 | 2993 |
| 2985 void visitTypeGuard(HTypeGuard node) { | 2994 void visitTypeGuard(HTypeGuard node) { |
| 2986 if (!propagator.hasComplexTypeGuards) return; | 2995 // Do nothing. Type guards are only used in the optimized version. |
| 2996 } |
| 2997 |
| 2998 void visitBailoutTarget(HBailoutTarget node) { |
| 2999 if (!propagator.hasComplexBailoutTargets) return; |
| 2987 | 3000 |
| 2988 indent--; | 3001 indent--; |
| 2989 addIndented('case ${node.state}:\n'); | 3002 addIndented('case ${node.state}:\n'); |
| 2990 indent++; | 3003 indent++; |
| 2991 addIndented('state = 0;\n'); | 3004 addIndented('state = 0;\n'); |
| 2992 | 3005 |
| 2993 setup.add(' case ${node.state}:\n'); | 3006 setup.add(' case ${node.state}:\n'); |
| 2994 int i = 0; | 3007 int i = 0; |
| 2995 for (HInstruction input in node.inputs) { | 3008 for (HInstruction input in node.inputs) { |
| 2996 input = unwrap(input); | 3009 input = unwrap(input); |
| 2997 String name = variableNames.getName(input); | 3010 String name = variableNames.getName(input); |
| 2998 setup.add(' '); | 3011 setup.add(' '); |
| 2999 if (!isVariableDeclared(name)) { | 3012 if (!isVariableDeclared(name)) { |
| 3000 declaredVariables.add(name); | 3013 declaredVariables.add(name); |
| 3001 setup.add('var '); | 3014 setup.add('var '); |
| 3002 } | 3015 } |
| 3003 setup.add('$name = env$i;\n'); | 3016 setup.add('$name = env$i;\n'); |
| 3004 i++; | 3017 i++; |
| 3005 } | 3018 } |
| 3006 setup.add(' break;\n'); | 3019 setup.add(' break;\n'); |
| 3007 } | 3020 } |
| 3008 | 3021 |
| 3009 void startBailoutCase(List<HTypeGuard> bailouts1, | 3022 void startBailoutCase(List<HBailoutTarget> bailouts1, |
| 3010 List<HTypeGuard> bailouts2) { | 3023 List<HBailoutTarget> bailouts2) { |
| 3011 indent--; | 3024 indent--; |
| 3012 if (!defaultClauseUsedInBailoutStack.last() && | 3025 if (!defaultClauseUsedInBailoutStack.last() && |
| 3013 bailouts1.length + bailouts2.length >= 2) { | 3026 bailouts1.length + bailouts2.length >= 2) { |
| 3014 addIndented('default:\n'); | 3027 addIndented('default:\n'); |
| 3015 int len = defaultClauseUsedInBailoutStack.length; | 3028 int len = defaultClauseUsedInBailoutStack.length; |
| 3016 defaultClauseUsedInBailoutStack[len - 1] = true; | 3029 defaultClauseUsedInBailoutStack[len - 1] = true; |
| 3017 } else { | 3030 } else { |
| 3018 handleBailoutCase(bailouts1); | 3031 handleBailoutCase(bailouts1); |
| 3019 handleBailoutCase(bailouts2); | 3032 handleBailoutCase(bailouts2); |
| 3020 } | 3033 } |
| 3021 indent++; | 3034 indent++; |
| 3022 } | 3035 } |
| 3023 | 3036 |
| 3024 void handleBailoutCase(List<HTypeGuard> guards) { | 3037 void handleBailoutCase(List<HBailoutTarget> targets) { |
| 3025 if (!defaultClauseUsedInBailoutStack.last() && guards.length >= 2) { | 3038 if (!defaultClauseUsedInBailoutStack.last() && targets.length >= 2) { |
| 3026 addIndented('default:\n'); | 3039 addIndented('default:\n'); |
| 3027 int len = defaultClauseUsedInBailoutStack.length; | 3040 int len = defaultClauseUsedInBailoutStack.length; |
| 3028 defaultClauseUsedInBailoutStack[len - 1] = true; | 3041 defaultClauseUsedInBailoutStack[len - 1] = true; |
| 3029 } else { | 3042 } else { |
| 3030 for (int i = 0, len = guards.length; i < len; i++) { | 3043 for (int i = 0, len = targets.length; i < len; i++) { |
| 3031 addIndented('case ${guards[i].state}:\n'); | 3044 addIndented('case ${targets[i].state}:\n'); |
| 3032 } | 3045 } |
| 3033 } | 3046 } |
| 3034 } | 3047 } |
| 3035 | 3048 |
| 3036 void startBailoutSwitch() { | 3049 void startBailoutSwitch() { |
| 3037 defaultClauseUsedInBailoutStack.add(false); | 3050 defaultClauseUsedInBailoutStack.add(false); |
| 3038 addIndented('switch (state) {\n'); | 3051 addIndented('switch (state) {\n'); |
| 3039 indent++; | 3052 indent++; |
| 3040 addIndented('case 0:\n'); | 3053 addIndented('case 0:\n'); |
| 3041 indent++; | 3054 indent++; |
| 3042 } | 3055 } |
| 3043 | 3056 |
| 3044 void endBailoutSwitch() { | 3057 void endBailoutSwitch() { |
| 3045 indent--; // Close 'case'. | 3058 indent--; // Close 'case'. |
| 3046 indent--; | 3059 indent--; |
| 3047 addIndented('}\n'); // Close 'switch'. | 3060 addIndented('}\n'); // Close 'switch'. |
| 3048 defaultClauseUsedInBailoutStack.removeLast(); | 3061 defaultClauseUsedInBailoutStack.removeLast(); |
| 3049 } | 3062 } |
| 3050 | 3063 |
| 3051 void beginLoop(HBasicBlock block) { | 3064 void beginLoop(HBasicBlock block) { |
| 3052 String newLabel = pushLabel(); | 3065 String newLabel = pushLabel(); |
| 3053 if (block.hasGuards()) { | 3066 if (block.hasBailoutTargets()) { |
| 3054 startBailoutCase(block.guards, const <HTypeGuard>[]); | 3067 startBailoutCase(block.bailoutTargets, const <HBailoutTarget>[]); |
| 3055 } | 3068 } |
| 3056 | 3069 |
| 3057 addIndentation(); | 3070 addIndentation(); |
| 3058 HLoopInformation loopInformation = block.loopInformation; | 3071 HLoopInformation loopInformation = block.loopInformation; |
| 3059 for (LabelElement label in loopInformation.labels) { | 3072 for (LabelElement label in loopInformation.labels) { |
| 3060 writeLabel(label); | 3073 writeLabel(label); |
| 3061 buffer.add(":"); | 3074 buffer.add(":"); |
| 3062 } | 3075 } |
| 3063 buffer.add('$newLabel: while (true) {\n'); | 3076 buffer.add('$newLabel: while (true) {\n'); |
| 3064 indent++; | 3077 indent++; |
| 3065 | 3078 |
| 3066 if (block.hasGuards()) { | 3079 if (block.hasBailoutTargets()) { |
| 3067 startBailoutSwitch(); | 3080 startBailoutSwitch(); |
| 3068 if (loopInformation.target !== null) { | 3081 if (loopInformation.target !== null) { |
| 3069 breakAction[loopInformation.target] = (TargetElement target) { | 3082 breakAction[loopInformation.target] = (TargetElement target) { |
| 3070 addIndented("break $newLabel;\n"); | 3083 addIndented("break $newLabel;\n"); |
| 3071 }; | 3084 }; |
| 3072 } | 3085 } |
| 3073 } | 3086 } |
| 3074 } | 3087 } |
| 3075 | 3088 |
| 3076 void endLoop(HBasicBlock block) { | 3089 void endLoop(HBasicBlock block) { |
| 3077 popLabel(); | 3090 popLabel(); |
| 3078 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; | 3091 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; |
| 3079 if (header.hasGuards()) { | 3092 if (header.hasBailoutTargets()) { |
| 3080 endBailoutSwitch(); | 3093 endBailoutSwitch(); |
| 3081 HLoopInformation info = header.loopInformation; | 3094 HLoopInformation info = header.loopInformation; |
| 3082 if (info.target != null) breakAction.remove(info.target); | 3095 if (info.target != null) breakAction.remove(info.target); |
| 3083 } | 3096 } |
| 3084 indent--; | 3097 indent--; |
| 3085 addIndented('}\n'); // Close 'while'. | 3098 addIndented('}\n'); // Close 'while'. |
| 3086 } | 3099 } |
| 3087 | 3100 |
| 3088 void handleLoopCondition(HLoopBranch node) { | 3101 void handleLoopCondition(HLoopBranch node) { |
| 3089 buffer.add('if (!'); | 3102 buffer.add('if (!'); |
| 3090 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE); | 3103 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE); |
| 3091 buffer.add(') break ${currentLabel()};\n'); | 3104 buffer.add(') break ${currentLabel()};\n'); |
| 3092 } | 3105 } |
| 3093 | 3106 |
| 3094 void generateIf(HIf node, HIfBlockInformation info) { | 3107 void generateIf(HIf node, HIfBlockInformation info) { |
| 3095 HStatementInformation thenGraph = info.thenGraph; | 3108 HStatementInformation thenGraph = info.thenGraph; |
| 3096 HStatementInformation elseGraph = info.elseGraph; | 3109 HStatementInformation elseGraph = info.elseGraph; |
| 3097 bool thenHasGuards = thenGraph.start.hasGuards(); | 3110 bool thenHasGuards = thenGraph.start.hasBailoutTargets(); |
| 3098 bool elseHasGuards = elseGraph.start.hasGuards(); | 3111 bool elseHasGuards = elseGraph.start.hasBailoutTargets(); |
| 3099 bool hasGuards = thenHasGuards || elseHasGuards; | 3112 bool hasGuards = thenHasGuards || elseHasGuards; |
| 3100 if (!hasGuards) return super.generateIf(node, info); | 3113 if (!hasGuards) return super.generateIf(node, info); |
| 3101 | 3114 |
| 3102 int elseKind = analyzeGraphForCodegen(elseGraph); | 3115 int elseKind = analyzeGraphForCodegen(elseGraph); |
| 3103 bool emptyElse = elseKind == SsaCodeGenerator.EMPTY; | 3116 bool emptyElse = elseKind == SsaCodeGenerator.EMPTY; |
| 3104 | 3117 |
| 3105 startBailoutCase(thenGraph.start.guards, | 3118 startBailoutCase(thenGraph.start.bailoutTargets, |
| 3106 emptyElse ? const <HTypeGuard>[] : elseGraph.start.guards); | 3119 emptyElse ? const <HBailoutTarget>[] : elseGraph.start.bailoutTargets); |
| 3107 | 3120 |
| 3108 addIndented('if ('); | 3121 addIndented('if ('); |
| 3109 int precedence = JSPrecedence.EXPRESSION_PRECEDENCE; | 3122 int precedence = JSPrecedence.EXPRESSION_PRECEDENCE; |
| 3110 // TODO(ngeoffray): Put the condition initialization in the | 3123 // TODO(ngeoffray): Put the condition initialization in the |
| 3111 // [setup] buffer. | 3124 // [setup] buffer. |
| 3112 List<HTypeGuard> guards = node.thenBlock.guards; | 3125 List<HBailoutTarget> targets = node.thenBlock.bailoutTargets; |
| 3113 for (int i = 0, len = guards.length; i < len; i++) { | 3126 for (int i = 0, len = targets.length; i < len; i++) { |
| 3114 buffer.add('state == ${guards[i].state} || '); | 3127 buffer.add('state == ${targets[i].state} || '); |
| 3115 } | 3128 } |
| 3116 buffer.add('(state == 0 && '); | 3129 buffer.add('(state == 0 && '); |
| 3117 precedence = JSPrecedence.BITWISE_OR_PRECEDENCE; | 3130 precedence = JSPrecedence.BITWISE_OR_PRECEDENCE; |
| 3118 use(node.inputs[0], precedence); | 3131 use(node.inputs[0], precedence); |
| 3119 | 3132 |
| 3120 buffer.add(')) {\n'); | 3133 buffer.add(')) {\n'); |
| 3121 | 3134 |
| 3122 indent++; | 3135 indent++; |
| 3123 if (thenHasGuards) startBailoutSwitch(); | 3136 if (thenHasGuards) startBailoutSwitch(); |
| 3124 generateStatements(thenGraph); | 3137 generateStatements(thenGraph); |
| 3125 if (thenHasGuards) endBailoutSwitch(); | 3138 if (thenHasGuards) endBailoutSwitch(); |
| 3126 indent--; | 3139 indent--; |
| 3127 | 3140 |
| 3128 if (!emptyElse) { | 3141 if (!emptyElse) { |
| 3129 addIndented('} else {\n'); | 3142 addIndented('} else {\n'); |
| 3130 indent++; | 3143 indent++; |
| 3131 if (elseHasGuards) startBailoutSwitch(); | 3144 if (elseHasGuards) startBailoutSwitch(); |
| 3132 generateStatements(elseGraph); | 3145 generateStatements(elseGraph); |
| 3133 if (elseHasGuards) endBailoutSwitch(); | 3146 if (elseHasGuards) endBailoutSwitch(); |
| 3134 indent--; | 3147 indent--; |
| 3135 } | 3148 } |
| 3136 | 3149 |
| 3137 addIndented('}\n'); | 3150 addIndented('}\n'); |
| 3138 } | 3151 } |
| 3139 | 3152 |
| 3140 void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 3153 void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 3141 if (labeledBlockInfo.body.start.hasGuards()) { | 3154 if (labeledBlockInfo.body.start.hasBailoutTargets()) { |
| 3142 indent--; | 3155 indent--; |
| 3143 handleBailoutCase(labeledBlockInfo.body.start.guards); | 3156 handleBailoutCase(labeledBlockInfo.body.start.bailoutTargets); |
| 3144 indent++; | 3157 indent++; |
| 3145 } | 3158 } |
| 3146 } | 3159 } |
| 3147 | 3160 |
| 3148 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 3161 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 3149 if (labeledBlockInfo.body.start.hasGuards()) { | 3162 if (labeledBlockInfo.body.start.hasBailoutTargets()) { |
| 3150 startBailoutSwitch(); | 3163 startBailoutSwitch(); |
| 3151 } | 3164 } |
| 3152 } | 3165 } |
| 3153 | 3166 |
| 3154 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 3167 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 3155 if (labeledBlockInfo.body.start.hasGuards()) { | 3168 if (labeledBlockInfo.body.start.hasBailoutTargets()) { |
| 3156 endBailoutSwitch(); | 3169 endBailoutSwitch(); |
| 3157 } | 3170 } |
| 3158 } | 3171 } |
| 3159 } | 3172 } |
| 3160 | 3173 |
| 3161 String singleIdentityComparison(HInstruction left, HInstruction right) { | 3174 String singleIdentityComparison(HInstruction left, HInstruction right) { |
| 3162 // Returns the single identity comparison (== or ===) or null if a more | 3175 // Returns the single identity comparison (== or ===) or null if a more |
| 3163 // complex expression is required. | 3176 // complex expression is required. |
| 3164 HType leftType = left.propagatedType; | 3177 HType leftType = left.propagatedType; |
| 3165 HType rightType = right.propagatedType; | 3178 HType rightType = right.propagatedType; |
| 3166 if (leftType.canBeNull() && rightType.canBeNull()) { | 3179 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 3167 if (left.isConstantNull() || right.isConstantNull() || | 3180 if (left.isConstantNull() || right.isConstantNull() || |
| 3168 (leftType.isPrimitive() && leftType == rightType)) { | 3181 (leftType.isPrimitive() && leftType == rightType)) { |
| 3169 return '=='; | 3182 return '=='; |
| 3170 } | 3183 } |
| 3171 return null; | 3184 return null; |
| 3172 } else { | 3185 } else { |
| 3173 return '==='; | 3186 return '==='; |
| 3174 } | 3187 } |
| 3175 } | 3188 } |
| OLD | NEW |