Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test/switch case #231

Merged
merged 2 commits into from Dec 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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"));
}
}