diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index 5ac31695ad5..6c62be54050 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -1,35 +1,35 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * The contents of this file are subject to the Netscape Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the JavaScript 2 Prototype. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License (the "GPL"), in which case the - * provisions of the GPL are applicable instead of those above. - * If you wish to allow use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the NPL, indicate your decision by - * deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete - * the provisions above, a recipient may use your version of this - * file under either the NPL or the GPL. - */ +* +* The contents of this file are subject to the Netscape Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/NPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is the JavaScript 2 Prototype. +* +* The Initial Developer of the Original Code is Netscape +* Communications Corporation. Portions created by Netscape are +* Copyright (C) 1998 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License (the "GPL"), in which case the +* provisions of the GPL are applicable instead of those above. +* If you wish to allow use of your version of this file only +* under the terms of the GPL and not to allow others to use your +* version of this file under the NPL, indicate your decision by +* deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the NPL or the GPL. +*/ #include "numerics.h" #include "world.h" @@ -42,819 +42,1243 @@ namespace JavaScript { namespace ICG { - using namespace VM; +using namespace VM; +using namespace JSTypes; - uint32 ICodeModule::sMaxID = 0; - - Formatter& operator<<(Formatter &f, ICodeGenerator &i) - { - return i.print(f); - } - - Formatter& operator<<(Formatter &f, ICodeModule &i) - { - return i.print(f); - } - - // - // ICodeGenerator - // - - ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting) - : topRegister(0), - registerBase(0), - maxRegister(0), - parameterCount(0), - exceptionRegister(NotARegister), - switchRegister(NotARegister), - variableList(new VariableList()) - { - iCode = new InstructionStream(); - iCodeOwner = true; - if (hasTryStatement) - exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]); - for (uint i = 0; i < switchStatementNesting; i++) { - String s = widenCString("__switchControlVariable__"); - char num[8]; - sprintf(num, "%.2d", i); - appendChars(s, num, strlen(num)); - if (switchRegister == NotARegister) - switchRegister = allocateVariable(world->identifiers[s]); - else - allocateVariable(world->identifiers[s]); - } - labelSet = new StatementLabels(); +uint32 ICodeModule::sMaxID = 0; + +Formatter& operator<<(Formatter &f, ICodeGenerator &i) +{ + return i.print(f); +} + +Formatter& operator<<(Formatter &f, ICodeModule &i) +{ + return i.print(f); +} + +// +// ICodeGenerator +// + +ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting) + : topRegister(0), + registerBase(0), + maxRegister(0), + parameterCount(0), + exceptionRegister(NotARegister), + switchRegister(NotARegister), + variableList(new VariableList()), + mWorld(world) +{ + iCode = new InstructionStream(); + iCodeOwner = true; + if (hasTryStatement) + exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]); + for (uint i = 0; i < switchStatementNesting; i++) { + String s = widenCString("__switchControlVariable__"); + char num[8]; + sprintf(num, "%.2d", i); + appendChars(s, num, strlen(num)); + if (switchRegister == NotARegister) + switchRegister = allocateVariable(world->identifiers[s]); + else + allocateVariable(world->identifiers[s]); } + labelSet = new StatementLabels(); +} - ICodeModule *ICodeGenerator::complete() - { - ASSERT(stitcher.empty()); - //ASSERT(labelSet == NULL); +ICodeModule *ICodeGenerator::complete() +{ + ASSERT(stitcher.empty()); + //ASSERT(labelSet == NULL); #ifdef DEBUG - for (LabelList::iterator i = labels.begin(); - i != labels.end(); i++) { - ASSERT((*i)->mBase == iCode); - ASSERT((*i)->mOffset <= iCode->size()); - } + for (LabelList::iterator i = labels.begin(); + i != labels.end(); i++) { + ASSERT((*i)->mBase == iCode); + ASSERT((*i)->mOffset <= iCode->size()); + } #endif - /* - for (InstructionIterator ii = iCode->begin(); - ii != iCode->end(); ii++) { - if ((*ii)->op() == BRANCH) { + /* + for (InstructionIterator ii = iCode->begin(); + ii != iCode->end(); ii++) { + if ((*ii)->op() == BRANCH) { + Instruction *t = *ii; + *ii = new ResolvedBranch(static_cast(*ii)->operand1->itsOffset); + delete t; + } + else + if ((*ii)->itsOp >= BRANCH_LT && (*ii)->itsOp <= BRANCH_GT) { Instruction *t = *ii; - *ii = new ResolvedBranch(static_cast(*ii)->operand1->itsOffset); + *ii = new ResolvedBranchCond((*ii)->itsOp, + static_cast(*ii)->itsOperand1->itsOffset, + static_cast(*ii)->itsOperand2); delete t; } - else - if ((*ii)->itsOp >= BRANCH_LT && (*ii)->itsOp <= BRANCH_GT) { - Instruction *t = *ii; - *ii = new ResolvedBranchCond((*ii)->itsOp, - static_cast(*ii)->itsOperand1->itsOffset, - static_cast(*ii)->itsOperand2); - delete t; - } - } - */ - markMaxRegister(); - ICodeModule* module = new ICodeModule(iCode, variableList, maxRegister, 0); - iCodeOwner = false; // give ownership to the module. - return module; } + */ + markMaxRegister(); + ICodeModule* module = new ICodeModule(iCode, variableList, maxRegister, 0); + iCodeOwner = false; // give ownership to the module. + 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(); + } +} + + +/********************************************************************/ + +Register ICodeGenerator::loadImmediate(double value) +{ + Register dest = getRegister(); + LoadImmediate *instr = new LoadImmediate(dest, value); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::loadString(String &value) +{ + Register dest = getRegister(); + LoadString *instr = new LoadString(dest, new JSString(value)); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::loadValue(JSValue value) +{ + Register dest = getRegister(); + LoadValue *instr = new LoadValue(dest, value); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::newObject() +{ + Register dest = getRegister(); + NewObject *instr = new NewObject(dest); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::newArray() +{ + Register dest = getRegister(); + NewArray *instr = new NewArray(dest); + iCode->push_back(instr); + return dest; +} + + + +Register ICodeGenerator::loadName(const StringAtom &name) +{ + Register dest = getRegister(); + LoadName *instr = new LoadName(dest, &name); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::saveName(const StringAtom &name, Register value) +{ + SaveName *instr = new SaveName(&name, value); + iCode->push_back(instr); +} + +Register ICodeGenerator::nameInc(const StringAtom &name) +{ + Register dest = getRegister(); + NameXcr *instr = new NameXcr(dest, &name, 1.0); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::nameDec(const StringAtom &name) +{ + Register dest = getRegister(); + NameXcr *instr = new NameXcr(dest, &name, -1.0); + iCode->push_back(instr); + return dest; +} + + + +Register ICodeGenerator::getProperty(Register base, const StringAtom &name) +{ + Register dest = getRegister(); + GetProp *instr = new GetProp(dest, base, &name); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::setProperty(Register base, const StringAtom &name, + Register value) +{ + SetProp *instr = new SetProp(base, &name, value); + iCode->push_back(instr); +} + +Register ICodeGenerator::propertyInc(Register base, const StringAtom &name) +{ + Register dest = getRegister(); + PropXcr *instr = new PropXcr(dest, base, &name, 1.0); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::propertyDec(Register base, const StringAtom &name) +{ + Register dest = getRegister(); + PropXcr *instr = new PropXcr(dest, base, &name, -1.0); + iCode->push_back(instr); + return dest; +} + + + +Register ICodeGenerator::getElement(Register base, Register index) +{ + Register dest = getRegister(); + GetElement *instr = new GetElement(dest, base, index); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::setElement(Register base, Register index, + Register value) +{ + SetElement *instr = new SetElement(base, index, value); + iCode->push_back(instr); +} + +Register ICodeGenerator::elementInc(Register base, Register index) +{ + Register dest = getRegister(); + ElemXcr *instr = new ElemXcr(dest, base, index, 1.0); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::elementDec(Register base, Register index) +{ + Register dest = getRegister(); + ElemXcr *instr = new ElemXcr(dest, base, index, -1.0); + iCode->push_back(instr); + return dest; +} + + +Register ICodeGenerator::op(ICodeOp op, Register source) +{ + Register dest = getRegister(); + ASSERT(source != NotARegister); + Compare *instr = new Compare (op, dest, source); + iCode->push_back(instr); + return dest; +} - 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(); - } - } +void ICodeGenerator::move(Register destination, Register source) +{ + ASSERT(destination != NotARegister); + ASSERT(source != NotARegister); + Move *instr = new Move(destination, source); + iCode->push_back(instr); +} +void ICodeGenerator::complement(Register destination, Register source) +{ + Not *instr = new Not(destination, source); + iCode->push_back(instr); +} - /********************************************************************/ +Register ICodeGenerator::test(Register source) +{ + Register dest = getRegister(); + Test *instr = new Test(dest, source); + iCode->push_back(instr); + return dest; +} - Register ICodeGenerator::loadImmediate(double value) - { - Register dest = getRegister(); - LoadImmediate *instr = new LoadImmediate(dest, value); - iCode->push_back(instr); - return dest; - } - - Register ICodeGenerator::loadString(String &value) - { - Register dest = getRegister(); - LoadString *instr = new LoadString(dest, new JSString(value)); - iCode->push_back(instr); - return dest; - } - - Register ICodeGenerator::newObject() - { - Register dest = getRegister(); - NewObject *instr = new NewObject(dest); - iCode->push_back(instr); - return dest; - } - - Register ICodeGenerator::newArray() - { - Register dest = getRegister(); - NewArray *instr = new NewArray(dest); - iCode->push_back(instr); - return dest; - } - - - - Register ICodeGenerator::loadName(const StringAtom &name) - { - Register dest = getRegister(); - LoadName *instr = new LoadName(dest, &name); - iCode->push_back(instr); - return dest; - } +Register ICodeGenerator::op(ICodeOp op, Register source1, + Register source2) +{ + ASSERT(source1 != NotARegister); + ASSERT(source2 != NotARegister); + Register dest = getRegister(); + Arithmetic *instr = new Arithmetic(op, dest, source1, source2); + iCode->push_back(instr); + return dest; +} - void ICodeGenerator::saveName(const StringAtom &name, Register value) - { - SaveName *instr = new SaveName(&name, value); - iCode->push_back(instr); +Register ICodeGenerator::call(Register target, RegisterList args) +{ + Register dest = getRegister(); + Call *instr = new Call(dest, target, args); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::callVoid(Register target, RegisterList args) +{ + Call *instr = new Call(NotARegister, target, args); + iCode->push_back(instr); +} + +void ICodeGenerator::branch(Label *label) +{ + Branch *instr = new Branch(label); + iCode->push_back(instr); +} + +void ICodeGenerator::branchConditional(Label *label, Register condition) +{ + ICodeOp branchOp = getBranchOp(); + ASSERT(branchOp != NOP); + GenericBranch *instr = new GenericBranch(branchOp, label, condition); + iCode->push_back(instr); +} + +void ICodeGenerator::branchTrue(Label *label, Register condition) +{ + GenericBranch *instr = new GenericBranch(BRANCH_TRUE, label, condition); + iCode->push_back(instr); +} + +void ICodeGenerator::branchFalse(Label *label, Register condition) +{ + GenericBranch *instr = new GenericBranch(BRANCH_FALSE, label, condition); + iCode->push_back(instr); +} + +void ICodeGenerator::branchNotConditional(Label *label, Register condition) +{ + ICodeOp branchOp = getBranchOp(); + ASSERT(branchOp != NOP); + switch (branchOp) { + case BRANCH_FALSE : branchOp = BRANCH_TRUE; break; + case BRANCH_TRUE : branchOp = BRANCH_FALSE; break; + case BRANCH_EQ : branchOp = BRANCH_NE; break; + case BRANCH_GE : branchOp = BRANCH_LT; break; + case BRANCH_GT : branchOp = BRANCH_LE; break; + case BRANCH_LE : branchOp = BRANCH_GT; break; + case BRANCH_LT : branchOp = BRANCH_GE; break; + case BRANCH_NE : branchOp = BRANCH_EQ; break; + default : NOT_REACHED("Expected a branch op"); break; + } + GenericBranch *instr = new GenericBranch(branchOp, label, condition); + iCode->push_back(instr); +} + +/********************************************************************/ + +Label *ICodeGenerator::getLabel() +{ + labels.push_back(new Label(NULL)); + return labels.back(); +} + +void ICodeGenerator::setLabel(Label *l) +{ + l->mBase = iCode; + 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(); + } } - Register ICodeGenerator::nameInc(const StringAtom &name) - { - Register dest = getRegister(); - NameXcr *instr = new NameXcr(dest, &name, 1.0); - iCode->push_back(instr); - return dest; + 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); - Register ICodeGenerator::nameDec(const StringAtom &name) - { - Register dest = getRegister(); - NameXcr *instr = new NameXcr(dest, &name, -1.0); - iCode->push_back(instr); - return dest; + // 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; - - Register ICodeGenerator::getProperty(Register base, const StringAtom &name) - { - Register dest = getRegister(); - GetProp *instr = new GetProp(dest, base, &name); - iCode->push_back(instr); - return dest; + 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 } - void ICodeGenerator::setProperty(Register base, const StringAtom &name, - Register value) - { - SetProp *instr = new SetProp(base, &name, value); - iCode->push_back(instr); - } + delete ics; + resetStatement(); +} - Register ICodeGenerator::propertyInc(Register base, const StringAtom &name) - { - Register dest = getRegister(); - PropXcr *instr = new PropXcr(dest, base, &name, 1.0); - iCode->push_back(instr); - return dest; - } +/************************************************************************/ - Register ICodeGenerator::propertyDec(Register base, const StringAtom &name) - { - Register dest = getRegister(); - PropXcr *instr = new PropXcr(dest, base, &name, -1.0); - iCode->push_back(instr); - return dest; - } - - - - Register ICodeGenerator::getElement(Register base, Register index) - { - Register dest = getRegister(); - GetElement *instr = new GetElement(dest, base, index); - iCode->push_back(instr); - return dest; - } - - void ICodeGenerator::setElement(Register base, Register index, - Register value) - { - SetElement *instr = new SetElement(base, index, value); - iCode->push_back(instr); - } - - Register ICodeGenerator::op(ICodeOp op, Register source) - { - Register dest = getRegister(); - ASSERT(source != NotARegister); - Compare *instr = new Compare (op, dest, source); - iCode->push_back(instr); - return dest; - } - - void ICodeGenerator::move(Register destination, Register source) - { - ASSERT(destination != NotARegister); - ASSERT(source != NotARegister); - Move *instr = new Move(destination, source); - iCode->push_back(instr); - } - - void ICodeGenerator::complement(Register destination, Register source) - { - Not *instr = new Not(destination, source); - iCode->push_back(instr); - } - - Register ICodeGenerator::op(ICodeOp op, Register source1, - Register source2) - { - ASSERT(source1 != NotARegister); - ASSERT(source2 != NotARegister); - Register dest = getRegister(); - Arithmetic *instr = new Arithmetic(op, dest, source1, source2); - iCode->push_back(instr); - return dest; - } - - Register ICodeGenerator::call(Register target, RegisterList args) - { - Register dest = getRegister(); - Call *instr = new Call(dest, target, args); - iCode->push_back(instr); - return dest; - } - - void ICodeGenerator::callVoid(Register target, RegisterList args) - { - Call *instr = new Call(NotARegister, target, args); - iCode->push_back(instr); - } - - void ICodeGenerator::branch(Label *label) - { - Branch *instr = new Branch(label); - iCode->push_back(instr); - } - - void ICodeGenerator::branchConditional(Label *label, Register condition) - { - ICodeOp branchOp = getBranchOp(); - if (branchOp == NOP) { - // XXXX emit convert to boolean / Test / ... - branchOp = BRANCH_NE; +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; } - GenericBranch *instr = new GenericBranch(branchOp, label, condition); - iCode->push_back(instr); - } - - void ICodeGenerator::branchNotConditional(Label *label, Register condition) - { - ICodeOp branchOp = getBranchOp(); - if (branchOp == NOP) { - // XXXX emit convert to boolean / Test / ... - branchOp = BRANCH_NE; + if (((*p)->stateKind == While_state) + || ((*p)->stateKind == Do_state) + || ((*p)->stateKind == For_state) + || ((*p)->stateKind == Switch_state)) { + (*p)->breakLabel = getLabel(); + branch((*p)->breakLabel); + return; } - switch (branchOp) { - case BRANCH_EQ : branchOp = BRANCH_NE; break; - case BRANCH_GE : branchOp = BRANCH_LT; break; - case BRANCH_GT : branchOp = BRANCH_LE; break; - case BRANCH_LE : branchOp = BRANCH_GT; break; - case BRANCH_LT : branchOp = BRANCH_GE; break; - case BRANCH_NE : branchOp = BRANCH_EQ; break; - default : NOT_REACHED("Expected a branch op"); break; - } - GenericBranch *instr = new GenericBranch(branchOp, label, condition); - iCode->push_back(instr); } - - /********************************************************************/ - - Label *ICodeGenerator::getLabel() - { - labels.push_back(new Label(NULL)); - return labels.back(); - } - - void ICodeGenerator::setLabel(Label *l) - { - l->mBase = iCode; - 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::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"); } + 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; - } +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; } - NOT_REACHED("no continue target available"); - } + 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; - } +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"); } - /********************************************************************/ + 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::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); +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); - } + 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::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::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); +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::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); +void ICodeGenerator::endFinallyStatement() +{ + TryCodeState *ics = static_cast(stitcher.back()); + ASSERT(ics->stateKind == Try_state); + rts(); +} + +/************************************************************************/ + + + + +ICodeOp ICodeGenerator::mapExprNodeToICodeOp(ExprNode::Kind kind) +{ + // can be an array later, when everything has settled down + switch (kind) { + // binary + case ExprNode::add: + return ADD; + case ExprNode::subtract: + return SUBTRACT; + case ExprNode::multiply: + return MULTIPLY; + case ExprNode::divide: + return DIVIDE; + case ExprNode::modulo: + return REMAINDER; + case ExprNode::leftShift: + return SHIFTLEFT; + case ExprNode::rightShift: + return SHIFTRIGHT; + case ExprNode::logicalRightShift: + return USHIFTRIGHT; + case ExprNode::bitwiseAnd: + return AND; + case ExprNode::bitwiseXor: + return XOR; + case ExprNode::bitwiseOr: + return OR; + // unary + case ExprNode::plus: + return POSATE; + case ExprNode::minus: + return NEGATE; + case ExprNode::complement: + return NOT; + + // relational + case ExprNode::equal: + return COMPARE_EQ; + case ExprNode::notEqual: + return COMPARE_NE; + case ExprNode::lessThan: + return COMPARE_LT; + case ExprNode::lessThanOrEqual: + return COMPARE_LE; + case ExprNode::greaterThan: + return COMPARE_GT; + case ExprNode::greaterThanOrEqual: + return COMPARE_GE; + case ExprNode::identical: + return STRICT_EQ; + case ExprNode::notIdentical: + return STRICT_NE; + case ExprNode::In: + return COMPARE_IN; + case ExprNode::Instanceof: + return INSTANCEOF; + + + default: + NOT_REACHED("Unimplemented kind"); + return NOP; + } +} + + +static bool generatedBoolean(ExprNode *p) +{ + switch (p->getKind()) { + case ExprNode::parentheses: + { + UnaryExprNode *u = static_cast(p); + return generatedBoolean(u->op); } - setLabel(ics->finallyHandler); + case ExprNode::True: + case ExprNode::False: + case ExprNode::equal: + case ExprNode::notEqual: + case ExprNode::lessThan: + case ExprNode::lessThanOrEqual: + case ExprNode::greaterThan: + case ExprNode::greaterThanOrEqual: + case ExprNode::identical: + case ExprNode::notIdentical: + case ExprNode::In: + case ExprNode::Instanceof: + case ExprNode::logicalAnd: + case ExprNode::logicalXor: + case ExprNode::logicalOr: + return true; } + return false; +} - void ICodeGenerator::endFinallyStatement() - { - TryCodeState *ics = static_cast(stitcher.back()); - ASSERT(ics->stateKind == Try_state); - rts(); + +/* + if trueBranch OR falseBranch are not null, the sub-expression should generate + a conditional branch do the appropriate target. If either branch is NULL, it + indicates that the label is immediately forthcoming. +*/ +Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label *trueBranch, Label *falseBranch) +{ + Register ret = NotARegister; + switch (p->getKind()) { + case ExprNode::True: + if (trueBranch || falseBranch) { + if (needBoolValueInBranch) + ret = loadValue(kTrue); + if (trueBranch) + branch(trueBranch); + } + else + ret = loadValue(kTrue); + break; + case ExprNode::False: + if (trueBranch || falseBranch) { + if (needBoolValueInBranch) + ret = loadValue(kFalse); + if (falseBranch) + branch(falseBranch); + } + else + ret = loadValue(kFalse); + break; + case ExprNode::parentheses: + { + UnaryExprNode *u = static_cast(p); + ret = genExpr(u->op, needBoolValueInBranch, trueBranch, falseBranch); + } + break; + case ExprNode::call : + { + InvokeExprNode *i = static_cast(p); + Register fn = genExpr(i->op); + RegisterList args; + ExprPairList *p = i->pairs; + while (p) { + args.push_back(genExpr(p->value)); + p = p->next; + } + ret = call(fn, args); + } + break; + case ExprNode::index : + { + BinaryExprNode *b = static_cast(p); + Register base = genExpr(b->op1); + Register index = genExpr(b->op2); + ret = getElement(base, index); + } + break; + case ExprNode::dot : + { + BinaryExprNode *b = static_cast(p); + Register base = genExpr(b->op1); + ret = getProperty(base, static_cast(b->op2)->name); + } + break; + case ExprNode::identifier : + { + /* + variable or name? If there's a 'with' in this scope, then it's + a name, otherwise look it up in the function variable map. + */ + + ret = loadName((static_cast(p))->name); + } + break; + case ExprNode::number : + ret = loadImmediate((static_cast(p))->value); + break; + case ExprNode::string : + ret = loadString(mWorld->identifiers[(static_cast(p))->str]); + break; + case ExprNode::postIncrement: + { + UnaryExprNode *u = static_cast(p); + if (u->op->getKind() == ExprNode::dot) { + BinaryExprNode *b = static_cast(u->op); + Register base = genExpr(b->op1); + ret = propertyInc(base, static_cast(b->op2)->name); + } + else + if (u->op->getKind() == ExprNode::identifier) { + // variable or name? see above + ret = nameInc((static_cast(u->op))->name); + } + else + if (u->op->getKind() == ExprNode::index) { + BinaryExprNode *b = static_cast(u->op); + Register base = genExpr(b->op1); + Register index = genExpr(b->op2); + ret = elementInc(base, index); + } + } + break; + case ExprNode::postDecrement: + { + UnaryExprNode *u = static_cast(p); + if (u->op->getKind() == ExprNode::dot) { + BinaryExprNode *b = static_cast(u->op); + Register base = genExpr(b->op1); + ret = propertyDec(base, static_cast(b->op2)->name); + } + else + if (u->op->getKind() == ExprNode::identifier) { + // variable or name? see above + ret = nameDec((static_cast(u->op))->name); + } + else + if (u->op->getKind() == ExprNode::index) { + BinaryExprNode *b = static_cast(u->op); + Register base = genExpr(b->op1); + Register index = genExpr(b->op2); + ret = elementInc(base, index); + } + } + break; + case ExprNode::plus: + case ExprNode::minus: + case ExprNode::complement: + { + UnaryExprNode *u = static_cast(p); + Register r = genExpr(u->op); + ret = op(mapExprNodeToICodeOp(p->getKind()), r); + } + break; + case ExprNode::add: + case ExprNode::subtract: + case ExprNode::multiply: + case ExprNode::divide: + case ExprNode::modulo: + case ExprNode::leftShift: + case ExprNode::rightShift: + case ExprNode::logicalRightShift: + case ExprNode::bitwiseAnd: + case ExprNode::bitwiseXor: + case ExprNode::bitwiseOr: + { + BinaryExprNode *b = static_cast(p); + Register r1 = genExpr(b->op1); + Register r2 = genExpr(b->op2); + ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2); + } + break; + case ExprNode::assignment: + { + BinaryExprNode *b = static_cast(p); + ret = genExpr(b->op2); + if (b->op1->getKind() == ExprNode::identifier) { + saveName((static_cast(b->op1))->name, ret); + } + else + if (b->op1->getKind() == ExprNode::dot) { + BinaryExprNode *lb = static_cast(b->op1); + Register base = genExpr(lb->op1); + setProperty(base, static_cast(lb->op2)->name, ret); + } + else + if (b->op1->getKind() == ExprNode::index) { + BinaryExprNode *lb = static_cast(b->op1); + Register base = genExpr(lb->op1); + Register index = genExpr(lb->op2); + setElement(base, index, ret); + } + } + break; + case ExprNode::equal: + case ExprNode::notEqual: + case ExprNode::lessThan: + case ExprNode::lessThanOrEqual: + case ExprNode::greaterThan: + case ExprNode::greaterThanOrEqual: + case ExprNode::identical: + case ExprNode::notIdentical: + case ExprNode::In: + case ExprNode::Instanceof: + { + BinaryExprNode *b = static_cast(p); + Register r1 = genExpr(b->op1); + Register r2 = genExpr(b->op2); + ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2); + if (trueBranch || falseBranch) { + if (trueBranch == NULL) + branchNotConditional(falseBranch, ret); + else { + branchConditional(trueBranch, ret); + if (falseBranch) + branch(falseBranch); + } + } + } + break; + case ExprNode::logicalAnd: + { + BinaryExprNode *b = static_cast(p); + if (trueBranch || falseBranch) { + genExpr(b->op1, needBoolValueInBranch, NULL, falseBranch); + genExpr(b->op2, needBoolValueInBranch, trueBranch, falseBranch); + } + else { + Label *fBranch = getLabel(); + Register r1 = genExpr(b->op1, true, NULL, fBranch); + if (!generatedBoolean(b->op1)) { + r1 = test(r1); + branchFalse(fBranch, r1); + } + Register r2 = genExpr(b->op2); + if (!generatedBoolean(b->op2)) { + r2 = test(r2); + } + if (r1 != r2) // FIXME, need a way to specify a dest??? + move(r1, r2); + setLabel(fBranch); + ret = r1; + } + } + break; + case ExprNode::logicalOr: + { + BinaryExprNode *b = static_cast(p); + if (trueBranch || falseBranch) { + genExpr(b->op1, needBoolValueInBranch, trueBranch, NULL); + genExpr(b->op2, needBoolValueInBranch, trueBranch, falseBranch); + } + else { + Label *tBranch = getLabel(); + Register r1 = genExpr(b->op1, true, tBranch, NULL); + if (!generatedBoolean(b->op1)) { + r1 = test(r1); + branchTrue(tBranch, r1); + } + Register r2 = genExpr(b->op2); + if (!generatedBoolean(b->op2)) { + r2 = test(r2); + } + if (r1 != r2) // FIXME, need a way to specify a dest??? + move(r1, r2); + setLabel(tBranch); + ret = r1; + } + } + break; + + case ExprNode::conditional: + { + TernaryExprNode *t = static_cast(p); + Label *fBranch = getLabel(); + Label *beyondBranch = getLabel(); + Register c = genExpr(t->op1, false, NULL, fBranch); + if (!generatedBoolean(t->op1)) { + c = test(c); + branchNotConditional(fBranch, c); + } + Register r1 = genExpr(t->op2); + branch(beyondBranch); + setLabel(fBranch); + Register r2 = genExpr(t->op3); + if (r1 != r2) // FIXME, need a way to specify a dest??? + move(r1, r2); + setLabel(beyondBranch); + ret = r1; + } + break; } + return ret; +} - /************************************************************************/ +/* + pre-pass to find: + variable & function definitions, + #nested switch statements + contains 'with' or 'eval' + contains 'try {} catch {} finally {}' +*/ - Formatter& ICodeGenerator::print(Formatter& f) - { - f << "ICG! " << (uint32)iCode->size() << "\n"; // << *iCode; - return VM::operator<<(f, *iCode); - } +/************************************************************************/ - Formatter& ICodeModule::print(Formatter& f) - { - f << "ICM! " << (uint32)its_iCode->size() << "\n"; - return VM::operator<<(f, *its_iCode); - } - -} // namespace ICG +Formatter& ICodeGenerator::print(Formatter& f) +{ + f << "ICG! " << (uint32)iCode->size() << "\n"; // << *iCode; + return VM::operator<<(f, *iCode); +} + +Formatter& ICodeModule::print(Formatter& f) +{ + f << "ICM! " << (uint32)its_iCode->size() << "\n"; + return VM::operator<<(f, *its_iCode); +} + +} // namespace ICG + } // namespace JavaScript diff --git a/mozilla/js/js2/icodegenerator.h b/mozilla/js/js2/icodegenerator.h index e6c4735b321..0d7ba55b2e1 100644 --- a/mozilla/js/js2/icodegenerator.h +++ b/mozilla/js/js2/icodegenerator.h @@ -131,6 +131,8 @@ namespace ICG { Register switchRegister; // register containing switch control value for most // recently in progress switch statement. VariableList *variableList; // name|register pair for each variable + + World *mWorld; // used to register strings @@ -158,6 +160,8 @@ namespace ICG { void branch(Label *label); void branchConditional(Label *label, Register condition); void branchNotConditional(Label *label, Register condition); + void branchTrue(Label *label, Register condition); + void branchFalse(Label *label, Register condition); void beginTry(Label *catchLabel, Label *finallyLabel) { iCode->push_back(new Tryin(catchLabel, finallyLabel)); } @@ -167,6 +171,8 @@ namespace ICG { void resetStatement() { if (labelSet) { delete labelSet; labelSet = NULL; } resetTopRegister(); } + ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind); + public: ICodeGenerator(World *world = NULL, bool hasTryStatement = false, @@ -182,14 +188,18 @@ namespace ICG { ICodeModule *complete(); + Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch = false, + Label *trueBranch = NULL, + Label *falseBranch = NULL); + + Register allocateVariable(const StringAtom& name) { Register result = getRegister(); (*variableList)[name] = result; registerBase = topRegister; return result; } Register findVariable(const StringAtom& name) { VariableList::iterator i = variableList->find(name); - // What's map? // ASSERT(i != map.end()); - return (*i).second; } + ASSERT(i != variableList->end()); return (*i).second; } Register allocateParameter(const StringAtom& name) { parameterCount++; return allocateVariable(name); } @@ -203,9 +213,11 @@ namespace ICG { void move(Register destination, Register source); void complement(Register destination, 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); @@ -224,7 +236,9 @@ namespace ICG { Register getElement(Register base, Register index); void setElement(Register base, Register index, Register value); - + Register elementInc(Register base, Register index); + Register elementDec(Register base, Register index); + Register getRegisterBase() { return topRegister; } InstructionStream *get_iCode() { return iCode; } StatementLabels *getStatementLabels() { return labelSet; labelSet = NULL; } @@ -285,7 +299,7 @@ namespace ICG { void beginLabelStatement(uint32 /* pos */, const StringAtom &label) { labelSet->push_back(&label); } - void endLabelStatement() { labelSet->pop_back(); } + void endLabelStatement() { if (labelSet) labelSet->pop_back(); } void continueStatement(uint32 pos); void breakStatement(uint32 pos); diff --git a/mozilla/js/js2/interpreter.cpp b/mozilla/js/js2/interpreter.cpp index 80314c280eb..4afb173fc4d 100644 --- a/mozilla/js/js2/interpreter.cpp +++ b/mozilla/js/js2/interpreter.cpp @@ -277,6 +277,21 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } break; +/* +versions below are not right, there is no 'array' type really, the index operation +turns into a get_property call like this, only we need to be using JSString throughout. + case GET_ELEMENT: + { + GetElement* ge = static_cast(instruction); + JSValue& base = (*registers)[src1(ge)]; + JSValue index = (*registers)[src2(ge)].toString(); + if (base.tag == JSValue::object_tag) { + JSObject* object = base.object; + (*registers)[dst(ge)] = object->getProperty(*index.string); + } + } + break; +*/ case GET_ELEMENT: { GetElement* ge = static_cast(instruction); @@ -297,6 +312,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } break; + case LOAD_IMMEDIATE: { LoadImmediate* li = static_cast(instruction); @@ -309,6 +325,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) (*registers)[dst(ls)] = JSValue(src1(ls)); } break; + case LOAD_VALUE: + { + LoadValue* lv = static_cast(instruction); + (*registers)[dst(lv)] = src1(lv); + } + break; case BRANCH: { GenericBranch* bra = @@ -357,6 +379,28 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } break; + case BRANCH_TRUE: + { + GenericBranch* bc = + static_cast(instruction); + ASSERT((*registers)[src1(bc)].isBoolean()); + if ((*registers)[src1(bc)].boolean) { + mPC = begin_pc + ofs(bc); + continue; + } + } + break; + case BRANCH_FALSE: + { + GenericBranch* bc = + static_cast(instruction); + ASSERT((*registers)[src1(bc)].isBoolean()); + if (!(*registers)[src1(bc)].boolean) { + mPC = begin_pc + ofs(bc); + continue; + } + } + break; case BRANCH_GE: { GenericBranch* bc = @@ -377,6 +421,74 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } break; + case SHIFTLEFT: + { + Arithmetic* shl = static_cast(instruction); + JSValue& dest = (*registers)[dst(shl)]; + JSValue& r1 = (*registers)[src1(shl)]; + JSValue& r2 = (*registers)[src2(shl)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toUInt32()); + dest = num1.i32 << (num2.u32 & 0x1F); + } + break; + case SHIFTRIGHT: + { + Arithmetic* shr = static_cast(instruction); + JSValue& dest = (*registers)[dst(shr)]; + JSValue& r1 = (*registers)[src1(shr)]; + JSValue& r2 = (*registers)[src2(shr)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toUInt32()); + dest = num1.i32 >> (num2.u32 & 0x1F); + } + break; + case USHIFTRIGHT: + { + Arithmetic* ushr = static_cast(instruction); + JSValue& dest = (*registers)[dst(ushr)]; + JSValue& r1 = (*registers)[src1(ushr)]; + JSValue& r2 = (*registers)[src2(ushr)]; + JSValue num1(r1.toUInt32()); + JSValue num2(r2.toUInt32()); + dest = num1.u32 >> (num2.u32 & 0x1F); + } + break; + + case AND: + { + Arithmetic* shr = static_cast(instruction); + JSValue& dest = (*registers)[dst(shr)]; + JSValue& r1 = (*registers)[src1(shr)]; + JSValue& r2 = (*registers)[src2(shr)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toInt32()); + dest = num1.i32 & num2.i32; + } + break; + case OR: + { + Arithmetic* shr = static_cast(instruction); + JSValue& dest = (*registers)[dst(shr)]; + JSValue& r1 = (*registers)[src1(shr)]; + JSValue& r2 = (*registers)[src2(shr)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toInt32()); + dest = num1.i32 | num2.i32; + } + break; + case XOR: + { + Arithmetic* shr = static_cast(instruction); + JSValue& dest = (*registers)[dst(shr)]; + JSValue& r1 = (*registers)[src1(shr)]; + JSValue& r2 = (*registers)[src2(shr)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toInt32()); + dest = num1.i32 ^ num2.i32; + } + break; + case ADD: { // could get clever here with Functional forms. @@ -462,11 +574,10 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) JSValue r = mGlobal->getVariable(*src1(nx)).toNumber(); dest = r; r.f64 += val3(nx); - mGlobal->setVariable(*src1(nx), dest); + mGlobal->setVariable(*src1(nx), r); } break; - case COMPARE_LT: case COMPARE_LE: case COMPARE_EQ: @@ -475,11 +586,44 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case COMPARE_GE: { Arithmetic* cmp = static_cast(instruction); - float64 diff = - ((*registers)[src1(cmp)].f64 - - (*registers)[src2(cmp)].f64); - (*registers)[dst(cmp)] = - JSValue(int32(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1))); + JSValue& dest = (*registers)[dst(cmp)]; + JSValue lv = (*registers)[src1(cmp)].toPrimitive(JSValue::Number); + JSValue rv = (*registers)[src2(cmp)].toPrimitive(JSValue::Number); + if (lv.isString() && rv.isString()) { + // XXX FIXME urgh, call w_strcmp ??? on a JSString ??? + } + else { + lv = lv.toNumber(); + rv = rv.toNumber(); + if (lv.isNaN() || rv.isNaN()) + dest = JSValue(); + else { + // FIXME, does this do the right thing for +/- infinity? + switch (instruction->op()) { + case COMPARE_LT: + dest = JSValue(lv.f64 < rv.f64); break; + case COMPARE_LE: + dest = JSValue(lv.f64 <= rv.f64); break; + case COMPARE_EQ: + dest = JSValue(lv.f64 == rv.f64); break; + case COMPARE_NE: + dest = JSValue(lv.f64 != rv.f64); break; + case COMPARE_GT: + dest = JSValue(lv.f64 > rv.f64); break; + case COMPARE_GE: + dest = JSValue(lv.f64 >= rv.f64); break; + } +// float64 diff = lv.f64 - rv.f64; +// dest = JSValue( (int32) (diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1))); + } + } + + } + break; + case TEST: + { + Test* tst = static_cast(instruction); + (*registers)[dst(tst)] = (*registers)[src1(tst)].toBoolean(); } break; case NEGATE: @@ -494,6 +638,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) (*registers)[dst(pos)] = (*registers)[src1(pos)].toNumber(); } break; + case BITNOT: + { + Bitnot* bn = static_cast(instruction); + (*registers)[dst(bn)] = JSValue(~(*registers)[src1(bn)].toInt32().i32); + } + break; +/* case NOT: { Not* nt = static_cast(instruction); @@ -501,7 +652,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) JSValue(int32(!(*registers)[src1(nt)].i32)); } break; - +*/ case THROW: { Throw* thrw = static_cast(instruction); @@ -610,7 +761,7 @@ void Context::addListener(Listener* listener) void Context::removeListener(Listener* listener) { ListenerIterator e = mListeners.end(); - ListenerIterator l = find(mListeners.begin(), e, listener); + ListenerIterator l = std::find(mListeners.begin(), e, listener); if (l != e) mListeners.erase(l); } diff --git a/mozilla/js/js2/jstypes.cpp b/mozilla/js/js2/jstypes.cpp index 4596926228e..03582f4258e 100644 --- a/mozilla/js/js2/jstypes.cpp +++ b/mozilla/js/js2/jstypes.cpp @@ -40,18 +40,54 @@ namespace JSTypes { // using JavaScript::StringAtom; -// the canonical undefined value. +// the canonical undefined value, etc. const JSValue kUndefinedValue; -const JSValue kNaN(0.0, 0.0); +const JSValue kNaN = JSValue(nan); +const JSValue kTrue = JSValue(true); +const JSValue kFalse = JSValue(false); + +#ifdef IS_LITTLE_ENDIAN +#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1]) +#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0]) +#else +#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0]) +#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1]) +#endif + +#define JSDOUBLE_HI32_SIGNBIT 0x80000000 +#define JSDOUBLE_HI32_EXPMASK 0x7ff00000 +#define JSDOUBLE_HI32_MANTMASK 0x000fffff + +#define JSDOUBLE_IS_NaN(x) \ + ((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \ + (JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK))) + +#define JSDOUBLE_IS_INFINITE(x) \ + ((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \ + !JSDOUBLE_LO32(x)) + +#define JSDOUBLE_IS_FINITE(x) \ + ((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK) + +#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \ + JSDOUBLE_LO32(d) == 0) - -JSValue::JSValue(float64 a, float64 b) +bool JSValue::isNaN() const { - f64 = a/b; - tag = f64_tag; + ASSERT(isNumber()); + switch (tag) { + case i32_tag: + case u32_tag: + return false; + case f64_tag: + return JSDOUBLE_IS_NaN(f64); + default: + NOT_REACHED("Broken compiler?"); + return true; + } } - + int JSValue::operator==(const JSValue& value) const { if (this->tag == value.tag) { @@ -62,6 +98,7 @@ int JSValue::operator==(const JSValue& value) const CASE(i32); CASE(u32); CASE(f32); CASE(i64); CASE(u64); CASE(f64); CASE(object); CASE(array); CASE(function); CASE(string); + CASE(boolean); #undef CASE // question: are all undefined values equal to one another? case undefined_tag: return 1; @@ -76,6 +113,9 @@ Formatter& operator<<(Formatter& f, const JSValue& value) case JSValue::i32_tag: f << float64(value.i32); break; + case JSValue::u32_tag: + f << float64(value.u32); + break; case JSValue::f64_tag: f << value.f64; break; @@ -87,39 +127,80 @@ Formatter& operator<<(Formatter& f, const JSValue& value) case JSValue::string_tag: f << *value.string; break; - default: + case JSValue::boolean_tag: + f << ((value.boolean) ? "true" : "false"); + break; + case JSValue::undefined_tag: f << "undefined"; break; + default: + NOT_REACHED("Bad tag"); } return f; } +JSValue JSValue::toPrimitive(ECMA_type hint) const +{ + switch (tag) { + case i32_tag: + case u32_tag: + case f64_tag: + case string_tag: + case boolean_tag: + case undefined_tag: + return *this; + + case object_tag: + case array_tag: + case function_tag: + if (hint == String) { + // FIXME + } + else { + // FIXME + } + break; + + default: + NOT_REACHED("Bad tag"); + } + return kUndefinedValue; +} + JSValue JSValue::valueToString(const JSValue& value) // can assume value is not a string { char *chrp; char buf[dtosStandardBufferSize]; switch (value.tag) { - case JSValue::i32_tag: + case i32_tag: chrp = doubleToStr(buf, dtosStandardBufferSize, value.i32, dtosStandard, 0); break; - case JSValue::f64_tag: + case u32_tag: + chrp = doubleToStr(buf, dtosStandardBufferSize, value.u32, dtosStandard, 0); + break; + case f64_tag: chrp = doubleToStr(buf, dtosStandardBufferSize, value.f64, dtosStandard, 0); break; - case JSValue::object_tag: + case object_tag: chrp = "object"; break; - case JSValue::array_tag: + case array_tag: chrp = "array"; break; - case JSValue::function_tag: + case function_tag: chrp = "function"; break; - case JSValue::string_tag: + case string_tag: return value; - default: + case boolean_tag: + chrp = (value.boolean) ? "true" : "false"; + break; + case undefined_tag: chrp = "undefined"; break; + default: + NOT_REACHED("Bad tag"); } return JSValue(new JSString(chrp)); } @@ -127,25 +208,142 @@ JSValue JSValue::valueToString(const JSValue& value) // can assume value is not JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not a number { switch (value.tag) { - case JSValue::i32_tag: - case JSValue::f64_tag: + case i32_tag: + return JSValue((float64)value.i32); + case u32_tag: + return JSValue((float64)value.u32); + case f64_tag: return value; - case JSValue::string_tag: + case string_tag: { JSString* str = value.string; const char16 *numEnd; double d = stringToDouble(str->begin(), str->end(), numEnd); return JSValue(d); } - case JSValue::object_tag: - case JSValue::array_tag: - case JSValue::function_tag: - break; - default: + case object_tag: + case array_tag: + case function_tag: + // XXX more needed : + // toNumber(toPrimitive(hint Number)) + return kUndefinedValue; + case boolean_tag: + return JSValue((value.boolean) ? 1.0 : 0.0); + case undefined_tag: return kNaN; - break; + default: + NOT_REACHED("Bad tag"); + return kUndefinedValue; } - return kUndefinedValue; +} + +JSValue JSValue::valueToBoolean(const JSValue& value) +{ + switch (value.tag) { + case i32_tag: + return JSValue(value.i32 != 0); + case u32_tag: + return JSValue(value.u32 != 0); + case f64_tag: + return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64)); + case string_tag: + return JSValue(value.string->length() != 0); + case boolean_tag: + return value; + case object_tag: + case array_tag: + case function_tag: + return kTrue; + case undefined_tag: + return kFalse; + default: + NOT_REACHED("Bad tag"); + return kUndefinedValue; + } +} + + +static const double two32 = 4294967296.0; +static const double two31 = 2147483648.0; + +JSValue JSValue::valueToInt32(const JSValue& value) +{ + double d; + switch (value.tag) { + case i32_tag: + return value; + case u32_tag: + d = value.u32; + break; + case f64_tag: + d = value.f64; + break; + case string_tag: + { + JSString* str = value.string; + const char16 *numEnd; + d = stringToDouble(str->begin(), str->end(), numEnd); + } + break; + case boolean_tag: + return JSValue((int32)((value.boolean) ? 1 : 0)); + case object_tag: + case array_tag: + case undefined_tag: + // toNumber(toPrimitive(hint Number)) + return kUndefinedValue; + default: + NOT_REACHED("Bad tag"); + return kUndefinedValue; + } + if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) ) + return JSValue((int32)0); + d = fmod(d, two32); + d = (d >= 0) ? d : d + two32; + if (d >= two31) + return JSValue((int32)(d - two32)); + else + return JSValue((int32)d); + +} + +JSValue JSValue::valueToUInt32(const JSValue& value) +{ + double d; + switch (value.tag) { + case i32_tag: + return JSValue((uint32)value.i32); + case u32_tag: + return value; + case f64_tag: + d = value.f64; + break; + case string_tag: + { + JSString* str = value.string; + const char16 *numEnd; + d = stringToDouble(str->begin(), str->end(), numEnd); + } + break; + case boolean_tag: + return JSValue((uint32)((value.boolean) ? 1 : 0)); + case object_tag: + case array_tag: + case undefined_tag: + // toNumber(toPrimitive(hint Number)) + return kUndefinedValue; + default: + NOT_REACHED("Bad tag"); + return kUndefinedValue; + } + if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d)) + return JSValue((uint32)0); + bool neg = (d < 0); + d = floor(neg ? -d : d); + d = neg ? -d : d; + d = fmod(d, two32); + d = (d >= 0) ? d : d + two32; + return JSValue((uint32)d); } JSFunction::~JSFunction() diff --git a/mozilla/js/js2/jstypes.h b/mozilla/js/js2/jstypes.h index 3d73456f36e..87ed30667d9 100644 --- a/mozilla/js/js2/jstypes.h +++ b/mozilla/js/js2/jstypes.h @@ -76,44 +76,66 @@ namespace JSTypes { JSArray* array; JSFunction *function; JSString *string; + bool boolean; }; + /* These are the ECMA types, for use in 'toPrimitive' calls */ + enum ECMA_type { + Undefined, Null, Boolean, Number, Object, String, + NoHint + }; + enum { i8_tag, u8_tag, i16_tag, u16_tag, i32_tag, u32_tag, i64_tag, u64_tag, f32_tag, f64_tag, - object_tag, array_tag, function_tag, string_tag, + object_tag, array_tag, function_tag, string_tag, boolean_tag, undefined_tag } tag; JSValue() : f64(0.0), tag(undefined_tag) {} explicit JSValue(int32 i32) : i32(i32), tag(i32_tag) {} + explicit JSValue(uint32 u32) : u32(u32), tag(u32_tag) {} explicit JSValue(float64 f64) : f64(f64), tag(f64_tag) {} explicit JSValue(JSObject* object) : object(object), tag(object_tag) {} explicit JSValue(JSArray* array) : array(array), tag(array_tag) {} explicit JSValue(JSFunction* function) : function(function), tag(function_tag) {} explicit JSValue(JSString* string) : string(string), tag(string_tag) {} + explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {} - JSValue(float64 a, float64 b); - int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); } + uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); } float64& operator=(float64 f64) { return (tag = f64_tag, this->f64 = f64); } JSObject*& operator=(JSObject* object) { return (tag = object_tag, this->object = object); } JSArray*& operator=(JSArray* array) { return (tag = array_tag, this->array = array); } JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); } JSString*& operator=(JSString* string) { return (tag = string_tag, this->string = string); } + bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); } bool isString() const { return (tag == string_tag); } - bool isNumber() const { return ((tag == f64_tag) || (tag == i32_tag)); } + bool isBoolean() const { return (tag == boolean_tag); } + bool isNumber() const { return (tag == f64_tag); } + /* this is correct wrt ECMA, The i32 & u32 kinds + will have to be converted to doubles anyway because + we can't have overflow happening in generic arithmetic */ + bool isNaN() const; JSValue toString() const { return (isString() ? *this : valueToString(*this)); } JSValue toNumber() const { return (isNumber() ? *this : valueToNumber(*this)); } + JSValue toInt32() const { return ((tag == i32_tag) ? *this : valueToInt32(*this)); } + JSValue toUInt32() const { return ((tag == u32_tag) ? *this : valueToUInt32(*this)); } + JSValue toBoolean() const { return ((tag == boolean_tag) ? *this : valueToBoolean(*this)); } + + JSValue toPrimitive(ECMA_type hint = NoHint) const; static JSValue valueToString(const JSValue& value); static JSValue valueToNumber(const JSValue& value); + static JSValue valueToInt32(const JSValue& value); + static JSValue valueToUInt32(const JSValue& value); + static JSValue valueToBoolean(const JSValue& value); int operator==(const JSValue& value) const; }; @@ -140,6 +162,8 @@ namespace JSTypes { extern const JSValue kUndefinedValue; extern const JSValue kNaN; + extern const JSValue kTrue; + extern const JSValue kFalse; /** * Basic behavior of all JS objects, mapping a name to a value, diff --git a/mozilla/js/js2/vmtypes.cpp b/mozilla/js/js2/vmtypes.cpp index 6d49b5d3a37..27d7dcc1a6d 100644 --- a/mozilla/js/js2/vmtypes.cpp +++ b/mozilla/js/js2/vmtypes.cpp @@ -107,6 +107,30 @@ namespace VM { return f; } + ICodeOp Instruction::getBranchOp() + { + // XXX FIXME, convert to table lookup or arithmetic after the dust settles + switch (mOpcode) { + case COMPARE_EQ: +// return BRANCH_EQ; + case COMPARE_NE: +// return BRANCH_NE; + case COMPARE_GE: +// return BRANCH_GE; + case COMPARE_GT: +// return BRANCH_GT; + case COMPARE_LE: +// return BRANCH_LE; + case COMPARE_LT: +// return BRANCH_LT; + case TEST: + return BRANCH_TRUE; + default: + NOT_REACHED("Unexpected branch code"); + return NOP; + } + } + } /* namespace VM */ } /* namespace JavaScript */ diff --git a/mozilla/js/js2/vmtypes.h b/mozilla/js/js2/vmtypes.h index da8512f483e..ca119ec786a 100644 --- a/mozilla/js/js2/vmtypes.h +++ b/mozilla/js/js2/vmtypes.h @@ -42,6 +42,7 @@ namespace JavaScript { namespace VM { + using JSTypes::JSValue; using JSTypes::JSValues; using JSTypes::JSString; @@ -51,11 +52,13 @@ namespace VM { BITNOT, /* dest, source */ BRANCH, /* target label */ BRANCH_EQ, /* target label, condition */ + BRANCH_FALSE, /* target label, condition */ BRANCH_GE, /* target label, condition */ BRANCH_GT, /* target label, condition */ BRANCH_LE, /* target label, condition */ BRANCH_LT, /* target label, condition */ BRANCH_NE, /* target label, condition */ + BRANCH_TRUE, /* target label, condition */ CALL, /* result, target, args */ COMPARE_EQ, /* dest, source */ COMPARE_GE, /* dest, source */ @@ -65,13 +68,15 @@ namespace VM { COMPARE_LT, /* dest, source */ COMPARE_NE, /* dest, source */ DIVIDE, /* dest, source1, source2 */ - GET_ELEMENT, /* dest, array, index */ + ELEM_XCR, /* dest, base, index, value */ + GET_ELEMENT, /* dest, base, index */ GET_PROP, /* dest, object, prop name */ INSTANCEOF, /* dest, source */ JSR, /* target */ LOAD_IMMEDIATE, /* dest, immediate value (double) */ LOAD_NAME, /* dest, name */ LOAD_STRING, /* dest, immediate value (string) */ + LOAD_VALUE, /* dest, immediate value (JSValue) */ MOVE, /* dest, source */ MULTIPLY, /* dest, source1, source2 */ NAME_XCR, /* dest, name, value */ @@ -88,13 +93,14 @@ namespace VM { RETURN_VOID, /* Return without a value */ RTS, /* Return to sender */ SAVE_NAME, /* name, source */ - SET_ELEMENT, /* base, source1, source2 */ + SET_ELEMENT, /* base, index, value */ SET_PROP, /* object, name, source */ SHIFTLEFT, /* dest, source1, source2 */ SHIFTRIGHT, /* dest, source1, source2 */ STRICT_EQ, /* dest, source */ STRICT_NE, /* dest, source */ SUBTRACT, /* dest, source1, source2 */ + TEST, /* dest, source */ THROW, /* exception value */ TRYIN, /* catch target, finally target */ TRYOUT, /* mmm, there is no try, only do */ @@ -114,11 +120,13 @@ namespace VM { "BITNOT ", "BRANCH ", "BRANCH_EQ ", + "BRANCH_FALSE ", "BRANCH_GE ", "BRANCH_GT ", "BRANCH_LE ", "BRANCH_LT ", "BRANCH_NE ", + "BRANCH_TRUE ", "CALL ", "COMPARE_EQ ", "COMPARE_GE ", @@ -128,6 +136,7 @@ namespace VM { "COMPARE_LT ", "COMPARE_NE ", "DIVIDE ", + "ELEM_XCR ", "GET_ELEMENT ", "GET_PROP ", "INSTANCEOF ", @@ -135,6 +144,7 @@ namespace VM { "LOAD_IMMEDIATE", "LOAD_NAME ", "LOAD_STRING ", + "LOAD_VALUE ", "MOVE ", "MULTIPLY ", "NAME_XCR ", @@ -158,6 +168,7 @@ namespace VM { "STRICT_EQ ", "STRICT_NE ", "SUBTRACT ", + "TEST ", "THROW ", "TRYIN ", "TRYOUT ", @@ -188,11 +199,7 @@ namespace VM { return f; } - ICodeOp getBranchOp() - { - return ((mOpcode >= COMPARE_EQ) && (mOpcode <= COMPARE_NE)) ? - (ICodeOp)(BRANCH_EQ + (mOpcode - COMPARE_EQ)) : NOP; - } + ICodeOp getBranchOp(); ICodeOp op() { return mOpcode; } @@ -445,6 +452,15 @@ namespace VM { /* print() and printOperands() inherited from GenericBranch */ }; + class BranchFalse : public GenericBranch { + public: + /* target label, condition */ + BranchFalse (Label* aOp1, Register aOp2) : + GenericBranch + (BRANCH_FALSE, aOp1, aOp2) {}; + /* print() and printOperands() inherited from GenericBranch */ + }; + class BranchGE : public GenericBranch { public: /* target label, condition */ @@ -490,6 +506,15 @@ namespace VM { /* print() and printOperands() inherited from GenericBranch */ }; + class BranchTrue : public GenericBranch { + public: + /* target label, condition */ + BranchTrue (Label* aOp1, Register aOp2) : + GenericBranch + (BRANCH_TRUE, aOp1, aOp2) {}; + /* print() and printOperands() inherited from GenericBranch */ + }; + class Call : public Instruction_3 { public: /* result, target, args */ @@ -578,6 +603,22 @@ namespace VM { /* print() and printOperands() inherited from Arithmetic */ }; + class ElemXcr : public Instruction_4 { + public: + /* dest, base, index, value */ + ElemXcr (Register aOp1, Register aOp2, Register aOp3, double aOp4) : + Instruction_4 + (ELEM_XCR, aOp1, aOp2, aOp3, aOp4) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[ELEM_XCR] << "\t" << "R" << mOp1 << ", " << "R" << mOp2 << ", " << "R" << mOp3 << ", " << mOp4; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1 << '=' << registers[mOp1] << ", " << "R" << mOp2 << '=' << registers[mOp2] << ", " << "R" << mOp3 << '=' << registers[mOp3]; + return f; + } + }; + class GetElement : public Instruction_3 { public: /* dest, array, index */ @@ -682,6 +723,22 @@ namespace VM { } }; + class LoadValue : public Instruction_2 { + public: + /* dest, immediate value (JSValue) */ + LoadValue (Register aOp1, JSValue aOp2) : + Instruction_2 + (LOAD_VALUE, aOp1, aOp2) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[LOAD_VALUE] << "\t" << "R" << mOp1 << ", " << mOp2; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1 << '=' << registers[mOp1]; + return f; + } + }; + class Move : public Instruction_2 { public: /* dest, source */ @@ -991,6 +1048,22 @@ namespace VM { /* print() and printOperands() inherited from Arithmetic */ }; + class Test : public Instruction_2 { + public: + /* dest, source */ + Test (Register aOp1, Register aOp2) : + Instruction_2 + (TEST, aOp1, aOp2) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[TEST] << "\t" << "R" << mOp1 << ", " << "R" << mOp2; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1 << '=' << registers[mOp1] << ", " << "R" << mOp2 << '=' << registers[mOp2]; + return f; + } + }; + class Throw : public Instruction_1 { public: /* exception value */ diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index 5ac31695ad5..6c62be54050 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -1,35 +1,35 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * The contents of this file are subject to the Netscape Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the JavaScript 2 Prototype. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License (the "GPL"), in which case the - * provisions of the GPL are applicable instead of those above. - * If you wish to allow use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the NPL, indicate your decision by - * deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete - * the provisions above, a recipient may use your version of this - * file under either the NPL or the GPL. - */ +* +* The contents of this file are subject to the Netscape Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/NPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is the JavaScript 2 Prototype. +* +* The Initial Developer of the Original Code is Netscape +* Communications Corporation. Portions created by Netscape are +* Copyright (C) 1998 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License (the "GPL"), in which case the +* provisions of the GPL are applicable instead of those above. +* If you wish to allow use of your version of this file only +* under the terms of the GPL and not to allow others to use your +* version of this file under the NPL, indicate your decision by +* deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the NPL or the GPL. +*/ #include "numerics.h" #include "world.h" @@ -42,819 +42,1243 @@ namespace JavaScript { namespace ICG { - using namespace VM; +using namespace VM; +using namespace JSTypes; - uint32 ICodeModule::sMaxID = 0; - - Formatter& operator<<(Formatter &f, ICodeGenerator &i) - { - return i.print(f); - } - - Formatter& operator<<(Formatter &f, ICodeModule &i) - { - return i.print(f); - } - - // - // ICodeGenerator - // - - ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting) - : topRegister(0), - registerBase(0), - maxRegister(0), - parameterCount(0), - exceptionRegister(NotARegister), - switchRegister(NotARegister), - variableList(new VariableList()) - { - iCode = new InstructionStream(); - iCodeOwner = true; - if (hasTryStatement) - exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]); - for (uint i = 0; i < switchStatementNesting; i++) { - String s = widenCString("__switchControlVariable__"); - char num[8]; - sprintf(num, "%.2d", i); - appendChars(s, num, strlen(num)); - if (switchRegister == NotARegister) - switchRegister = allocateVariable(world->identifiers[s]); - else - allocateVariable(world->identifiers[s]); - } - labelSet = new StatementLabels(); +uint32 ICodeModule::sMaxID = 0; + +Formatter& operator<<(Formatter &f, ICodeGenerator &i) +{ + return i.print(f); +} + +Formatter& operator<<(Formatter &f, ICodeModule &i) +{ + return i.print(f); +} + +// +// ICodeGenerator +// + +ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting) + : topRegister(0), + registerBase(0), + maxRegister(0), + parameterCount(0), + exceptionRegister(NotARegister), + switchRegister(NotARegister), + variableList(new VariableList()), + mWorld(world) +{ + iCode = new InstructionStream(); + iCodeOwner = true; + if (hasTryStatement) + exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]); + for (uint i = 0; i < switchStatementNesting; i++) { + String s = widenCString("__switchControlVariable__"); + char num[8]; + sprintf(num, "%.2d", i); + appendChars(s, num, strlen(num)); + if (switchRegister == NotARegister) + switchRegister = allocateVariable(world->identifiers[s]); + else + allocateVariable(world->identifiers[s]); } + labelSet = new StatementLabels(); +} - ICodeModule *ICodeGenerator::complete() - { - ASSERT(stitcher.empty()); - //ASSERT(labelSet == NULL); +ICodeModule *ICodeGenerator::complete() +{ + ASSERT(stitcher.empty()); + //ASSERT(labelSet == NULL); #ifdef DEBUG - for (LabelList::iterator i = labels.begin(); - i != labels.end(); i++) { - ASSERT((*i)->mBase == iCode); - ASSERT((*i)->mOffset <= iCode->size()); - } + for (LabelList::iterator i = labels.begin(); + i != labels.end(); i++) { + ASSERT((*i)->mBase == iCode); + ASSERT((*i)->mOffset <= iCode->size()); + } #endif - /* - for (InstructionIterator ii = iCode->begin(); - ii != iCode->end(); ii++) { - if ((*ii)->op() == BRANCH) { + /* + for (InstructionIterator ii = iCode->begin(); + ii != iCode->end(); ii++) { + if ((*ii)->op() == BRANCH) { + Instruction *t = *ii; + *ii = new ResolvedBranch(static_cast(*ii)->operand1->itsOffset); + delete t; + } + else + if ((*ii)->itsOp >= BRANCH_LT && (*ii)->itsOp <= BRANCH_GT) { Instruction *t = *ii; - *ii = new ResolvedBranch(static_cast(*ii)->operand1->itsOffset); + *ii = new ResolvedBranchCond((*ii)->itsOp, + static_cast(*ii)->itsOperand1->itsOffset, + static_cast(*ii)->itsOperand2); delete t; } - else - if ((*ii)->itsOp >= BRANCH_LT && (*ii)->itsOp <= BRANCH_GT) { - Instruction *t = *ii; - *ii = new ResolvedBranchCond((*ii)->itsOp, - static_cast(*ii)->itsOperand1->itsOffset, - static_cast(*ii)->itsOperand2); - delete t; - } - } - */ - markMaxRegister(); - ICodeModule* module = new ICodeModule(iCode, variableList, maxRegister, 0); - iCodeOwner = false; // give ownership to the module. - return module; } + */ + markMaxRegister(); + ICodeModule* module = new ICodeModule(iCode, variableList, maxRegister, 0); + iCodeOwner = false; // give ownership to the module. + 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(); + } +} + + +/********************************************************************/ + +Register ICodeGenerator::loadImmediate(double value) +{ + Register dest = getRegister(); + LoadImmediate *instr = new LoadImmediate(dest, value); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::loadString(String &value) +{ + Register dest = getRegister(); + LoadString *instr = new LoadString(dest, new JSString(value)); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::loadValue(JSValue value) +{ + Register dest = getRegister(); + LoadValue *instr = new LoadValue(dest, value); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::newObject() +{ + Register dest = getRegister(); + NewObject *instr = new NewObject(dest); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::newArray() +{ + Register dest = getRegister(); + NewArray *instr = new NewArray(dest); + iCode->push_back(instr); + return dest; +} + + + +Register ICodeGenerator::loadName(const StringAtom &name) +{ + Register dest = getRegister(); + LoadName *instr = new LoadName(dest, &name); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::saveName(const StringAtom &name, Register value) +{ + SaveName *instr = new SaveName(&name, value); + iCode->push_back(instr); +} + +Register ICodeGenerator::nameInc(const StringAtom &name) +{ + Register dest = getRegister(); + NameXcr *instr = new NameXcr(dest, &name, 1.0); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::nameDec(const StringAtom &name) +{ + Register dest = getRegister(); + NameXcr *instr = new NameXcr(dest, &name, -1.0); + iCode->push_back(instr); + return dest; +} + + + +Register ICodeGenerator::getProperty(Register base, const StringAtom &name) +{ + Register dest = getRegister(); + GetProp *instr = new GetProp(dest, base, &name); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::setProperty(Register base, const StringAtom &name, + Register value) +{ + SetProp *instr = new SetProp(base, &name, value); + iCode->push_back(instr); +} + +Register ICodeGenerator::propertyInc(Register base, const StringAtom &name) +{ + Register dest = getRegister(); + PropXcr *instr = new PropXcr(dest, base, &name, 1.0); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::propertyDec(Register base, const StringAtom &name) +{ + Register dest = getRegister(); + PropXcr *instr = new PropXcr(dest, base, &name, -1.0); + iCode->push_back(instr); + return dest; +} + + + +Register ICodeGenerator::getElement(Register base, Register index) +{ + Register dest = getRegister(); + GetElement *instr = new GetElement(dest, base, index); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::setElement(Register base, Register index, + Register value) +{ + SetElement *instr = new SetElement(base, index, value); + iCode->push_back(instr); +} + +Register ICodeGenerator::elementInc(Register base, Register index) +{ + Register dest = getRegister(); + ElemXcr *instr = new ElemXcr(dest, base, index, 1.0); + iCode->push_back(instr); + return dest; +} + +Register ICodeGenerator::elementDec(Register base, Register index) +{ + Register dest = getRegister(); + ElemXcr *instr = new ElemXcr(dest, base, index, -1.0); + iCode->push_back(instr); + return dest; +} + + +Register ICodeGenerator::op(ICodeOp op, Register source) +{ + Register dest = getRegister(); + ASSERT(source != NotARegister); + Compare *instr = new Compare (op, dest, source); + iCode->push_back(instr); + return dest; +} - 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(); - } - } +void ICodeGenerator::move(Register destination, Register source) +{ + ASSERT(destination != NotARegister); + ASSERT(source != NotARegister); + Move *instr = new Move(destination, source); + iCode->push_back(instr); +} +void ICodeGenerator::complement(Register destination, Register source) +{ + Not *instr = new Not(destination, source); + iCode->push_back(instr); +} - /********************************************************************/ +Register ICodeGenerator::test(Register source) +{ + Register dest = getRegister(); + Test *instr = new Test(dest, source); + iCode->push_back(instr); + return dest; +} - Register ICodeGenerator::loadImmediate(double value) - { - Register dest = getRegister(); - LoadImmediate *instr = new LoadImmediate(dest, value); - iCode->push_back(instr); - return dest; - } - - Register ICodeGenerator::loadString(String &value) - { - Register dest = getRegister(); - LoadString *instr = new LoadString(dest, new JSString(value)); - iCode->push_back(instr); - return dest; - } - - Register ICodeGenerator::newObject() - { - Register dest = getRegister(); - NewObject *instr = new NewObject(dest); - iCode->push_back(instr); - return dest; - } - - Register ICodeGenerator::newArray() - { - Register dest = getRegister(); - NewArray *instr = new NewArray(dest); - iCode->push_back(instr); - return dest; - } - - - - Register ICodeGenerator::loadName(const StringAtom &name) - { - Register dest = getRegister(); - LoadName *instr = new LoadName(dest, &name); - iCode->push_back(instr); - return dest; - } +Register ICodeGenerator::op(ICodeOp op, Register source1, + Register source2) +{ + ASSERT(source1 != NotARegister); + ASSERT(source2 != NotARegister); + Register dest = getRegister(); + Arithmetic *instr = new Arithmetic(op, dest, source1, source2); + iCode->push_back(instr); + return dest; +} - void ICodeGenerator::saveName(const StringAtom &name, Register value) - { - SaveName *instr = new SaveName(&name, value); - iCode->push_back(instr); +Register ICodeGenerator::call(Register target, RegisterList args) +{ + Register dest = getRegister(); + Call *instr = new Call(dest, target, args); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::callVoid(Register target, RegisterList args) +{ + Call *instr = new Call(NotARegister, target, args); + iCode->push_back(instr); +} + +void ICodeGenerator::branch(Label *label) +{ + Branch *instr = new Branch(label); + iCode->push_back(instr); +} + +void ICodeGenerator::branchConditional(Label *label, Register condition) +{ + ICodeOp branchOp = getBranchOp(); + ASSERT(branchOp != NOP); + GenericBranch *instr = new GenericBranch(branchOp, label, condition); + iCode->push_back(instr); +} + +void ICodeGenerator::branchTrue(Label *label, Register condition) +{ + GenericBranch *instr = new GenericBranch(BRANCH_TRUE, label, condition); + iCode->push_back(instr); +} + +void ICodeGenerator::branchFalse(Label *label, Register condition) +{ + GenericBranch *instr = new GenericBranch(BRANCH_FALSE, label, condition); + iCode->push_back(instr); +} + +void ICodeGenerator::branchNotConditional(Label *label, Register condition) +{ + ICodeOp branchOp = getBranchOp(); + ASSERT(branchOp != NOP); + switch (branchOp) { + case BRANCH_FALSE : branchOp = BRANCH_TRUE; break; + case BRANCH_TRUE : branchOp = BRANCH_FALSE; break; + case BRANCH_EQ : branchOp = BRANCH_NE; break; + case BRANCH_GE : branchOp = BRANCH_LT; break; + case BRANCH_GT : branchOp = BRANCH_LE; break; + case BRANCH_LE : branchOp = BRANCH_GT; break; + case BRANCH_LT : branchOp = BRANCH_GE; break; + case BRANCH_NE : branchOp = BRANCH_EQ; break; + default : NOT_REACHED("Expected a branch op"); break; + } + GenericBranch *instr = new GenericBranch(branchOp, label, condition); + iCode->push_back(instr); +} + +/********************************************************************/ + +Label *ICodeGenerator::getLabel() +{ + labels.push_back(new Label(NULL)); + return labels.back(); +} + +void ICodeGenerator::setLabel(Label *l) +{ + l->mBase = iCode; + 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(); + } } - Register ICodeGenerator::nameInc(const StringAtom &name) - { - Register dest = getRegister(); - NameXcr *instr = new NameXcr(dest, &name, 1.0); - iCode->push_back(instr); - return dest; + 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); - Register ICodeGenerator::nameDec(const StringAtom &name) - { - Register dest = getRegister(); - NameXcr *instr = new NameXcr(dest, &name, -1.0); - iCode->push_back(instr); - return dest; + // 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; - - Register ICodeGenerator::getProperty(Register base, const StringAtom &name) - { - Register dest = getRegister(); - GetProp *instr = new GetProp(dest, base, &name); - iCode->push_back(instr); - return dest; + 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 } - void ICodeGenerator::setProperty(Register base, const StringAtom &name, - Register value) - { - SetProp *instr = new SetProp(base, &name, value); - iCode->push_back(instr); - } + delete ics; + resetStatement(); +} - Register ICodeGenerator::propertyInc(Register base, const StringAtom &name) - { - Register dest = getRegister(); - PropXcr *instr = new PropXcr(dest, base, &name, 1.0); - iCode->push_back(instr); - return dest; - } +/************************************************************************/ - Register ICodeGenerator::propertyDec(Register base, const StringAtom &name) - { - Register dest = getRegister(); - PropXcr *instr = new PropXcr(dest, base, &name, -1.0); - iCode->push_back(instr); - return dest; - } - - - - Register ICodeGenerator::getElement(Register base, Register index) - { - Register dest = getRegister(); - GetElement *instr = new GetElement(dest, base, index); - iCode->push_back(instr); - return dest; - } - - void ICodeGenerator::setElement(Register base, Register index, - Register value) - { - SetElement *instr = new SetElement(base, index, value); - iCode->push_back(instr); - } - - Register ICodeGenerator::op(ICodeOp op, Register source) - { - Register dest = getRegister(); - ASSERT(source != NotARegister); - Compare *instr = new Compare (op, dest, source); - iCode->push_back(instr); - return dest; - } - - void ICodeGenerator::move(Register destination, Register source) - { - ASSERT(destination != NotARegister); - ASSERT(source != NotARegister); - Move *instr = new Move(destination, source); - iCode->push_back(instr); - } - - void ICodeGenerator::complement(Register destination, Register source) - { - Not *instr = new Not(destination, source); - iCode->push_back(instr); - } - - Register ICodeGenerator::op(ICodeOp op, Register source1, - Register source2) - { - ASSERT(source1 != NotARegister); - ASSERT(source2 != NotARegister); - Register dest = getRegister(); - Arithmetic *instr = new Arithmetic(op, dest, source1, source2); - iCode->push_back(instr); - return dest; - } - - Register ICodeGenerator::call(Register target, RegisterList args) - { - Register dest = getRegister(); - Call *instr = new Call(dest, target, args); - iCode->push_back(instr); - return dest; - } - - void ICodeGenerator::callVoid(Register target, RegisterList args) - { - Call *instr = new Call(NotARegister, target, args); - iCode->push_back(instr); - } - - void ICodeGenerator::branch(Label *label) - { - Branch *instr = new Branch(label); - iCode->push_back(instr); - } - - void ICodeGenerator::branchConditional(Label *label, Register condition) - { - ICodeOp branchOp = getBranchOp(); - if (branchOp == NOP) { - // XXXX emit convert to boolean / Test / ... - branchOp = BRANCH_NE; +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; } - GenericBranch *instr = new GenericBranch(branchOp, label, condition); - iCode->push_back(instr); - } - - void ICodeGenerator::branchNotConditional(Label *label, Register condition) - { - ICodeOp branchOp = getBranchOp(); - if (branchOp == NOP) { - // XXXX emit convert to boolean / Test / ... - branchOp = BRANCH_NE; + if (((*p)->stateKind == While_state) + || ((*p)->stateKind == Do_state) + || ((*p)->stateKind == For_state) + || ((*p)->stateKind == Switch_state)) { + (*p)->breakLabel = getLabel(); + branch((*p)->breakLabel); + return; } - switch (branchOp) { - case BRANCH_EQ : branchOp = BRANCH_NE; break; - case BRANCH_GE : branchOp = BRANCH_LT; break; - case BRANCH_GT : branchOp = BRANCH_LE; break; - case BRANCH_LE : branchOp = BRANCH_GT; break; - case BRANCH_LT : branchOp = BRANCH_GE; break; - case BRANCH_NE : branchOp = BRANCH_EQ; break; - default : NOT_REACHED("Expected a branch op"); break; - } - GenericBranch *instr = new GenericBranch(branchOp, label, condition); - iCode->push_back(instr); } - - /********************************************************************/ - - Label *ICodeGenerator::getLabel() - { - labels.push_back(new Label(NULL)); - return labels.back(); - } - - void ICodeGenerator::setLabel(Label *l) - { - l->mBase = iCode; - 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::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"); } + 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; - } +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; } - NOT_REACHED("no continue target available"); - } + 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; - } +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"); } - /********************************************************************/ + 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::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); +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); - } + 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::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::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); +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::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); +void ICodeGenerator::endFinallyStatement() +{ + TryCodeState *ics = static_cast(stitcher.back()); + ASSERT(ics->stateKind == Try_state); + rts(); +} + +/************************************************************************/ + + + + +ICodeOp ICodeGenerator::mapExprNodeToICodeOp(ExprNode::Kind kind) +{ + // can be an array later, when everything has settled down + switch (kind) { + // binary + case ExprNode::add: + return ADD; + case ExprNode::subtract: + return SUBTRACT; + case ExprNode::multiply: + return MULTIPLY; + case ExprNode::divide: + return DIVIDE; + case ExprNode::modulo: + return REMAINDER; + case ExprNode::leftShift: + return SHIFTLEFT; + case ExprNode::rightShift: + return SHIFTRIGHT; + case ExprNode::logicalRightShift: + return USHIFTRIGHT; + case ExprNode::bitwiseAnd: + return AND; + case ExprNode::bitwiseXor: + return XOR; + case ExprNode::bitwiseOr: + return OR; + // unary + case ExprNode::plus: + return POSATE; + case ExprNode::minus: + return NEGATE; + case ExprNode::complement: + return NOT; + + // relational + case ExprNode::equal: + return COMPARE_EQ; + case ExprNode::notEqual: + return COMPARE_NE; + case ExprNode::lessThan: + return COMPARE_LT; + case ExprNode::lessThanOrEqual: + return COMPARE_LE; + case ExprNode::greaterThan: + return COMPARE_GT; + case ExprNode::greaterThanOrEqual: + return COMPARE_GE; + case ExprNode::identical: + return STRICT_EQ; + case ExprNode::notIdentical: + return STRICT_NE; + case ExprNode::In: + return COMPARE_IN; + case ExprNode::Instanceof: + return INSTANCEOF; + + + default: + NOT_REACHED("Unimplemented kind"); + return NOP; + } +} + + +static bool generatedBoolean(ExprNode *p) +{ + switch (p->getKind()) { + case ExprNode::parentheses: + { + UnaryExprNode *u = static_cast(p); + return generatedBoolean(u->op); } - setLabel(ics->finallyHandler); + case ExprNode::True: + case ExprNode::False: + case ExprNode::equal: + case ExprNode::notEqual: + case ExprNode::lessThan: + case ExprNode::lessThanOrEqual: + case ExprNode::greaterThan: + case ExprNode::greaterThanOrEqual: + case ExprNode::identical: + case ExprNode::notIdentical: + case ExprNode::In: + case ExprNode::Instanceof: + case ExprNode::logicalAnd: + case ExprNode::logicalXor: + case ExprNode::logicalOr: + return true; } + return false; +} - void ICodeGenerator::endFinallyStatement() - { - TryCodeState *ics = static_cast(stitcher.back()); - ASSERT(ics->stateKind == Try_state); - rts(); + +/* + if trueBranch OR falseBranch are not null, the sub-expression should generate + a conditional branch do the appropriate target. If either branch is NULL, it + indicates that the label is immediately forthcoming. +*/ +Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label *trueBranch, Label *falseBranch) +{ + Register ret = NotARegister; + switch (p->getKind()) { + case ExprNode::True: + if (trueBranch || falseBranch) { + if (needBoolValueInBranch) + ret = loadValue(kTrue); + if (trueBranch) + branch(trueBranch); + } + else + ret = loadValue(kTrue); + break; + case ExprNode::False: + if (trueBranch || falseBranch) { + if (needBoolValueInBranch) + ret = loadValue(kFalse); + if (falseBranch) + branch(falseBranch); + } + else + ret = loadValue(kFalse); + break; + case ExprNode::parentheses: + { + UnaryExprNode *u = static_cast(p); + ret = genExpr(u->op, needBoolValueInBranch, trueBranch, falseBranch); + } + break; + case ExprNode::call : + { + InvokeExprNode *i = static_cast(p); + Register fn = genExpr(i->op); + RegisterList args; + ExprPairList *p = i->pairs; + while (p) { + args.push_back(genExpr(p->value)); + p = p->next; + } + ret = call(fn, args); + } + break; + case ExprNode::index : + { + BinaryExprNode *b = static_cast(p); + Register base = genExpr(b->op1); + Register index = genExpr(b->op2); + ret = getElement(base, index); + } + break; + case ExprNode::dot : + { + BinaryExprNode *b = static_cast(p); + Register base = genExpr(b->op1); + ret = getProperty(base, static_cast(b->op2)->name); + } + break; + case ExprNode::identifier : + { + /* + variable or name? If there's a 'with' in this scope, then it's + a name, otherwise look it up in the function variable map. + */ + + ret = loadName((static_cast(p))->name); + } + break; + case ExprNode::number : + ret = loadImmediate((static_cast(p))->value); + break; + case ExprNode::string : + ret = loadString(mWorld->identifiers[(static_cast(p))->str]); + break; + case ExprNode::postIncrement: + { + UnaryExprNode *u = static_cast(p); + if (u->op->getKind() == ExprNode::dot) { + BinaryExprNode *b = static_cast(u->op); + Register base = genExpr(b->op1); + ret = propertyInc(base, static_cast(b->op2)->name); + } + else + if (u->op->getKind() == ExprNode::identifier) { + // variable or name? see above + ret = nameInc((static_cast(u->op))->name); + } + else + if (u->op->getKind() == ExprNode::index) { + BinaryExprNode *b = static_cast(u->op); + Register base = genExpr(b->op1); + Register index = genExpr(b->op2); + ret = elementInc(base, index); + } + } + break; + case ExprNode::postDecrement: + { + UnaryExprNode *u = static_cast(p); + if (u->op->getKind() == ExprNode::dot) { + BinaryExprNode *b = static_cast(u->op); + Register base = genExpr(b->op1); + ret = propertyDec(base, static_cast(b->op2)->name); + } + else + if (u->op->getKind() == ExprNode::identifier) { + // variable or name? see above + ret = nameDec((static_cast(u->op))->name); + } + else + if (u->op->getKind() == ExprNode::index) { + BinaryExprNode *b = static_cast(u->op); + Register base = genExpr(b->op1); + Register index = genExpr(b->op2); + ret = elementInc(base, index); + } + } + break; + case ExprNode::plus: + case ExprNode::minus: + case ExprNode::complement: + { + UnaryExprNode *u = static_cast(p); + Register r = genExpr(u->op); + ret = op(mapExprNodeToICodeOp(p->getKind()), r); + } + break; + case ExprNode::add: + case ExprNode::subtract: + case ExprNode::multiply: + case ExprNode::divide: + case ExprNode::modulo: + case ExprNode::leftShift: + case ExprNode::rightShift: + case ExprNode::logicalRightShift: + case ExprNode::bitwiseAnd: + case ExprNode::bitwiseXor: + case ExprNode::bitwiseOr: + { + BinaryExprNode *b = static_cast(p); + Register r1 = genExpr(b->op1); + Register r2 = genExpr(b->op2); + ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2); + } + break; + case ExprNode::assignment: + { + BinaryExprNode *b = static_cast(p); + ret = genExpr(b->op2); + if (b->op1->getKind() == ExprNode::identifier) { + saveName((static_cast(b->op1))->name, ret); + } + else + if (b->op1->getKind() == ExprNode::dot) { + BinaryExprNode *lb = static_cast(b->op1); + Register base = genExpr(lb->op1); + setProperty(base, static_cast(lb->op2)->name, ret); + } + else + if (b->op1->getKind() == ExprNode::index) { + BinaryExprNode *lb = static_cast(b->op1); + Register base = genExpr(lb->op1); + Register index = genExpr(lb->op2); + setElement(base, index, ret); + } + } + break; + case ExprNode::equal: + case ExprNode::notEqual: + case ExprNode::lessThan: + case ExprNode::lessThanOrEqual: + case ExprNode::greaterThan: + case ExprNode::greaterThanOrEqual: + case ExprNode::identical: + case ExprNode::notIdentical: + case ExprNode::In: + case ExprNode::Instanceof: + { + BinaryExprNode *b = static_cast(p); + Register r1 = genExpr(b->op1); + Register r2 = genExpr(b->op2); + ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2); + if (trueBranch || falseBranch) { + if (trueBranch == NULL) + branchNotConditional(falseBranch, ret); + else { + branchConditional(trueBranch, ret); + if (falseBranch) + branch(falseBranch); + } + } + } + break; + case ExprNode::logicalAnd: + { + BinaryExprNode *b = static_cast(p); + if (trueBranch || falseBranch) { + genExpr(b->op1, needBoolValueInBranch, NULL, falseBranch); + genExpr(b->op2, needBoolValueInBranch, trueBranch, falseBranch); + } + else { + Label *fBranch = getLabel(); + Register r1 = genExpr(b->op1, true, NULL, fBranch); + if (!generatedBoolean(b->op1)) { + r1 = test(r1); + branchFalse(fBranch, r1); + } + Register r2 = genExpr(b->op2); + if (!generatedBoolean(b->op2)) { + r2 = test(r2); + } + if (r1 != r2) // FIXME, need a way to specify a dest??? + move(r1, r2); + setLabel(fBranch); + ret = r1; + } + } + break; + case ExprNode::logicalOr: + { + BinaryExprNode *b = static_cast(p); + if (trueBranch || falseBranch) { + genExpr(b->op1, needBoolValueInBranch, trueBranch, NULL); + genExpr(b->op2, needBoolValueInBranch, trueBranch, falseBranch); + } + else { + Label *tBranch = getLabel(); + Register r1 = genExpr(b->op1, true, tBranch, NULL); + if (!generatedBoolean(b->op1)) { + r1 = test(r1); + branchTrue(tBranch, r1); + } + Register r2 = genExpr(b->op2); + if (!generatedBoolean(b->op2)) { + r2 = test(r2); + } + if (r1 != r2) // FIXME, need a way to specify a dest??? + move(r1, r2); + setLabel(tBranch); + ret = r1; + } + } + break; + + case ExprNode::conditional: + { + TernaryExprNode *t = static_cast(p); + Label *fBranch = getLabel(); + Label *beyondBranch = getLabel(); + Register c = genExpr(t->op1, false, NULL, fBranch); + if (!generatedBoolean(t->op1)) { + c = test(c); + branchNotConditional(fBranch, c); + } + Register r1 = genExpr(t->op2); + branch(beyondBranch); + setLabel(fBranch); + Register r2 = genExpr(t->op3); + if (r1 != r2) // FIXME, need a way to specify a dest??? + move(r1, r2); + setLabel(beyondBranch); + ret = r1; + } + break; } + return ret; +} - /************************************************************************/ +/* + pre-pass to find: + variable & function definitions, + #nested switch statements + contains 'with' or 'eval' + contains 'try {} catch {} finally {}' +*/ - Formatter& ICodeGenerator::print(Formatter& f) - { - f << "ICG! " << (uint32)iCode->size() << "\n"; // << *iCode; - return VM::operator<<(f, *iCode); - } +/************************************************************************/ - Formatter& ICodeModule::print(Formatter& f) - { - f << "ICM! " << (uint32)its_iCode->size() << "\n"; - return VM::operator<<(f, *its_iCode); - } - -} // namespace ICG +Formatter& ICodeGenerator::print(Formatter& f) +{ + f << "ICG! " << (uint32)iCode->size() << "\n"; // << *iCode; + return VM::operator<<(f, *iCode); +} + +Formatter& ICodeModule::print(Formatter& f) +{ + f << "ICM! " << (uint32)its_iCode->size() << "\n"; + return VM::operator<<(f, *its_iCode); +} + +} // namespace ICG + } // namespace JavaScript diff --git a/mozilla/js2/src/icodegenerator.h b/mozilla/js2/src/icodegenerator.h index e6c4735b321..0d7ba55b2e1 100644 --- a/mozilla/js2/src/icodegenerator.h +++ b/mozilla/js2/src/icodegenerator.h @@ -131,6 +131,8 @@ namespace ICG { Register switchRegister; // register containing switch control value for most // recently in progress switch statement. VariableList *variableList; // name|register pair for each variable + + World *mWorld; // used to register strings @@ -158,6 +160,8 @@ namespace ICG { void branch(Label *label); void branchConditional(Label *label, Register condition); void branchNotConditional(Label *label, Register condition); + void branchTrue(Label *label, Register condition); + void branchFalse(Label *label, Register condition); void beginTry(Label *catchLabel, Label *finallyLabel) { iCode->push_back(new Tryin(catchLabel, finallyLabel)); } @@ -167,6 +171,8 @@ namespace ICG { void resetStatement() { if (labelSet) { delete labelSet; labelSet = NULL; } resetTopRegister(); } + ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind); + public: ICodeGenerator(World *world = NULL, bool hasTryStatement = false, @@ -182,14 +188,18 @@ namespace ICG { ICodeModule *complete(); + Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch = false, + Label *trueBranch = NULL, + Label *falseBranch = NULL); + + Register allocateVariable(const StringAtom& name) { Register result = getRegister(); (*variableList)[name] = result; registerBase = topRegister; return result; } Register findVariable(const StringAtom& name) { VariableList::iterator i = variableList->find(name); - // What's map? // ASSERT(i != map.end()); - return (*i).second; } + ASSERT(i != variableList->end()); return (*i).second; } Register allocateParameter(const StringAtom& name) { parameterCount++; return allocateVariable(name); } @@ -203,9 +213,11 @@ namespace ICG { void move(Register destination, Register source); void complement(Register destination, 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); @@ -224,7 +236,9 @@ namespace ICG { Register getElement(Register base, Register index); void setElement(Register base, Register index, Register value); - + Register elementInc(Register base, Register index); + Register elementDec(Register base, Register index); + Register getRegisterBase() { return topRegister; } InstructionStream *get_iCode() { return iCode; } StatementLabels *getStatementLabels() { return labelSet; labelSet = NULL; } @@ -285,7 +299,7 @@ namespace ICG { void beginLabelStatement(uint32 /* pos */, const StringAtom &label) { labelSet->push_back(&label); } - void endLabelStatement() { labelSet->pop_back(); } + void endLabelStatement() { if (labelSet) labelSet->pop_back(); } void continueStatement(uint32 pos); void breakStatement(uint32 pos); diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index 80314c280eb..4afb173fc4d 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -277,6 +277,21 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } break; +/* +versions below are not right, there is no 'array' type really, the index operation +turns into a get_property call like this, only we need to be using JSString throughout. + case GET_ELEMENT: + { + GetElement* ge = static_cast(instruction); + JSValue& base = (*registers)[src1(ge)]; + JSValue index = (*registers)[src2(ge)].toString(); + if (base.tag == JSValue::object_tag) { + JSObject* object = base.object; + (*registers)[dst(ge)] = object->getProperty(*index.string); + } + } + break; +*/ case GET_ELEMENT: { GetElement* ge = static_cast(instruction); @@ -297,6 +312,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } break; + case LOAD_IMMEDIATE: { LoadImmediate* li = static_cast(instruction); @@ -309,6 +325,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) (*registers)[dst(ls)] = JSValue(src1(ls)); } break; + case LOAD_VALUE: + { + LoadValue* lv = static_cast(instruction); + (*registers)[dst(lv)] = src1(lv); + } + break; case BRANCH: { GenericBranch* bra = @@ -357,6 +379,28 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } break; + case BRANCH_TRUE: + { + GenericBranch* bc = + static_cast(instruction); + ASSERT((*registers)[src1(bc)].isBoolean()); + if ((*registers)[src1(bc)].boolean) { + mPC = begin_pc + ofs(bc); + continue; + } + } + break; + case BRANCH_FALSE: + { + GenericBranch* bc = + static_cast(instruction); + ASSERT((*registers)[src1(bc)].isBoolean()); + if (!(*registers)[src1(bc)].boolean) { + mPC = begin_pc + ofs(bc); + continue; + } + } + break; case BRANCH_GE: { GenericBranch* bc = @@ -377,6 +421,74 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } break; + case SHIFTLEFT: + { + Arithmetic* shl = static_cast(instruction); + JSValue& dest = (*registers)[dst(shl)]; + JSValue& r1 = (*registers)[src1(shl)]; + JSValue& r2 = (*registers)[src2(shl)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toUInt32()); + dest = num1.i32 << (num2.u32 & 0x1F); + } + break; + case SHIFTRIGHT: + { + Arithmetic* shr = static_cast(instruction); + JSValue& dest = (*registers)[dst(shr)]; + JSValue& r1 = (*registers)[src1(shr)]; + JSValue& r2 = (*registers)[src2(shr)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toUInt32()); + dest = num1.i32 >> (num2.u32 & 0x1F); + } + break; + case USHIFTRIGHT: + { + Arithmetic* ushr = static_cast(instruction); + JSValue& dest = (*registers)[dst(ushr)]; + JSValue& r1 = (*registers)[src1(ushr)]; + JSValue& r2 = (*registers)[src2(ushr)]; + JSValue num1(r1.toUInt32()); + JSValue num2(r2.toUInt32()); + dest = num1.u32 >> (num2.u32 & 0x1F); + } + break; + + case AND: + { + Arithmetic* shr = static_cast(instruction); + JSValue& dest = (*registers)[dst(shr)]; + JSValue& r1 = (*registers)[src1(shr)]; + JSValue& r2 = (*registers)[src2(shr)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toInt32()); + dest = num1.i32 & num2.i32; + } + break; + case OR: + { + Arithmetic* shr = static_cast(instruction); + JSValue& dest = (*registers)[dst(shr)]; + JSValue& r1 = (*registers)[src1(shr)]; + JSValue& r2 = (*registers)[src2(shr)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toInt32()); + dest = num1.i32 | num2.i32; + } + break; + case XOR: + { + Arithmetic* shr = static_cast(instruction); + JSValue& dest = (*registers)[dst(shr)]; + JSValue& r1 = (*registers)[src1(shr)]; + JSValue& r2 = (*registers)[src2(shr)]; + JSValue num1(r1.toInt32()); + JSValue num2(r2.toInt32()); + dest = num1.i32 ^ num2.i32; + } + break; + case ADD: { // could get clever here with Functional forms. @@ -462,11 +574,10 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) JSValue r = mGlobal->getVariable(*src1(nx)).toNumber(); dest = r; r.f64 += val3(nx); - mGlobal->setVariable(*src1(nx), dest); + mGlobal->setVariable(*src1(nx), r); } break; - case COMPARE_LT: case COMPARE_LE: case COMPARE_EQ: @@ -475,11 +586,44 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case COMPARE_GE: { Arithmetic* cmp = static_cast(instruction); - float64 diff = - ((*registers)[src1(cmp)].f64 - - (*registers)[src2(cmp)].f64); - (*registers)[dst(cmp)] = - JSValue(int32(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1))); + JSValue& dest = (*registers)[dst(cmp)]; + JSValue lv = (*registers)[src1(cmp)].toPrimitive(JSValue::Number); + JSValue rv = (*registers)[src2(cmp)].toPrimitive(JSValue::Number); + if (lv.isString() && rv.isString()) { + // XXX FIXME urgh, call w_strcmp ??? on a JSString ??? + } + else { + lv = lv.toNumber(); + rv = rv.toNumber(); + if (lv.isNaN() || rv.isNaN()) + dest = JSValue(); + else { + // FIXME, does this do the right thing for +/- infinity? + switch (instruction->op()) { + case COMPARE_LT: + dest = JSValue(lv.f64 < rv.f64); break; + case COMPARE_LE: + dest = JSValue(lv.f64 <= rv.f64); break; + case COMPARE_EQ: + dest = JSValue(lv.f64 == rv.f64); break; + case COMPARE_NE: + dest = JSValue(lv.f64 != rv.f64); break; + case COMPARE_GT: + dest = JSValue(lv.f64 > rv.f64); break; + case COMPARE_GE: + dest = JSValue(lv.f64 >= rv.f64); break; + } +// float64 diff = lv.f64 - rv.f64; +// dest = JSValue( (int32) (diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1))); + } + } + + } + break; + case TEST: + { + Test* tst = static_cast(instruction); + (*registers)[dst(tst)] = (*registers)[src1(tst)].toBoolean(); } break; case NEGATE: @@ -494,6 +638,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) (*registers)[dst(pos)] = (*registers)[src1(pos)].toNumber(); } break; + case BITNOT: + { + Bitnot* bn = static_cast(instruction); + (*registers)[dst(bn)] = JSValue(~(*registers)[src1(bn)].toInt32().i32); + } + break; +/* case NOT: { Not* nt = static_cast(instruction); @@ -501,7 +652,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) JSValue(int32(!(*registers)[src1(nt)].i32)); } break; - +*/ case THROW: { Throw* thrw = static_cast(instruction); @@ -610,7 +761,7 @@ void Context::addListener(Listener* listener) void Context::removeListener(Listener* listener) { ListenerIterator e = mListeners.end(); - ListenerIterator l = find(mListeners.begin(), e, listener); + ListenerIterator l = std::find(mListeners.begin(), e, listener); if (l != e) mListeners.erase(l); } diff --git a/mozilla/js2/src/jstypes.cpp b/mozilla/js2/src/jstypes.cpp index 4596926228e..03582f4258e 100644 --- a/mozilla/js2/src/jstypes.cpp +++ b/mozilla/js2/src/jstypes.cpp @@ -40,18 +40,54 @@ namespace JSTypes { // using JavaScript::StringAtom; -// the canonical undefined value. +// the canonical undefined value, etc. const JSValue kUndefinedValue; -const JSValue kNaN(0.0, 0.0); +const JSValue kNaN = JSValue(nan); +const JSValue kTrue = JSValue(true); +const JSValue kFalse = JSValue(false); + +#ifdef IS_LITTLE_ENDIAN +#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1]) +#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0]) +#else +#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0]) +#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1]) +#endif + +#define JSDOUBLE_HI32_SIGNBIT 0x80000000 +#define JSDOUBLE_HI32_EXPMASK 0x7ff00000 +#define JSDOUBLE_HI32_MANTMASK 0x000fffff + +#define JSDOUBLE_IS_NaN(x) \ + ((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \ + (JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK))) + +#define JSDOUBLE_IS_INFINITE(x) \ + ((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \ + !JSDOUBLE_LO32(x)) + +#define JSDOUBLE_IS_FINITE(x) \ + ((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK) + +#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \ + JSDOUBLE_LO32(d) == 0) - -JSValue::JSValue(float64 a, float64 b) +bool JSValue::isNaN() const { - f64 = a/b; - tag = f64_tag; + ASSERT(isNumber()); + switch (tag) { + case i32_tag: + case u32_tag: + return false; + case f64_tag: + return JSDOUBLE_IS_NaN(f64); + default: + NOT_REACHED("Broken compiler?"); + return true; + } } - + int JSValue::operator==(const JSValue& value) const { if (this->tag == value.tag) { @@ -62,6 +98,7 @@ int JSValue::operator==(const JSValue& value) const CASE(i32); CASE(u32); CASE(f32); CASE(i64); CASE(u64); CASE(f64); CASE(object); CASE(array); CASE(function); CASE(string); + CASE(boolean); #undef CASE // question: are all undefined values equal to one another? case undefined_tag: return 1; @@ -76,6 +113,9 @@ Formatter& operator<<(Formatter& f, const JSValue& value) case JSValue::i32_tag: f << float64(value.i32); break; + case JSValue::u32_tag: + f << float64(value.u32); + break; case JSValue::f64_tag: f << value.f64; break; @@ -87,39 +127,80 @@ Formatter& operator<<(Formatter& f, const JSValue& value) case JSValue::string_tag: f << *value.string; break; - default: + case JSValue::boolean_tag: + f << ((value.boolean) ? "true" : "false"); + break; + case JSValue::undefined_tag: f << "undefined"; break; + default: + NOT_REACHED("Bad tag"); } return f; } +JSValue JSValue::toPrimitive(ECMA_type hint) const +{ + switch (tag) { + case i32_tag: + case u32_tag: + case f64_tag: + case string_tag: + case boolean_tag: + case undefined_tag: + return *this; + + case object_tag: + case array_tag: + case function_tag: + if (hint == String) { + // FIXME + } + else { + // FIXME + } + break; + + default: + NOT_REACHED("Bad tag"); + } + return kUndefinedValue; +} + JSValue JSValue::valueToString(const JSValue& value) // can assume value is not a string { char *chrp; char buf[dtosStandardBufferSize]; switch (value.tag) { - case JSValue::i32_tag: + case i32_tag: chrp = doubleToStr(buf, dtosStandardBufferSize, value.i32, dtosStandard, 0); break; - case JSValue::f64_tag: + case u32_tag: + chrp = doubleToStr(buf, dtosStandardBufferSize, value.u32, dtosStandard, 0); + break; + case f64_tag: chrp = doubleToStr(buf, dtosStandardBufferSize, value.f64, dtosStandard, 0); break; - case JSValue::object_tag: + case object_tag: chrp = "object"; break; - case JSValue::array_tag: + case array_tag: chrp = "array"; break; - case JSValue::function_tag: + case function_tag: chrp = "function"; break; - case JSValue::string_tag: + case string_tag: return value; - default: + case boolean_tag: + chrp = (value.boolean) ? "true" : "false"; + break; + case undefined_tag: chrp = "undefined"; break; + default: + NOT_REACHED("Bad tag"); } return JSValue(new JSString(chrp)); } @@ -127,25 +208,142 @@ JSValue JSValue::valueToString(const JSValue& value) // can assume value is not JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not a number { switch (value.tag) { - case JSValue::i32_tag: - case JSValue::f64_tag: + case i32_tag: + return JSValue((float64)value.i32); + case u32_tag: + return JSValue((float64)value.u32); + case f64_tag: return value; - case JSValue::string_tag: + case string_tag: { JSString* str = value.string; const char16 *numEnd; double d = stringToDouble(str->begin(), str->end(), numEnd); return JSValue(d); } - case JSValue::object_tag: - case JSValue::array_tag: - case JSValue::function_tag: - break; - default: + case object_tag: + case array_tag: + case function_tag: + // XXX more needed : + // toNumber(toPrimitive(hint Number)) + return kUndefinedValue; + case boolean_tag: + return JSValue((value.boolean) ? 1.0 : 0.0); + case undefined_tag: return kNaN; - break; + default: + NOT_REACHED("Bad tag"); + return kUndefinedValue; } - return kUndefinedValue; +} + +JSValue JSValue::valueToBoolean(const JSValue& value) +{ + switch (value.tag) { + case i32_tag: + return JSValue(value.i32 != 0); + case u32_tag: + return JSValue(value.u32 != 0); + case f64_tag: + return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64)); + case string_tag: + return JSValue(value.string->length() != 0); + case boolean_tag: + return value; + case object_tag: + case array_tag: + case function_tag: + return kTrue; + case undefined_tag: + return kFalse; + default: + NOT_REACHED("Bad tag"); + return kUndefinedValue; + } +} + + +static const double two32 = 4294967296.0; +static const double two31 = 2147483648.0; + +JSValue JSValue::valueToInt32(const JSValue& value) +{ + double d; + switch (value.tag) { + case i32_tag: + return value; + case u32_tag: + d = value.u32; + break; + case f64_tag: + d = value.f64; + break; + case string_tag: + { + JSString* str = value.string; + const char16 *numEnd; + d = stringToDouble(str->begin(), str->end(), numEnd); + } + break; + case boolean_tag: + return JSValue((int32)((value.boolean) ? 1 : 0)); + case object_tag: + case array_tag: + case undefined_tag: + // toNumber(toPrimitive(hint Number)) + return kUndefinedValue; + default: + NOT_REACHED("Bad tag"); + return kUndefinedValue; + } + if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) ) + return JSValue((int32)0); + d = fmod(d, two32); + d = (d >= 0) ? d : d + two32; + if (d >= two31) + return JSValue((int32)(d - two32)); + else + return JSValue((int32)d); + +} + +JSValue JSValue::valueToUInt32(const JSValue& value) +{ + double d; + switch (value.tag) { + case i32_tag: + return JSValue((uint32)value.i32); + case u32_tag: + return value; + case f64_tag: + d = value.f64; + break; + case string_tag: + { + JSString* str = value.string; + const char16 *numEnd; + d = stringToDouble(str->begin(), str->end(), numEnd); + } + break; + case boolean_tag: + return JSValue((uint32)((value.boolean) ? 1 : 0)); + case object_tag: + case array_tag: + case undefined_tag: + // toNumber(toPrimitive(hint Number)) + return kUndefinedValue; + default: + NOT_REACHED("Bad tag"); + return kUndefinedValue; + } + if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d)) + return JSValue((uint32)0); + bool neg = (d < 0); + d = floor(neg ? -d : d); + d = neg ? -d : d; + d = fmod(d, two32); + d = (d >= 0) ? d : d + two32; + return JSValue((uint32)d); } JSFunction::~JSFunction() diff --git a/mozilla/js2/src/jstypes.h b/mozilla/js2/src/jstypes.h index 3d73456f36e..87ed30667d9 100644 --- a/mozilla/js2/src/jstypes.h +++ b/mozilla/js2/src/jstypes.h @@ -76,44 +76,66 @@ namespace JSTypes { JSArray* array; JSFunction *function; JSString *string; + bool boolean; }; + /* These are the ECMA types, for use in 'toPrimitive' calls */ + enum ECMA_type { + Undefined, Null, Boolean, Number, Object, String, + NoHint + }; + enum { i8_tag, u8_tag, i16_tag, u16_tag, i32_tag, u32_tag, i64_tag, u64_tag, f32_tag, f64_tag, - object_tag, array_tag, function_tag, string_tag, + object_tag, array_tag, function_tag, string_tag, boolean_tag, undefined_tag } tag; JSValue() : f64(0.0), tag(undefined_tag) {} explicit JSValue(int32 i32) : i32(i32), tag(i32_tag) {} + explicit JSValue(uint32 u32) : u32(u32), tag(u32_tag) {} explicit JSValue(float64 f64) : f64(f64), tag(f64_tag) {} explicit JSValue(JSObject* object) : object(object), tag(object_tag) {} explicit JSValue(JSArray* array) : array(array), tag(array_tag) {} explicit JSValue(JSFunction* function) : function(function), tag(function_tag) {} explicit JSValue(JSString* string) : string(string), tag(string_tag) {} + explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {} - JSValue(float64 a, float64 b); - int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); } + uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); } float64& operator=(float64 f64) { return (tag = f64_tag, this->f64 = f64); } JSObject*& operator=(JSObject* object) { return (tag = object_tag, this->object = object); } JSArray*& operator=(JSArray* array) { return (tag = array_tag, this->array = array); } JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); } JSString*& operator=(JSString* string) { return (tag = string_tag, this->string = string); } + bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); } bool isString() const { return (tag == string_tag); } - bool isNumber() const { return ((tag == f64_tag) || (tag == i32_tag)); } + bool isBoolean() const { return (tag == boolean_tag); } + bool isNumber() const { return (tag == f64_tag); } + /* this is correct wrt ECMA, The i32 & u32 kinds + will have to be converted to doubles anyway because + we can't have overflow happening in generic arithmetic */ + bool isNaN() const; JSValue toString() const { return (isString() ? *this : valueToString(*this)); } JSValue toNumber() const { return (isNumber() ? *this : valueToNumber(*this)); } + JSValue toInt32() const { return ((tag == i32_tag) ? *this : valueToInt32(*this)); } + JSValue toUInt32() const { return ((tag == u32_tag) ? *this : valueToUInt32(*this)); } + JSValue toBoolean() const { return ((tag == boolean_tag) ? *this : valueToBoolean(*this)); } + + JSValue toPrimitive(ECMA_type hint = NoHint) const; static JSValue valueToString(const JSValue& value); static JSValue valueToNumber(const JSValue& value); + static JSValue valueToInt32(const JSValue& value); + static JSValue valueToUInt32(const JSValue& value); + static JSValue valueToBoolean(const JSValue& value); int operator==(const JSValue& value) const; }; @@ -140,6 +162,8 @@ namespace JSTypes { extern const JSValue kUndefinedValue; extern const JSValue kNaN; + extern const JSValue kTrue; + extern const JSValue kFalse; /** * Basic behavior of all JS objects, mapping a name to a value, diff --git a/mozilla/js2/src/vmtypes.cpp b/mozilla/js2/src/vmtypes.cpp index 6d49b5d3a37..27d7dcc1a6d 100644 --- a/mozilla/js2/src/vmtypes.cpp +++ b/mozilla/js2/src/vmtypes.cpp @@ -107,6 +107,30 @@ namespace VM { return f; } + ICodeOp Instruction::getBranchOp() + { + // XXX FIXME, convert to table lookup or arithmetic after the dust settles + switch (mOpcode) { + case COMPARE_EQ: +// return BRANCH_EQ; + case COMPARE_NE: +// return BRANCH_NE; + case COMPARE_GE: +// return BRANCH_GE; + case COMPARE_GT: +// return BRANCH_GT; + case COMPARE_LE: +// return BRANCH_LE; + case COMPARE_LT: +// return BRANCH_LT; + case TEST: + return BRANCH_TRUE; + default: + NOT_REACHED("Unexpected branch code"); + return NOP; + } + } + } /* namespace VM */ } /* namespace JavaScript */ diff --git a/mozilla/js2/src/vmtypes.h b/mozilla/js2/src/vmtypes.h index da8512f483e..ca119ec786a 100644 --- a/mozilla/js2/src/vmtypes.h +++ b/mozilla/js2/src/vmtypes.h @@ -42,6 +42,7 @@ namespace JavaScript { namespace VM { + using JSTypes::JSValue; using JSTypes::JSValues; using JSTypes::JSString; @@ -51,11 +52,13 @@ namespace VM { BITNOT, /* dest, source */ BRANCH, /* target label */ BRANCH_EQ, /* target label, condition */ + BRANCH_FALSE, /* target label, condition */ BRANCH_GE, /* target label, condition */ BRANCH_GT, /* target label, condition */ BRANCH_LE, /* target label, condition */ BRANCH_LT, /* target label, condition */ BRANCH_NE, /* target label, condition */ + BRANCH_TRUE, /* target label, condition */ CALL, /* result, target, args */ COMPARE_EQ, /* dest, source */ COMPARE_GE, /* dest, source */ @@ -65,13 +68,15 @@ namespace VM { COMPARE_LT, /* dest, source */ COMPARE_NE, /* dest, source */ DIVIDE, /* dest, source1, source2 */ - GET_ELEMENT, /* dest, array, index */ + ELEM_XCR, /* dest, base, index, value */ + GET_ELEMENT, /* dest, base, index */ GET_PROP, /* dest, object, prop name */ INSTANCEOF, /* dest, source */ JSR, /* target */ LOAD_IMMEDIATE, /* dest, immediate value (double) */ LOAD_NAME, /* dest, name */ LOAD_STRING, /* dest, immediate value (string) */ + LOAD_VALUE, /* dest, immediate value (JSValue) */ MOVE, /* dest, source */ MULTIPLY, /* dest, source1, source2 */ NAME_XCR, /* dest, name, value */ @@ -88,13 +93,14 @@ namespace VM { RETURN_VOID, /* Return without a value */ RTS, /* Return to sender */ SAVE_NAME, /* name, source */ - SET_ELEMENT, /* base, source1, source2 */ + SET_ELEMENT, /* base, index, value */ SET_PROP, /* object, name, source */ SHIFTLEFT, /* dest, source1, source2 */ SHIFTRIGHT, /* dest, source1, source2 */ STRICT_EQ, /* dest, source */ STRICT_NE, /* dest, source */ SUBTRACT, /* dest, source1, source2 */ + TEST, /* dest, source */ THROW, /* exception value */ TRYIN, /* catch target, finally target */ TRYOUT, /* mmm, there is no try, only do */ @@ -114,11 +120,13 @@ namespace VM { "BITNOT ", "BRANCH ", "BRANCH_EQ ", + "BRANCH_FALSE ", "BRANCH_GE ", "BRANCH_GT ", "BRANCH_LE ", "BRANCH_LT ", "BRANCH_NE ", + "BRANCH_TRUE ", "CALL ", "COMPARE_EQ ", "COMPARE_GE ", @@ -128,6 +136,7 @@ namespace VM { "COMPARE_LT ", "COMPARE_NE ", "DIVIDE ", + "ELEM_XCR ", "GET_ELEMENT ", "GET_PROP ", "INSTANCEOF ", @@ -135,6 +144,7 @@ namespace VM { "LOAD_IMMEDIATE", "LOAD_NAME ", "LOAD_STRING ", + "LOAD_VALUE ", "MOVE ", "MULTIPLY ", "NAME_XCR ", @@ -158,6 +168,7 @@ namespace VM { "STRICT_EQ ", "STRICT_NE ", "SUBTRACT ", + "TEST ", "THROW ", "TRYIN ", "TRYOUT ", @@ -188,11 +199,7 @@ namespace VM { return f; } - ICodeOp getBranchOp() - { - return ((mOpcode >= COMPARE_EQ) && (mOpcode <= COMPARE_NE)) ? - (ICodeOp)(BRANCH_EQ + (mOpcode - COMPARE_EQ)) : NOP; - } + ICodeOp getBranchOp(); ICodeOp op() { return mOpcode; } @@ -445,6 +452,15 @@ namespace VM { /* print() and printOperands() inherited from GenericBranch */ }; + class BranchFalse : public GenericBranch { + public: + /* target label, condition */ + BranchFalse (Label* aOp1, Register aOp2) : + GenericBranch + (BRANCH_FALSE, aOp1, aOp2) {}; + /* print() and printOperands() inherited from GenericBranch */ + }; + class BranchGE : public GenericBranch { public: /* target label, condition */ @@ -490,6 +506,15 @@ namespace VM { /* print() and printOperands() inherited from GenericBranch */ }; + class BranchTrue : public GenericBranch { + public: + /* target label, condition */ + BranchTrue (Label* aOp1, Register aOp2) : + GenericBranch + (BRANCH_TRUE, aOp1, aOp2) {}; + /* print() and printOperands() inherited from GenericBranch */ + }; + class Call : public Instruction_3 { public: /* result, target, args */ @@ -578,6 +603,22 @@ namespace VM { /* print() and printOperands() inherited from Arithmetic */ }; + class ElemXcr : public Instruction_4 { + public: + /* dest, base, index, value */ + ElemXcr (Register aOp1, Register aOp2, Register aOp3, double aOp4) : + Instruction_4 + (ELEM_XCR, aOp1, aOp2, aOp3, aOp4) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[ELEM_XCR] << "\t" << "R" << mOp1 << ", " << "R" << mOp2 << ", " << "R" << mOp3 << ", " << mOp4; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1 << '=' << registers[mOp1] << ", " << "R" << mOp2 << '=' << registers[mOp2] << ", " << "R" << mOp3 << '=' << registers[mOp3]; + return f; + } + }; + class GetElement : public Instruction_3 { public: /* dest, array, index */ @@ -682,6 +723,22 @@ namespace VM { } }; + class LoadValue : public Instruction_2 { + public: + /* dest, immediate value (JSValue) */ + LoadValue (Register aOp1, JSValue aOp2) : + Instruction_2 + (LOAD_VALUE, aOp1, aOp2) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[LOAD_VALUE] << "\t" << "R" << mOp1 << ", " << mOp2; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1 << '=' << registers[mOp1]; + return f; + } + }; + class Move : public Instruction_2 { public: /* dest, source */ @@ -991,6 +1048,22 @@ namespace VM { /* print() and printOperands() inherited from Arithmetic */ }; + class Test : public Instruction_2 { + public: + /* dest, source */ + Test (Register aOp1, Register aOp2) : + Instruction_2 + (TEST, aOp1, aOp2) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[TEST] << "\t" << "R" << mOp1 << ", " << "R" << mOp2; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1 << '=' << registers[mOp1] << ", " << "R" << mOp2 << '=' << registers[mOp2]; + return f; + } + }; + class Throw : public Instruction_1 { public: /* exception value */