More switch parsing/code generation cleanups: now IRFactory constructs the proper parsed tree for the switch statement which removed the need for tree mutations in NodeTransformer and during code generation.

This commit is contained in:
igor%mir2.org 2004-08-07 20:08:38 +00:00
Родитель 61215cbb33
Коммит 06080a4162
6 изменённых файлов: 151 добавлений и 121 удалений

Просмотреть файл

@ -86,21 +86,94 @@ final class IRFactory
Node createSwitch(Node expr, int lineno)
{
return new Node.Jump(Token.SWITCH, expr, lineno);
//
// The switch will be rewritten from:
//
// switch (expr) {
// case test1: statements1;
// ...
// default: statementsDefault;
// ...
// case testN: statementsN;
// }
//
// to:
//
// {
// switch (expr) {
// case test1: goto label1;
// ...
// case testN: goto labelN;
// }
// goto labelDefault;
// label1:
// statements1;
// ...
// labelDefault:
// statementsDefault;
// ...
// labelN:
// statementsN;
// breakLabel:
// }
//
// where inside switch each "break;" without label will be replaced
// by "goto breakLabel".
//
// If the original switch does not have the default label, then
// the transformed code would contain after the switch instead of
// goto labelDefault;
// the following goto:
// goto breakLabel;
//
Node.Jump switchNode = new Node.Jump(Token.SWITCH, expr, lineno);
Node block = new Node(Token.BLOCK, switchNode);
return block;
}
void addSwitchCase(Node switchNode, Node expression, Node statements)
/**
* If caseExpression argument is null it indicate default label.
*/
void addSwitchCase(Node switchBlock, Node caseExpression, Node statements)
{
if (switchBlock.getType() != Token.BLOCK) throw Kit.codeBug();
Node.Jump switchNode = (Node.Jump)switchBlock.getFirstChild();
if (switchNode.getType() != Token.SWITCH) throw Kit.codeBug();
Node caseNode = new Node(Token.CASE, expression, statements);
switchNode.addChildToBack(caseNode);
Node.Target gotoTarget = new Node.Target();
if (caseExpression != null) {
Node.Jump caseNode = new Node.Jump(Token.CASE, caseExpression);
caseNode.target = gotoTarget;
switchNode.addChildToBack(caseNode);
} else {
switchNode.setDefault(gotoTarget);
}
switchBlock.addChildToBack(gotoTarget);
switchBlock.addChildToBack(statements);
}
void addSwitchDefault(Node switchNode, Node statements)
void closeSwitch(Node switchBlock)
{
if (switchBlock.getType() != Token.BLOCK) throw Kit.codeBug();
Node.Jump switchNode = (Node.Jump)switchBlock.getFirstChild();
if (switchNode.getType() != Token.SWITCH) throw Kit.codeBug();
Node defaultNode = new Node(Token.DEFAULT, statements);
switchNode.addChildToBack(defaultNode);
Node.Target switchBreakTarget = new Node.Target();
// switchNode.target is only used by NodeTransformer
// to detect switch end
switchNode.target = switchBreakTarget;
Node.Jump defaultGoto = new Node.Jump(Token.GOTO);
Node.Target defaultTarget = switchNode.getDefault();
if (defaultTarget != null) {
defaultGoto.target = defaultTarget;
} else {
defaultGoto.target = switchBreakTarget;
}
switchBlock.addChildAfter(defaultGoto, switchNode);
switchBlock.addChildToBack(switchBreakTarget);
}
Node createVariables(int lineno)

Просмотреть файл

