Browse Source

enables switch-case with string constants

tags/rel_3_25_0_ga
chibash 5 years ago
parent
commit
52138ca440
3 changed files with 81 additions and 2 deletions
  1. BIN
      javassist.jar
  2. 50
    2
      src/main/javassist/compiler/CodeGen.java
  3. 31
    0
      src/test/javassist/JvstTest5.java

BIN
javassist.jar View File


+ 50
- 2
src/main/javassist/compiler/CodeGen.java View File

@@ -542,7 +542,23 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
}

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>();
@@ -565,6 +581,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
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()) {
@@ -575,9 +592,18 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
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;
@@ -600,6 +626,8 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
defaultPc = endPc;

bytecode.write32bit(opcodePc2, defaultPc - opcodePc);
for (int addr: gotoDefaults)
bytecode.write16bit(addr, defaultPc - addr + 1);

patchGoto(breakList, endPc);
breakList = prevBreakList;
@@ -613,6 +641,26 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
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
{

+ 31
- 0
src/test/javassist/JvstTest5.java View File

@@ -453,4 +453,35 @@ public class JvstTest5 extends JvstTestRoot {
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"));
}
}

Loading…
Cancel
Save