Codegen for statements. Blew off old statement API and most of the test

functions for now, sorry.
This commit is contained in:
rogerl%netscape.com 2000-05-24 02:11:39 +00:00
Родитель 9044170ca3
Коммит bbd7ed8e62
6 изменённых файлов: 570 добавлений и 2306 удалений

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

@ -85,14 +85,11 @@ ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switch
else
allocateVariable(world->identifiers[s]);
}
labelSet = new StatementLabels();
}
ICodeModule *ICodeGenerator::complete()
{
ASSERT(stitcher.empty());
//ASSERT(labelSet == NULL);
#ifdef DEBUG
for (LabelList::iterator i = labels.begin();
i != labels.end(); i++) {
@ -101,6 +98,11 @@ ICodeModule *ICodeGenerator::complete()
}
#endif
/*
XXX FIXME
I wanted to do the following rather than have to have the label set hanging around as well
as the ICodeModule. Branches have since changed, but the concept is still good and should
be re-introduced at some point.
for (InstructionIterator ii = iCode->begin();
ii != iCode->end(); ii++) {
if ((*ii)->op() == BRANCH) {
@ -124,20 +126,6 @@ ICodeModule *ICodeGenerator::complete()
return module;
}
TryCodeState::TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg)
: ICodeState(Try_state, icg),
catchHandler(catchLabel),
finallyHandler(finallyLabel),
finallyInvoker(NULL),
beyondCatch(NULL)
{
if (catchHandler) {
beyondCatch = icg->getLabel();
if (finallyLabel)
finallyInvoker = icg->getLabel();
}
}
/********************************************************************/
@ -398,494 +386,6 @@ void ICodeGenerator::setLabel(Label *l)
l->mOffset = iCode->size();
}
void ICodeGenerator::setLabel(InstructionStream *stream, Label *l)
{
l->mBase = stream;
l->mOffset = stream->size();
}
/********************************************************************/
void ICodeGenerator::mergeStream(InstructionStream *sideStream)
{
// change InstructionStream to be a class that also remembers
// if it contains any labels (maybe even remembers the labels
// themselves?) in order to avoid running this loop unnecessarily.
for (LabelList::iterator i = labels.begin();
i != labels.end(); i++) {
if ((*i)->mBase == sideStream) {
(*i)->mBase = iCode;
(*i)->mOffset += iCode->size();
}
}
for (InstructionIterator ii = sideStream->begin();
ii != sideStream->end(); ii++) {
iCode->push_back(*ii);
}
}
/********************************************************************/
void ICodeGenerator::beginWhileStatement(uint32)
{
WhileCodeState *ics = new WhileCodeState(this);
addStitcher(ics);
// insert a branch to the while condition, which we're
// moving to follow the while block
branch(ics->whileCondition);
iCode = new InstructionStream();
}
void ICodeGenerator::endWhileExpression(Register condition)
{
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.back());
ASSERT(ics->stateKind == While_state);
branchConditional(ics->whileBody, condition);
resetTopRegister();
// stash away the condition expression and switch
// back to the main stream
iCode = ics->swapStream(iCode);
// mark the start of the while block
setLabel(ics->whileBody);
}
void ICodeGenerator::endWhileStatement()
{
// recover the while stream
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.back());
ASSERT(ics->stateKind == While_state);
stitcher.pop_back();
// mark the start of the condition code
// which is where continues will target
setLabel(ics->whileCondition);
// and re-attach it to the main stream
mergeStream(ics->whileExpressionStream);
if (ics->breakLabel != NULL)
setLabel(ics->breakLabel);
delete ics;
resetStatement();
}
/********************************************************************/
void ICodeGenerator::beginForStatement(uint32)
{
ForCodeState *ics = new ForCodeState(this);
addStitcher(ics);
branch(ics->forCondition);
// begin the stream for collecting the condition expression
iCode = new InstructionStream();
setLabel(ics->forCondition);
resetTopRegister();
}
void ICodeGenerator::forCondition(Register condition)
{
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
ASSERT(ics->stateKind == For_state);
// finsh off the test expression by adding the branch to the body
branchConditional(ics->forBody, condition);
// switch back to main stream
iCode = ics->swapStream(iCode);
// begin the stream for collecting the increment expression
iCode = new InstructionStream();
ics->continueLabel = getLabel();
// can't lazily insert this since we haven't seen the body yet
// ??? could just remember the offset
setLabel(ics->continueLabel);
resetTopRegister();
}
void ICodeGenerator::forIncrement()
{
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
ASSERT(ics->stateKind == For_state);
// now switch back to the main stream
iCode = ics->swapStream2(iCode);
setLabel(ics->forBody);
resetTopRegister();
}
void ICodeGenerator::endForStatement()
{
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
ASSERT(ics->stateKind == For_state);
stitcher.pop_back();
mergeStream(ics->forIncrementStream);
mergeStream(ics->forConditionStream);
if (ics->breakLabel != NULL)
setLabel(ics->breakLabel);
delete ics;
resetStatement();
}
/********************************************************************/
void ICodeGenerator::beginDoStatement(uint32)
{
DoCodeState *ics = new DoCodeState(this);
addStitcher(ics);
// mark the top of the loop body
setLabel(ics->doBody);
}
void ICodeGenerator::endDoStatement()
{
DoCodeState *ics = static_cast<DoCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Do_state);
// mark the start of the do conditional
setLabel(ics->doCondition);
if (ics->continueLabel != NULL)
setLabel(ics->continueLabel);
resetTopRegister();
}
void ICodeGenerator::endDoExpression(Register condition)
{
DoCodeState *ics = static_cast<DoCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Do_state);
stitcher.pop_back();
// add branch to top of do block
branchConditional(ics->doBody, condition);
if (ics->breakLabel != NULL)
setLabel(ics->breakLabel);
delete ics;
resetStatement();
}
/********************************************************************/
void ICodeGenerator::beginSwitchStatement(uint32, Register expression)
{
// stash the control expression value
// hmmm, need to track depth of nesting here....
move(switchRegister, expression);
// build an instruction stream for the case statements, the case
// expressions are generated into the main stream directly, the
// case statements are then added back in afterwards.
InstructionStream *x = new InstructionStream();
SwitchCodeState *ics = new SwitchCodeState(switchRegister++, this);
ics->swapStream(x);
addStitcher(ics);
}
void ICodeGenerator::endCaseCondition(Register expression)
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
Label *caseLabel = getLabel();
Register r = op(COMPARE_EQ, expression, ics->controlValue);
branchConditional(caseLabel, r);
// mark the case in the Case Statement stream
setLabel(ics->caseStatementsStream, caseLabel);
resetTopRegister();
}
void ICodeGenerator::beginCaseStatement(uint32 /* pos */)
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
// switch to Case Statement stream
iCode = ics->swapStream(iCode);
}
void ICodeGenerator::endCaseStatement()
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
// do more to guarantee correct blocking?
ASSERT(ics->stateKind == Switch_state);
// switch back to Case Conditional stream
iCode = ics->swapStream(iCode);
resetTopRegister();
}
void ICodeGenerator::beginDefaultStatement(uint32 /* pos */)
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
ASSERT(ics->defaultLabel == NULL);
ics->defaultLabel = getLabel();
setLabel(ics->caseStatementsStream, ics->defaultLabel);
// switch to Case Statement stream
iCode = ics->swapStream(iCode);
}
void ICodeGenerator::endDefaultStatement()
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
// do more to guarantee correct blocking?
ASSERT(ics->defaultLabel != NULL);
// switch to Case Statement stream
iCode = ics->swapStream(iCode);
resetTopRegister();
}
void ICodeGenerator::endSwitchStatement()
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
stitcher.pop_back();
// ground out the case chain at the default block or fall thru
// to the break label
if (ics->defaultLabel != NULL)
branch(ics->defaultLabel);
else {
if (ics->breakLabel == NULL)
ics->breakLabel = getLabel();
branch(ics->breakLabel);
}
// dump all the case statements into the main stream
mergeStream(ics->caseStatementsStream);
if (ics->breakLabel != NULL)
setLabel(ics->breakLabel);
delete ics;
--switchRegister;
resetStatement();
}
/********************************************************************/
void ICodeGenerator::beginIfStatement(uint32, Register condition)
{
IfCodeState *ics = new IfCodeState(this);
addStitcher(ics);
branchNotConditional(ics->elseLabel, condition);
resetTopRegister();
}
void ICodeGenerator::beginElseStatement(bool hasElse)
{
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.back());
ASSERT(ics->stateKind == If_state);
if (hasElse) {
Label *beyondElse = getLabel();
ics->beyondElse = beyondElse;
branch(beyondElse);
}
setLabel(ics->elseLabel);
resetTopRegister();
}
void ICodeGenerator::endIfStatement()
{
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.back());
ASSERT(ics->stateKind == If_state);
stitcher.pop_back();
if (ics->beyondElse != NULL) { // had an else
setLabel(ics->beyondElse); // the beyond else label
}
delete ics;
resetStatement();
}
/************************************************************************/
void ICodeGenerator::breakStatement(uint32 /* pos */)
{
for (std::vector<ICodeState *>::reverse_iterator p =
stitcher.rbegin(); p != stitcher.rend(); p++) {
if ((*p)->breakLabel != NULL) {
branch((*p)->breakLabel);
return;
}
if (((*p)->stateKind == While_state)
|| ((*p)->stateKind == Do_state)
|| ((*p)->stateKind == For_state)
|| ((*p)->stateKind == Switch_state)) {
(*p)->breakLabel = getLabel();
branch((*p)->breakLabel);
return;
}
}
NOT_REACHED("no break target available");
}
void ICodeGenerator::breakStatement(uint32 /* pos */,
const StringAtom &label)
{
for (std::vector<ICodeState *>::reverse_iterator p =
stitcher.rbegin(); p != stitcher.rend(); p++) {
if ((*p)->labelSet) {
for (StatementLabels::iterator i = (*p)->labelSet->begin();
i != (*p)->labelSet->end(); i++) {
if ((*i) == &label) {
if ((*p)->breakLabel == NULL)
(*p)->breakLabel = getLabel();
branch((*p)->breakLabel);
return;
}
}
}
}
NOT_REACHED("no break target available");
}
void ICodeGenerator::continueStatement(uint32 /* pos */)
{
for (std::vector<ICodeState *>::reverse_iterator p =
stitcher.rbegin(); p != stitcher.rend(); p++) {
if ((*p)->continueLabel != NULL) {
branch((*p)->continueLabel);
return;
}
if (((*p)->stateKind == While_state)
|| ((*p)->stateKind == Do_state)
|| ((*p)->stateKind == For_state)) {
(*p)->continueLabel = getLabel();
branch((*p)->continueLabel);
return;
}
}
NOT_REACHED("no continue target available");
}
void ICodeGenerator::continueStatement(uint32 /* pos */,
const StringAtom &label)
{
for (std::vector<ICodeState *>::reverse_iterator p =
stitcher.rbegin(); p != stitcher.rend(); p++) {
if ((*p)->labelSet) {
for (StatementLabels::iterator i = (*p)->labelSet->begin();
i != (*p)->labelSet->end(); i++) {
if ((*i) == &label) {
if ((*p)->continueLabel == NULL)
(*p)->continueLabel = getLabel();
branch((*p)->continueLabel);
return;
}
}
}
}
NOT_REACHED("no continue target available");
}
/********************************************************************/
void ICodeGenerator::beginTryStatement(uint32 /* pos */,
bool hasCatch, bool hasFinally)
{
ASSERT(exceptionRegister != NotARegister);
TryCodeState *ics = new TryCodeState((hasCatch) ? getLabel() : NULL,
(hasFinally) ? getLabel() : NULL, this);
addStitcher(ics);
beginTry(ics->catchHandler, ics->finallyInvoker);
}
void ICodeGenerator::endTryBlock()
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
endTry();
if (ics->finallyHandler)
jsr(ics->finallyHandler);
if (ics->beyondCatch)
branch(ics->beyondCatch);
}
void ICodeGenerator::endTryStatement()
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
stitcher.pop_back();
if (ics->beyondCatch)
setLabel(ics->beyondCatch);
resetStatement();
}
void ICodeGenerator::beginCatchStatement(uint32 /* pos */)
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
ASSERT(ics->catchHandler);
setLabel(ics->catchHandler);
}
void ICodeGenerator::endCatchExpression(Register exceptionId)
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
move(exceptionRegister, exceptionId);
}
void ICodeGenerator::endCatchStatement()
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
if (ics->finallyHandler)
jsr(ics->finallyHandler);
throwStatement(0, exceptionRegister);
}
void ICodeGenerator::beginFinallyStatement(uint32 /* pos */)
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
ASSERT(ics->finallyHandler);
if (ics->finallyInvoker) {
setLabel(ics->finallyInvoker);
jsr(ics->finallyHandler);
throwStatement(0, exceptionRegister);
}
setLabel(ics->finallyHandler);
}
void ICodeGenerator::endFinallyStatement()
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
rts();
}
/************************************************************************/
@ -1025,6 +525,12 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
ret = genExpr(u->op, needBoolValueInBranch, trueBranch, falseBranch);
}
break;
case ExprNode::New:
{
// FIXME - handle args, etc...
ret = newObject();
}
break;
case ExprNode::call :
{
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
@ -1059,8 +565,11 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
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.
*/
ret = loadName((static_cast<IdentifierExprNode *>(p))->name);
Register v = findVariable((static_cast<IdentifierExprNode *>(p))->name);
if (v != NotARegister)
ret = v;
else
ret = loadName((static_cast<IdentifierExprNode *>(p))->name);
}
break;
case ExprNode::number :
@ -1145,7 +654,11 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
ret = genExpr(b->op2);
if (b->op1->getKind() == ExprNode::identifier) {
saveName((static_cast<IdentifierExprNode *>(b->op1))->name, ret);
Register v = findVariable((static_cast<IdentifierExprNode *>(b->op1))->name);
if (v != NotARegister)
move(v, ret);
else
saveName((static_cast<IdentifierExprNode *>(b->op1))->name, ret);
}
else
if (b->op1->getKind() == ExprNode::dot) {
@ -1282,10 +795,8 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
Label *fBranch = getLabel();
Label *beyondBranch = getLabel();
Register c = genExpr(t->op1, false, NULL, fBranch);
if (!generatedBoolean(t->op1)) {
c = test(c);
branchNotConditional(fBranch, c);
}
if (!generatedBoolean(t->op1))
branchNotConditional(fBranch, test(c));
Register r1 = genExpr(t->op2);
branch(beyondBranch);
setLabel(fBranch);
@ -1305,13 +816,203 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
}
/*
pre-pass to find:
need pre-pass to find:
variable & function definitions,
#nested switch statements
contains 'with' or 'eval'
contains 'try {} catch {} finally {}'
*/
bool LabelEntry::containsLabel(const StringAtom *label)
{
if (labelSet) {
for (LabelSet::iterator i = labelSet->begin(); i != labelSet->end(); i++)
if ( (*i) == label )
return true;
}
return false;
}
Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
{
Register ret = NotARegister;
switch (p->getKind()) {
case StmtNode::expression:
{
ExprStmtNode *e = static_cast<ExprStmtNode *>(p);
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));
genStmt(i->stmt);
setLabel(falseLabel);
}
break;
case StmtNode::IfElse:
{
Label *falseLabel = getLabel();
Label *beyondLabel = getLabel();
BinaryStmtNode *i = static_cast<BinaryStmtNode *>(p);
Register c = genExpr(i->expr, false, NULL, falseLabel);
if (!generatedBoolean(i->expr))
branchNotConditional(falseLabel, test(c));
genStmt(i->stmt);
branch(beyondLabel);
setLabel(falseLabel);
genStmt(i->stmt2);
}
break;
case StmtNode::Switch:
{
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.
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);
}
// else it's the default case... THIS IS NOT DONE YET....
else
genStmt(c->stmt);
s = s->next;
}
setLabel(e->breakLabel);
mLabelStack.pop_back();
}
break;
case StmtNode::While:
{
LabelEntry *e = new LabelEntry(currentLabelSet, getLabel(), getLabel());
mLabelStack.push_back(e);
branch(e->continueLabel);
UnaryStmtNode *w = static_cast<UnaryStmtNode *>(p);
Label *whileBodyTopLabel = getLabel();
setLabel(whileBodyTopLabel);
genStmt(w->stmt);
setLabel(e->continueLabel);
Register c = genExpr(w->expr, false, whileBodyTopLabel, NULL);
if (!generatedBoolean(w->expr))
branchConditional(whileBodyTopLabel, test(c));
setLabel(e->breakLabel);
mLabelStack.pop_back();
}
break;
case StmtNode::For:
{
LabelEntry *e = new LabelEntry(currentLabelSet, getLabel(), getLabel());
mLabelStack.push_back(e);
ForStmtNode *f = static_cast<ForStmtNode *>(p);
if (f->initializer)
genStmt(f->initializer);
Label *forTestLabel = getLabel();
branch(forTestLabel);
Label *forBlockTop = getLabel();
setLabel(forBlockTop);
genStmt(f->stmt);
setLabel(e->continueLabel);
if (f->expr3)
genExpr(f->expr3);
setLabel(forTestLabel);
if (f->expr2) {
Register c = genExpr(f->expr2, false, forBlockTop, NULL);
if (!generatedBoolean(f->expr2))
branchConditional(forBlockTop, test(c));
}
setLabel(e->breakLabel);
mLabelStack.pop_back();
}
break;
case StmtNode::block:
{
BlockStmtNode *b = static_cast<BlockStmtNode *>(p);
StmtNode *s = b->statements;
while (s) {
genStmt(s);
s = s->next;
}
}
break;
case StmtNode::label:
{
LabelStmtNode *l = static_cast<LabelStmtNode *>(p);
// ok, there's got to be a cleverer way of doing this...
if (currentLabelSet != NULL) {
currentLabelSet = new LabelSet();
currentLabelSet->push_back(&l->name);
genStmt(l->stmt, currentLabelSet);
delete currentLabelSet;
}
else {
currentLabelSet->push_back(&l->name);
genStmt(l->stmt, currentLabelSet);
currentLabelSet->pop_back();
}
}
break;
case StmtNode::Break:
{
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->breakLabel);
branch(e->breakLabel);
}
else
NOT_REACHED("break label not in label set");
}
else {
ASSERT(!mLabelStack.empty());
LabelEntry *e = mLabelStack.back();
ASSERT(e->breakLabel);
branch(e->breakLabel);
}
}
break;
default:
NOT_REACHED("unimplemented statement kind");
}
return ret;
}
/************************************************************************/

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

