}
private void atSwitchStmnt(Stmnt st) throws CompileError {
+ boolean isString = false;
+ if (typeChecker != null) {
+ doTypeCheck(st.head());
+ isString = typeChecker.exprType == TypeChecker.CLASS
+ && typeChecker.arrayDim == 0
+ && TypeChecker.jvmJavaLangString.equals(typeChecker.className);
+ }
+
compileExpr(st.head());
+ int tmpVar = -1;
+ if (isString) {
+ tmpVar = getMaxLocals();
+ incMaxLocals(1);
+ bytecode.addAstore(tmpVar);
+ bytecode.addAload(tmpVar);
+ bytecode.addInvokevirtual(TypeChecker.jvmJavaLangString, "hashCode", "()I");
+ }
List<Integer> prevBreakList = breakList;
breakList = new ArrayList<Integer>();
bytecode.addGap(npairs * 8);
long[] pairs = new long[npairs];
+ ArrayList<Integer> gotoDefaults = new ArrayList<Integer>();
int ipairs = 0;
int defaultPc = -1;
for (ASTList list = body; list != null; list = list.tail()) {
else if (op != CASE)
fatal();
else {
+ int curPos = bytecode.currentPc();
+ long caseLabel;
+ if (isString) {
+ // computeStringLabel() also adds bytecode as its side-effects.
+ caseLabel = (long)computeStringLabel(label.head(), tmpVar, gotoDefaults);
+ }
+ else
+ caseLabel = (long)computeLabel(label.head());
+
pairs[ipairs++]
- = ((long)computeLabel(label.head()) << 32) +
- ((long)(bytecode.currentPc() - opcodePc) & 0xffffffff);
+ = (caseLabel << 32) +
+ ((long)(curPos - opcodePc) & 0xffffffff);
}
hasReturned = false;
defaultPc = endPc;
bytecode.write32bit(opcodePc2, defaultPc - opcodePc);
+ for (int addr: gotoDefaults)
+ bytecode.write16bit(addr, defaultPc - addr + 1);
patchGoto(breakList, endPc);
breakList = prevBreakList;
throw new CompileError("bad case label");
}
+ private int computeStringLabel(ASTree expr, int tmpVar, List<Integer> gotoDefaults)
+ throws CompileError
+ {
+ doTypeCheck(expr);
+ expr = TypeChecker.stripPlusExpr(expr);
+ if (expr instanceof StringL) {
+ String label = ((StringL)expr).get();
+ bytecode.addAload(tmpVar);
+ bytecode.addLdc(label);
+ bytecode.addInvokevirtual(TypeChecker.jvmJavaLangString, "equals",
+ "(Ljava/lang/Object;)Z");
+ bytecode.addOpcode(IFEQ);
+ Integer pc = Integer.valueOf(bytecode.currentPc());
+ bytecode.addIndex(0);
+ gotoDefaults.add(pc);
+ return (int)label.hashCode();
+ }
+ throw new CompileError("bad case label");
+ }
+
private void atBreakStmnt(Stmnt st, boolean notCont)
throws CompileError
{
cc.getClassFile().compact();
cc.toClass(test5.DefineClassCapability.class);
}
+
+ public void testSwitchCaseWithStringConstant() throws Exception {
+ CtClass cc = sloader.get("test5.SwitchCase");
+ cc.addMethod(CtNewMethod.make(
+ "public int run() {" +
+ " String s = \"foobar\";\n" +
+ " switch (s) {\n" +
+ " case STR1: return 1;\n" +
+ " case \"foobar\": return 2;\n" +
+ " default: return 3; }\n" +
+ "}\n", cc));
+ cc.writeFile();
+ Object obj = make(cc.getName());
+ assertEquals(2, invoke(obj, "run"));
+ }
+
+ public void testSwitchCaseWithStringConstant2() throws Exception {
+ CtClass cc = sloader.makeClass("test5.SwitchCase2");
+ cc.addMethod(CtNewMethod.make(
+ "public int run() {" +
+ " String s = \"foo\";\n" +
+ " switch (s) {\n" +
+ " case test5.SwitchCase.STR1: return 1;\n" +
+ " case \"foobar\": return 2;\n" +
+ " }\n" +
+ " return 3;\n" +
+ "}\n", cc));
+ cc.writeFile();
+ Object obj = make(cc.getName());
+ assertEquals(1, invoke(obj, "run"));
+ }
}