@ -496,11 +496,6 @@ public class Interpreter
break;
}
case Token.CASE:
// Skip case condition
child = child.getNext();
// fallthrough
case Token.DEFAULT:
case Token.SCRIPT:
case Token.LABEL:
case Token.LOOP:
@ -1039,43 +1034,32 @@ public class Interpreter
private void visitSwitch(Node.Jump switchNode)
{
Node child = switchNode.getFirstChild();
// See comments in IRFactory.createSwitch() for description
// of SWITCH node
updateLineNumber(switchNode);
visitExpression(child);
ObjArray cases = (ObjArray) switchNode.getProp(Node.CASES_PROP);
for (int i = 0; i < cases.size(); i++) {
Node thisCase = (Node)cases.get(i);
Node test = thisCase.getFirstChild();
// the case expression is the firstmost child
// the rest will be generated when the case
// statements are encountered as siblings of
// the switch statement.
Node child = switchNode.getFirstChild();
visitExpression(child);
for (Node.Jump caseNode = (Node.Jump)child.getNext();
caseNode != null;
caseNode = (Node.Jump)caseNode.getNext())
{
if (caseNode.getType() != Token.CASE)
throw badTree(caseNode);
Node test = caseNode.getFirstChild();
addIcode(Icode_DUP);
stackChange(1);
visitExpression(test);
addToken(Token.SHEQ);
stackChange(-1);
Node.Target target = new Node.Target();
thisCase.addChildAfter(target, test);
// If true, Icode_IFEQ_POP will jump and remove case value
// from stack
addGoto(target, Icode_IFEQ_POP);
addGoto(caseNode.target, Icode_IFEQ_POP);
stackChange(-1);
}
addIcode(Icode_POP);
stackChange(-1);
Node defaultNode = (Node) switchNode.getProp(Node.DEFAULT_PROP);
if (defaultNode != null) {
Node.Target defaultTarget = new Node.Target();
defaultNode.getFirstChild().addChildToFront(defaultTarget);
addGoto(defaultTarget, Token.GOTO);
}
Node.Target breakTarget = switchNode.target;
addGoto(breakTarget, Token.GOTO);
}
private void visitCall(Node node)

Просмотреть файл

@ -51,10 +51,8 @@ public class Node
LOCAL_PROP = 2,
LOCAL_BLOCK_PROP = 3,
REGEXP_PROP = 4,
CASES_PROP = 5,
DEFAULT_PROP = 6,
CASEARRAY_PROP = 7,
SPECIAL_PROP_PROP = 8,
CASEARRAY_PROP = 5,
SPECIAL_PROP_PROP = 6,
/*
the following properties are defined and manipulated by the
optimizer -
@ -67,15 +65,15 @@ public class Node
matches.
*/
TARGETBLOCK_PROP = 9,
VARIABLE_PROP = 10,
ISNUMBER_PROP = 11,
DIRECTCALL_PROP = 12,
SPECIALCALL_PROP = 13,
SKIP_INDEXES_PROP = 14, // array of skipped indexes of array literal
OBJECT_IDS_PROP = 15, // array of properties for object literal
INCRDECR_PROP = 16, // pre or post type of increment/decerement
LAST_PROP = 16;
TARGETBLOCK_PROP = 7,
VARIABLE_PROP = 8,
ISNUMBER_PROP = 9,
DIRECTCALL_PROP = 10,
SPECIALCALL_PROP = 11,
SKIP_INDEXES_PROP = 12, // array of skipped indexes of array literal
OBJECT_IDS_PROP = 13, // array of properties for object literal
INCRDECR_PROP = 14, // pre or post type of increment/decerement
LAST_PROP = 14;
// values of ISNUMBER_PROP to specify
// which of the children are Number types
@ -158,6 +156,20 @@ public class Node
this.label = label;
}
public final Target getDefault()
{
if (!(type == Token.SWITCH)) Kit.codeBug();
return target2;
}
public final void setDefault(Target defaultTarget)
{
if (!(type == Token.SWITCH)) Kit.codeBug();
if (defaultTarget == null) Kit.codeBug();
if (target2 != null) Kit.codeBug(); //only once
target2 = defaultTarget;
}
public final Target getFinally()
{
if (!(type == Token.TRY)) Kit.codeBug();
@ -419,8 +431,6 @@ public class Node
case LOCAL_PROP: return "local";
case LOCAL_BLOCK_PROP: return "local_block";
case REGEXP_PROP: return "regexp";
case CASES_PROP: return "cases";
case DEFAULT_PROP: return "default";
case CASEARRAY_PROP: return "casearray";
case SPECIAL_PROP_PROP: return "special_prop";

Просмотреть файл

@ -144,37 +144,10 @@ public class NodeTransformer
case Token.SWITCH:
{
Node.Target breakTarget = new Node.Target();
parent.addChildAfter(breakTarget, node);
// make all children siblings except for selector
Node sib = node;
Node child = node.getFirstChild().next;
while (child != null) {
Node next = child.next;
node.removeChild(child);
parent.addChildAfter(child, sib);
sib = child;
child = next;
}
((Node.Jump)node).target = breakTarget;
loops.push(node);
Node.Jump switchNode = (Node.Jump)node;
Node breakTarget = switchNode.target;
loops.push(switchNode);
loopEnds.push(breakTarget);
node.putProp(Node.CASES_PROP, new ObjArray());
break;
}
case Token.DEFAULT:
case Token.CASE:
{
Node sw = (Node) loops.peek();
if (type == Token.CASE) {
ObjArray cases = (ObjArray) sw.getProp(Node.CASES_PROP);
cases.add(node);
} else {
sw.putProp(Node.DEFAULT_PROP, node);
}
break;
}

Просмотреть файл

@ -554,13 +554,11 @@ public class Parser
nf.addChildToBack(block, statement());
}
if (caseExpression != null) {
nf.addSwitchCase(pn, caseExpression, block);
} else {
nf.addSwitchDefault(pn, block);
}
// caseExpression == null => add default lable
nf.addSwitchCase(pn, caseExpression, block);
}
decompiler.addEOL(Token.RC);
nf.closeSwitch(pn);
break;
}

