зеркало из https://github.com/mozilla/pjs.git
Codegen for statements. Blew off old statement API and most of the test
functions for now, sorry.
This commit is contained in:
Родитель
9044170ca3
Коммит
bbd7ed8e62
|
@ -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 */
|
||||
|
|
459
js/js2/js2.cpp
459
js/js2/js2.cpp
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче