From 2cd8ea4b80483cd3f778faeddfca2867be5634b4 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Wed, 24 May 2000 02:11:39 +0000 Subject: [PATCH] Codegen for statements. Blew off old statement API and most of the test functions for now, sorry. git-svn-id: svn://10.0.0.236/trunk@70700 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/js2/icodegenerator.cpp | 727 ++++++++-------------------- mozilla/js/js2/icodegenerator.h | 252 +--------- mozilla/js/js2/js2.cpp | 459 ++---------------- mozilla/js2/src/icodegenerator.cpp | 727 ++++++++-------------------- mozilla/js2/src/icodegenerator.h | 252 +--------- mozilla/js2/tests/cpp/js2_shell.cpp | 459 ++---------------- 6 files changed, 570 insertions(+), 2306 deletions(-) diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index 1bc02f30a74..a151b8dc6e7 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -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(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(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(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(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(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(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(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(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(stitcher.back()); - ASSERT(ics->stateKind == Switch_state); - // switch to Case Statement stream - iCode = ics->swapStream(iCode); -} - -void ICodeGenerator::endCaseStatement() -{ - SwitchCodeState *ics = - static_cast(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(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(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(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(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(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::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::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::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::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(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(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(stitcher.back()); - ASSERT(ics->stateKind == Try_state); - ASSERT(ics->catchHandler); - setLabel(ics->catchHandler); -} - -void ICodeGenerator::endCatchExpression(Register exceptionId) -{ - TryCodeState *ics = static_cast(stitcher.back()); - ASSERT(ics->stateKind == Try_state); - move(exceptionRegister, exceptionId); -} - -void ICodeGenerator::endCatchStatement() -{ - TryCodeState *ics = static_cast(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(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(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(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(p))->name); + Register v = findVariable((static_cast(p))->name); + if (v != NotARegister) + ret = v; + else + ret = loadName((static_cast(p))->name); } break; case ExprNode::number : @@ -1145,7 +654,11 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label BinaryExprNode *b = static_cast(p); ret = genExpr(b->op2); if (b->op1->getKind() == ExprNode::identifier) { - saveName((static_cast(b->op1))->name, ret); + Register v = findVariable((static_cast(b->op1))->name); + if (v != NotARegister) + move(v, ret); + else + saveName((static_cast(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(p); + ret = genExpr(e->expr); + } + break; + case StmtNode::If: + { + Label *falseLabel = getLabel(); + UnaryStmtNode *i = static_cast(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(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(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(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(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(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(p); + StmtNode *s = b->statements; + while (s) { + genStmt(s); + s = s->next; + } + } + break; + + case StmtNode::label: + { + LabelStmtNode *l = static_cast(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(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; +} + + /************************************************************************/ diff --git a/mozilla/js/js2/icodegenerator.h b/mozilla/js/js2/icodegenerator.h index b9d173cb26a..a0f95b2937e 100644 --- a/mozilla/js/js2/icodegenerator.h +++ b/mozilla/js/js2/icodegenerator.h @@ -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 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 > VariableList; @@ -104,6 +75,22 @@ namespace ICG { }; + typedef std::vector 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 LabelStack; + Formatter& operator<<(Formatter &f, ICodeModule &i); /****************************************************************/ @@ -118,8 +105,6 @@ namespace ICG { InstructionStream *iCode; bool iCodeOwner; LabelList labels; - std::vector 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 */ diff --git a/mozilla/js/js2/js2.cpp b/mozilla/js/js2/js2.cpp index 1a40cc34c43..0edf07f5e3c 100644 --- a/mozilla/js/js2/js2.cpp +++ b/mozilla/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; diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index 1bc02f30a74..a151b8dc6e7 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -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(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(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(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(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(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(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(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(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(stitcher.back()); - ASSERT(ics->stateKind == Switch_state); - // switch to Case Statement stream - iCode = ics->swapStream(iCode); -} - -void ICodeGenerator::endCaseStatement() -{ - SwitchCodeState *ics = - static_cast(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(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(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(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(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(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::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::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::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::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(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(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(stitcher.back()); - ASSERT(ics->stateKind == Try_state); - ASSERT(ics->catchHandler); - setLabel(ics->catchHandler); -} - -void ICodeGenerator::endCatchExpression(Register exceptionId) -{ - TryCodeState *ics = static_cast(stitcher.back()); - ASSERT(ics->stateKind == Try_state); - move(exceptionRegister, exceptionId); -} - -void ICodeGenerator::endCatchStatement() -{ - TryCodeState *ics = static_cast(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(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(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(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(p))->name); + Register v = findVariable((static_cast(p))->name); + if (v != NotARegister) + ret = v; + else + ret = loadName((static_cast(p))->name); } break; case ExprNode::number : @@ -1145,7 +654,11 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label BinaryExprNode *b = static_cast(p); ret = genExpr(b->op2); if (b->op1->getKind() == ExprNode::identifier) { - saveName((static_cast(b->op1))->name, ret); + Register v = findVariable((static_cast(b->op1))->name); + if (v != NotARegister) + move(v, ret); + else + saveName((static_cast(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(p); + ret = genExpr(e->expr); + } + break; + case StmtNode::If: + { + Label *falseLabel = getLabel(); + UnaryStmtNode *i = static_cast(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(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(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(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(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(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(p); + StmtNode *s = b->statements; + while (s) { + genStmt(s); + s = s->next; + } + } + break; + + case StmtNode::label: + { + LabelStmtNode *l = static_cast(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(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; +} + + /************************************************************************/ diff --git a/mozilla/js2/src/icodegenerator.h b/mozilla/js2/src/icodegenerator.h index b9d173cb26a..a0f95b2937e 100644 --- a/mozilla/js2/src/icodegenerator.h +++ b/mozilla/js2/src/icodegenerator.h @@ -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 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 > VariableList; @@ -104,6 +75,22 @@ namespace ICG { }; + typedef std::vector 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 LabelStack; + Formatter& operator<<(Formatter &f, ICodeModule &i); /****************************************************************/ @@ -118,8 +105,6 @@ namespace ICG { InstructionStream *iCode; bool iCodeOwner; LabelList labels; - std::vector 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 */ diff --git a/mozilla/js2/tests/cpp/js2_shell.cpp b/mozilla/js2/tests/cpp/js2_shell.cpp index 1a40cc34c43..0edf07f5e3c 100644 --- a/mozilla/js2/tests/cpp/js2_shell.cpp +++ b/mozilla/js2/tests/cpp/js2_shell.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;