1.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue May 07 14:36:57 2013 +0200 1.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue May 07 14:43:17 2013 +0200 1.3 @@ -71,6 +71,7 @@ 1.4 import java.util.EnumSet; 1.5 import java.util.Iterator; 1.6 import java.util.List; 1.7 + 1.8 import jdk.internal.dynalink.support.NameCodec; 1.9 import jdk.internal.org.objectweb.asm.Handle; 1.10 import jdk.internal.org.objectweb.asm.MethodVisitor; 1.11 @@ -189,7 +190,7 @@ 1.12 @Override 1.13 public void begin() { 1.14 classEmitter.beginMethod(this); 1.15 - stack = new ArrayDeque<>(); 1.16 + newStack(); 1.17 method.visitCode(); 1.18 } 1.19 1.20 @@ -205,6 +206,10 @@ 1.21 classEmitter.endMethod(this); 1.22 } 1.23 1.24 + private void newStack() { 1.25 + stack = new ArrayDeque<>(); 1.26 + } 1.27 + 1.28 @Override 1.29 public String toString() { 1.30 return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this); 1.31 @@ -484,7 +489,7 @@ 1.32 name = THIS_DEBUGGER.symbolName(); 1.33 } 1.34 1.35 - method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot()); 1.36 + method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start.getLabel(), end.getLabel(), symbol.getSlot()); 1.37 } 1.38 1.39 /** 1.40 @@ -509,17 +514,6 @@ 1.41 } 1.42 1.43 /** 1.44 - * Associate a variable with a given range 1.45 - * 1.46 - * @param name name of the variable 1.47 - * @param start start 1.48 - * @param end end 1.49 - */ 1.50 - void markerVariable(final String name, final Label start, final Label end) { 1.51 - method.visitLocalVariable(name, Type.OBJECT.getDescriptor(), null, start, end, 0); 1.52 - } 1.53 - 1.54 - /** 1.55 * Pops two integer types from the stack, performs a bitwise and and pushes 1.56 * the result 1.57 * 1.58 @@ -626,7 +620,7 @@ 1.59 * @param typeDescriptor type descriptor for exception 1.60 */ 1.61 void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) { 1.62 - method.visitTryCatchBlock(entry, exit, recovery, typeDescriptor); 1.63 + method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor); 1.64 } 1.65 1.66 /** 1.67 @@ -638,7 +632,7 @@ 1.68 * @param clazz exception class 1.69 */ 1.70 void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) { 1.71 - method.visitTryCatchBlock(entry, exit, recovery, CompilerConstants.className(clazz)); 1.72 + method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), CompilerConstants.className(clazz)); 1.73 } 1.74 1.75 /** 1.76 @@ -1228,6 +1222,14 @@ 1.77 return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true); 1.78 } 1.79 1.80 + static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) { 1.81 + final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length]; 1.82 + for (int i = 0; i < table.length; i++) { 1.83 + internalLabels[i] = table[i].getLabel(); 1.84 + } 1.85 + return internalLabels; 1.86 + } 1.87 + 1.88 /** 1.89 * Generate a lookup switch, popping the switch value from the stack 1.90 * 1.91 @@ -1235,10 +1237,10 @@ 1.92 * @param values case values for the table 1.93 * @param table default label 1.94 */ 1.95 - void lookupswitch(final Label defaultLabel, final int[] values, final Label[] table) { 1.96 + void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection<Label> table) { 1.97 debug("lookupswitch", peekType()); 1.98 popType(Type.INT); 1.99 - method.visitLookupSwitchInsn(defaultLabel, values, table); 1.100 + method.visitLookupSwitchInsn(defaultLabel.getLabel(), values, getLabels(table)); 1.101 } 1.102 1.103 /** 1.104 @@ -1248,10 +1250,10 @@ 1.105 * @param defaultLabel default label 1.106 * @param table label table 1.107 */ 1.108 - void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label[] table) { 1.109 + void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label... table) { 1.110 debug("tableswitch", peekType()); 1.111 popType(Type.INT); 1.112 - method.visitTableSwitchInsn(lo, hi, defaultLabel, table); 1.113 + method.visitTableSwitchInsn(lo, hi, defaultLabel.getLabel(), getLabels(table)); 1.114 } 1.115 1.116 /** 1.117 @@ -1358,7 +1360,7 @@ 1.118 popType(); 1.119 } 1.120 mergeStackTo(label); 1.121 - method.visitJumpInsn(opcode, label); 1.122 + method.visitJumpInsn(opcode, label.getLabel()); 1.123 } 1.124 1.125 /** 1.126 @@ -1487,9 +1489,9 @@ 1.127 * @param label destination label 1.128 */ 1.129 void _goto(final Label label) { 1.130 - debug("goto", label); 1.131 + //debug("goto", label); 1.132 jump(GOTO, label, 0); 1.133 - stack = null; 1.134 + stack = null; //whoever reaches the point after us provides the stack, because we don't 1.135 } 1.136 1.137 /** 1.138 @@ -1521,13 +1523,24 @@ 1.139 /** 1.140 * A join in control flow - helper function that makes sure all entry stacks 1.141 * discovered for the join point so far are equivalent 1.142 - * @param label 1.143 + * 1.144 + * MergeStack: we are about to enter a label. If its stack, label.getStack() is null 1.145 + * we have never been here before. Then we are expected to carry a stack with us. 1.146 + * 1.147 + * @param label label 1.148 */ 1.149 private void mergeStackTo(final Label label) { 1.150 + //sometimes we can do a merge stack without having a stack - i.e. when jumping ahead to dead code 1.151 + //see NASHORN-73. So far we had been saved by the line number nodes. This should have been fixed 1.152 + //by Lower removing everything after an unconditionally executed terminating statement OR a break 1.153 + //or continue in a block. Previously code left over after breaks and continues was still there 1.154 + //and caused bytecode to be generated - which crashed on stack not being there, as the merge 1.155 + //was not in fact preceeded by a visit. Furthermore, this led to ASM putting out its NOP NOP NOP 1.156 + //ATHROW sequences instead of no code being generated at all. This should now be fixed. 1.157 + assert stack != null : label + " entered with no stack. deadcode that remains?"; 1.158 + 1.159 final ArrayDeque<Type> labelStack = label.getStack(); 1.160 - //debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label); 1.161 if (labelStack == null) { 1.162 - assert stack != null; 1.163 label.setStack(stack.clone()); 1.164 return; 1.165 } 1.166 @@ -1548,14 +1561,14 @@ 1.167 if (stack == null) { 1.168 stack = label.getStack(); 1.169 if (stack == null) { 1.170 - stack = new ArrayDeque<>(); //we don't have a stack at this point. 1.171 + newStack(); 1.172 } 1.173 } 1.174 debug_label(label); 1.175 1.176 mergeStackTo(label); //we have to merge our stack to whatever is in the label 1.177 1.178 - method.visitLabel(label); 1.179 + method.visitLabel(label.getLabel()); 1.180 } 1.181 1.182 /** 1.183 @@ -2018,8 +2031,13 @@ 1.184 * @param line line number 1.185 * @param label label 1.186 */ 1.187 - void lineNumber(final int line, final Label label) { 1.188 - method.visitLineNumber(line, label); 1.189 + void lineNumber(final int line) { 1.190 + if (env._debug_lines) { 1.191 + debug_label("[LINE]", line); 1.192 + final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label(); 1.193 + method.visitLabel(l); 1.194 + method.visitLineNumber(line, l); 1.195 + } 1.196 } 1.197 1.198 /* 1.199 @@ -2116,7 +2134,7 @@ 1.200 pad--; 1.201 } 1.202 1.203 - if (!stack.isEmpty()) { 1.204 + if (stack != null && !stack.isEmpty()) { 1.205 sb.append("{"); 1.206 sb.append(stack.size()); 1.207 sb.append(":");