Просмотреть файл

@ -1400,10 +1400,6 @@ class BodyCodegen
--withNesting;
break;
case Token.CASE:
case Token.DEFAULT:
// XXX shouldn't these be StatementNodes?
case Token.SCRIPT:
case Token.BLOCK:
case Token.EMPTY:
@ -2112,38 +2108,37 @@ class BodyCodegen
+")V");
}
private void acquireTargetLabel(Node.Target target)
private int getTargetLabel(Node.Target target)
{
if (target.labelId == -1) {
target.labelId = cfw.acquireLabel();
}
return target.labelId;
}
private void visitTarget(Node.Target target)
{
acquireTargetLabel(target);
cfw.markLabel(target.labelId);
int label = getTargetLabel(target);
cfw.markLabel(label);
}
private void visitGOTO(Node.Jump node, int type, Node child)
{
Node.Target target = node.target;
acquireTargetLabel(target);
int targetLabel = target.labelId;
if (type == Token.IFEQ || type == Token.IFNE) {
if (child == null) throw Codegen.badTree();
int targetLabel = getTargetLabel(target);
int fallThruLabel = cfw.acquireLabel();
if (type == Token.IFEQ)
generateIfJump(child, node, targetLabel, fallThruLabel);
else
generateIfJump(child, node, fallThruLabel, targetLabel);
cfw.markLabel(fallThruLabel);
}
else {
} else {
if (type == Token.JSR)
cfw.add(ByteCode.JSR, targetLabel);
addGoto(target, ByteCode.JSR);
else
cfw.add(ByteCode.GOTO, targetLabel);
addGoto(target, ByteCode.GOTO);
}
}
@ -2883,41 +2878,32 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
cfw.add(ByteCode.ATHROW);
}
private void visitSwitch(Node.Jump node, Node child)
private void visitSwitch(Node.Jump switchNode, Node child)
{
generateExpression(child, node);
// See comments in IRFactory.createSwitch() for description
// of SWITCH node
generateExpression(child, switchNode);
// save selector value
short selector = getNewWordLocal();
cfw.addAStore(selector);
ObjArray cases = (ObjArray) node.getProp(Node.CASES_PROP);
for (int i=0; i < cases.size(); i++) {
Node thisCase = (Node) cases.get(i);
Node first = thisCase.getFirstChild();
generateExpression(first, thisCase);
for (Node.Jump caseNode = (Node.Jump)child.getNext();
caseNode != null;
caseNode = (Node.Jump)caseNode.getNext())
{
if (caseNode.getType() != Token.CASE)
throw Codegen.badTree();
Node test = caseNode.getFirstChild();
generateExpression(test, caseNode);
cfw.addALoad(selector);
addScriptRuntimeInvoke("shallowEq",
"(Ljava/lang/Object;"
+"Ljava/lang/Object;"
+")Z");
Node.Target target = new Node.Target();
thisCase.replaceChild(first, target);
acquireTargetLabel(target);
cfw.add(ByteCode.IFNE, target.labelId);
addGoto(caseNode.target, ByteCode.IFNE);
}
releaseWordLocal(selector);
Node defaultNode = (Node) node.getProp(Node.DEFAULT_PROP);
if (defaultNode != null) {
Node.Target defaultTarget = new Node.Target();
defaultNode.getFirstChild().addChildToFront(defaultTarget);
acquireTargetLabel(defaultTarget);
cfw.add(ByteCode.GOTO, defaultTarget.labelId);
}
Node.Target breakTarget = node.target;
acquireTargetLabel(breakTarget);
cfw.add(ByteCode.GOTO, breakTarget.labelId);
}
private void visitTypeofname(Node node)
@ -3884,6 +3870,12 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
cfw.markLabel(beyond);
}
private void addGoto(Node.Target target, byte jumpcode)
{
int targetLabel = getTargetLabel(target);
cfw.add(jumpcode, targetLabel);
}
private void addObjectToDouble()
{
addScriptRuntimeInvoke("toNumber", "(Ljava/lang/Object;)D");