@ -47,36 +47,7 @@ namespace ICG {
using namespace VM;
class ICodeGenerator; // forward declaration
enum StateKind {
While_state,
If_state,
Do_state,
Switch_state,
For_state,
Try_state
};
typedef std::vector<const StringAtom *> StatementLabels;
class ICodeState {
public :
ICodeState(StateKind kind, ICodeGenerator *icg); // inline below
virtual ~ICodeState() { }
virtual Label *getBreakLabel(ICodeGenerator *) \
{ ASSERT(false); return NULL; }
virtual Label *getContinueLabel(ICodeGenerator *) \
{ ASSERT(false); return NULL;}
StateKind stateKind;
uint32 statementLabelBase;
Label *breakLabel;
Label *continueLabel;
StatementLabels *labelSet;
};
typedef std::map<String, Register, std::less<String> > VariableList;
@ -104,6 +75,22 @@ namespace ICG {
};
typedef std::vector<const StringAtom *> LabelSet;
class LabelEntry {
public:
LabelEntry(LabelSet *labelSet, Label *breakLabel)
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(NULL) { }
LabelEntry(LabelSet *labelSet, Label *breakLabel, Label *continueLabel)
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(continueLabel) { }
bool containsLabel(const StringAtom *label);
LabelSet *labelSet;
Label *breakLabel;
Label *continueLabel;
};
typedef std::vector<LabelEntry *> LabelStack;
Formatter& operator<<(Formatter &f, ICodeModule &i);
/****************************************************************/
@ -118,8 +105,6 @@ namespace ICG {
InstructionStream *iCode;
bool iCodeOwner;
LabelList labels;
std::vector<ICodeState *> stitcher;
StatementLabels *labelSet;
Register topRegister; // highest (currently) alloacated register
Register registerBase; // start of registers available for expression temps
@ -134,7 +119,7 @@ namespace ICG {
World *mWorld; // used to register strings
LabelStack mLabelStack;
void markMaxRegister() \
{ if (topRegister > maxRegister) maxRegister = topRegister; }
@ -145,15 +130,11 @@ namespace ICG {
void resetTopRegister() \
{ markMaxRegister(); topRegister = registerBase; }
void addStitcher(ICodeState *ics) \
{ stitcher.push_back(ics); }
ICodeOp getBranchOp() \
{ return (iCode->empty()) ? NOP : iCode->back()->getBranchOp(); }
void setLabel(Label *label);
void setLabel(InstructionStream *stream, Label *label);
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
void rts() { iCode->push_back(new Rts()); }
@ -168,8 +149,7 @@ namespace ICG {
void endTry()
{ iCode->push_back(new Tryout()); }
void resetStatement()
{ if (labelSet) { delete labelSet; labelSet = NULL; } resetTopRegister(); }
void resetStatement() { resetTopRegister(); }
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
@ -183,14 +163,16 @@ namespace ICG {
if (iCodeOwner)
delete iCode;
}
void mergeStream(InstructionStream *sideStream);
ICodeModule *complete();
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)
@ -199,7 +181,7 @@ namespace ICG {
Register findVariable(const StringAtom& name)
{ VariableList::iterator i = variableList->find(name);
ASSERT(i != variableList->end()); return (*i).second; }
return (i == variableList->end()) ? NotARegister : (*i).second; }
Register allocateParameter(const StringAtom& name)
{ parameterCount++; return allocateVariable(name); }
@ -215,8 +197,6 @@ namespace ICG {
Register logicalNot(Register source);
Register test(Register source);
Register compare(ICodeOp op, Register source1, Register source2);
Register loadValue(JSValue value);
Register loadImmediate(double value);
Register loadString(String &value);
@ -241,85 +221,8 @@ namespace ICG {
Register getRegisterBase() { return topRegister; }
InstructionStream *get_iCode() { return iCode; }
StatementLabels *getStatementLabels() { return labelSet; labelSet = NULL; }
Label *getLabel();
// Rather than have the ICG client maniplate labels and branches, it
// uses the following calls to describe the high level looping
// constructs being generated. The functions listed below are
// expected to be called in the order listed for each construct,
// (internal error otherwise).
// The ICG will enforce correct nesting and closing.
// expression statements
void beginStatement(uint32 /*pos*/) { }
void endStatement() { resetStatement(); }
void returnStatement() { iCode->push_back(new ReturnVoid()); }
void returnStatement(Register result) \
{ if (result == NotARegister) returnStatement(); \
else iCode->push_back(new Return(result)); resetStatement(); }
void beginWhileStatement(uint32 pos);
void endWhileExpression(Register condition);
void endWhileStatement();
void beginDoStatement(uint32 pos);
void endDoStatement();
void endDoExpression(Register condition);
void beginIfStatement(uint32 pos, Register condition);
void beginElseStatement(bool hasElse); // required, regardless of
// existence of else clause
void endIfStatement();
// for ( ... in ...) statements get turned into generic for
// statements by the parser (ok?)
void beginForStatement(uint32 pos); // for initialization is
// emitted prior to this call
void forCondition(Register condition); // required
void forIncrement(); // required
void endForStatement();
void beginSwitchStatement(uint32 pos, Register expression);
void endCaseCondition(Register expression);
void beginCaseStatement(uint32 pos);
void endCaseStatement();
// optionally
void beginDefaultStatement(uint32 pos);
void endDefaultStatement();
void endSwitchStatement();
void beginLabelStatement(uint32 /* pos */, const StringAtom &label)
{ labelSet->push_back(&label); }
void endLabelStatement() { if (labelSet) labelSet->pop_back(); }
void continueStatement(uint32 pos);
void breakStatement(uint32 pos);
void continueStatement(uint32 pos, const StringAtom &label);
void breakStatement(uint32 pos, const StringAtom &label);
void throwStatement(uint32 /* pos */, Register expression)
{ iCode->push_back(new Throw(expression)); }
void beginTryStatement(uint32 pos, bool hasCatch, bool hasFinally);
void endTryBlock();
void endTryStatement();
void beginCatchStatement(uint32 pos);
void endCatchExpression(Register exceptionId);
void endCatchStatement();
void beginFinallyStatement(uint32 pos);
void endFinallyStatement();
};
@ -329,113 +232,6 @@ namespace ICG {
std::ostream &operator<<(std::ostream &s, StringAtom &str);
*/
class WhileCodeState : public ICodeState {
public:
WhileCodeState(ICodeGenerator *icg); // inline below
InstructionStream *swapStream(InstructionStream *iCode) \
{ InstructionStream *t = whileExpressionStream; \
whileExpressionStream = iCode; return t; }
virtual Label *getBreakLabel(ICodeGenerator *icg) \
{ if (breakLabel == NULL) breakLabel = icg->getLabel(); \
return breakLabel; }
virtual Label *getContinueLabel(ICodeGenerator *) \
{ return whileCondition; }
Label *whileCondition;
Label *whileBody;
InstructionStream *whileExpressionStream;
};
class ForCodeState : public ICodeState {
public:
ForCodeState(ICodeGenerator *icg); // inline below
InstructionStream *swapStream(InstructionStream *iCode) \
{ InstructionStream *t = forConditionStream; \
forConditionStream = iCode; return t; }
InstructionStream *swapStream2(InstructionStream *iCode) \
{ InstructionStream *t = forIncrementStream; \
forIncrementStream = iCode; return t; }
virtual Label *getBreakLabel(ICodeGenerator *icg) \
{ if (breakLabel == NULL) breakLabel = icg->getLabel(); \
return breakLabel; }
virtual Label *getContinueLabel(ICodeGenerator *) \
{ ASSERT(continueLabel); return continueLabel; }
Label *forCondition;
Label *forBody;
InstructionStream *forConditionStream;
InstructionStream *forIncrementStream;
};
class IfCodeState : public ICodeState {
public:
IfCodeState(ICodeGenerator *icg)
: ICodeState(If_state, icg), elseLabel(icg->getLabel()), beyondElse(NULL) { }
Label *elseLabel;
Label *beyondElse;
};
class DoCodeState : public ICodeState {
public:
DoCodeState(ICodeGenerator *icg)
: ICodeState(Do_state, icg), doBody(icg->getLabel()),
doCondition(icg->getLabel()) { }
virtual Label *getBreakLabel(ICodeGenerator *icg) \
{ if (breakLabel == NULL) breakLabel = icg->getLabel();
return breakLabel; }
virtual Label *getContinueLabel(ICodeGenerator *) \
{ return doCondition; }
Label *doBody;
Label *doCondition;
};
class SwitchCodeState : public ICodeState {
public:
SwitchCodeState(Register control, ICodeGenerator *icg); // inline below
InstructionStream *swapStream(InstructionStream *iCode) \
{ InstructionStream *t = caseStatementsStream; \
caseStatementsStream = iCode; return t; }
virtual Label *getBreakLabel(ICodeGenerator *icg) \
{ if (breakLabel == NULL) breakLabel = icg->getLabel();
return breakLabel; }
Register controlValue;
Label *defaultLabel;
InstructionStream *caseStatementsStream;
};
class TryCodeState : public ICodeState {
public:
TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg);
Label *catchHandler;
Label *finallyHandler;
Label *finallyInvoker;
Label *beyondCatch;
};
inline ICodeState::ICodeState(StateKind kind, ICodeGenerator *icg)
: stateKind(kind),
breakLabel(NULL), continueLabel(NULL),
labelSet(icg->getStatementLabels()) { }
inline SwitchCodeState::SwitchCodeState(Register control,
ICodeGenerator *icg)
: ICodeState(Switch_state, icg), controlValue(control),
defaultLabel(NULL), caseStatementsStream(icg->get_iCode()) {}
inline WhileCodeState::WhileCodeState(ICodeGenerator *icg)
: ICodeState(While_state, icg), whileCondition(icg->getLabel()),
whileBody(icg->getLabel()), whileExpressionStream(icg->get_iCode()) {}
inline ForCodeState::ForCodeState(ICodeGenerator *icg)
: ICodeState(For_state, icg), forCondition(icg->getLabel()),
forBody(icg->getLabel()), forConditionStream(icg->get_iCode()),
forIncrementStream(icg->get_iCode()) {}
} /* namespace IGC */

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

@ -99,15 +99,18 @@ static JSValue print(const JSValues &argv)
}
static void genCode(World &world, Context &cx, ExprNode *p)
static void genCode(World &world, Context &cx, StmtNode *p)
{
ICodeGenerator icg(&world);
icg.beginStatement(0);
Register ret = icg.genExpr(p);
icg.endStatement();
icg.returnStatement(ret);
Register ret = NotARegister;
while (p) {
ret = icg.genStmt(p);
p = p->next;
}
if (ret != NotARegister)
icg.addInstruction(new Return(ret));
else
icg.addInstruction(new ReturnVoid());
stdOut << '\n';
stdOut << icg;
JSValue result = cx.interpret(icg.complete(), JSValues());
@ -120,25 +123,6 @@ static void readEvalPrint(FILE *in, World &world)
Context cx(world, &glob);
StringAtom& printName = world.identifiers[widenCString("print")];
glob.defineNativeFunction(printName, print);
/*
hack an object a, with property p = 4.0 into the global scope
*/
{
ICodeGenerator icg;
// var global = new Object();
StringAtom& global = world.identifiers[widenCString("a")];
icg.beginStatement(0);
icg.saveName(global, icg.newObject());
// global.counter = 0;
StringAtom& prop = world.identifiers[widenCString("p")];
icg.beginStatement(0);
icg.setProperty(icg.loadName(global), prop, icg.loadImmediate(4.0));
icg.returnStatement();
cx.interpret(icg.complete(), JSValues());
}
String buffer;
string line;
@ -177,7 +161,7 @@ static void readEvalPrint(FILE *in, World &world)
stdOut << '\n';
#if 0
// Generate code for parsedStatements, which is a linked list of zero or more statements
genCode(world, cx, parseTree);
genCode(world, cx, parsedStatements);
#endif
}
clear(buffer);
@ -227,248 +211,60 @@ class Tracer : public Context::Listener {
}
};
static void testICG(World &world)
{
//
// testing ICG
//
uint32 pos = 0;
ICodeGenerator icg(&world, true, 1);
// var i,j;
// i is bound to var #0, j to var #1
Register r_i = icg.allocateVariable(world.identifiers[widenCString("i")]);
Register r_j = icg.allocateVariable(world.identifiers[widenCString("j")]);
Register r_x = icg.allocateVariable(world.identifiers[widenCString("x")]);
// i = j + 2;
icg.beginStatement(pos);
Register r1 = icg.loadImmediate(2.0);
icg.move(r_i, icg.op(ADD, r1, r_j));
// j = a.b
icg.beginStatement(pos);
r1 = icg.loadName(world.identifiers[widenCString("a")]);
r1 = icg.getProperty(r1, world.identifiers[widenCString("b")]);
icg.move(r_j, r1);
// label1 : while (i) { while (i) { i = i + j; break label1; } }
icg.beginLabelStatement(pos, world.identifiers[widenCString("label1")]);
icg.beginWhileStatement(pos);
icg.endWhileExpression(icg.test(r_i));
icg.beginWhileStatement(pos);
icg.endWhileExpression(icg.test(r_i));
icg.move(r_i, icg.op(ADD, r_i, r_j));
icg.breakStatement(pos, world.identifiers[widenCString("label1")]);
icg.endWhileStatement();
icg.endWhileStatement();
icg.endLabelStatement();
// if (i) if (j) i = 3; else j = 4;
icg.beginIfStatement(pos, icg.test(r_i));
icg.beginIfStatement(pos, icg.test(r_j));
icg.move(r_i, icg.loadImmediate(3));
icg.beginElseStatement(true);
icg.move(r_j, icg.loadImmediate(4));
icg.endIfStatement();
icg.beginElseStatement(false);
icg.endIfStatement();
// try {
// if (i) if (j) i = 3; else j = 4;
// throw j;
// }
// catch (x) {
// j = x;
// }
// finally {
// i = 5;
// }
icg.beginTryStatement(pos, true, true); // hasCatch, hasFinally
icg.beginIfStatement(pos, icg.test(r_i));
icg.beginIfStatement(pos, icg.test(r_j));
icg.move(r_i, icg.loadImmediate(3));
icg.beginElseStatement(true);
icg.beginStatement(pos);
icg.move(r_j, icg.loadImmediate(4));
icg.endIfStatement();
icg.beginElseStatement(false);
icg.endIfStatement();
icg.throwStatement(pos, r_j);
icg.endTryBlock();
icg.beginCatchStatement(pos);
icg.endCatchExpression(r_x);
icg.beginStatement(pos);
icg.move(r_j, r_x);
icg.endCatchStatement();
icg.beginFinallyStatement(pos);
icg.beginStatement(pos);
icg.move(r_i, icg.loadImmediate(5));
icg.endFinallyStatement();
icg.endTryStatement();
// switch (i) { case 3: case 4: j = 4; break; case 5: j = 5; break; default : j = 6; }
icg.beginSwitchStatement(pos, r_i);
// case 3, note empty case statement (?necessary???)
icg.endCaseCondition(icg.loadImmediate(3));
icg.beginCaseStatement(pos);
icg.endCaseStatement();
// case 4
icg.endCaseCondition(icg.loadImmediate(4));
icg.beginCaseStatement(pos);
icg.beginStatement(pos);
icg.move(r_j, icg.loadImmediate(4));
icg.breakStatement(pos);
icg.endCaseStatement();
// case 5
icg.endCaseCondition(icg.loadImmediate(5));
icg.beginCaseStatement(pos);
icg.beginStatement(pos);
icg.move(r_j, icg.loadImmediate(5));
icg.breakStatement(pos);
icg.endCaseStatement();
// default
icg.beginDefaultStatement(pos);
icg.beginStatement(pos);
icg.move(r_j, icg.loadImmediate(6));
icg.endDefaultStatement();
icg.endSwitchStatement();
// for ( ; i; i = i + 1 ) j = 99;
icg.beginForStatement(pos);
icg.forCondition(icg.test(r_i));
icg.move(r_i, icg.op(ADD, r_i, icg.loadImmediate(1)));
icg.forIncrement();
icg.move(r_j, icg.loadImmediate(99));
icg.endForStatement();
ICodeModule *icm = icg.complete();
stdOut << icg;
delete icm;
}
static float64 testFunctionCall(World &world, float64 n)
{
JSScope glob;
Context cx(world, &glob);
/*
Tracer t;
cx.addListener(&t);
*/
jsd.attachToContext(&cx);
uint32 position = 0;
//StringAtom& global = world.identifiers[widenCString("global")];
StringAtom& sum = world.identifiers[widenCString("sum")];
ICodeGenerator fun;
// function sum(n) { if (n > 1) return 1 + sum(n - 1); else return 1; }
// n is bound to var #0.
Register r_n =
fun.allocateVariable(world.identifiers[widenCString("n")]);
fun.beginStatement(position);
Register r1 = fun.op(COMPARE_LT, fun.loadImmediate(1.0), r_n);
fun.beginIfStatement(position, r1);
fun.beginStatement(position);
r1 = fun.op(SUBTRACT, r_n, fun.loadImmediate(1.0));
RegisterList args(1);
args[0] = r1;
r1 = fun.call(fun.loadName(sum), args);
fun.returnStatement(fun.op(ADD, fun.loadImmediate(1.0), r1));
fun.beginElseStatement(true);
fun.beginStatement(position);
fun.returnStatement(fun.loadImmediate(1.0));
fun.endIfStatement();
ICodeModule *funCode = fun.complete();
stdOut << fun;
// now a script :
// return sum(n);
ICodeGenerator script;
script.beginStatement(position);
r1 = script.loadName(sum);
RegisterList args_2(1);
args_2[0] = script.loadImmediate(n);
script.returnStatement(script.call(r1, args_2));
stdOut << script;
// preset the global property "sum" to contain the above function
glob.defineFunction(sum, funCode);
JSValue result = cx.interpret(script.complete(), JSValues());
stdOut << "sum(" << n << ") = " << result.f64 << "\n";
return result.f64;
}
static void testPrint(World &world)
{
JSScope glob;
Context cx(world, &glob);
uint32 position = 0;
StringAtom& printName = world.identifiers[widenCString("print")];
String text = widenCString("pi is ");
String piVal = widenCString("3.14159");
ICodeGenerator script;
script.beginStatement(position);
Register r1 = script.loadName(printName);
RegisterList args_2(1);
Register r2 = script.op(POSATE, script.loadString(piVal));
args_2[0] = script.op(ADD, script.loadString(text), r2);
script.returnStatement(script.call(r1, args_2));
stdOut << script;
glob.defineNativeFunction(printName, print);
JSValue result = cx.interpret(script.complete(), JSValues());
}
static float64 testFactorial(World &world, float64 n)
{
JSScope glob;
Context cx(world, &glob);
// generate code for factorial, and interpret it.
uint32 position = 0;
uint32 pos = 0;
ICodeGenerator icg;
// fact(n) {
// var result = 1;
Register r_n = icg.allocateVariable(world.identifiers[widenCString("n")]);
Register r_result = icg.allocateVariable(world.identifiers[widenCString("result")]);
icg.beginStatement(position);
icg.move(r_result, icg.loadImmediate(1.0));
StringAtom &n_name = world.identifiers[widenCString("n")];
StringAtom &result_name = world.identifiers[widenCString("result")];
Register r_n = icg.allocateVariable(n_name);
Register r_result = icg.allocateVariable(result_name);
Arena a;
ExprStmtNode *e = new(a) ExprStmtNode(pos, StmtNode::expression, new(a) BinaryExprNode(pos, ExprNode::assignment,
new(a) IdentifierExprNode(pos, ExprNode::identifier, result_name),
new(a) NumberExprNode(pos, 1.0) ) );
icg.genStmt(e);
// while (n > 1) {
// result = result * n;
// n = n - 1;
// }
{
icg.beginWhileStatement(position);
Register r1 = icg.loadImmediate(1.0);
Register r2 = icg.op(COMPARE_LT, r1, r_n);
icg.endWhileExpression(r2);
r2 = icg.op(MULTIPLY, r_result, r_n);
icg.move(r_result, r2);
icg.beginStatement(position);
r1 = icg.loadImmediate(1.0);
r2 = icg.op(SUBTRACT, r_n, r1);
icg.move(r_n, r2);
icg.endWhileStatement();
BinaryExprNode *c = new(a) BinaryExprNode(pos, ExprNode::greaterThan,
new(a) IdentifierExprNode(pos, ExprNode::identifier, n_name),
new(a) NumberExprNode(pos, 1.0) ) ;
ExprStmtNode *e1 = new(a) ExprStmtNode(pos, StmtNode::expression, new(a) BinaryExprNode(pos, ExprNode::assignment,
new(a) IdentifierExprNode(pos, ExprNode::identifier, result_name),
new(a) BinaryExprNode(pos, ExprNode::multiply,
new(a) IdentifierExprNode(pos, ExprNode::identifier, result_name),
new(a) IdentifierExprNode(pos, ExprNode::identifier, n_name) ) ) );
ExprStmtNode *e2 = new(a) ExprStmtNode(pos, StmtNode::expression, new(a) BinaryExprNode(pos, ExprNode::assignment,
new(a) IdentifierExprNode(pos, ExprNode::identifier, n_name),
new(a) BinaryExprNode(pos, ExprNode::subtract,
new(a) IdentifierExprNode(pos, ExprNode::identifier, n_name),
new(a) NumberExprNode(pos, 1.0) ) ) );
e1->next = e2;
BlockStmtNode *b = new(a) BlockStmtNode(pos, StmtNode::block, NULL, e1);
UnaryStmtNode *w = new(a) UnaryStmtNode(pos, StmtNode::While, c, b);
icg.genStmt(w);
}
// return result;
icg.returnStatement(r_result);
icg.addInstruction(new Return(r_result));
ICodeModule *icm = icg.complete();
stdOut << icg;
@ -479,10 +275,9 @@ static float64 testFactorial(World &world, float64 n)
// now a script :
// return fact(n);
ICodeGenerator script;
script.beginStatement(position);
RegisterList args(1);
args[0] = script.loadImmediate(n);
script.returnStatement(script.call(script.loadName(fact), args));
script.addInstruction(new Return(script.call(script.loadName(fact), args)));
stdOut << script;
// install a listener so we can trace execution of factorial.
@ -498,161 +293,6 @@ static float64 testFactorial(World &world, float64 n)
return result.f64;
}
static float64 testObjects(World &world, int32 n)
{
JSScope glob;
Context cx(world, &glob);
// create some objects, put some properties, and retrieve them.
uint32 position = 0;
ICodeGenerator initCG;
// var global = new Object();
StringAtom& global = world.identifiers[widenCString("global")];
initCG.beginStatement(position);
initCG.saveName(global, initCG.newObject());
// global.counter = 0;
StringAtom& counter = world.identifiers[widenCString("counter")];
initCG.beginStatement(position);
initCG.setProperty(initCG.loadName(global), counter, initCG.loadImmediate(0.0));
// var array = new Array();
StringAtom& array = world.identifiers[widenCString("array")];
initCG.beginStatement(position);
initCG.saveName(array, initCG.newArray());
initCG.returnStatement();
ICodeModule* initCode = initCG.complete();
stdOut << initCG;
// function increment()
// {
// var i = global.counter;
// array[i] = i;
// return ++global.counter;
// }
ICodeGenerator incrCG;
incrCG.beginStatement(position);
Register robject = incrCG.loadName(global);
Register roldvalue = incrCG.getProperty(robject, counter);
Register rarray = incrCG.loadName(array);
incrCG.setElement(rarray, roldvalue, roldvalue);
Register rvalue = incrCG.op(ADD, roldvalue, incrCG.loadImmediate(1.0));
incrCG.setProperty(robject, counter, rvalue);
incrCG.returnStatement(rvalue);
ICodeModule* incrCode = incrCG.complete();
stdOut << incrCG;
// run initialization code.
JSValues args;
cx.interpret(initCode, args);
// call the increment function some number of times.
JSValue result;
while (n-- > 0)
result = cx.interpret(incrCode, args);
stdOut << "result = " << result.f64 << "\n";
delete initCode;
delete incrCode;
return result.f64;
}
static float64 testProto(World &world, int32 n)
{
JSScope glob;
Context cx(world, &glob);
Tracer t;
cx.addListener(&t);
// create some objects, put some properties, and retrieve them.
uint32 position = 0;
ICodeGenerator initCG;
// var proto = new Object();
StringAtom& proto = world.identifiers[widenCString("proto")];
initCG.beginStatement(position);
initCG.saveName(proto, initCG.newObject());
// function increment()
// {
// this.counter = this.counter + 1;
// }
ICodeGenerator incrCG;
StringAtom& counter = world.identifiers[widenCString("counter")];
incrCG.beginStatement(position);
Register rthis = incrCG.allocateVariable(world.identifiers[widenCString("counter")]);
Register rcounter = incrCG.getProperty(rthis, counter);
incrCG.setProperty(rthis, counter, incrCG.op(ADD, rcounter, incrCG.loadImmediate(1.0)));
incrCG.returnStatement();
StringAtom& increment = world.identifiers[widenCString("increment")];
ICodeModule* incrCode = incrCG.complete();
glob.defineFunction(increment, incrCode);
// proto.increment = increment;
initCG.beginStatement(position);
initCG.setProperty(initCG.loadName(proto), increment, initCG.loadName(increment));
// var global = new Object();
StringAtom& global = world.identifiers[widenCString("global")];
initCG.beginStatement(position);
initCG.saveName(global, initCG.newObject());
// global.counter = 0;
initCG.beginStatement(position);
initCG.setProperty(initCG.loadName(global), counter, initCG.loadImmediate(0.0));
// global.proto = proto;
// initCG.beginStatement(position);
// initCG.setProperty(initCG.loadName(global), proto, initCG.loadName(proto));
initCG.returnStatement();
ICodeModule* initCode = initCG.complete();
stdOut << initCG;
// run initialization code.
JSValues args;
cx.interpret(initCode, args);
// objects now exist, do real prototype chain manipulation.
JSObject* globalObject = glob.getVariable(global).object;
globalObject->setPrototype(glob.getVariable(proto).object);
// generate call to global.increment()
ICodeGenerator callCG;
callCG.beginStatement(position);
RegisterList argList(1);
Register rglobal = argList[0] = callCG.loadName(global);
callCG.call(callCG.getProperty(rglobal, increment), argList);
callCG.returnStatement();
ICodeModule* callCode = callCG.complete();
// call the increment method some number of times.
while (n-- > 0)
(void) cx.interpret(callCode, args);
JSValue result = glob.getVariable(global).object->getProperty(counter);
stdOut << "result = " << result.f64 << "\n";
delete initCode;
delete incrCode;
delete callCode;
return result.f64;
}
} /* namespace Shell */
@ -668,11 +308,6 @@ int main(int argc, char **argv)
using namespace Shell;
#if 0
assert(testFactorial(world, 5) == 120);
assert(testObjects(world, 5) == 5);
assert(testProto(world, 5) == 5);
testICG(world);
// assert(testFunctionCall(world, 5) == 5);
testPrint(world);
#endif
readEvalPrint(stdin, world);
return 0;

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

@ -85,14 +85,11 @@ ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switch
else
allocateVariable(world->identifiers[s]);
}
labelSet = new StatementLabels();
}
ICodeModule *ICodeGenerator::complete()
{
ASSERT(stitcher.empty());
//ASSERT(labelSet == NULL);
#ifdef DEBUG
for (LabelList::iterator i = labels.begin();
i != labels.end(); i++) {
@ -101,6 +98,11 @@ ICodeModule *ICodeGenerator::complete()
}
#endif
/*
XXX FIXME
I wanted to do the following rather than have to have the label set hanging around as well
as the ICodeModule. Branches have since changed, but the concept is still good and should
be re-introduced at some point.
for (InstructionIterator ii = iCode->begin();
ii != iCode->end(); ii++) {
if ((*ii)->op() == BRANCH) {
@ -124,20 +126,6 @@ ICodeModule *ICodeGenerator::complete()
return module;
}
TryCodeState::TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg)
: ICodeState(Try_state, icg),
catchHandler(catchLabel),
finallyHandler(finallyLabel),
finallyInvoker(NULL),
beyondCatch(NULL)
{
if (catchHandler) {
beyondCatch = icg->getLabel();
if (finallyLabel)
finallyInvoker = icg->getLabel();
}
}
/********************************************************************/
@ -398,494 +386,6 @@ void ICodeGenerator::setLabel(Label *l)
l->mOffset = iCode->size();
}
void ICodeGenerator::setLabel(InstructionStream *stream, Label *l)
{
l->mBase = stream;
l->mOffset = stream->size();
}
/********************************************************************/
void ICodeGenerator::mergeStream(InstructionStream *sideStream)
{
// change InstructionStream to be a class that also remembers
// if it contains any labels (maybe even remembers the labels
// themselves?) in order to avoid running this loop unnecessarily.
for (LabelList::iterator i = labels.begin();
i != labels.end(); i++) {
if ((*i)->mBase == sideStream) {
(*i)->mBase = iCode;
(*i)->mOffset += iCode->size();
}
}
for (InstructionIterator ii = sideStream->begin();
ii != sideStream->end(); ii++) {
iCode->push_back(*ii);
}
}
/********************************************************************/
void ICodeGenerator::beginWhileStatement(uint32)
{
WhileCodeState *ics = new WhileCodeState(this);
addStitcher(ics);
// insert a branch to the while condition, which we're
// moving to follow the while block
branch(ics->whileCondition);
iCode = new InstructionStream();
}
void ICodeGenerator::endWhileExpression(Register condition)
{
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.back());
ASSERT(ics->stateKind == While_state);
branchConditional(ics->whileBody, condition);
resetTopRegister();
// stash away the condition expression and switch
// back to the main stream
iCode = ics->swapStream(iCode);
// mark the start of the while block
setLabel(ics->whileBody);
}
void ICodeGenerator::endWhileStatement()
{
// recover the while stream
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.back());
ASSERT(ics->stateKind == While_state);
stitcher.pop_back();
// mark the start of the condition code
// which is where continues will target
setLabel(ics->whileCondition);
// and re-attach it to the main stream
mergeStream(ics->whileExpressionStream);
if (ics->breakLabel != NULL)
setLabel(ics->breakLabel);
delete ics;
resetStatement();
}
/********************************************************************/
void ICodeGenerator::beginForStatement(uint32)
{
ForCodeState *ics = new ForCodeState(this);
addStitcher(ics);
branch(ics->forCondition);
// begin the stream for collecting the condition expression
iCode = new InstructionStream();
setLabel(ics->forCondition);
resetTopRegister();
}
void ICodeGenerator::forCondition(Register condition)
{
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
ASSERT(ics->stateKind == For_state);
// finsh off the test expression by adding the branch to the body
branchConditional(ics->forBody, condition);
// switch back to main stream
iCode = ics->swapStream(iCode);
// begin the stream for collecting the increment expression
iCode = new InstructionStream();
ics->continueLabel = getLabel();
// can't lazily insert this since we haven't seen the body yet
// ??? could just remember the offset
setLabel(ics->continueLabel);
resetTopRegister();
}
void ICodeGenerator::forIncrement()
{
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
ASSERT(ics->stateKind == For_state);
// now switch back to the main stream
iCode = ics->swapStream2(iCode);
setLabel(ics->forBody);
resetTopRegister();
}
void ICodeGenerator::endForStatement()
{
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
ASSERT(ics->stateKind == For_state);
stitcher.pop_back();
mergeStream(ics->forIncrementStream);
mergeStream(ics->forConditionStream);
if (ics->breakLabel != NULL)
setLabel(ics->breakLabel);
delete ics;
resetStatement();
}
/********************************************************************/
void ICodeGenerator::beginDoStatement(uint32)
{
DoCodeState *ics = new DoCodeState(this);
addStitcher(ics);
// mark the top of the loop body
setLabel(ics->doBody);
}
void ICodeGenerator::endDoStatement()
{
DoCodeState *ics = static_cast<DoCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Do_state);
// mark the start of the do conditional
setLabel(ics->doCondition);
if (ics->continueLabel != NULL)
setLabel(ics->continueLabel);
resetTopRegister();
}
void ICodeGenerator::endDoExpression(Register condition)
{
DoCodeState *ics = static_cast<DoCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Do_state);
stitcher.pop_back();
// add branch to top of do block
branchConditional(ics->doBody, condition);
if (ics->breakLabel != NULL)
setLabel(ics->breakLabel);
delete ics;
resetStatement();
}
/********************************************************************/
void ICodeGenerator::beginSwitchStatement(uint32, Register expression)
{
// stash the control expression value
// hmmm, need to track depth of nesting here....
move(switchRegister, expression);
// build an instruction stream for the case statements, the case
// expressions are generated into the main stream directly, the
// case statements are then added back in afterwards.
InstructionStream *x = new InstructionStream();
SwitchCodeState *ics = new SwitchCodeState(switchRegister++, this);
ics->swapStream(x);
addStitcher(ics);
}
void ICodeGenerator::endCaseCondition(Register expression)
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
Label *caseLabel = getLabel();
Register r = op(COMPARE_EQ, expression, ics->controlValue);
branchConditional(caseLabel, r);
// mark the case in the Case Statement stream
setLabel(ics->caseStatementsStream, caseLabel);
resetTopRegister();
}
void ICodeGenerator::beginCaseStatement(uint32 /* pos */)
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
// switch to Case Statement stream
iCode = ics->swapStream(iCode);
}
void ICodeGenerator::endCaseStatement()
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
// do more to guarantee correct blocking?
ASSERT(ics->stateKind == Switch_state);
// switch back to Case Conditional stream
iCode = ics->swapStream(iCode);
resetTopRegister();
}
void ICodeGenerator::beginDefaultStatement(uint32 /* pos */)
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
ASSERT(ics->defaultLabel == NULL);
ics->defaultLabel = getLabel();
setLabel(ics->caseStatementsStream, ics->defaultLabel);
// switch to Case Statement stream
iCode = ics->swapStream(iCode);
}
void ICodeGenerator::endDefaultStatement()
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
// do more to guarantee correct blocking?
ASSERT(ics->defaultLabel != NULL);
// switch to Case Statement stream
iCode = ics->swapStream(iCode);
resetTopRegister();
}
void ICodeGenerator::endSwitchStatement()
{
SwitchCodeState *ics =
static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
stitcher.pop_back();
// ground out the case chain at the default block or fall thru
// to the break label
if (ics->defaultLabel != NULL)
branch(ics->defaultLabel);
else {
if (ics->breakLabel == NULL)
ics->breakLabel = getLabel();
branch(ics->breakLabel);
}
// dump all the case statements into the main stream
mergeStream(ics->caseStatementsStream);
if (ics->breakLabel != NULL)
setLabel(ics->breakLabel);
delete ics;
--switchRegister;
resetStatement();
}
/********************************************************************/
void ICodeGenerator::beginIfStatement(uint32, Register condition)
{
IfCodeState *ics = new IfCodeState(this);
addStitcher(ics);
branchNotConditional(ics->elseLabel, condition);
resetTopRegister();
}
void ICodeGenerator::beginElseStatement(bool hasElse)
{
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.back());
ASSERT(ics->stateKind == If_state);
if (hasElse) {
Label *beyondElse = getLabel();
ics->beyondElse = beyondElse;
branch(beyondElse);
}
setLabel(ics->elseLabel);
resetTopRegister();
}
void ICodeGenerator::endIfStatement()
{
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.back());
ASSERT(ics->stateKind == If_state);
stitcher.pop_back();
if (ics->beyondElse != NULL) { // had an else
setLabel(ics->beyondElse); // the beyond else label
}
delete ics;
resetStatement();
}
/************************************************************************/
void ICodeGenerator::breakStatement(uint32 /* pos */)
{
for (std::vector<ICodeState *>::reverse_iterator p =
stitcher.rbegin(); p != stitcher.rend(); p++) {
if ((*p)->breakLabel != NULL) {
branch((*p)->breakLabel);
return;
}
if (((*p)->stateKind == While_state)
|| ((*p)->stateKind == Do_state)
|| ((*p)->stateKind == For_state)
|| ((*p)->stateKind == Switch_state)) {
(*p)->breakLabel = getLabel();
branch((*p)->breakLabel);
return;
}
}
NOT_REACHED("no break target available");
}
void ICodeGenerator::breakStatement(uint32 /* pos */,
const StringAtom &label)
{
for (std::vector<ICodeState *>::reverse_iterator p =
stitcher.rbegin(); p != stitcher.rend(); p++) {
if ((*p)->labelSet) {
for (StatementLabels::iterator i = (*p)->labelSet->begin();
i != (*p)->labelSet->end(); i++) {
if ((*i) == &label) {
if ((*p)->breakLabel == NULL)
(*p)->breakLabel = getLabel();
branch((*p)->breakLabel);
return;
}
}
}
}
NOT_REACHED("no break target available");
}
void ICodeGenerator::continueStatement(uint32 /* pos */)
{
for (std::vector<ICodeState *>::reverse_iterator p =
stitcher.rbegin(); p != stitcher.rend(); p++) {
if ((*p)->continueLabel != NULL) {
branch((*p)->continueLabel);
return;
}
if (((*p)->stateKind == While_state)
|| ((*p)->stateKind == Do_state)
|| ((*p)->stateKind == For_state)) {
(*p)->continueLabel = getLabel();
branch((*p)->continueLabel);
return;
}
}
NOT_REACHED("no continue target available");
}
void ICodeGenerator::continueStatement(uint32 /* pos */,
const StringAtom &label)
{
for (std::vector<ICodeState *>::reverse_iterator p =
stitcher.rbegin(); p != stitcher.rend(); p++) {
if ((*p)->labelSet) {
for (StatementLabels::iterator i = (*p)->labelSet->begin();
i != (*p)->labelSet->end(); i++) {
if ((*i) == &label) {
if ((*p)->continueLabel == NULL)
(*p)->continueLabel = getLabel();
branch((*p)->continueLabel);
return;
}
}
}
}
NOT_REACHED("no continue target available");
}
/********************************************************************/
void ICodeGenerator::beginTryStatement(uint32 /* pos */,
bool hasCatch, bool hasFinally)
{
ASSERT(exceptionRegister != NotARegister);
TryCodeState *ics = new TryCodeState((hasCatch) ? getLabel() : NULL,
(hasFinally) ? getLabel() : NULL, this);
addStitcher(ics);
beginTry(ics->catchHandler, ics->finallyInvoker);
}
void ICodeGenerator::endTryBlock()
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
endTry();
if (ics->finallyHandler)
jsr(ics->finallyHandler);
if (ics->beyondCatch)
branch(ics->beyondCatch);
}
void ICodeGenerator::endTryStatement()
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
stitcher.pop_back();
if (ics->beyondCatch)
setLabel(ics->beyondCatch);
resetStatement();
}
void ICodeGenerator::beginCatchStatement(uint32 /* pos */)
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
ASSERT(ics->catchHandler);
setLabel(ics->catchHandler);
}
void ICodeGenerator::endCatchExpression(Register exceptionId)
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
move(exceptionRegister, exceptionId);
}
void ICodeGenerator::endCatchStatement()
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
if (ics->finallyHandler)
jsr(ics->finallyHandler);
throwStatement(0, exceptionRegister);
}
void ICodeGenerator::beginFinallyStatement(uint32 /* pos */)
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
ASSERT(ics->finallyHandler);
if (ics->finallyInvoker) {
setLabel(ics->finallyInvoker);
jsr(ics->finallyHandler);
throwStatement(0, exceptionRegister);
}
setLabel(ics->finallyHandler);
}
void ICodeGenerator::endFinallyStatement()
{
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Try_state);
rts();
}
/************************************************************************/
@ -1025,6 +525,12 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
ret = genExpr(u->op, needBoolValueInBranch, trueBranch, falseBranch);
}
break;
case ExprNode::New:
{
// FIXME - handle args, etc...
ret = newObject();
}
break;
case ExprNode::call :
{
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
@ -1059,8 +565,11 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
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.
*/
ret = loadName((static_cast<IdentifierExprNode *>(p))->name);
Register v = findVariable((static_cast<IdentifierExprNode *>(p))->name);
if (v != NotARegister)
ret = v;
else
ret = loadName((static_cast<IdentifierExprNode *>(p))->name);
}
break;
case ExprNode::number :
@ -1145,7 +654,11 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
ret = genExpr(b->op2);
if (b->op1->getKind() == ExprNode::identifier) {
saveName((static_cast<IdentifierExprNode *>(b->op1))->name, ret);
Register v = findVariable((static_cast<IdentifierExprNode *>(b->op1))->name);
if (v != NotARegister)
move(v, ret);
else
saveName((static_cast<IdentifierExprNode *>(b->op1))->name, ret);
}
else
if (b->op1->getKind() == ExprNode::dot) {
@ -1282,10 +795,8 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
Label *fBranch = getLabel();
Label *beyondBranch = getLabel();
Register c = genExpr(t->op1, false, NULL, fBranch);
if (!generatedBoolean(t->op1)) {
c = test(c);
branchNotConditional(fBranch, c);
}
if (!generatedBoolean(t->op1))
branchNotConditional(fBranch, test(c));
Register r1 = genExpr(t->op2);
branch(beyondBranch);
setLabel(fBranch);
@ -1305,13 +816,203 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
}
/*
pre-pass to find:
need pre-pass to find:
variable & function definitions,
#nested switch statements
contains 'with' or 'eval'
contains 'try {} catch {} finally {}'
*/
bool LabelEntry::containsLabel(const StringAtom *label)
{
if (labelSet) {
for (LabelSet::iterator i = labelSet->begin(); i != labelSet->end(); i++)
if ( (*i) == label )
return true;
}
return false;
}
Register ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
{
Register ret = NotARegister;
switch (p->getKind()) {
case StmtNode::expression:
{
ExprStmtNode *e = static_cast<ExprStmtNode *>(p);
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));
genStmt(i->stmt);
setLabel(falseLabel);
}
break;
case StmtNode::IfElse:
{
Label *falseLabel = getLabel();
Label *beyondLabel = getLabel();
BinaryStmtNode *i = static_cast<BinaryStmtNode *>(p);
Register c = genExpr(i->expr, false, NULL, falseLabel);
if (!generatedBoolean(i->expr))
branchNotConditional(falseLabel, test(c));
genStmt(i->stmt);
branch(beyondLabel);
setLabel(falseLabel);
genStmt(i->stmt2);
}
break;
case StmtNode::Switch:
{
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.
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);
}
// else it's the default case... THIS IS NOT DONE YET....
else
genStmt(c->stmt);
s = s->next;
}
setLabel(e->breakLabel);
mLabelStack.pop_back();
}
break;
case StmtNode::While:
{
LabelEntry *e = new LabelEntry(currentLabelSet, getLabel(), getLabel());
mLabelStack.push_back(e);
branch(e->continueLabel);
UnaryStmtNode *w = static_cast<UnaryStmtNode *>(p);
Label *whileBodyTopLabel = getLabel();
setLabel(whileBodyTopLabel);
genStmt(w->stmt);
setLabel(e->continueLabel);
Register c = genExpr(w->expr, false, whileBodyTopLabel, NULL);
if (!generatedBoolean(w->expr))
branchConditional(whileBodyTopLabel, test(c));
setLabel(e->breakLabel);
mLabelStack.pop_back();
}
break;
case StmtNode::For:
{
LabelEntry *e = new LabelEntry(currentLabelSet, getLabel(), getLabel());
mLabelStack.push_back(e);
ForStmtNode *f = static_cast<ForStmtNode *>(p);
if (f->initializer)
genStmt(f->initializer);
Label *forTestLabel = getLabel();
branch(forTestLabel);
Label *forBlockTop = getLabel();
setLabel(forBlockTop);
genStmt(f->stmt);
setLabel(e->continueLabel);
if (f->expr3)
genExpr(f->expr3);
setLabel(forTestLabel);
if (f->expr2) {
Register c = genExpr(f->expr2, false, forBlockTop, NULL);
if (!generatedBoolean(f->expr2))
branchConditional(forBlockTop, test(c));
}
setLabel(e->breakLabel);
mLabelStack.pop_back();
}
break;
case StmtNode::block:
{
BlockStmtNode *b = static_cast<BlockStmtNode *>(p);
StmtNode *s = b->statements;
while (s) {
genStmt(s);
s = s->next;
}
}
break;
case StmtNode::label:
{
LabelStmtNode *l = static_cast<LabelStmtNode *>(p);
// ok, there's got to be a cleverer way of doing this...
if (currentLabelSet != NULL) {
currentLabelSet = new LabelSet();
currentLabelSet->push_back(&l->name);
genStmt(l->stmt, currentLabelSet);
delete currentLabelSet;
}
else {
currentLabelSet->push_back(&l->name);
genStmt(l->stmt, currentLabelSet);
currentLabelSet->pop_back();
}
}
break;
case StmtNode::Break:
{
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->breakLabel);
branch(e->breakLabel);
}
else
NOT_REACHED("break label not in label set");
}
else {
ASSERT(!mLabelStack.empty());
LabelEntry *e = mLabelStack.back();
ASSERT(e->breakLabel);
branch(e->breakLabel);
}
}
break;
default:
NOT_REACHED("unimplemented statement kind");
}
return ret;
}
/************************************************************************/

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

