Skip to content

Commit

Permalink
Merge pull request #231 from jboss-javassist/test/switch-case
Browse files Browse the repository at this point in the history
Supporting switch-case statements with string constants.
  • Loading branch information
chibash committed Dec 11, 2018
2 parents 1a3d637 + c9ab465 commit ba22607
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 2 deletions.
5 changes: 5 additions & 0 deletions Readme.html
Expand Up @@ -281,6 +281,11 @@ <h2>Hints</h2>

<h2>Changes</h2>

<p>-version 3.25
<ul>
<li>GitHub Issue #72.
</ul>

<p>-version 3.24.1 on December 9, 2018
<ul>
<li>GitHub Issue #228, #229</li>
Expand Down
Binary file modified javassist.jar
Binary file not shown.
52 changes: 50 additions & 2 deletions src/main/javassist/compiler/CodeGen.java
Expand Up @@ -542,7 +542,23 @@ private void atForStmnt(Stmnt st) throws CompileError {
}

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>();
Expand All @@ -565,6 +581,7 @@ private void atSwitchStmnt(Stmnt st) throws CompileError {
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()) {
Expand All @@ -575,9 +592,18 @@ private void atSwitchStmnt(Stmnt st) throws CompileError {
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;
Expand All @@ -600,6 +626,8 @@ else if (op != CASE)
defaultPc = endPc;

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

patchGoto(breakList, endPc);
breakList = prevBreakList;
Expand All @@ -613,6 +641,26 @@ private int computeLabel(ASTree expr) throws CompileError {
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
{
Expand Down
31 changes: 31 additions & 0 deletions src/test/javassist/JvstTest5.java
Expand Up @@ -453,4 +453,35 @@ public void testNestHostAttributeCopy() throws Exception {
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"));
}
}

0 comments on commit ba22607

Please sign in to comment.