mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-11 16:32:59 +00:00
Statement fun
This commit is contained in:
parent
b6ac1476df
commit
573531b249
@ -61,32 +61,27 @@ Formatter& operator<<(Formatter &f, ICodeModule &i)
|
||||
// ICodeGenerator
|
||||
//
|
||||
|
||||
ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting)
|
||||
ICodeGenerator::ICodeGenerator(World *world)
|
||||
: topRegister(0),
|
||||
registerBase(0),
|
||||
maxRegister(0),
|
||||
parameterCount(0),
|
||||
exceptionRegister(NotARegister),
|
||||
switchRegister(NotARegister),
|
||||
variableList(new VariableList()),
|
||||
mWorld(world)
|
||||
mWorld(world),
|
||||
mInstructionMap(new InstructionMap())
|
||||
{
|
||||
iCode = new InstructionStream();
|
||||
iCodeOwner = true;
|
||||
if (hasTryStatement)
|
||||
exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]);
|
||||
for (uint i = 0; i < switchStatementNesting; i++) {
|
||||
String s = widenCString("__switchControlVariable__");
|
||||
char num[8];
|
||||
sprintf(num, "%.2d", i);
|
||||
appendChars(s, num, strlen(num));
|
||||
if (switchRegister == NotARegister)
|
||||
switchRegister = allocateVariable(world->identifiers[s]);
|
||||
else
|
||||
allocateVariable(world->identifiers[s]);
|
||||
}
|
||||
}
|
||||
|
||||
Register ICodeGenerator::allocateVariable(const StringAtom& name)
|
||||
{
|
||||
if (exceptionRegister == NotARegister) {
|
||||
exceptionRegister = grabRegister(mWorld->identifiers[widenCString("__exceptionObject__")]);
|
||||
}
|
||||
return grabRegister(name);
|
||||
}
|
||||
|
||||
ICodeModule *ICodeGenerator::complete()
|
||||
{
|
||||
@ -121,7 +116,7 @@ ICodeModule *ICodeGenerator::complete()
|
||||
}
|
||||
*/
|
||||
markMaxRegister();
|
||||
ICodeModule* module = new ICodeModule(iCode, variableList, maxRegister, 0);
|
||||
ICodeModule* module = new ICodeModule(iCode, variableList, maxRegister, 0, mInstructionMap);
|
||||
iCodeOwner = false; // give ownership to the module.
|
||||
return module;
|
||||
}
|
||||
@ -333,45 +328,29 @@ void ICodeGenerator::branch(Label *label)
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::branchConditional(Label *label, Register condition)
|
||||
{
|
||||
ICodeOp branchOp = getBranchOp();
|
||||
ASSERT(branchOp != NOP);
|
||||
GenericBranch *instr = new GenericBranch(branchOp, label, condition);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::branchTrue(Label *label, Register condition)
|
||||
GenericBranch *ICodeGenerator::branchTrue(Label *label, Register condition)
|
||||
{
|
||||
GenericBranch *instr = new GenericBranch(BRANCH_TRUE, label, condition);
|
||||
iCode->push_back(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
void ICodeGenerator::branchFalse(Label *label, Register condition)
|
||||
GenericBranch *ICodeGenerator::branchFalse(Label *label, Register condition)
|
||||
{
|
||||
GenericBranch *instr = new GenericBranch(BRANCH_FALSE, label, condition);
|
||||
iCode->push_back(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
void ICodeGenerator::branchNotConditional(Label *label, Register condition)
|
||||
void ICodeGenerator::returnStmt(Register r)
|
||||
{
|
||||
ICodeOp branchOp = getBranchOp();
|
||||
ASSERT(branchOp != NOP);
|
||||
switch (branchOp) {
|
||||
case BRANCH_FALSE : branchOp = BRANCH_TRUE; break;
|
||||
case BRANCH_TRUE : branchOp = BRANCH_FALSE; break;
|
||||
case BRANCH_EQ : branchOp = BRANCH_NE; break;
|
||||
case BRANCH_GE : branchOp = BRANCH_LT; break;
|
||||
case BRANCH_GT : branchOp = BRANCH_LE; break;
|
||||
case BRANCH_LE : branchOp = BRANCH_GT; break;
|
||||
case BRANCH_LT : branchOp = BRANCH_GE; break;
|
||||
case BRANCH_NE : branchOp = BRANCH_EQ; break;
|
||||
default : NOT_REACHED("Expected a branch op"); break;
|
||||
}
|
||||
GenericBranch *instr = new GenericBranch(branchOp, label, condition);
|
||||
iCode->push_back(instr);
|
||||
if (r == NotARegister)
|
||||
iCode->push_back(new ReturnVoid());
|
||||
else
|
||||
iCode->push_back(new Return(r));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Label *ICodeGenerator::getLabel()
|
||||
@ -492,10 +471,13 @@ static bool generatedBoolean(ExprNode *p)
|
||||
|
||||
/*
|
||||
if trueBranch OR falseBranch are not null, the sub-expression should generate
|
||||
a conditional branch do the appropriate target. If either branch is NULL, it
|
||||
a conditional branch to the appropriate target. If either branch is NULL, it
|
||||
indicates that the label is immediately forthcoming.
|
||||
*/
|
||||
Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label *trueBranch, Label *falseBranch)
|
||||
Register ICodeGenerator::genExpr(ExprNode *p,
|
||||
bool needBoolValueInBranch,
|
||||
Label *trueBranch,
|
||||
Label *falseBranch)
|
||||
{
|
||||
Register ret = NotARegister;
|
||||
switch (p->getKind()) {
|
||||
@ -561,13 +543,13 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
break;
|
||||
case ExprNode::identifier :
|
||||
{
|
||||
/*
|
||||
variable or name? If there's a 'with' in this scope, then it's
|
||||
a name, otherwise look it up in the function variable map.
|
||||
*/
|
||||
Register v = findVariable((static_cast<IdentifierExprNode *>(p))->name);
|
||||
if (v != NotARegister)
|
||||
ret = v;
|
||||
if (mWithinWith) {
|
||||
Register v = findVariable((static_cast<IdentifierExprNode *>(p))->name);
|
||||
if (v != NotARegister)
|
||||
ret = v;
|
||||
else
|
||||
ret = loadName((static_cast<IdentifierExprNode *>(p))->name);
|
||||
}
|
||||
else
|
||||
ret = loadName((static_cast<IdentifierExprNode *>(p))->name);
|
||||
}
|
||||
@ -688,9 +670,9 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2);
|
||||
if (trueBranch || falseBranch) {
|
||||
if (trueBranch == NULL)
|
||||
branchNotConditional(falseBranch, ret);
|
||||
branchFalse(falseBranch, ret);
|
||||
else {
|
||||
branchConditional(trueBranch, ret);
|
||||
branchTrue(trueBranch, ret);
|
||||
if (falseBranch)
|
||||
branch(falseBranch);
|
||||
}
|
||||
@ -706,9 +688,9 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
ret = op(mapExprNodeToICodeOp(p->getKind()), r2, r1); // will return reverse case
|
||||
if (trueBranch || falseBranch) {
|
||||
if (trueBranch == NULL)
|
||||
branchNotConditional(falseBranch, ret);
|
||||
branchFalse(falseBranch, ret);
|
||||
else {
|
||||
branchConditional(trueBranch, ret);
|
||||
branchTrue(trueBranch, ret);
|
||||
if (falseBranch)
|
||||
branch(falseBranch);
|
||||
}
|
||||
@ -725,9 +707,9 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2);
|
||||
if (trueBranch || falseBranch) {
|
||||
if (trueBranch == NULL)
|
||||
branchNotConditional(falseBranch, ret);
|
||||
branchFalse(falseBranch, ret);
|
||||
else {
|
||||
branchConditional(trueBranch, ret);
|
||||
branchTrue(trueBranch, ret);
|
||||
if (falseBranch)
|
||||
branch(falseBranch);
|
||||
}
|
||||
@ -796,7 +778,7 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
Label *beyondBranch = getLabel();
|
||||
Register c = genExpr(t->op1, false, NULL, fBranch);
|
||||
if (!generatedBoolean(t->op1))
|
||||
branchNotConditional(fBranch, test(c));
|
||||
branchFalse(fBranch, test(c));
|
||||
Register r1 = genExpr(t->op2);
|
||||
branch(beyondBranch);
|
||||
setLabel(fBranch);
|
||||
@ -818,7 +800,6 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
/*
|
||||
need pre-pass to find:
|
||||
variable & function definitions,
|
||||
#nested switch statements
|
||||
contains 'with' or 'eval'
|
||||
contains 'try {} catch {} finally {}'
|
||||
*/
|
||||
@ -838,6 +819,11 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
{
|
||||
Register ret = NotARegister;
|
||||
|
||||
startStatement(p->pos);
|
||||
if (exceptionRegister == NotARegister) {
|
||||
exceptionRegister = grabRegister(mWorld->identifiers[widenCString("__exceptionObject__")]);
|
||||
}
|
||||
|
||||
switch (p->getKind()) {
|
||||
case StmtNode::expression:
|
||||
{
|
||||
@ -845,13 +831,25 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
ret = genExpr(e->expr);
|
||||
}
|
||||
break;
|
||||
case StmtNode::Throw:
|
||||
{
|
||||
ExprStmtNode *e = static_cast<ExprStmtNode *>(p);
|
||||
throwStmt(genExpr(e->expr));
|
||||
}
|
||||
break;
|
||||
case StmtNode::Return:
|
||||
{
|
||||
ExprStmtNode *e = static_cast<ExprStmtNode *>(p);
|
||||
returnStmt(ret = genExpr(e->expr));
|
||||
}
|
||||
break;
|
||||
case StmtNode::If:
|
||||
{
|
||||
Label *falseLabel = getLabel();
|
||||
UnaryStmtNode *i = static_cast<UnaryStmtNode *>(p);
|
||||
Register c = genExpr(i->expr, false, NULL, falseLabel);
|
||||
if (!generatedBoolean(i->expr))
|
||||
branchNotConditional(falseLabel, test(c));
|
||||
branchFalse(falseLabel, test(c));
|
||||
genStmt(i->stmt);
|
||||
setLabel(falseLabel);
|
||||
}
|
||||
@ -863,38 +861,78 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
BinaryStmtNode *i = static_cast<BinaryStmtNode *>(p);
|
||||
Register c = genExpr(i->expr, false, NULL, falseLabel);
|
||||
if (!generatedBoolean(i->expr))
|
||||
branchNotConditional(falseLabel, test(c));
|
||||
branchFalse(falseLabel, test(c));
|
||||
genStmt(i->stmt);
|
||||
branch(beyondLabel);
|
||||
setLabel(falseLabel);
|
||||
genStmt(i->stmt2);
|
||||
}
|
||||
break;
|
||||
case StmtNode::With:
|
||||
{
|
||||
UnaryStmtNode *w = static_cast<UnaryStmtNode *>(p);
|
||||
Register o = genExpr(w->expr);
|
||||
bool withinWith = mWithinWith;
|
||||
mWithinWith = true;
|
||||
beginWith(o);
|
||||
genStmt(w->stmt);
|
||||
endWith();
|
||||
mWithinWith = withinWith;
|
||||
}
|
||||
break;
|
||||
case StmtNode::Switch:
|
||||
{
|
||||
Label *defaultLabel = NULL;
|
||||
LabelEntry *e = new LabelEntry(currentLabelSet, getLabel());
|
||||
mLabelStack.push_back(e);
|
||||
SwitchStmtNode *sw = static_cast<SwitchStmtNode *>(p);
|
||||
Register sc = genExpr(sw->expr);
|
||||
StmtNode *s = sw->statements;
|
||||
// ECMA requires case & default statements to be immediate children of switch
|
||||
// unlike C where they can be arbitrarily deeply nested in other statements.
|
||||
// unlike C where they can be arbitrarily deeply nested in other statements.
|
||||
Label *nextCaseLabel = NULL;
|
||||
GenericBranch *lastBranch = NULL;
|
||||
while (s) {
|
||||
ASSERT(s->getKind() == StmtNode::Case);
|
||||
UnaryStmtNode *c = static_cast<UnaryStmtNode *>(s);
|
||||
if (c->expr) {
|
||||
Label *beyondCaseLabel = getLabel();
|
||||
Register r = genExpr(c->expr);
|
||||
Register eq = op(COMPARE_EQ, r, sc);
|
||||
branchNotConditional(beyondCaseLabel, eq);
|
||||
genStmt(c->stmt);
|
||||
setLabel(beyondCaseLabel);
|
||||
if (s->getKind() == StmtNode::Case) {
|
||||
ExprStmtNode *c = static_cast<ExprStmtNode *>(s);
|
||||
if (c->expr) {
|
||||
if (nextCaseLabel)
|
||||
setLabel(nextCaseLabel);
|
||||
nextCaseLabel = getLabel();
|
||||
Register r = genExpr(c->expr);
|
||||
Register eq = op(COMPARE_EQ, r, sc);
|
||||
lastBranch = branchFalse(nextCaseLabel, eq);
|
||||
}
|
||||
else {
|
||||
defaultLabel = getLabel();
|
||||
setLabel(defaultLabel);
|
||||
}
|
||||
}
|
||||
// else it's the default case... THIS IS NOT DONE YET....
|
||||
else
|
||||
genStmt(c->stmt);
|
||||
genStmt(s);
|
||||
s = s->next;
|
||||
}
|
||||
if (nextCaseLabel)
|
||||
setLabel(nextCaseLabel);
|
||||
if (defaultLabel && lastBranch)
|
||||
lastBranch->setTarget(defaultLabel);
|
||||
|
||||
setLabel(e->breakLabel);
|
||||
mLabelStack.pop_back();
|
||||
}
|
||||
break;
|
||||
case StmtNode::DoWhile:
|
||||
{
|
||||
LabelEntry *e = new LabelEntry(currentLabelSet, getLabel(), getLabel());
|
||||
mLabelStack.push_back(e);
|
||||
UnaryStmtNode *d = static_cast<UnaryStmtNode *>(p);
|
||||
Label *doBodyTopLabel = getLabel();
|
||||
setLabel(doBodyTopLabel);
|
||||
genStmt(d->stmt);
|
||||
setLabel(e->continueLabel);
|
||||
Register c = genExpr(d->expr, false, doBodyTopLabel, NULL);
|
||||
if (!generatedBoolean(d->expr))
|
||||
branchTrue(doBodyTopLabel, test(c));
|
||||
setLabel(e->breakLabel);
|
||||
mLabelStack.pop_back();
|
||||
}
|
||||
@ -914,7 +952,7 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
setLabel(e->continueLabel);
|
||||
Register c = genExpr(w->expr, false, whileBodyTopLabel, NULL);
|
||||
if (!generatedBoolean(w->expr))
|
||||
branchConditional(whileBodyTopLabel, test(c));
|
||||
branchTrue(whileBodyTopLabel, test(c));
|
||||
|
||||
setLabel(e->breakLabel);
|
||||
mLabelStack.pop_back();
|
||||
@ -943,7 +981,7 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
if (f->expr2) {
|
||||
Register c = genExpr(f->expr2, false, forBlockTop, NULL);
|
||||
if (!generatedBoolean(f->expr2))
|
||||
branchConditional(forBlockTop, test(c));
|
||||
branchTrue(forBlockTop, test(c));
|
||||
}
|
||||
|
||||
setLabel(e->breakLabel);
|
||||
@ -1003,12 +1041,84 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
ASSERT(e->breakLabel);
|
||||
branch(e->breakLabel);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case StmtNode::Continue:
|
||||
{
|
||||
GoStmtNode *g = static_cast<GoStmtNode *>(p);
|
||||
if (g->label) {
|
||||
LabelEntry *e = NULL;
|
||||
for (LabelStack::reverse_iterator i = mLabelStack.rbegin(); i != mLabelStack.rend(); i++) {
|
||||
e = (*i);
|
||||
if (e->containsLabel(g->name))
|
||||
break;
|
||||
}
|
||||
if (e) {
|
||||
ASSERT(e->continueLabel);
|
||||
branch(e->continueLabel);
|
||||
}
|
||||
else
|
||||
NOT_REACHED("continue label not in label set");
|
||||
}
|
||||
else {
|
||||
ASSERT(!mLabelStack.empty());
|
||||
LabelEntry *e = mLabelStack.back();
|
||||
ASSERT(e->continueLabel);
|
||||
branch(e->continueLabel);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case StmtNode::Try:
|
||||
{
|
||||
/*
|
||||
The finallyInvoker is a little stub used by the interpreter to
|
||||
invoke the finally handler on the (exceptional) way out of the
|
||||
try block assuming there are no catch clauses.
|
||||
*/
|
||||
Register ex = NotARegister;
|
||||
TryStmtNode *t = static_cast<TryStmtNode *>(p);
|
||||
Label *catchLabel = (t->catches) ? getLabel() : NULL;
|
||||
Label *finallyInvoker = (t->finally) ? getLabel() : NULL;
|
||||
Label *finallyLabel = (t->finally) ? getLabel() : NULL;
|
||||
Label *beyondLabel = getLabel();
|
||||
beginTry(catchLabel, finallyLabel);
|
||||
genStmt(t->stmt);
|
||||
endTry();
|
||||
if (finallyLabel)
|
||||
jsr(finallyLabel);
|
||||
branch(beyondLabel);
|
||||
if (catchLabel) {
|
||||
setLabel(catchLabel);
|
||||
CatchClause *c = t->catches;
|
||||
while (c) {
|
||||
// Bind the incoming exception ...
|
||||
setRegisterForVariable(c->name, exceptionRegister);
|
||||
|
||||
genStmt(c->stmt);
|
||||
if (finallyLabel)
|
||||
jsr(finallyLabel);
|
||||
throwStmt(exceptionRegister);
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
if (finallyLabel) {
|
||||
setLabel(finallyInvoker);
|
||||
jsr(finallyLabel);
|
||||
throwStmt(exceptionRegister);
|
||||
|
||||
setLabel(finallyLabel);
|
||||
genStmt(t->finally);
|
||||
rts();
|
||||
}
|
||||
setLabel(beyondLabel);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED("unimplemented statement kind");
|
||||
}
|
||||
resetStatement();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1018,8 +1128,18 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
|
||||
Formatter& ICodeGenerator::print(Formatter& f)
|
||||
{
|
||||
f << "ICG! " << (uint32)iCode->size() << "\n"; // << *iCode;
|
||||
return VM::operator<<(f, *iCode);
|
||||
f << "ICG! " << (uint32)iCode->size() << "\n";
|
||||
VM::operator<<(f, *iCode);
|
||||
f << " Src : Instr" << "\n";
|
||||
for (InstructionMap::iterator i = mInstructionMap->begin(); i != mInstructionMap->end(); i++)
|
||||
{
|
||||
printDec( f, (*i)->first, 6);
|
||||
f << " : ";
|
||||
printDec( f, (*i)->second, 6);
|
||||
f << "\n";
|
||||
// f << (*i)->first << " : " << (*i)->second << "\n";
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
Formatter& ICodeModule::print(Formatter& f)
|
||||
|
@ -49,19 +49,22 @@ namespace ICG {
|
||||
|
||||
|
||||
typedef std::map<String, Register, std::less<String> > VariableList;
|
||||
|
||||
typedef std::pair<uint32, uint32> InstructionMapping;
|
||||
typedef std::vector<InstructionMapping *> InstructionMap;
|
||||
|
||||
|
||||
class ICodeModule {
|
||||
public:
|
||||
ICodeModule(InstructionStream *iCode, VariableList *variables,
|
||||
uint32 maxRegister, uint32 maxParameter) :
|
||||
uint32 maxRegister, uint32 maxParameter, InstructionMap *instructionMap) :
|
||||
its_iCode(iCode), itsVariables(variables),
|
||||
itsParameterCount(maxParameter), itsMaxRegister(maxRegister),
|
||||
mID(++sMaxID) { }
|
||||
mID(++sMaxID), mInstructionMap(instructionMap) { }
|
||||
~ICodeModule()
|
||||
{
|
||||
delete its_iCode;
|
||||
delete itsVariables;
|
||||
delete mInstructionMap;
|
||||
}
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
@ -71,6 +74,8 @@ namespace ICG {
|
||||
uint32 itsParameterCount;
|
||||
uint32 itsMaxRegister;
|
||||
uint32 mID;
|
||||
InstructionMap *mInstructionMap;
|
||||
|
||||
static uint32 sMaxID;
|
||||
|
||||
};
|
||||
@ -111,16 +116,15 @@ namespace ICG {
|
||||
uint32 maxRegister; // highest (ever) allocated register
|
||||
uint32 parameterCount; // number of parameters declared for the function
|
||||
// these must come before any variables declared.
|
||||
Register exceptionRegister; // reserved to carry the exception object, only has a value
|
||||
// for functions that contain try/catch statements.
|
||||
Register switchRegister; // register containing switch control value for most
|
||||
// recently in progress switch statement.
|
||||
Register exceptionRegister; // reserved to carry the exception object.
|
||||
VariableList *variableList; // name|register pair for each variable
|
||||
|
||||
World *mWorld; // used to register strings
|
||||
|
||||
LabelStack mLabelStack;
|
||||
|
||||
World *mWorld; // used to register strings
|
||||
LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct
|
||||
InstructionMap *mInstructionMap;// maps source position to instruction index
|
||||
|
||||
bool mWithinWith; // state from genStmt that indicates generating code beneath a with statement
|
||||
|
||||
void markMaxRegister() \
|
||||
{ if (topRegister > maxRegister) maxRegister = topRegister; }
|
||||
|
||||
@ -130,61 +134,75 @@ namespace ICG {
|
||||
void resetTopRegister() \
|
||||
{ markMaxRegister(); topRegister = registerBase; }
|
||||
|
||||
ICodeOp getBranchOp() \
|
||||
{ return (iCode->empty()) ? NOP : iCode->back()->getBranchOp(); }
|
||||
|
||||
|
||||
void setLabel(Label *label);
|
||||
|
||||
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
|
||||
void rts() { iCode->push_back(new Rts()); }
|
||||
void branch(Label *label);
|
||||
void branchConditional(Label *label, Register condition);
|
||||
void branchNotConditional(Label *label, Register condition);
|
||||
void branchTrue(Label *label, Register condition);
|
||||
void branchFalse(Label *label, Register condition);
|
||||
GenericBranch *branchTrue(Label *label, Register condition);
|
||||
GenericBranch *branchFalse(Label *label, Register condition);
|
||||
|
||||
void beginTry(Label *catchLabel, Label *finallyLabel)
|
||||
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
|
||||
void endTry()
|
||||
{ iCode->push_back(new Tryout()); }
|
||||
|
||||
void beginWith(Register obj)
|
||||
{ iCode->push_back(new Within(obj)); }
|
||||
void endWith()
|
||||
{ iCode->push_back(new Without()); }
|
||||
|
||||
|
||||
void resetStatement() { resetTopRegister(); }
|
||||
|
||||
void setRegisterForVariable(const StringAtom& name, Register r)
|
||||
{ (*variableList)[name] = r; }
|
||||
|
||||
|
||||
void startStatement(uint32 pos) { mInstructionMap->push_back(new InstructionMapping(pos, iCode->size())); }
|
||||
|
||||
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
|
||||
|
||||
Register grabRegister(const StringAtom& name)
|
||||
{
|
||||
Register result = getRegister();
|
||||
(*variableList)[name] = result;
|
||||
registerBase = topRegister;
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
ICodeGenerator(World *world = NULL,
|
||||
bool hasTryStatement = false,
|
||||
uint32 switchStatementNesting = 0);
|
||||
ICodeGenerator(World *world = NULL);
|
||||
|
||||
~ICodeGenerator()
|
||||
{
|
||||
if (iCodeOwner)
|
||||
if (iCodeOwner) {
|
||||
delete iCode;
|
||||
delete mInstructionMap;
|
||||
}
|
||||
}
|
||||
|
||||
ICodeModule *complete();
|
||||
|
||||
Register genExpr(ExprNode *p, bool needBoolValueInBranch = false,
|
||||
Register genExpr(ExprNode *p,
|
||||
bool needBoolValueInBranch = false,
|
||||
Label *trueBranch = NULL,
|
||||
Label *falseBranch = NULL);
|
||||
Register genStmt(StmtNode *p, LabelSet *currentLabelSet = NULL);
|
||||
|
||||
|
||||
void addInstruction(Instruction *i) { iCode->push_back(i); }
|
||||
|
||||
|
||||
Register allocateVariable(const StringAtom& name)
|
||||
{ Register result = getRegister(); (*variableList)[name] = result;
|
||||
registerBase = topRegister; return result; }
|
||||
void returnStmt(Register r);
|
||||
void throwStmt(Register r)
|
||||
{ iCode->push_back(new Throw(r)); }
|
||||
|
||||
Register allocateVariable(const StringAtom& name);
|
||||
Register findVariable(const StringAtom& name)
|
||||
{ VariableList::iterator i = variableList->find(name);
|
||||
return (i == variableList->end()) ? NotARegister : (*i).second; }
|
||||
|
||||
Register allocateParameter(const StringAtom& name)
|
||||
{ parameterCount++; return allocateVariable(name); }
|
||||
{ parameterCount++; return grabRegister(name); }
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
|
@ -46,7 +46,6 @@ const JSValue kNaN = JSValue(nan);
|
||||
const JSValue kTrue = JSValue(true);
|
||||
const JSValue kFalse = JSValue(false);
|
||||
|
||||
// PATRICK, HELP!!!!!
|
||||
const JSType Any_Type = JSType(NULL);
|
||||
const JSType Integer_Type = JSType(&Any_Type);
|
||||
const JSType Number_Type = JSType(&Integer_Type);
|
||||
@ -151,6 +150,20 @@ int JSValue::operator==(const JSValue& value) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
Formatter& operator<<(Formatter& f, const JSObject& obj)
|
||||
{
|
||||
obj.printProperties(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
void JSObject::printProperties(Formatter& f) const
|
||||
{
|
||||
for (JSProperties::const_iterator i = mProperties.begin(); i != mProperties.end(); i++) {
|
||||
f << (*i).first << " : " << (*i).second;
|
||||
f << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
Formatter& operator<<(Formatter& f, const JSValue& value)
|
||||
{
|
||||
switch (value.tag) {
|
||||
@ -164,9 +177,16 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
|
||||
f << value.f64;
|
||||
break;
|
||||
case JSValue::object_tag:
|
||||
{
|
||||
printFormat(f, "Object @ 0x%08X\n", value.object);
|
||||
f << *value.object;
|
||||
}
|
||||
break;
|
||||
case JSValue::array_tag:
|
||||
printFormat(f, "Array @ 0x%08X", value.object);
|
||||
break;
|
||||
case JSValue::function_tag:
|
||||
printFormat(f, "0x%08X", value.object);
|
||||
printFormat(f, "Function @ 0x%08X", value.object);
|
||||
break;
|
||||
case JSValue::string_tag:
|
||||
f << *value.string;
|
||||
|
@ -217,8 +217,12 @@ namespace JSTypes {
|
||||
{
|
||||
return mPrototype;
|
||||
}
|
||||
|
||||
void printProperties(Formatter& f) const;
|
||||
};
|
||||
|
||||
Formatter& operator<<(Formatter& f, const JSObject& obj);
|
||||
|
||||
/**
|
||||
* Private representation of a JavaScript array.
|
||||
*/
|
||||
@ -369,7 +373,10 @@ namespace JSTypes {
|
||||
|
||||
const JSValue& getVariable(const String& name)
|
||||
{
|
||||
return getProperty(name);
|
||||
const JSValue& ret = getProperty(name);
|
||||
if (ret.isUndefined() && mParent)
|
||||
return mParent->getVariable(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSValue& setVariable(const String& name, const JSValue& value)
|
||||
|
@ -107,30 +107,6 @@ namespace VM {
|
||||
return f;
|
||||
}
|
||||
|
||||
ICodeOp Instruction::getBranchOp()
|
||||
{
|
||||
// XXX FIXME, convert to table lookup or arithmetic after the dust settles
|
||||
switch (mOpcode) {
|
||||
case COMPARE_EQ:
|
||||
// return BRANCH_EQ;
|
||||
case COMPARE_NE:
|
||||
// return BRANCH_NE;
|
||||
case COMPARE_GE:
|
||||
// return BRANCH_GE;
|
||||
case COMPARE_GT:
|
||||
// return BRANCH_GT;
|
||||
case COMPARE_LE:
|
||||
// return BRANCH_LE;
|
||||
case COMPARE_LT:
|
||||
// return BRANCH_LT;
|
||||
case TEST:
|
||||
return BRANCH_TRUE;
|
||||
default:
|
||||
NOT_REACHED("Unexpected branch code");
|
||||
return NOP;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace VM */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
@ -51,27 +51,21 @@ namespace VM {
|
||||
AND, /* dest, source1, source2 */
|
||||
BITNOT, /* dest, source */
|
||||
BRANCH, /* target label */
|
||||
BRANCH_EQ, /* target label, condition */
|
||||
BRANCH_FALSE, /* target label, condition */
|
||||
BRANCH_GE, /* target label, condition */
|
||||
BRANCH_GT, /* target label, condition */
|
||||
BRANCH_LE, /* target label, condition */
|
||||
BRANCH_LT, /* target label, condition */
|
||||
BRANCH_NE, /* target label, condition */
|
||||
BRANCH_TRUE, /* target label, condition */
|
||||
CALL, /* result, target, args */
|
||||
COMPARE_EQ, /* dest, source */
|
||||
COMPARE_GE, /* dest, source */
|
||||
COMPARE_GT, /* dest, source */
|
||||
COMPARE_IN, /* dest, source */
|
||||
COMPARE_LE, /* dest, source */
|
||||
COMPARE_LT, /* dest, source */
|
||||
COMPARE_NE, /* dest, source */
|
||||
COMPARE_EQ, /* dest, source1, source2 */
|
||||
COMPARE_GE, /* dest, source1, source2 */
|
||||
COMPARE_GT, /* dest, source1, source2 */
|
||||
COMPARE_IN, /* dest, source1, source2 */
|
||||
COMPARE_LE, /* dest, source1, source2 */
|
||||
COMPARE_LT, /* dest, source1, source2 */
|
||||
COMPARE_NE, /* dest, source1, source2 */
|
||||
DIVIDE, /* dest, source1, source2 */
|
||||
ELEM_XCR, /* dest, base, index, value */
|
||||
GET_ELEMENT, /* dest, base, index */
|
||||
GET_PROP, /* dest, object, prop name */
|
||||
INSTANCEOF, /* dest, source */
|
||||
INSTANCEOF, /* dest, source1, source2 */
|
||||
JSR, /* target */
|
||||
LOAD_IMMEDIATE, /* dest, immediate value (double) */
|
||||
LOAD_NAME, /* dest, name */
|
||||
@ -97,8 +91,8 @@ namespace VM {
|
||||
SET_PROP, /* object, name, source */
|
||||
SHIFTLEFT, /* dest, source1, source2 */
|
||||
SHIFTRIGHT, /* dest, source1, source2 */
|
||||
STRICT_EQ, /* dest, source */
|
||||
STRICT_NE, /* dest, source */
|
||||
STRICT_EQ, /* dest, source1, source2 */
|
||||
STRICT_NE, /* dest, source1, source2 */
|
||||
SUBTRACT, /* dest, source1, source2 */
|
||||
TEST, /* dest, source */
|
||||
THROW, /* exception value */
|
||||
@ -120,13 +114,7 @@ namespace VM {
|
||||
"AND ",
|
||||
"BITNOT ",
|
||||
"BRANCH ",
|
||||
"BRANCH_EQ ",
|
||||
"BRANCH_FALSE ",
|
||||
"BRANCH_GE ",
|
||||
"BRANCH_GT ",
|
||||
"BRANCH_LE ",
|
||||
"BRANCH_LT ",
|
||||
"BRANCH_NE ",
|
||||
"BRANCH_TRUE ",
|
||||
"CALL ",
|
||||
"COMPARE_EQ ",
|
||||
@ -200,8 +188,6 @@ namespace VM {
|
||||
return f;
|
||||
}
|
||||
|
||||
ICodeOp getBranchOp();
|
||||
|
||||
ICodeOp op() { return mOpcode; }
|
||||
|
||||
virtual int32 count() { return 0; }
|
||||
@ -390,6 +376,7 @@ namespace VM {
|
||||
|
||||
void resolveTo (uint32 aOffset) { mOp1->mOffset = aOffset; }
|
||||
uint32 getOffset() { return mOp1->mOffset; }
|
||||
void setTarget(Label *label) { mOp1 = label; }
|
||||
};
|
||||
|
||||
/********************************************************************/
|
||||
@ -436,7 +423,7 @@ namespace VM {
|
||||
GenericBranch
|
||||
(BRANCH, aOp1) {};
|
||||
virtual Formatter& print(Formatter& f) {
|
||||
f << opcodeNames[BRANCH] << "\t" << "Offset " << mOp1->mOffset;
|
||||
f << opcodeNames[BRANCH] << "\t" << "Offset " << ((mOp1) ? mOp1->mOffset : NotAnOffset);
|
||||
return f;
|
||||
}
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) {
|
||||
@ -444,15 +431,6 @@ namespace VM {
|
||||
}
|
||||
};
|
||||
|
||||
class BranchEQ : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchEQ (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_EQ, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchFalse : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
@ -462,51 +440,6 @@ namespace VM {
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchGE : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchGE (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_GE, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchGT : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchGT (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_GT, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchLE : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchLE (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_LE, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchLT : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchLT (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_LT, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchNE : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchNE (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_NE, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchTrue : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
@ -668,7 +601,7 @@ namespace VM {
|
||||
GenericBranch
|
||||
(JSR, aOp1) {};
|
||||
virtual Formatter& print(Formatter& f) {
|
||||
f << opcodeNames[JSR] << "\t" << "Offset " << mOp1->mOffset;
|
||||
f << opcodeNames[JSR] << "\t" << "Offset " << ((mOp1) ? mOp1->mOffset : NotAnOffset);
|
||||
return f;
|
||||
}
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) {
|
||||
@ -1088,7 +1021,7 @@ namespace VM {
|
||||
Instruction_2<Label*, Label*>
|
||||
(TRYIN, aOp1, aOp2) {};
|
||||
virtual Formatter& print(Formatter& f) {
|
||||
f << opcodeNames[TRYIN] << "\t" << "Offset " << mOp1->mOffset << ", " << "Offset " << mOp2->mOffset;
|
||||
f << opcodeNames[TRYIN] << "\t" << "Offset " << ((mOp1) ? mOp1->mOffset : NotAnOffset) << ", " << "Offset " << ((mOp2) ? mOp2->mOffset : NotAnOffset);
|
||||
return f;
|
||||
}
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) {
|
||||
|
@ -61,32 +61,27 @@ Formatter& operator<<(Formatter &f, ICodeModule &i)
|
||||
// ICodeGenerator
|
||||
//
|
||||
|
||||
ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting)
|
||||
ICodeGenerator::ICodeGenerator(World *world)
|
||||
: topRegister(0),
|
||||
registerBase(0),
|
||||
maxRegister(0),
|
||||
parameterCount(0),
|
||||
exceptionRegister(NotARegister),
|
||||
switchRegister(NotARegister),
|
||||
variableList(new VariableList()),
|
||||
mWorld(world)
|
||||
mWorld(world),
|
||||
mInstructionMap(new InstructionMap())
|
||||
{
|
||||
iCode = new InstructionStream();
|
||||
iCodeOwner = true;
|
||||
if (hasTryStatement)
|
||||
exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]);
|
||||
for (uint i = 0; i < switchStatementNesting; i++) {
|
||||
String s = widenCString("__switchControlVariable__");
|
||||
char num[8];
|
||||
sprintf(num, "%.2d", i);
|
||||
appendChars(s, num, strlen(num));
|
||||
if (switchRegister == NotARegister)
|
||||
switchRegister = allocateVariable(world->identifiers[s]);
|
||||
else
|
||||
allocateVariable(world->identifiers[s]);
|
||||
}
|
||||
}
|
||||
|
||||
Register ICodeGenerator::allocateVariable(const StringAtom& name)
|
||||
{
|
||||
if (exceptionRegister == NotARegister) {
|
||||
exceptionRegister = grabRegister(mWorld->identifiers[widenCString("__exceptionObject__")]);
|
||||
}
|
||||
return grabRegister(name);
|
||||
}
|
||||
|
||||
ICodeModule *ICodeGenerator::complete()
|
||||
{
|
||||
@ -121,7 +116,7 @@ ICodeModule *ICodeGenerator::complete()
|
||||
}
|
||||
*/
|
||||
markMaxRegister();
|
||||
ICodeModule* module = new ICodeModule(iCode, variableList, maxRegister, 0);
|
||||
ICodeModule* module = new ICodeModule(iCode, variableList, maxRegister, 0, mInstructionMap);
|
||||
iCodeOwner = false; // give ownership to the module.
|
||||
return module;
|
||||
}
|
||||
@ -333,45 +328,29 @@ void ICodeGenerator::branch(Label *label)
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::branchConditional(Label *label, Register condition)
|
||||
{
|
||||
ICodeOp branchOp = getBranchOp();
|
||||
ASSERT(branchOp != NOP);
|
||||
GenericBranch *instr = new GenericBranch(branchOp, label, condition);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::branchTrue(Label *label, Register condition)
|
||||
GenericBranch *ICodeGenerator::branchTrue(Label *label, Register condition)
|
||||
{
|
||||
GenericBranch *instr = new GenericBranch(BRANCH_TRUE, label, condition);
|
||||
iCode->push_back(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
void ICodeGenerator::branchFalse(Label *label, Register condition)
|
||||
GenericBranch *ICodeGenerator::branchFalse(Label *label, Register condition)
|
||||
{
|
||||
GenericBranch *instr = new GenericBranch(BRANCH_FALSE, label, condition);
|
||||
iCode->push_back(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
void ICodeGenerator::branchNotConditional(Label *label, Register condition)
|
||||
void ICodeGenerator::returnStmt(Register r)
|
||||
{
|
||||
ICodeOp branchOp = getBranchOp();
|
||||
ASSERT(branchOp != NOP);
|
||||
switch (branchOp) {
|
||||
case BRANCH_FALSE : branchOp = BRANCH_TRUE; break;
|
||||
case BRANCH_TRUE : branchOp = BRANCH_FALSE; break;
|
||||
case BRANCH_EQ : branchOp = BRANCH_NE; break;
|
||||
case BRANCH_GE : branchOp = BRANCH_LT; break;
|
||||
case BRANCH_GT : branchOp = BRANCH_LE; break;
|
||||
case BRANCH_LE : branchOp = BRANCH_GT; break;
|
||||
case BRANCH_LT : branchOp = BRANCH_GE; break;
|
||||
case BRANCH_NE : branchOp = BRANCH_EQ; break;
|
||||
default : NOT_REACHED("Expected a branch op"); break;
|
||||
}
|
||||
GenericBranch *instr = new GenericBranch(branchOp, label, condition);
|
||||
iCode->push_back(instr);
|
||||
if (r == NotARegister)
|
||||
iCode->push_back(new ReturnVoid());
|
||||
else
|
||||
iCode->push_back(new Return(r));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Label *ICodeGenerator::getLabel()
|
||||
@ -492,10 +471,13 @@ static bool generatedBoolean(ExprNode *p)
|
||||
|
||||
/*
|
||||
if trueBranch OR falseBranch are not null, the sub-expression should generate
|
||||
a conditional branch do the appropriate target. If either branch is NULL, it
|
||||
a conditional branch to the appropriate target. If either branch is NULL, it
|
||||
indicates that the label is immediately forthcoming.
|
||||
*/
|
||||
Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label *trueBranch, Label *falseBranch)
|
||||
Register ICodeGenerator::genExpr(ExprNode *p,
|
||||
bool needBoolValueInBranch,
|
||||
Label *trueBranch,
|
||||
Label *falseBranch)
|
||||
{
|
||||
Register ret = NotARegister;
|
||||
switch (p->getKind()) {
|
||||
@ -561,13 +543,13 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
break;
|
||||
case ExprNode::identifier :
|
||||
{
|
||||
/*
|
||||
variable or name? If there's a 'with' in this scope, then it's
|
||||
a name, otherwise look it up in the function variable map.
|
||||
*/
|
||||
Register v = findVariable((static_cast<IdentifierExprNode *>(p))->name);
|
||||
if (v != NotARegister)
|
||||
ret = v;
|
||||
if (mWithinWith) {
|
||||
Register v = findVariable((static_cast<IdentifierExprNode *>(p))->name);
|
||||
if (v != NotARegister)
|
||||
ret = v;
|
||||
else
|
||||
ret = loadName((static_cast<IdentifierExprNode *>(p))->name);
|
||||
}
|
||||
else
|
||||
ret = loadName((static_cast<IdentifierExprNode *>(p))->name);
|
||||
}
|
||||
@ -688,9 +670,9 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2);
|
||||
if (trueBranch || falseBranch) {
|
||||
if (trueBranch == NULL)
|
||||
branchNotConditional(falseBranch, ret);
|
||||
branchFalse(falseBranch, ret);
|
||||
else {
|
||||
branchConditional(trueBranch, ret);
|
||||
branchTrue(trueBranch, ret);
|
||||
if (falseBranch)
|
||||
branch(falseBranch);
|
||||
}
|
||||
@ -706,9 +688,9 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
ret = op(mapExprNodeToICodeOp(p->getKind()), r2, r1); // will return reverse case
|
||||
if (trueBranch || falseBranch) {
|
||||
if (trueBranch == NULL)
|
||||
branchNotConditional(falseBranch, ret);
|
||||
branchFalse(falseBranch, ret);
|
||||
else {
|
||||
branchConditional(trueBranch, ret);
|
||||
branchTrue(trueBranch, ret);
|
||||
if (falseBranch)
|
||||
branch(falseBranch);
|
||||
}
|
||||
@ -725,9 +707,9 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2);
|
||||
if (trueBranch || falseBranch) {
|
||||
if (trueBranch == NULL)
|
||||
branchNotConditional(falseBranch, ret);
|
||||
branchFalse(falseBranch, ret);
|
||||
else {
|
||||
branchConditional(trueBranch, ret);
|
||||
branchTrue(trueBranch, ret);
|
||||
if (falseBranch)
|
||||
branch(falseBranch);
|
||||
}
|
||||
@ -796,7 +778,7 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
Label *beyondBranch = getLabel();
|
||||
Register c = genExpr(t->op1, false, NULL, fBranch);
|
||||
if (!generatedBoolean(t->op1))
|
||||
branchNotConditional(fBranch, test(c));
|
||||
branchFalse(fBranch, test(c));
|
||||
Register r1 = genExpr(t->op2);
|
||||
branch(beyondBranch);
|
||||
setLabel(fBranch);
|
||||
@ -818,7 +800,6 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
|
||||
/*
|
||||
need pre-pass to find:
|
||||
variable & function definitions,
|
||||
#nested switch statements
|
||||
contains 'with' or 'eval'
|
||||
contains 'try {} catch {} finally {}'
|
||||
*/
|
||||
@ -838,6 +819,11 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
{
|
||||
Register ret = NotARegister;
|
||||
|
||||
startStatement(p->pos);
|
||||
if (exceptionRegister == NotARegister) {
|
||||
exceptionRegister = grabRegister(mWorld->identifiers[widenCString("__exceptionObject__")]);
|
||||
}
|
||||
|
||||
switch (p->getKind()) {
|
||||
case StmtNode::expression:
|
||||
{
|
||||
@ -845,13 +831,25 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
ret = genExpr(e->expr);
|
||||
}
|
||||
break;
|
||||
case StmtNode::Throw:
|
||||
{
|
||||
ExprStmtNode *e = static_cast<ExprStmtNode *>(p);
|
||||
throwStmt(genExpr(e->expr));
|
||||
}
|
||||
break;
|
||||
case StmtNode::Return:
|
||||
{
|
||||
ExprStmtNode *e = static_cast<ExprStmtNode *>(p);
|
||||
returnStmt(ret = genExpr(e->expr));
|
||||
}
|
||||
break;
|
||||
case StmtNode::If:
|
||||
{
|
||||
Label *falseLabel = getLabel();
|
||||
UnaryStmtNode *i = static_cast<UnaryStmtNode *>(p);
|
||||
Register c = genExpr(i->expr, false, NULL, falseLabel);
|
||||
if (!generatedBoolean(i->expr))
|
||||
branchNotConditional(falseLabel, test(c));
|
||||
branchFalse(falseLabel, test(c));
|
||||
genStmt(i->stmt);
|
||||
setLabel(falseLabel);
|
||||
}
|
||||
@ -863,38 +861,78 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
BinaryStmtNode *i = static_cast<BinaryStmtNode *>(p);
|
||||
Register c = genExpr(i->expr, false, NULL, falseLabel);
|
||||
if (!generatedBoolean(i->expr))
|
||||
branchNotConditional(falseLabel, test(c));
|
||||
branchFalse(falseLabel, test(c));
|
||||
genStmt(i->stmt);
|
||||
branch(beyondLabel);
|
||||
setLabel(falseLabel);
|
||||
genStmt(i->stmt2);
|
||||
}
|
||||
break;
|
||||
case StmtNode::With:
|
||||
{
|
||||
UnaryStmtNode *w = static_cast<UnaryStmtNode *>(p);
|
||||
Register o = genExpr(w->expr);
|
||||
bool withinWith = mWithinWith;
|
||||
mWithinWith = true;
|
||||
beginWith(o);
|
||||
genStmt(w->stmt);
|
||||
endWith();
|
||||
mWithinWith = withinWith;
|
||||
}
|
||||
break;
|
||||
case StmtNode::Switch:
|
||||
{
|
||||
Label *defaultLabel = NULL;
|
||||
LabelEntry *e = new LabelEntry(currentLabelSet, getLabel());
|
||||
mLabelStack.push_back(e);
|
||||
SwitchStmtNode *sw = static_cast<SwitchStmtNode *>(p);
|
||||
Register sc = genExpr(sw->expr);
|
||||
StmtNode *s = sw->statements;
|
||||
// ECMA requires case & default statements to be immediate children of switch
|
||||
// unlike C where they can be arbitrarily deeply nested in other statements.
|
||||
// unlike C where they can be arbitrarily deeply nested in other statements.
|
||||
Label *nextCaseLabel = NULL;
|
||||
GenericBranch *lastBranch = NULL;
|
||||
while (s) {
|
||||
ASSERT(s->getKind() == StmtNode::Case);
|
||||
UnaryStmtNode *c = static_cast<UnaryStmtNode *>(s);
|
||||
if (c->expr) {
|
||||
Label *beyondCaseLabel = getLabel();
|
||||
Register r = genExpr(c->expr);
|
||||
Register eq = op(COMPARE_EQ, r, sc);
|
||||
branchNotConditional(beyondCaseLabel, eq);
|
||||
genStmt(c->stmt);
|
||||
setLabel(beyondCaseLabel);
|
||||
if (s->getKind() == StmtNode::Case) {
|
||||
ExprStmtNode *c = static_cast<ExprStmtNode *>(s);
|
||||
if (c->expr) {
|
||||
if (nextCaseLabel)
|
||||
setLabel(nextCaseLabel);
|
||||
nextCaseLabel = getLabel();
|
||||
Register r = genExpr(c->expr);
|
||||
Register eq = op(COMPARE_EQ, r, sc);
|
||||
lastBranch = branchFalse(nextCaseLabel, eq);
|
||||
}
|
||||
else {
|
||||
defaultLabel = getLabel();
|
||||
setLabel(defaultLabel);
|
||||
}
|
||||
}
|
||||
// else it's the default case... THIS IS NOT DONE YET....
|
||||
else
|
||||
genStmt(c->stmt);
|
||||
genStmt(s);
|
||||
s = s->next;
|
||||
}
|
||||
if (nextCaseLabel)
|
||||
setLabel(nextCaseLabel);
|
||||
if (defaultLabel && lastBranch)
|
||||
lastBranch->setTarget(defaultLabel);
|
||||
|
||||
setLabel(e->breakLabel);
|
||||
mLabelStack.pop_back();
|
||||
}
|
||||
break;
|
||||
case StmtNode::DoWhile:
|
||||
{
|
||||
LabelEntry *e = new LabelEntry(currentLabelSet, getLabel(), getLabel());
|
||||
mLabelStack.push_back(e);
|
||||
UnaryStmtNode *d = static_cast<UnaryStmtNode *>(p);
|
||||
Label *doBodyTopLabel = getLabel();
|
||||
setLabel(doBodyTopLabel);
|
||||
genStmt(d->stmt);
|
||||
setLabel(e->continueLabel);
|
||||
Register c = genExpr(d->expr, false, doBodyTopLabel, NULL);
|
||||
if (!generatedBoolean(d->expr))
|
||||
branchTrue(doBodyTopLabel, test(c));
|
||||
setLabel(e->breakLabel);
|
||||
mLabelStack.pop_back();
|
||||
}
|
||||
@ -914,7 +952,7 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
setLabel(e->continueLabel);
|
||||
Register c = genExpr(w->expr, false, whileBodyTopLabel, NULL);
|
||||
if (!generatedBoolean(w->expr))
|
||||
branchConditional(whileBodyTopLabel, test(c));
|
||||
branchTrue(whileBodyTopLabel, test(c));
|
||||
|
||||
setLabel(e->breakLabel);
|
||||
mLabelStack.pop_back();
|
||||
@ -943,7 +981,7 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
if (f->expr2) {
|
||||
Register c = genExpr(f->expr2, false, forBlockTop, NULL);
|
||||
if (!generatedBoolean(f->expr2))
|
||||
branchConditional(forBlockTop, test(c));
|
||||
branchTrue(forBlockTop, test(c));
|
||||
}
|
||||
|
||||
setLabel(e->breakLabel);
|
||||
@ -1003,12 +1041,84 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
ASSERT(e->breakLabel);
|
||||
branch(e->breakLabel);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case StmtNode::Continue:
|
||||
{
|
||||
GoStmtNode *g = static_cast<GoStmtNode *>(p);
|
||||
if (g->label) {
|
||||
LabelEntry *e = NULL;
|
||||
for (LabelStack::reverse_iterator i = mLabelStack.rbegin(); i != mLabelStack.rend(); i++) {
|
||||
e = (*i);
|
||||
if (e->containsLabel(g->name))
|
||||
break;
|
||||
}
|
||||
if (e) {
|
||||
ASSERT(e->continueLabel);
|
||||
branch(e->continueLabel);
|
||||
}
|
||||
else
|
||||
NOT_REACHED("continue label not in label set");
|
||||
}
|
||||
else {
|
||||
ASSERT(!mLabelStack.empty());
|
||||
LabelEntry *e = mLabelStack.back();
|
||||
ASSERT(e->continueLabel);
|
||||
branch(e->continueLabel);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case StmtNode::Try:
|
||||
{
|
||||
/*
|
||||
The finallyInvoker is a little stub used by the interpreter to
|
||||
invoke the finally handler on the (exceptional) way out of the
|
||||
try block assuming there are no catch clauses.
|
||||
*/
|
||||
Register ex = NotARegister;
|
||||
TryStmtNode *t = static_cast<TryStmtNode *>(p);
|
||||
Label *catchLabel = (t->catches) ? getLabel() : NULL;
|
||||
Label *finallyInvoker = (t->finally) ? getLabel() : NULL;
|
||||
Label *finallyLabel = (t->finally) ? getLabel() : NULL;
|
||||
Label *beyondLabel = getLabel();
|
||||
beginTry(catchLabel, finallyLabel);
|
||||
genStmt(t->stmt);
|
||||
endTry();
|
||||
if (finallyLabel)
|
||||
jsr(finallyLabel);
|
||||
branch(beyondLabel);
|
||||
if (catchLabel) {
|
||||
setLabel(catchLabel);
|
||||
CatchClause *c = t->catches;
|
||||
while (c) {
|
||||
// Bind the incoming exception ...
|
||||
setRegisterForVariable(c->name, exceptionRegister);
|
||||
|
||||
genStmt(c->stmt);
|
||||
if (finallyLabel)
|
||||
jsr(finallyLabel);
|
||||
throwStmt(exceptionRegister);
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
if (finallyLabel) {
|
||||
setLabel(finallyInvoker);
|
||||
jsr(finallyLabel);
|
||||
throwStmt(exceptionRegister);
|
||||
|
||||
setLabel(finallyLabel);
|
||||
genStmt(t->finally);
|
||||
rts();
|
||||
}
|
||||
setLabel(beyondLabel);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED("unimplemented statement kind");
|
||||
}
|
||||
resetStatement();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1018,8 +1128,18 @@ Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
|
||||
Formatter& ICodeGenerator::print(Formatter& f)
|
||||
{
|
||||
f << "ICG! " << (uint32)iCode->size() << "\n"; // << *iCode;
|
||||
return VM::operator<<(f, *iCode);
|
||||
f << "ICG! " << (uint32)iCode->size() << "\n";
|
||||
VM::operator<<(f, *iCode);
|
||||
f << " Src : Instr" << "\n";
|
||||
for (InstructionMap::iterator i = mInstructionMap->begin(); i != mInstructionMap->end(); i++)
|
||||
{
|
||||
printDec( f, (*i)->first, 6);
|
||||
f << " : ";
|
||||
printDec( f, (*i)->second, 6);
|
||||
f << "\n";
|
||||
// f << (*i)->first << " : " << (*i)->second << "\n";
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
Formatter& ICodeModule::print(Formatter& f)
|
||||
|
@ -49,19 +49,22 @@ namespace ICG {
|
||||
|
||||
|
||||
typedef std::map<String, Register, std::less<String> > VariableList;
|
||||
|
||||
typedef std::pair<uint32, uint32> InstructionMapping;
|
||||
typedef std::vector<InstructionMapping *> InstructionMap;
|
||||
|
||||
|
||||
class ICodeModule {
|
||||
public:
|
||||
ICodeModule(InstructionStream *iCode, VariableList *variables,
|
||||
uint32 maxRegister, uint32 maxParameter) :
|
||||
uint32 maxRegister, uint32 maxParameter, InstructionMap *instructionMap) :
|
||||
its_iCode(iCode), itsVariables(variables),
|
||||
itsParameterCount(maxParameter), itsMaxRegister(maxRegister),
|
||||
mID(++sMaxID) { }
|
||||
mID(++sMaxID), mInstructionMap(instructionMap) { }
|
||||
~ICodeModule()
|
||||
{
|
||||
delete its_iCode;
|
||||
delete itsVariables;
|
||||
delete mInstructionMap;
|
||||
}
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
@ -71,6 +74,8 @@ namespace ICG {
|
||||
uint32 itsParameterCount;
|
||||
uint32 itsMaxRegister;
|
||||
uint32 mID;
|
||||
InstructionMap *mInstructionMap;
|
||||
|
||||
static uint32 sMaxID;
|
||||
|
||||
};
|
||||
@ -111,16 +116,15 @@ namespace ICG {
|
||||
uint32 maxRegister; // highest (ever) allocated register
|
||||
uint32 parameterCount; // number of parameters declared for the function
|
||||
// these must come before any variables declared.
|
||||
Register exceptionRegister; // reserved to carry the exception object, only has a value
|
||||
// for functions that contain try/catch statements.
|
||||
Register switchRegister; // register containing switch control value for most
|
||||
// recently in progress switch statement.
|
||||
Register exceptionRegister; // reserved to carry the exception object.
|
||||
VariableList *variableList; // name|register pair for each variable
|
||||
|
||||
World *mWorld; // used to register strings
|
||||
|
||||
LabelStack mLabelStack;
|
||||
|
||||
World *mWorld; // used to register strings
|
||||
LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct
|
||||
InstructionMap *mInstructionMap;// maps source position to instruction index
|
||||
|
||||
bool mWithinWith; // state from genStmt that indicates generating code beneath a with statement
|
||||
|
||||
void markMaxRegister() \
|
||||
{ if (topRegister > maxRegister) maxRegister = topRegister; }
|
||||
|
||||
@ -130,61 +134,75 @@ namespace ICG {
|
||||
void resetTopRegister() \
|
||||
{ markMaxRegister(); topRegister = registerBase; }
|
||||
|
||||
ICodeOp getBranchOp() \
|
||||
{ return (iCode->empty()) ? NOP : iCode->back()->getBranchOp(); }
|
||||
|
||||
|
||||
void setLabel(Label *label);
|
||||
|
||||
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
|
||||
void rts() { iCode->push_back(new Rts()); }
|
||||
void branch(Label *label);
|
||||
void branchConditional(Label *label, Register condition);
|
||||
void branchNotConditional(Label *label, Register condition);
|
||||
void branchTrue(Label *label, Register condition);
|
||||
void branchFalse(Label *label, Register condition);
|
||||
GenericBranch *branchTrue(Label *label, Register condition);
|
||||
GenericBranch *branchFalse(Label *label, Register condition);
|
||||
|
||||
void beginTry(Label *catchLabel, Label *finallyLabel)
|
||||
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
|
||||
void endTry()
|
||||
{ iCode->push_back(new Tryout()); }
|
||||
|
||||
void beginWith(Register obj)
|
||||
{ iCode->push_back(new Within(obj)); }
|
||||
void endWith()
|
||||
{ iCode->push_back(new Without()); }
|
||||
|
||||
|
||||
void resetStatement() { resetTopRegister(); }
|
||||
|
||||
void setRegisterForVariable(const StringAtom& name, Register r)
|
||||
{ (*variableList)[name] = r; }
|
||||
|
||||
|
||||
void startStatement(uint32 pos) { mInstructionMap->push_back(new InstructionMapping(pos, iCode->size())); }
|
||||
|
||||
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
|
||||
|
||||
Register grabRegister(const StringAtom& name)
|
||||
{
|
||||
Register result = getRegister();
|
||||
(*variableList)[name] = result;
|
||||
registerBase = topRegister;
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
ICodeGenerator(World *world = NULL,
|
||||
bool hasTryStatement = false,
|
||||
uint32 switchStatementNesting = 0);
|
||||
ICodeGenerator(World *world = NULL);
|
||||
|
||||
~ICodeGenerator()
|
||||
{
|
||||
if (iCodeOwner)
|
||||
if (iCodeOwner) {
|
||||
delete iCode;
|
||||
delete mInstructionMap;
|
||||
}
|
||||
}
|
||||
|
||||
ICodeModule *complete();
|
||||
|
||||
Register genExpr(ExprNode *p, bool needBoolValueInBranch = false,
|
||||
Register genExpr(ExprNode *p,
|
||||
bool needBoolValueInBranch = false,
|
||||
Label *trueBranch = NULL,
|
||||
Label *falseBranch = NULL);
|
||||
Register genStmt(StmtNode *p, LabelSet *currentLabelSet = NULL);
|
||||
|
||||
|
||||
void addInstruction(Instruction *i) { iCode->push_back(i); }
|
||||
|
||||
|
||||
Register allocateVariable(const StringAtom& name)
|
||||
{ Register result = getRegister(); (*variableList)[name] = result;
|
||||
registerBase = topRegister; return result; }
|
||||
void returnStmt(Register r);
|
||||
void throwStmt(Register r)
|
||||
{ iCode->push_back(new Throw(r)); }
|
||||
|
||||
Register allocateVariable(const StringAtom& name);
|
||||
Register findVariable(const StringAtom& name)
|
||||
{ VariableList::iterator i = variableList->find(name);
|
||||
return (i == variableList->end()) ? NotARegister : (*i).second; }
|
||||
|
||||
Register allocateParameter(const StringAtom& name)
|
||||
{ parameterCount++; return allocateVariable(name); }
|
||||
{ parameterCount++; return grabRegister(name); }
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
|
@ -46,7 +46,6 @@ const JSValue kNaN = JSValue(nan);
|
||||
const JSValue kTrue = JSValue(true);
|
||||
const JSValue kFalse = JSValue(false);
|
||||
|
||||
// PATRICK, HELP!!!!!
|
||||
const JSType Any_Type = JSType(NULL);
|
||||
const JSType Integer_Type = JSType(&Any_Type);
|
||||
const JSType Number_Type = JSType(&Integer_Type);
|
||||
@ -151,6 +150,20 @@ int JSValue::operator==(const JSValue& value) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
Formatter& operator<<(Formatter& f, const JSObject& obj)
|
||||
{
|
||||
obj.printProperties(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
void JSObject::printProperties(Formatter& f) const
|
||||
{
|
||||
for (JSProperties::const_iterator i = mProperties.begin(); i != mProperties.end(); i++) {
|
||||
f << (*i).first << " : " << (*i).second;
|
||||
f << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
Formatter& operator<<(Formatter& f, const JSValue& value)
|
||||
{
|
||||
switch (value.tag) {
|
||||
@ -164,9 +177,16 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
|
||||
f << value.f64;
|
||||
break;
|
||||
case JSValue::object_tag:
|
||||
{
|
||||
printFormat(f, "Object @ 0x%08X\n", value.object);
|
||||
f << *value.object;
|
||||
}
|
||||
break;
|
||||
case JSValue::array_tag:
|
||||
printFormat(f, "Array @ 0x%08X", value.object);
|
||||
break;
|
||||
case JSValue::function_tag:
|
||||
printFormat(f, "0x%08X", value.object);
|
||||
printFormat(f, "Function @ 0x%08X", value.object);
|
||||
break;
|
||||
case JSValue::string_tag:
|
||||
f << *value.string;
|
||||
|
@ -217,8 +217,12 @@ namespace JSTypes {
|
||||
{
|
||||
return mPrototype;
|
||||
}
|
||||
|
||||
void printProperties(Formatter& f) const;
|
||||
};
|
||||
|
||||
Formatter& operator<<(Formatter& f, const JSObject& obj);
|
||||
|
||||
/**
|
||||
* Private representation of a JavaScript array.
|
||||
*/
|
||||
@ -369,7 +373,10 @@ namespace JSTypes {
|
||||
|
||||
const JSValue& getVariable(const String& name)
|
||||
{
|
||||
return getProperty(name);
|
||||
const JSValue& ret = getProperty(name);
|
||||
if (ret.isUndefined() && mParent)
|
||||
return mParent->getVariable(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSValue& setVariable(const String& name, const JSValue& value)
|
||||
|
@ -107,30 +107,6 @@ namespace VM {
|
||||
return f;
|
||||
}
|
||||
|
||||
ICodeOp Instruction::getBranchOp()
|
||||
{
|
||||
// XXX FIXME, convert to table lookup or arithmetic after the dust settles
|
||||
switch (mOpcode) {
|
||||
case COMPARE_EQ:
|
||||
// return BRANCH_EQ;
|
||||
case COMPARE_NE:
|
||||
// return BRANCH_NE;
|
||||
case COMPARE_GE:
|
||||
// return BRANCH_GE;
|
||||
case COMPARE_GT:
|
||||
// return BRANCH_GT;
|
||||
case COMPARE_LE:
|
||||
// return BRANCH_LE;
|
||||
case COMPARE_LT:
|
||||
// return BRANCH_LT;
|
||||
case TEST:
|
||||
return BRANCH_TRUE;
|
||||
default:
|
||||
NOT_REACHED("Unexpected branch code");
|
||||
return NOP;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace VM */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
@ -51,27 +51,21 @@ namespace VM {
|
||||
AND, /* dest, source1, source2 */
|
||||
BITNOT, /* dest, source */
|
||||
BRANCH, /* target label */
|
||||
BRANCH_EQ, /* target label, condition */
|
||||
BRANCH_FALSE, /* target label, condition */
|
||||
BRANCH_GE, /* target label, condition */
|
||||
BRANCH_GT, /* target label, condition */
|
||||
BRANCH_LE, /* target label, condition */
|
||||
BRANCH_LT, /* target label, condition */
|
||||
BRANCH_NE, /* target label, condition */
|
||||
BRANCH_TRUE, /* target label, condition */
|
||||
CALL, /* result, target, args */
|
||||
COMPARE_EQ, /* dest, source */
|
||||
COMPARE_GE, /* dest, source */
|
||||
COMPARE_GT, /* dest, source */
|
||||
COMPARE_IN, /* dest, source */
|
||||
COMPARE_LE, /* dest, source */
|
||||
COMPARE_LT, /* dest, source */
|
||||
COMPARE_NE, /* dest, source */
|
||||
COMPARE_EQ, /* dest, source1, source2 */
|
||||
COMPARE_GE, /* dest, source1, source2 */
|
||||
COMPARE_GT, /* dest, source1, source2 */
|
||||
COMPARE_IN, /* dest, source1, source2 */
|
||||
COMPARE_LE, /* dest, source1, source2 */
|
||||
COMPARE_LT, /* dest, source1, source2 */
|
||||
COMPARE_NE, /* dest, source1, source2 */
|
||||
DIVIDE, /* dest, source1, source2 */
|
||||
ELEM_XCR, /* dest, base, index, value */
|
||||
GET_ELEMENT, /* dest, base, index */
|
||||
GET_PROP, /* dest, object, prop name */
|
||||
INSTANCEOF, /* dest, source */
|
||||
INSTANCEOF, /* dest, source1, source2 */
|
||||
JSR, /* target */
|
||||
LOAD_IMMEDIATE, /* dest, immediate value (double) */
|
||||
LOAD_NAME, /* dest, name */
|
||||
@ -97,8 +91,8 @@ namespace VM {
|
||||
SET_PROP, /* object, name, source */
|
||||
SHIFTLEFT, /* dest, source1, source2 */
|
||||
SHIFTRIGHT, /* dest, source1, source2 */
|
||||
STRICT_EQ, /* dest, source */
|
||||
STRICT_NE, /* dest, source */
|
||||
STRICT_EQ, /* dest, source1, source2 */
|
||||
STRICT_NE, /* dest, source1, source2 */
|
||||
SUBTRACT, /* dest, source1, source2 */
|
||||
TEST, /* dest, source */
|
||||
THROW, /* exception value */
|
||||
@ -120,13 +114,7 @@ namespace VM {
|
||||
"AND ",
|
||||
"BITNOT ",
|
||||
"BRANCH ",
|
||||
"BRANCH_EQ ",
|
||||
"BRANCH_FALSE ",
|
||||
"BRANCH_GE ",
|
||||
"BRANCH_GT ",
|
||||
"BRANCH_LE ",
|
||||
"BRANCH_LT ",
|
||||
"BRANCH_NE ",
|
||||
"BRANCH_TRUE ",
|
||||
"CALL ",
|
||||
"COMPARE_EQ ",
|
||||
@ -200,8 +188,6 @@ namespace VM {
|
||||
return f;
|
||||
}
|
||||
|
||||
ICodeOp getBranchOp();
|
||||
|
||||
ICodeOp op() { return mOpcode; }
|
||||
|
||||
virtual int32 count() { return 0; }
|
||||
@ -390,6 +376,7 @@ namespace VM {
|
||||
|
||||
void resolveTo (uint32 aOffset) { mOp1->mOffset = aOffset; }
|
||||
uint32 getOffset() { return mOp1->mOffset; }
|
||||
void setTarget(Label *label) { mOp1 = label; }
|
||||
};
|
||||
|
||||
/********************************************************************/
|
||||
@ -436,7 +423,7 @@ namespace VM {
|
||||
GenericBranch
|
||||
(BRANCH, aOp1) {};
|
||||
virtual Formatter& print(Formatter& f) {
|
||||
f << opcodeNames[BRANCH] << "\t" << "Offset " << mOp1->mOffset;
|
||||
f << opcodeNames[BRANCH] << "\t" << "Offset " << ((mOp1) ? mOp1->mOffset : NotAnOffset);
|
||||
return f;
|
||||
}
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) {
|
||||
@ -444,15 +431,6 @@ namespace VM {
|
||||
}
|
||||
};
|
||||
|
||||
class BranchEQ : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchEQ (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_EQ, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchFalse : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
@ -462,51 +440,6 @@ namespace VM {
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchGE : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchGE (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_GE, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchGT : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchGT (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_GT, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchLE : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchLE (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_LE, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchLT : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchLT (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_LT, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchNE : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
BranchNE (Label* aOp1, Register aOp2) :
|
||||
GenericBranch
|
||||
(BRANCH_NE, aOp1, aOp2) {};
|
||||
/* print() and printOperands() inherited from GenericBranch */
|
||||
};
|
||||
|
||||
class BranchTrue : public GenericBranch {
|
||||
public:
|
||||
/* target label, condition */
|
||||
@ -668,7 +601,7 @@ namespace VM {
|
||||
GenericBranch
|
||||
(JSR, aOp1) {};
|
||||
virtual Formatter& print(Formatter& f) {
|
||||
f << opcodeNames[JSR] << "\t" << "Offset " << mOp1->mOffset;
|
||||
f << opcodeNames[JSR] << "\t" << "Offset " << ((mOp1) ? mOp1->mOffset : NotAnOffset);
|
||||
return f;
|
||||
}
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) {
|
||||
@ -1088,7 +1021,7 @@ namespace VM {
|
||||
Instruction_2<Label*, Label*>
|
||||
(TRYIN, aOp1, aOp2) {};
|
||||
virtual Formatter& print(Formatter& f) {
|
||||
f << opcodeNames[TRYIN] << "\t" << "Offset " << mOp1->mOffset << ", " << "Offset " << mOp2->mOffset;
|
||||
f << opcodeNames[TRYIN] << "\t" << "Offset " << ((mOp1) ? mOp1->mOffset : NotAnOffset) << ", " << "Offset " << ((mOp2) ? mOp2->mOffset : NotAnOffset);
|
||||
return f;
|
||||
}
|
||||
virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) {
|
||||
|
Loading…
Reference in New Issue
Block a user