@ -47,36 +47,7 @@ namespace ICG {
using namespace VM;
class ICodeGenerator; // forward declaration
enum StateKind {
While_state,
If_state,
Do_state,
Switch_state,
For_state,
Try_state
};
typedef std::vector<const StringAtom *> StatementLabels;
class ICodeState {
public :
ICodeState(StateKind kind, ICodeGenerator *icg); // inline below
virtual ~ICodeState() { }
virtual Label *getBreakLabel(ICodeGenerator *) \
{ ASSERT(false); return NULL; }
virtual Label *getContinueLabel(ICodeGenerator *) \
{ ASSERT(false); return NULL;}
StateKind stateKind;
uint32 statementLabelBase;
Label *breakLabel;
Label *continueLabel;
StatementLabels *labelSet;
};
typedef std::map<String, Register, std::less<String> > VariableList;
@ -104,6 +75,22 @@ namespace ICG {
};
typedef std::vector<const StringAtom *> LabelSet;
class LabelEntry {
public:
LabelEntry(LabelSet *labelSet, Label *breakLabel)
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(NULL) { }
LabelEntry(LabelSet *labelSet, Label *breakLabel, Label *continueLabel)
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(continueLabel) { }
bool containsLabel(const StringAtom *label);
LabelSet *labelSet;
Label *breakLabel;
Label *continueLabel;
};
typedef std::vector<LabelEntry *> LabelStack;
Formatter& operator<<(Formatter &f, ICodeModule &i);
/****************************************************************/
@ -118,8 +105,6 @@ namespace ICG {
InstructionStream *iCode;
bool iCodeOwner;
LabelList labels;
std::vector<ICodeState *> stitcher;
StatementLabels *labelSet;
Register topRegister; // highest (currently) alloacated register
Register registerBase; // start of registers available for expression temps
@ -134,7 +119,7 @@ namespace ICG {
World *mWorld; // used to register strings
LabelStack mLabelStack;
void markMaxRegister() \
{ if (topRegister > maxRegister) maxRegister = topRegister; }
@ -145,15 +130,11 @@ namespace ICG {
void resetTopRegister() \
{ markMaxRegister(); topRegister = registerBase; }
void addStitcher(ICodeState *ics) \
{ stitcher.push_back(ics); }
ICodeOp getBranchOp() \
{ return (iCode->empty()) ? NOP : iCode->back()->getBranchOp(); }
void setLabel(Label *label);
void setLabel(InstructionStream *stream, Label *label);
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
void rts() { iCode->push_back(new Rts()); }
@ -168,8 +149,7 @@ namespace ICG {
void endTry()
{ iCode->push_back(new Tryout()); }
void resetStatement()
{ if (labelSet) { delete labelSet; labelSet = NULL; } resetTopRegister(); }
void resetStatement() { resetTopRegister(); }
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
@ -183,14 +163,16 @@ namespace ICG {
if (iCodeOwner)
delete iCode;
}
void mergeStream(InstructionStream *sideStream);
ICodeModule *complete();
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)
@ -199,7 +181,7 @@ namespace ICG {
Register findVariable(const StringAtom& name)
{ VariableList::iterator i = variableList->find(name);
ASSERT(i != variableList->end()); return (*i).second; }
return (i == variableList->end()) ? NotARegister : (*i).second; }
Register allocateParameter(const StringAtom& name)
{ parameterCount++; return allocateVariable(name); }
@ -215,8 +197,6 @@ namespace ICG {
Register logicalNot(Register source);
Register test(Register source);
Register compare(ICodeOp op, Register source1, Register source2);
Register loadValue(JSValue value);
Register loadImmediate(double value);
Register loadString(String &value);
@ -241,85 +221,8 @@ namespace ICG {
Register getRegisterBase() { return topRegister; }
InstructionStream *get_iCode() { return iCode; }
StatementLabels *getStatementLabels() { return labelSet; labelSet = NULL; }
Label *getLabel();
// Rather than have the ICG client maniplate labels and branches, it
// uses the following calls to describe the high level looping
// constructs being generated. The functions listed below are
// expected to be called in the order listed for each construct,
// (internal error otherwise).
// The ICG will enforce correct nesting and closing.
// expression statements
void beginStatement(uint32 /*pos*/) { }
void endStatement() { resetStatement(); }
void returnStatement() { iCode->push_back(new ReturnVoid()); }
void returnStatement(Register result) \
{ if (result == NotARegister) returnStatement(); \
else iCode->push_back(new Return(result)); resetStatement(); }
void beginWhileStatement(uint32 pos);
void endWhileExpression(Register condition);
void endWhileStatement();
void beginDoStatement(uint32 pos);
void endDoStatement();
void endDoExpression(Register condition);
void beginIfStatement(uint32 pos, Register condition);
void beginElseStatement(bool hasElse); // required, regardless of
// existence of else clause
void endIfStatement();
// for ( ... in ...) statements get turned into generic for
// statements by the parser (ok?)
void beginForStatement(uint32 pos); // for initialization is
// emitted prior to this call
void forCondition(Register condition); // required
void forIncrement(); // required
void endForStatement();
void beginSwitchStatement(uint32 pos, Register expression);
void endCaseCondition(Register expression);
void beginCaseStatement(uint32 pos);
void endCaseStatement();
// optionally
void beginDefaultStatement(uint32 pos);
void endDefaultStatement();
void endSwitchStatement();
void beginLabelStatement(uint32 /* pos */, const StringAtom &label)
{ labelSet->push_back(&label); }
void endLabelStatement() { if (labelSet) labelSet->pop_back(); }
void continueStatement(uint32 pos);
void breakStatement(uint32 pos);
void continueStatement(uint32 pos, const StringAtom &label);
void breakStatement(uint32 pos, const StringAtom &label);
void throwStatement(uint32 /* pos */, Register expression)
{ iCode->push_back(new Throw(expression)); }
void beginTryStatement(uint32 pos, bool hasCatch, bool hasFinally);
void endTryBlock();
void endTryStatement();
void beginCatchStatement(uint32 pos);
void endCatchExpression(Register exceptionId);
void endCatchStatement();
void beginFinallyStatement(uint32 pos);
void endFinallyStatement();
};
@ -329,113 +232,6 @@ namespace ICG {
std::ostream &operator<<(std::ostream &s, StringAtom &str);
*/
class WhileCodeState : public ICodeState {
public:
WhileCodeState(ICodeGenerator *icg); // inline below
InstructionStream *swapStream(InstructionStream *iCode) \
{ InstructionStream *t = whileExpressionStream; \
whileExpressionStream = iCode; return t; }
virtual Label *getBreakLabel(ICodeGenerator *icg) \
{ if (breakLabel == NULL) breakLabel = icg->getLabel(); \
return breakLabel; }
virtual Label *getContinueLabel(ICodeGenerator *) \
{ return whileCondition; }
Label *whileCondition;
Label *whileBody;
InstructionStream *whileExpressionStream;
};
class ForCodeState : public ICodeState {
public:
ForCodeState(ICodeGenerator *icg); // inline below
InstructionStream *swapStream(InstructionStream *iCode) \
{ InstructionStream *t = forConditionStream; \
forConditionStream = iCode; return t; }
InstructionStream *swapStream2(InstructionStream *iCode) \
{ InstructionStream *t = forIncrementStream; \
forIncrementStream = iCode; return t; }
virtual Label *getBreakLabel(ICodeGenerator *icg) \
{ if (breakLabel == NULL) breakLabel = icg->getLabel(); \
return breakLabel; }
virtual Label *getContinueLabel(ICodeGenerator *) \
{ ASSERT(continueLabel); return continueLabel; }
Label *forCondition;
Label *forBody;
InstructionStream *forConditionStream;
InstructionStream *forIncrementStream;
};
class IfCodeState : public ICodeState {
public:
IfCodeState(ICodeGenerator *icg)
: ICodeState(If_state, icg), elseLabel(icg->getLabel()), beyondElse(NULL) { }
Label *elseLabel;
Label *beyondElse;
};
class DoCodeState : public ICodeState {
public:
DoCodeState(ICodeGenerator *icg)
: ICodeState(Do_state, icg), doBody(icg->getLabel()),
doCondition(icg->getLabel()) { }
virtual Label *getBreakLabel(ICodeGenerator *icg) \
{ if (breakLabel == NULL) breakLabel = icg->getLabel();
return breakLabel; }
virtual Label *getContinueLabel(ICodeGenerator *) \
{ return doCondition; }
Label *doBody;
Label *doCondition;
};
class SwitchCodeState : public ICodeState {
public:
SwitchCodeState(Register control, ICodeGenerator *icg); // inline below
InstructionStream *swapStream(InstructionStream *iCode) \
{ InstructionStream *t = caseStatementsStream; \
caseStatementsStream = iCode; return t; }
virtual Label *getBreakLabel(ICodeGenerator *icg) \
{ if (breakLabel == NULL) breakLabel = icg->getLabel();
return breakLabel; }
Register controlValue;
Label *defaultLabel;
InstructionStream *caseStatementsStream;
};
class TryCodeState : public ICodeState {
public:
TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg);
Label *catchHandler;
Label *finallyHandler;
Label *finallyInvoker;
Label *beyondCatch;
};
inline ICodeState::ICodeState(StateKind kind, ICodeGenerator *icg)
: stateKind(kind),
breakLabel(NULL), continueLabel(NULL),
labelSet(icg->getStatementLabels()) { }
inline SwitchCodeState::SwitchCodeState(Register control,
ICodeGenerator *icg)
: ICodeState(Switch_state, icg), controlValue(control),
defaultLabel(NULL), caseStatementsStream(icg->get_iCode()) {}
inline WhileCodeState::WhileCodeState(ICodeGenerator *icg)
: ICodeState(While_state, icg), whileCondition(icg->getLabel()),
whileBody(icg->getLabel()), whileExpressionStream(icg->get_iCode()) {}
inline ForCodeState::ForCodeState(ICodeGenerator *icg)
: ICodeState(For_state, icg), forCondition(icg->getLabel()),
forBody(icg->getLabel()), forConditionStream(icg->get_iCode()),
forIncrementStream(icg->get_iCode()) {}
} /* namespace IGC */

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

@ -99,15 +99,18 @@ static JSValue print(const JSValues &argv)
}
static void genCode(World &world, Context &cx, ExprNode *p)
static void genCode(World &world, Context &cx, StmtNode *p)
{
ICodeGenerator icg(&world);
icg.beginStatement(0);
Register ret = icg.genExpr(p);
icg.endStatement();
icg.returnStatement(ret);
Register ret = NotARegister;
while (p) {
ret = icg.genStmt(p);
p = p->next;
}
if (ret != NotARegister)
icg.addInstruction(new Return(ret));
else
icg.addInstruction(new ReturnVoid());
stdOut << '\n';
stdOut << icg;
JSValue result = cx.interpret(icg.complete(), JSValues());
@ -120,25 +123,6 @@ static void readEvalPrint(FILE *in, World &world)
Context cx(world, &glob);
StringAtom& printName = world.identifiers[widenCString("print")];
glob.defineNativeFunction(printName, print);
/*
hack an object a, with property p = 4.0 into the global scope
*/
{
ICodeGenerator icg;
// var global = new Object();
StringAtom& global = world.identifiers[widenCString("a")];
icg.beginStatement(0);
icg.saveName(global, icg.newObject());
// global.counter = 0;
StringAtom& prop = world.identifiers[widenCString("p")];
icg.beginStatement(0);
icg.setProperty(icg.loadName(global), prop, icg.loadImmediate(4.0));
icg.returnStatement();
cx.interpret(icg.complete(), JSValues());
}
String buffer;
string line;
@ -177,7 +161,7 @@ static void readEvalPrint(FILE *in, World &world)
stdOut << '\n';
#if 0
// Generate code for parsedStatements, which is a linked list of zero or more statements
genCode(world, cx, parseTree);
genCode(world, cx, parsedStatements);
#endif
}
clear(buffer);
@ -227,248 +211,60 @@ class Tracer : public Context::Listener {
}
};
static void testICG(World &world)
{
//
// testing ICG
//
uint32 pos = 0;
ICodeGenerator icg(&world, true, 1);
// var i,j;
// i is bound to var #0, j to var #1
Register r_i = icg.allocateVariable(world.identifiers[widenCString("i")]);
Register r_j = icg.allocateVariable(world.identifiers[widenCString("j")]);
Register r_x = icg.allocateVariable(world.identifiers[widenCString("x")]);
// i = j + 2;
icg.beginStatement(pos);
Register r1 = icg.loadImmediate(2.0);
icg.move(r_i, icg.op(ADD, r1, r_j));
// j = a.b
icg.beginStatement(pos);
r1 = icg.loadName(world.identifiers[widenCString("a")]);
r1 = icg.getProperty(r1, world.identifiers[widenCString("b")]);
icg.move(r_j, r1);
// label1 : while (i) { while (i) { i = i + j; break label1; } }
icg.beginLabelStatement(pos, world.identifiers[widenCString("label1")]);
icg.beginWhileStatement(pos);
icg.endWhileExpression(icg.test(r_i));
icg.beginWhileStatement(pos);
icg.endWhileExpression(icg.test(r_i));
icg.move(r_i, icg.op(ADD, r_i, r_j));
icg.breakStatement(pos, world.identifiers[widenCString("label1")]);
icg.endWhileStatement();
icg.endWhileStatement();
icg.endLabelStatement();
// if (i) if (j) i = 3; else j = 4;
icg.beginIfStatement(pos, icg.test(r_i));
icg.beginIfStatement(pos, icg.test(r_j));
icg.move(r_i, icg.loadImmediate(3));
icg.beginElseStatement(true);
icg.move(r_j, icg.loadImmediate(4));
icg.endIfStatement();
icg.beginElseStatement(false);
icg.endIfStatement();
// try {
// if (i) if (j) i = 3; else j = 4;
// throw j;
// }
// catch (x) {
// j = x;
// }
// finally {
// i = 5;
// }
icg.beginTryStatement(pos, true, true); // hasCatch, hasFinally
icg.beginIfStatement(pos, icg.test(r_i));
icg.beginIfStatement(pos, icg.test(r_j));
icg.move(r_i, icg.loadImmediate(3));
icg.beginElseStatement(true);
icg.beginStatement(pos);
icg.move(r_j, icg.loadImmediate(4));
icg.endIfStatement();
icg.beginElseStatement(false);
icg.endIfStatement();
icg.throwStatement(pos, r_j);
icg.endTryBlock();
icg.beginCatchStatement(pos);
icg.endCatchExpression(r_x);
icg.beginStatement(pos);
icg.move(r_j, r_x);
icg.endCatchStatement();
icg.beginFinallyStatement(pos);
icg.beginStatement(pos);
icg.move(r_i, icg.loadImmediate(5));
icg.endFinallyStatement();
icg.endTryStatement();
// switch (i) { case 3: case 4: j = 4; break; case 5: j = 5; break; default : j = 6; }
icg.beginSwitchStatement(pos, r_i);
// case 3, note empty case statement (?necessary???)
icg.endCaseCondition(icg.loadImmediate(3));
icg.beginCaseStatement(pos);
icg.endCaseStatement();
// case 4
icg.endCaseCondition(icg.loadImmediate(4));
icg.beginCaseStatement(pos);
icg.beginStatement(pos);
icg.move(r_j, icg.loadImmediate(4));
icg.breakStatement(pos);
icg.endCaseStatement();
// case 5
icg.endCaseCondition(icg.loadImmediate(5));
icg.beginCaseStatement(pos);
icg.beginStatement(pos);
icg.move(r_j, icg.loadImmediate(5));
icg.breakStatement(pos);
icg.endCaseStatement();
// default
icg.beginDefaultStatement(pos);
icg.beginStatement(pos);
icg.move(r_j, icg.loadImmediate(6));
icg.endDefaultStatement();
icg.endSwitchStatement();
// for ( ; i; i = i + 1 ) j = 99;
icg.beginForStatement(pos);
icg.forCondition(icg.test(r_i));
icg.move(r_i, icg.op(ADD, r_i, icg.loadImmediate(1)));
icg.forIncrement();
icg.move(r_j, icg.loadImmediate(99));
icg.endForStatement();
ICodeModule *icm = icg.complete();
stdOut << icg;
delete icm;
}
static float64 testFunctionCall(World &world, float64 n)
{
JSScope glob;
Context cx(world, &glob);
/*
Tracer t;
cx.addListener(&t);
*/
jsd.attachToContext(&cx);
uint32 position = 0;
//StringAtom& global = world.identifiers[widenCString("global")];
StringAtom& sum = world.identifiers[widenCString("sum")];
ICodeGenerator fun;
// function sum(n) { if (n > 1) return 1 + sum(n - 1); else return 1; }
// n is bound to var #0.
Register r_n =
fun.allocateVariable(world.identifiers[widenCString("n")]);
fun.beginStatement(position);
Register r1 = fun.op(COMPARE_LT, fun.loadImmediate(1.0), r_n);
fun.beginIfStatement(position, r1);
fun.beginStatement(position);
r1 = fun.op(SUBTRACT, r_n, fun.loadImmediate(1.0));
RegisterList args(1);
args[0] = r1;
r1 = fun.call(fun.loadName(sum), args);
fun.returnStatement(fun.op(ADD, fun.loadImmediate(1.0), r1));
fun.beginElseStatement(true);
fun.beginStatement(position);
fun.returnStatement(fun.loadImmediate(1.0));
fun.endIfStatement();
ICodeModule *funCode = fun.complete();
stdOut << fun;
// now a script :
// return sum(n);
ICodeGenerator script;
script.beginStatement(position);
r1 = script.loadName(sum);
RegisterList args_2(1);
args_2[0] = script.loadImmediate(n);
script.returnStatement(script.call(r1, args_2));
stdOut << script;
// preset the global property "sum" to contain the above function
glob.defineFunction(sum, funCode);
JSValue result = cx.interpret(script.complete(), JSValues());
stdOut << "sum(" << n << ") = " << result.f64 << "\n";
return result.f64;
}
static void testPrint(World &world)
{
JSScope glob;
Context cx(world, &glob);
uint32 position = 0;
StringAtom& printName = world.identifiers[widenCString("print")];
String text = widenCString("pi is ");
String piVal = widenCString("3.14159");
ICodeGenerator script;
script.beginStatement(position);
Register r1 = script.loadName(printName);
RegisterList args_2(1);
Register r2 = script.op(POSATE, script.loadString(piVal));
args_2[0] = script.op(ADD, script.loadString(text), r2);
script.returnStatement(script.call(r1, args_2));
stdOut << script;
glob.defineNativeFunction(printName, print);
JSValue result = cx.interpret(script.complete(), JSValues());
}
static float64 testFactorial(World &world, float64 n)
{
JSScope glob;
Context cx(world, &glob);
// generate code for factorial, and interpret it.
uint32 position = 0;
uint32 pos = 0;
ICodeGenerator icg;
// fact(n) {
// var result = 1;
Register r_n = icg.allocateVariable(world.identifiers[widenCString("n")]);
Register r_result = icg.allocateVariable(world.identifiers[widenCString("result")]);
icg.beginStatement(position);
icg.move(r_result, icg.loadImmediate(1.0));
StringAtom &n_name = world.identifiers[widenCString("n")];
StringAtom &result_name = world.identifiers[widenCString("result")];
Register r_n = icg.allocateVariable(n_name);
Register r_result = icg.allocateVariable(result_name);
Arena a;
ExprStmtNode *e = new(a) ExprStmtNode(pos, StmtNode::expression, new(a) BinaryExprNode(pos, ExprNode::assignment,
new(a) IdentifierExprNode(pos, ExprNode::identifier, result_name),
new(a) NumberExprNode(pos, 1.0) ) );
icg.genStmt(e);
// while (n > 1) {
// result = result * n;
// n = n - 1;
// }
{
icg.beginWhileStatement(position);
Register r1 = icg.loadImmediate(1.0);
Register r2 = icg.op(COMPARE_LT, r1, r_n);
icg.endWhileExpression(r2);
r2 = icg.op(MULTIPLY, r_result, r_n);
icg.move(r_result, r2);
icg.beginStatement(position);
r1 = icg.loadImmediate(1.0);
r2 = icg.op(SUBTRACT, r_n, r1);
icg.move(r_n, r2);
icg.endWhileStatement();
BinaryExprNode *c = new(a) BinaryExprNode(pos, ExprNode::greaterThan,
new(a) IdentifierExprNode(pos, ExprNode::identifier, n_name),
new(a) NumberExprNode(pos, 1.0) ) ;
ExprStmtNode *e1 = new(a) ExprStmtNode(pos, StmtNode::expression, new(a) BinaryExprNode(pos, ExprNode::assignment,
new(a) IdentifierExprNode(pos, ExprNode::identifier, result_name),
new(a) BinaryExprNode(pos, ExprNode::multiply,
new(a) IdentifierExprNode(pos, ExprNode::identifier, result_name),
new(a) IdentifierExprNode(pos, ExprNode::identifier, n_name) ) ) );
ExprStmtNode *e2 = new(a) ExprStmtNode(pos, StmtNode::expression, new(a) BinaryExprNode(pos, ExprNode::assignment,
new(a) IdentifierExprNode(pos, ExprNode::identifier, n_name),
new(a) BinaryExprNode(pos, ExprNode::subtract,
new(a) IdentifierExprNode(pos, ExprNode::identifier, n_name),
new(a) NumberExprNode(pos, 1.0) ) ) );
e1->next = e2;
BlockStmtNode *b = new(a) BlockStmtNode(pos, StmtNode::block, NULL, e1);
UnaryStmtNode *w = new(a) UnaryStmtNode(pos, StmtNode::While, c, b);
icg.genStmt(w);
}
// return result;
icg.returnStatement(r_result);
icg.addInstruction(new Return(r_result));
ICodeModule *icm = icg.complete();
stdOut << icg;
@ -479,10 +275,9 @@ static float64 testFactorial(World &world, float64 n)
// now a script :
// return fact(n);
ICodeGenerator script;
script.beginStatement(position);
RegisterList args(1);
args[0] = script.loadImmediate(n);
script.returnStatement(script.call(script.loadName(fact), args));
script.addInstruction(new Return(script.call(script.loadName(fact), args)));
stdOut << script;
// install a listener so we can trace execution of factorial.
@ -498,161 +293,6 @@ static float64 testFactorial(World &world, float64 n)
return result.f64;
}
static float64 testObjects(World &world, int32 n)
{
JSScope glob;
Context cx(world, &glob);
// create some objects, put some properties, and retrieve them.
uint32 position = 0;
ICodeGenerator initCG;
// var global = new Object();
StringAtom& global = world.identifiers[widenCString("global")];
initCG.beginStatement(position);
initCG.saveName(global, initCG.newObject());
// global.counter = 0;
StringAtom& counter = world.identifiers[widenCString("counter")];
initCG.beginStatement(position);
initCG.setProperty(initCG.loadName(global), counter, initCG.loadImmediate(0.0));
// var array = new Array();
StringAtom& array = world.identifiers[widenCString("array")];
initCG.beginStatement(position);
initCG.saveName(array, initCG.newArray());
initCG.returnStatement();
ICodeModule* initCode = initCG.complete();
stdOut << initCG;
// function increment()
// {
// var i = global.counter;
// array[i] = i;
// return ++global.counter;
// }
ICodeGenerator incrCG;
incrCG.beginStatement(position);
Register robject = incrCG.loadName(global);
Register roldvalue = incrCG.getProperty(robject, counter);
Register rarray = incrCG.loadName(array);
incrCG.setElement(rarray, roldvalue, roldvalue);
Register rvalue = incrCG.op(ADD, roldvalue, incrCG.loadImmediate(1.0));
incrCG.setProperty(robject, counter, rvalue);
incrCG.returnStatement(rvalue);
ICodeModule* incrCode = incrCG.complete();
stdOut << incrCG;
// run initialization code.
JSValues args;
cx.interpret(initCode, args);
// call the increment function some number of times.
JSValue result;
while (n-- > 0)
result = cx.interpret(incrCode, args);
stdOut << "result = " << result.f64 << "\n";
delete initCode;
delete incrCode;
return result.f64;
}
static float64 testProto(World &world, int32 n)
{
JSScope glob;
Context cx(world, &glob);
Tracer t;
cx.addListener(&t);
// create some objects, put some properties, and retrieve them.
uint32 position = 0;
ICodeGenerator initCG;
// var proto = new Object();
StringAtom& proto = world.identifiers[widenCString("proto")];
initCG.beginStatement(position);
initCG.saveName(proto, initCG.newObject());
// function increment()
// {
// this.counter = this.counter + 1;
// }
ICodeGenerator incrCG;
StringAtom& counter = world.identifiers[widenCString("counter")];
incrCG.beginStatement(position);
Register rthis = incrCG.allocateVariable(world.identifiers[widenCString("counter")]);
Register rcounter = incrCG.getProperty(rthis, counter);
incrCG.setProperty(rthis, counter, incrCG.op(ADD, rcounter, incrCG.loadImmediate(1.0)));
incrCG.returnStatement();
StringAtom& increment = world.identifiers[widenCString("increment")];
ICodeModule* incrCode = incrCG.complete();
glob.defineFunction(increment, incrCode);
// proto.increment = increment;
initCG.beginStatement(position);
initCG.setProperty(initCG.loadName(proto), increment, initCG.loadName(increment));
// var global = new Object();
StringAtom& global = world.identifiers[widenCString("global")];
initCG.beginStatement(position);
initCG.saveName(global, initCG.newObject());
// global.counter = 0;
initCG.beginStatement(position);
initCG.setProperty(initCG.loadName(global), counter, initCG.loadImmediate(0.0));
// global.proto = proto;
// initCG.beginStatement(position);
// initCG.setProperty(initCG.loadName(global), proto, initCG.loadName(proto));
initCG.returnStatement();
ICodeModule* initCode = initCG.complete();
stdOut << initCG;
// run initialization code.
JSValues args;
cx.interpret(initCode, args);
// objects now exist, do real prototype chain manipulation.
JSObject* globalObject = glob.getVariable(global).object;
globalObject->setPrototype(glob.getVariable(proto).object);
// generate call to global.increment()
ICodeGenerator callCG;
callCG.beginStatement(position);
RegisterList argList(1);
Register rglobal = argList[0] = callCG.loadName(global);
callCG.call(callCG.getProperty(rglobal, increment), argList);
callCG.returnStatement();
ICodeModule* callCode = callCG.complete();
// call the increment method some number of times.
while (n-- > 0)
(void) cx.interpret(callCode, args);
JSValue result = glob.getVariable(global).object->getProperty(counter);
stdOut << "result = " << result.f64 << "\n";
delete initCode;
delete incrCode;
delete callCode;
return result.f64;
}
} /* namespace Shell */
@ -668,11 +308,6 @@ int main(int argc, char **argv)
using namespace Shell;
#if 0
assert(testFactorial(world, 5) == 120);
assert(testObjects(world, 5) == 5);
assert(testProto(world, 5) == 5);
testICG(world);
// assert(testFunctionCall(world, 5) == 5);
testPrint(world);
#endif
readEvalPrint(stdin, world);
return 0;