Chromium Code Reviews| 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 882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1158 } | 1160 } |
| 1159 if (!isGeneratingExpression()) { | 1161 if (!isGeneratingExpression()) { |
| 1160 buffer.add(';\n'); | 1162 buffer.add(';\n'); |
| 1161 } | 1163 } |
| 1162 } | 1164 } |
| 1163 } | 1165 } |
| 1164 | 1166 |
| 1165 void iterateBasicBlock(HBasicBlock node) { | 1167 void iterateBasicBlock(HBasicBlock node) { |
| 1166 HInstruction instruction = node.first; | 1168 HInstruction instruction = node.first; |
| 1167 while (instruction !== node.last) { | 1169 while (instruction !== node.last) { |
| 1168 if (instruction is HTypeGuard) { | 1170 if (instruction is HTypeGuard || instruction is HBailoutTarget) { |
| 1169 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 1171 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 1170 } else if (!isGenerateAtUseSite(instruction)) { | 1172 } else if (!isGenerateAtUseSite(instruction)) { |
| 1171 expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; | 1173 expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; |
| 1172 define(instruction); | 1174 define(instruction); |
| 1173 } | 1175 } |
| 1174 instruction = instruction.next; | 1176 instruction = instruction.next; |
| 1175 } | 1177 } |
| 1176 assignPhisOfSuccessors(node); | 1178 assignPhisOfSuccessors(node); |
| 1177 if (instruction is HLoopBranch && isGeneratingExpression()) { | 1179 if (instruction is HLoopBranch && isGeneratingExpression()) { |
| 1178 addExpressionSeparator(); | 1180 addExpressionSeparator(); |
| (...skipping 1523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2702 | 2704 |
| 2703 int maxBailoutParameters; | 2705 int maxBailoutParameters; |
| 2704 | 2706 |
| 2705 HBasicBlock beginGraph(HGraph graph) => graph.entry; | 2707 HBasicBlock beginGraph(HGraph graph) => graph.entry; |
| 2706 void endGraph(HGraph graph) {} | 2708 void endGraph(HGraph graph) {} |
| 2707 | 2709 |
| 2708 void bailout(HTypeGuard guard, String reason) { | 2710 void bailout(HTypeGuard guard, String reason) { |
| 2709 if (maxBailoutParameters === null) { | 2711 if (maxBailoutParameters === null) { |
| 2710 maxBailoutParameters = 0; | 2712 maxBailoutParameters = 0; |
| 2711 work.guards.forEach((HTypeGuard workGuard) { | 2713 work.guards.forEach((HTypeGuard workGuard) { |
| 2712 int inputLength = workGuard.inputs.length; | 2714 HBailoutTarget target = workGuard.bailoutTarget; |
| 2715 int inputLength = target.inputs.length; | |
| 2713 if (inputLength > maxBailoutParameters) { | 2716 if (inputLength > maxBailoutParameters) { |
| 2714 maxBailoutParameters = inputLength; | 2717 maxBailoutParameters = inputLength; |
| 2715 } | 2718 } |
| 2716 }); | 2719 }); |
| 2717 } | 2720 } |
| 2718 HInstruction input = guard.guarded; | 2721 HInstruction input = guard.guarded; |
| 2722 HBailoutTarget target = guard.bailoutTarget; | |
| 2719 Namer namer = compiler.namer; | 2723 Namer namer = compiler.namer; |
| 2720 Element element = work.element; | 2724 Element element = work.element; |
| 2721 buffer.add('return '); | 2725 buffer.add('return '); |
| 2722 if (element.isInstanceMember()) { | 2726 if (element.isInstanceMember()) { |
| 2723 // TODO(ngeoffray): This does not work in case we come from a | 2727 // TODO(ngeoffray): This does not work in case we come from a |
| 2724 // super call. We must make bailout names unique. | 2728 // super call. We must make bailout names unique. |
| 2725 buffer.add('this.${namer.getBailoutName(element)}'); | 2729 buffer.add('this.${namer.getBailoutName(element)}'); |
| 2726 } else { | 2730 } else { |
| 2727 buffer.add(namer.isolateBailoutAccess(element)); | 2731 buffer.add(namer.isolateBailoutAccess(element)); |
| 2728 } | 2732 } |
| 2729 buffer.add('(${guard.state}'); | 2733 buffer.add('(${guard.state}'); |
| 2730 // TODO(ngeoffray): try to put a variable at a deterministic | 2734 // TODO(ngeoffray): try to put a variable at a deterministic |
| 2731 // location, so that multiple bailout calls put the variable at | 2735 // location, so that multiple bailout calls put the variable at |
| 2732 // the same parameter index. | 2736 // the same parameter index. |
| 2733 int i = 0; | 2737 int i = 0; |
| 2734 for (; i < guard.inputs.length; i++) { | 2738 for (; i < target.inputs.length; i++) { |
| 2739 assert(guard.inputs.indexOf(target.inputs[i]) >= 0); | |
| 2735 buffer.add(', '); | 2740 buffer.add(', '); |
| 2736 use(guard.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 2741 use(target.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 2737 } | 2742 } |
| 2738 // Make sure we call the bailout method with the number of | 2743 // Make sure we call the bailout method with the number of |
| 2739 // arguments it expects. This avoids having the underlying | 2744 // arguments it expects. This avoids having the underlying |
| 2740 // JS engine fill them in for us. | 2745 // JS engine fill them in for us. |
| 2741 for (; i < maxBailoutParameters; i++) { | 2746 for (; i < maxBailoutParameters; i++) { |
| 2742 buffer.add(', 0'); | 2747 buffer.add(', 0'); |
| 2743 } | 2748 } |
| 2744 buffer.add(')'); | 2749 buffer.add(')'); |
| 2745 } | 2750 } |
| 2746 | 2751 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2820 buffer.add(' && '); | 2825 buffer.add(' && '); |
| 2821 checkType(input, indexingBehavior, negative: true); | 2826 checkType(input, indexingBehavior, negative: true); |
| 2822 buffer.add('))) '); | 2827 buffer.add('))) '); |
| 2823 bailout(node, 'Not a string or array'); | 2828 bailout(node, 'Not a string or array'); |
| 2824 } else { | 2829 } else { |
| 2825 compiler.internalError('Unexpected type guard', instruction: input); | 2830 compiler.internalError('Unexpected type guard', instruction: input); |
| 2826 } | 2831 } |
| 2827 buffer.add(';\n'); | 2832 buffer.add(';\n'); |
| 2828 } | 2833 } |
| 2829 | 2834 |
| 2835 void visitBailoutTarget(HBailoutTarget target) { | |
| 2836 // Do nothing. Bailout targets are only used in the non-optimized version. | |
| 2837 } | |
| 2838 | |
| 2830 void beginLoop(HBasicBlock block) { | 2839 void beginLoop(HBasicBlock block) { |
| 2831 addIndentation(); | 2840 addIndentation(); |
| 2832 HLoopInformation info = block.loopInformation; | 2841 HLoopInformation info = block.loopInformation; |
| 2833 for (LabelElement label in info.labels) { | 2842 for (LabelElement label in info.labels) { |
| 2834 writeLabel(label); | 2843 writeLabel(label); |
| 2835 buffer.add(":"); | 2844 buffer.add(":"); |
| 2836 } | 2845 } |
| 2837 buffer.add('while (true) {\n'); | 2846 buffer.add('while (true) {\n'); |
| 2838 indent++; | 2847 indent++; |
| 2839 } | 2848 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2890 return labels.last(); | 2899 return labels.last(); |
| 2891 } | 2900 } |
| 2892 | 2901 |
| 2893 HBasicBlock beginGraph(HGraph graph) { | 2902 HBasicBlock beginGraph(HGraph graph) { |
| 2894 propagator = new SsaBailoutPropagator(compiler, generateAtUseSite); | 2903 propagator = new SsaBailoutPropagator(compiler, generateAtUseSite); |
| 2895 propagator.visitGraph(graph); | 2904 propagator.visitGraph(graph); |
| 2896 // TODO(ngeoffray): We could avoid generating the state at the | 2905 // TODO(ngeoffray): We could avoid generating the state at the |
| 2897 // call site for non-complex bailout methods. | 2906 // call site for non-complex bailout methods. |
| 2898 newParameters.add('state'); | 2907 newParameters.add('state'); |
| 2899 | 2908 |
| 2900 if (propagator.hasComplexTypeGuards) { | 2909 if (propagator.hasComplexBailoutTargets) { |
| 2901 // Use generic parameters that will be assigned to | 2910 // Use generic parameters that will be assigned to |
| 2902 // the right variables in the setup phase. | 2911 // the right variables in the setup phase. |
| 2903 for (int i = 0; i < propagator.maxBailoutParameters; i++) { | 2912 for (int i = 0; i < propagator.maxBailoutParameters; i++) { |
| 2904 String name = 'env$i'; | 2913 String name = 'env$i'; |
| 2905 declaredVariables.add(name); | 2914 declaredVariables.add(name); |
| 2906 newParameters.add(', $name'); | 2915 newParameters.add(', $name'); |
| 2907 } | 2916 } |
| 2908 | 2917 |
| 2909 startBailoutSwitch(); | 2918 startBailoutSwitch(); |
| 2910 | 2919 |
| 2911 // The setup phase of a bailout function sets up the environment for | 2920 // The setup phase of a bailout function sets up the environment for |
| 2912 // each bailout target. Each bailout target will populate this | 2921 // each bailout target. Each bailout target will populate this |
| 2913 // setup phase. It is put at the beginning of the function. | 2922 // setup phase. It is put at the beginning of the function. |
| 2914 setup.add(' switch (state) {\n'); | 2923 setup.add(' switch (state) {\n'); |
| 2915 return graph.entry; | 2924 return graph.entry; |
| 2916 } else { | 2925 } else { |
| 2917 // We have a simple type guard, so we can reuse the names that | 2926 // We have a simple bailout target, so we can reuse the names that |
| 2918 // the type guard expects. | 2927 // the bailout target expects. |
| 2919 for (HInstruction input in propagator.firstTypeGuard.inputs) { | 2928 for (HInstruction input in propagator.firstBailoutTarget.inputs) { |
| 2920 input = unwrap(input); | 2929 input = unwrap(input); |
| 2921 String name = variableNames.getName(input); | 2930 String name = variableNames.getName(input); |
| 2922 declaredVariables.add(name); | 2931 declaredVariables.add(name); |
| 2923 newParameters.add(', $name'); | 2932 newParameters.add(', $name'); |
| 2924 } | 2933 } |
| 2925 | 2934 |
| 2926 // We change the first instruction of the first guard to be the | 2935 // We change the first instruction of the first guard to be the |
| 2927 // guard. We will change it back in the call to [endGraph]. | 2936 // bailout target. We will change it back in the call to [endGraph]. |
| 2928 HBasicBlock block = propagator.firstTypeGuard.block; | 2937 HBasicBlock block = propagator.firstBailoutTarget.block; |
| 2929 savedFirstInstruction = block.first; | 2938 savedFirstInstruction = block.first; |
| 2930 block.first = propagator.firstTypeGuard; | 2939 block.first = propagator.firstBailoutTarget; |
| 2931 return block; | 2940 return block; |
| 2932 } | 2941 } |
| 2933 } | 2942 } |
| 2934 | 2943 |
| 2935 // If argument is a [HCheck] and it does not have a name, we try to | 2944 // If argument is a [HCheck] and it does not have a name, we try to |
| 2936 // find the name of its checked input. Note that there must be a | 2945 // find the name of its checked input. Note that there must be a |
| 2937 // name, otherwise the instruction would not be in the live | 2946 // name, otherwise the instruction would not be in the live |
| 2938 // environment. | 2947 // environment. |
| 2939 HInstruction unwrap(HInstruction argument) { | 2948 HInstruction unwrap(HInstruction argument) { |
| 2940 while (argument is HCheck && !variableNames.hasName(argument)) { | 2949 while (argument is HCheck && !variableNames.hasName(argument)) { |
| 2941 argument = argument.checkedInput; | 2950 argument = argument.checkedInput; |
| 2942 } | 2951 } |
| 2943 assert(variableNames.hasName(argument)); | 2952 assert(variableNames.hasName(argument)); |
| 2944 return argument; | 2953 return argument; |
| 2945 } | 2954 } |
| 2946 | 2955 |
| 2947 void endGraph(HGraph graph) { | 2956 void endGraph(HGraph graph) { |
| 2948 if (propagator.hasComplexTypeGuards) { | 2957 if (propagator.hasComplexBailoutTargets) { |
| 2949 indent--; // Close original case. | 2958 indent--; // Close original case. |
| 2950 indent--; | 2959 indent--; |
| 2951 addIndented('}\n'); // Close 'switch'. | 2960 addIndented('}\n'); // Close 'switch'. |
| 2952 setup.add(' }\n'); | 2961 setup.add(' }\n'); |
| 2953 } else { | 2962 } else { |
| 2954 // Put back the original first instruction of the block. | 2963 // Put back the original first instruction of the block. |
| 2955 propagator.firstTypeGuard.block.first = savedFirstInstruction; | 2964 propagator.firstBailoutTarget.block.first = savedFirstInstruction; |
| 2956 } | 2965 } |
| 2957 } | 2966 } |
| 2958 | 2967 |
| 2959 bool visitAndOrInfo(HAndOrBlockInformation info) => false; | 2968 bool visitAndOrInfo(HAndOrBlockInformation info) => false; |
| 2960 | 2969 |
| 2961 bool visitIfInfo(HIfBlockInformation info) { | 2970 bool visitIfInfo(HIfBlockInformation info) { |
| 2962 if (info.thenGraph.start.hasGuards()) return false; | 2971 if (info.thenGraph.start.hasBailoutTargets()) return false; |
| 2963 if (info.elseGraph.start.hasGuards()) return false; | 2972 if (info.elseGraph.start.hasBailoutTargets()) return false; |
| 2964 return super.visitIfInfo(info); | 2973 return super.visitIfInfo(info); |
| 2965 } | 2974 } |
| 2966 | 2975 |
| 2967 bool visitLoopInfo(HLoopBlockInformation info) { | 2976 bool visitLoopInfo(HLoopBlockInformation info) { |
| 2968 if (info.start.hasGuards()) return false; | 2977 if (info.start.hasBailoutTargets()) return false; |
| 2969 if (info.loopHeader.hasGuards()) return false; | 2978 if (info.loopHeader.hasBailoutTargets()) return false; |
| 2970 return super.visitLoopInfo(info); | 2979 return super.visitLoopInfo(info); |
| 2971 } | 2980 } |
| 2972 | 2981 |
| 2973 bool visitTryInfo(HTryBlockInformation info) => false; | 2982 bool visitTryInfo(HTryBlockInformation info) => false; |
| 2974 bool visitSequenceInfo(HStatementSequenceInformation info) => false; | 2983 bool visitSequenceInfo(HStatementSequenceInformation info) => false; |
| 2975 | 2984 |
| 2976 void visitTypeGuard(HTypeGuard node) { | 2985 void visitTypeGuard(HTypeGuard node) { |
| 2977 if (!propagator.hasComplexTypeGuards) return; | 2986 // Do nothing. Type guards are only used in the optimized version. |
| 2987 } | |
| 2988 | |
| 2989 void visitBailoutTarget(HBailoutTarget node) { | |
| 2990 if (!propagator.hasComplexBailoutTargets) return; | |
| 2978 | 2991 |
| 2979 indent--; | 2992 indent--; |
| 2980 addIndented('case ${node.state}:\n'); | 2993 addIndented('case ${node.state}:\n'); |
| 2981 indent++; | 2994 indent++; |
| 2982 addIndented('state = 0;\n'); | 2995 addIndented('state = 0;\n'); |
| 2983 | 2996 |
| 2984 setup.add(' case ${node.state}:\n'); | 2997 setup.add(' case ${node.state}:\n'); |
| 2985 int i = 0; | 2998 int i = 0; |
| 2986 for (HInstruction input in node.inputs) { | 2999 for (HInstruction input in node.inputs) { |
| 2987 input = unwrap(input); | 3000 input = unwrap(input); |
| 2988 String name = variableNames.getName(input); | 3001 String name = variableNames.getName(input); |
| 2989 setup.add(' '); | 3002 setup.add(' '); |
| 2990 if (!isVariableDeclared(name)) { | 3003 if (!isVariableDeclared(name)) { |
| 2991 declaredVariables.add(name); | 3004 declaredVariables.add(name); |
| 2992 setup.add('var '); | 3005 setup.add('var '); |
| 2993 } | 3006 } |
| 2994 setup.add('$name = env$i;\n'); | 3007 setup.add('$name = env$i;\n'); |
| 2995 i++; | 3008 i++; |
| 2996 } | 3009 } |
| 2997 setup.add(' break;\n'); | 3010 setup.add(' break;\n'); |
| 2998 } | 3011 } |
| 2999 | 3012 |
| 3000 void startBailoutCase(List<HTypeGuard> bailouts1, | 3013 void startBailoutCase(List<HBailoutTarget> bailouts1, |
| 3001 List<HTypeGuard> bailouts2) { | 3014 List<HBailoutTarget> bailouts2) { |
| 3002 indent--; | 3015 indent--; |
| 3003 handleBailoutCase(bailouts1); | 3016 handleBailoutCase(bailouts1); |
| 3004 handleBailoutCase(bailouts2); | 3017 handleBailoutCase(bailouts2); |
| 3005 indent++; | 3018 indent++; |
| 3006 } | 3019 } |
| 3007 | 3020 |
| 3008 void handleBailoutCase(List<HTypeGuard> guards) { | 3021 void handleBailoutCase(List<HBailoutTarget> targets) { |
| 3009 for (int i = 0, len = guards.length; i < len; i++) { | 3022 for (int i = 0, len = targets.length; i < len; i++) { |
| 3010 addIndented('case ${guards[i].state}:\n'); | 3023 addIndented('case ${targets[i].state}:\n'); |
| 3011 } | 3024 } |
| 3012 } | 3025 } |
| 3013 | 3026 |
| 3014 void startBailoutSwitch() { | 3027 void startBailoutSwitch() { |
| 3015 addIndented('switch (state) {\n'); | 3028 addIndented('switch (state) {\n'); |
| 3016 indent++; | 3029 indent++; |
| 3017 addIndented('case 0:\n'); | 3030 addIndented('case 0:\n'); |
| 3018 indent++; | 3031 indent++; |
| 3019 } | 3032 } |
| 3020 | 3033 |
| 3021 void endBailoutSwitch() { | 3034 void endBailoutSwitch() { |
| 3022 indent--; // Close 'case'. | 3035 indent--; // Close 'case'. |
| 3023 indent--; | 3036 indent--; |
| 3024 addIndented('}\n'); // Close 'switch'. | 3037 addIndented('}\n'); // Close 'switch'. |
| 3025 } | 3038 } |
| 3026 | 3039 |
| 3027 void beginLoop(HBasicBlock block) { | 3040 void beginLoop(HBasicBlock block) { |
| 3028 String newLabel = pushLabel(); | 3041 String newLabel = pushLabel(); |
| 3029 if (block.hasGuards()) { | 3042 if (block.hasBailoutTargets()) { |
| 3030 startBailoutCase(block.guards, const <HTypeGuard>[]); | 3043 startBailoutCase(block.bailoutTargets, const <HBailoutTarget>[]); |
| 3031 } | 3044 } |
| 3032 | 3045 |
| 3033 addIndentation(); | 3046 addIndentation(); |
| 3034 HLoopInformation loopInformation = block.loopInformation; | 3047 HLoopInformation loopInformation = block.loopInformation; |
| 3035 for (LabelElement label in loopInformation.labels) { | 3048 for (LabelElement label in loopInformation.labels) { |
| 3036 writeLabel(label); | 3049 writeLabel(label); |
| 3037 buffer.add(":"); | 3050 buffer.add(":"); |
| 3038 } | 3051 } |
| 3039 buffer.add('$newLabel: while (true) {\n'); | 3052 buffer.add('$newLabel: while (true) {\n'); |
| 3040 indent++; | 3053 indent++; |
| 3041 | 3054 |
| 3042 if (block.hasGuards()) { | 3055 if (block.hasBailoutTargets()) { |
| 3043 startBailoutSwitch(); | 3056 startBailoutSwitch(); |
| 3044 if (loopInformation.target !== null) { | 3057 if (loopInformation.target !== null) { |
| 3045 breakAction[loopInformation.target] = (TargetElement target) { | 3058 breakAction[loopInformation.target] = (TargetElement target) { |
| 3046 addIndented("break $newLabel;\n"); | 3059 addIndented("break $newLabel;\n"); |
| 3047 }; | 3060 }; |
| 3048 } | 3061 } |
| 3049 } | 3062 } |
| 3050 } | 3063 } |
| 3051 | 3064 |
| 3052 void endLoop(HBasicBlock block) { | 3065 void endLoop(HBasicBlock block) { |
| 3053 popLabel(); | 3066 popLabel(); |
| 3054 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; | 3067 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; |
| 3055 if (header.hasGuards()) { | 3068 if (header.hasBailoutTargets()) { |
| 3056 endBailoutSwitch(); | 3069 endBailoutSwitch(); |
| 3057 HLoopInformation info = header.loopInformation; | 3070 HLoopInformation info = header.loopInformation; |
| 3058 if (info.target != null) breakAction.remove(info.target); | 3071 if (info.target != null) breakAction.remove(info.target); |
| 3059 } | 3072 } |
| 3060 indent--; | 3073 indent--; |
| 3061 addIndented('}\n'); // Close 'while'. | 3074 addIndented('}\n'); // Close 'while'. |
| 3062 } | 3075 } |
| 3063 | 3076 |
| 3064 void handleLoopCondition(HLoopBranch node) { | 3077 void handleLoopCondition(HLoopBranch node) { |
| 3065 buffer.add('if (!'); | 3078 buffer.add('if (!'); |
| 3066 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE); | 3079 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE); |
| 3067 buffer.add(') break ${currentLabel()};\n'); | 3080 buffer.add(') break ${currentLabel()};\n'); |
| 3068 } | 3081 } |
| 3069 | 3082 |
| 3070 void generateIf(HIf node, HIfBlockInformation info) { | 3083 void generateIf(HIf node, HIfBlockInformation info) { |
| 3071 HStatementInformation thenGraph = info.thenGraph; | 3084 HStatementInformation thenGraph = info.thenGraph; |
| 3072 HStatementInformation elseGraph = info.elseGraph; | 3085 HStatementInformation elseGraph = info.elseGraph; |
| 3073 bool thenHasGuards = thenGraph.start.hasGuards(); | 3086 bool thenHasGuards = thenGraph.start.hasBailoutTargets(); |
| 3074 bool elseHasGuards = elseGraph.start.hasGuards(); | 3087 bool elseHasGuards = elseGraph.start.hasBailoutTargets(); |
| 3075 bool hasGuards = thenHasGuards || elseHasGuards; | 3088 bool hasGuards = thenHasGuards || elseHasGuards; |
| 3076 if (!hasGuards) return super.generateIf(node, info); | 3089 if (!hasGuards) return super.generateIf(node, info); |
| 3077 | 3090 |
| 3078 int elseKind = analyzeGraphForCodegen(elseGraph); | 3091 int elseKind = analyzeGraphForCodegen(elseGraph); |
| 3079 bool emptyElse = elseKind == SsaCodeGenerator.EMPTY; | 3092 bool emptyElse = elseKind == SsaCodeGenerator.EMPTY; |
| 3080 | 3093 |
| 3081 startBailoutCase(thenGraph.start.guards, | 3094 startBailoutCase(thenGraph.start.bailoutTargets, |
| 3082 emptyElse ? const <HTypeGuard>[] : elseGraph.start.guards); | 3095 emptyElse ? const <HBailoutTarget>[] : elseGraph.start.bailoutTargets); |
| 3083 | 3096 |
| 3084 addIndented('if ('); | 3097 addIndented('if ('); |
| 3085 int precedence = JSPrecedence.EXPRESSION_PRECEDENCE; | 3098 int precedence = JSPrecedence.EXPRESSION_PRECEDENCE; |
| 3086 // TODO(ngeoffray): Put the condition initialization in the | 3099 // TODO(ngeoffray): Put the condition initialization in the |
| 3087 // [setup] buffer. | 3100 // [setup] buffer. |
| 3088 List<HTypeGuard> guards = node.thenBlock.guards; | 3101 List<HBailoutTarget> guards = node.thenBlock.bailoutTargets; |
|
ricow1
2012/07/23 12:52:26
rename guards to targets
floitsch
2012/07/23 13:27:48
Done.
| |
| 3089 for (int i = 0, len = guards.length; i < len; i++) { | 3102 for (int i = 0, len = guards.length; i < len; i++) { |
| 3090 buffer.add('state == ${guards[i].state} || '); | 3103 buffer.add('state == ${guards[i].state} || '); |
| 3091 } | 3104 } |
| 3092 buffer.add('(state == 0 && '); | 3105 buffer.add('(state == 0 && '); |
| 3093 precedence = JSPrecedence.BITWISE_OR_PRECEDENCE; | 3106 precedence = JSPrecedence.BITWISE_OR_PRECEDENCE; |
| 3094 use(node.inputs[0], precedence); | 3107 use(node.inputs[0], precedence); |
| 3095 | 3108 |
| 3096 buffer.add(')) {\n'); | 3109 buffer.add(')) {\n'); |
| 3097 | 3110 |
| 3098 indent++; | 3111 indent++; |
| 3099 if (thenHasGuards) startBailoutSwitch(); | 3112 if (thenHasGuards) startBailoutSwitch(); |
| 3100 generateStatements(thenGraph); | 3113 generateStatements(thenGraph); |
| 3101 if (thenHasGuards) endBailoutSwitch(); | 3114 if (thenHasGuards) endBailoutSwitch(); |
| 3102 indent--; | 3115 indent--; |
| 3103 | 3116 |
| 3104 if (!emptyElse) { | 3117 if (!emptyElse) { |
| 3105 addIndented('} else {\n'); | 3118 addIndented('} else {\n'); |
| 3106 indent++; | 3119 indent++; |
| 3107 if (elseHasGuards) startBailoutSwitch(); | 3120 if (elseHasGuards) startBailoutSwitch(); |
| 3108 generateStatements(elseGraph); | 3121 generateStatements(elseGraph); |
| 3109 if (elseHasGuards) endBailoutSwitch(); | 3122 if (elseHasGuards) endBailoutSwitch(); |
| 3110 indent--; | 3123 indent--; |
| 3111 } | 3124 } |
| 3112 | 3125 |
| 3113 addIndented('}\n'); | 3126 addIndented('}\n'); |
| 3114 } | 3127 } |
| 3115 | 3128 |
| 3116 void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 3129 void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 3117 if (labeledBlockInfo.body.start.hasGuards()) { | 3130 if (labeledBlockInfo.body.start.hasBailoutTargets()) { |
| 3118 indent--; | 3131 indent--; |
| 3119 handleBailoutCase(labeledBlockInfo.body.start.guards); | 3132 handleBailoutCase(labeledBlockInfo.body.start.bailoutTargets); |
| 3120 indent++; | 3133 indent++; |
| 3121 } | 3134 } |
| 3122 } | 3135 } |
| 3123 | 3136 |
| 3124 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 3137 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 3125 if (labeledBlockInfo.body.start.hasGuards()) { | 3138 if (labeledBlockInfo.body.start.hasBailoutTargets()) { |
| 3126 startBailoutSwitch(); | 3139 startBailoutSwitch(); |
| 3127 } | 3140 } |
| 3128 } | 3141 } |
| 3129 | 3142 |
| 3130 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 3143 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 3131 if (labeledBlockInfo.body.start.hasGuards()) { | 3144 if (labeledBlockInfo.body.start.hasBailoutTargets()) { |
| 3132 endBailoutSwitch(); | 3145 endBailoutSwitch(); |
| 3133 } | 3146 } |
| 3134 } | 3147 } |
| 3135 } | 3148 } |
| 3136 | 3149 |
| 3137 String singleIdentityComparison(HInstruction left, HInstruction right) { | 3150 String singleIdentityComparison(HInstruction left, HInstruction right) { |
| 3138 // Returns the single identity comparison (== or ===) or null if a more | 3151 // Returns the single identity comparison (== or ===) or null if a more |
| 3139 // complex expression is required. | 3152 // complex expression is required. |
| 3140 HType leftType = left.propagatedType; | 3153 HType leftType = left.propagatedType; |
| 3141 HType rightType = right.propagatedType; | 3154 HType rightType = right.propagatedType; |
| 3142 if (leftType.canBeNull() && rightType.canBeNull()) { | 3155 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 3143 if (left.isConstantNull() || right.isConstantNull() || | 3156 if (left.isConstantNull() || right.isConstantNull() || |
| 3144 (leftType.isPrimitive() && leftType == rightType)) { | 3157 (leftType.isPrimitive() && leftType == rightType)) { |
| 3145 return '=='; | 3158 return '=='; |
| 3146 } | 3159 } |
| 3147 return null; | 3160 return null; |
| 3148 } else { | 3161 } else { |
| 3149 return '==='; | 3162 return '==='; |
| 3150 } | 3163 } |
| 3151 } | 3164 } |
| OLD | NEW |