Statement fun

This commit is contained in:
rogerl%netscape.com 2000-05-26 22:33:05 +00:00
parent b6ac1476df
commit 573531b249
12 changed files with 580 additions and 432 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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 */

View File

@ -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*/) {

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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 */

View File

@ -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*/) {