/* -*- 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. */ #ifndef icodegenerator_h #define icodegenerator_h #include <vector> #include <stack> #include <iostream> #include "utilities.h" #include "parser.h" #include "vmtypes.h" #define NS_JSICG JavaScript::IGC namespace JavaScript { namespace ICG { using namespace VM; class ICodeGenerator; // forward declaration enum StateKind { While_state, If_state, Do_state, Switch_state, For_state }; class ICodeState { public : ICodeState(StateKind kind, ICodeGenerator *icg); // inline below virtual ~ICodeState() { } virtual Label *getBreakLabel(ICodeGenerator *) \ { ASSERT(false); return NULL; } virtual Label *getContinueLabel(ICodeGenerator *) \ { ASSERT(false); return NULL;} StateKind stateKind; Register registerBase; Label *breakLabel; Label *continueLabel; }; class ICodeModule { public: ICodeModule(InstructionStream *iCode, uint32 maxRegister, uint32 maxVariable) : its_iCode(iCode), itsMaxRegister(maxRegister), itsMaxVariable(maxVariable) { } InstructionStream *its_iCode; uint32 itsMaxRegister; uint32 itsMaxVariable; }; /****************************************************************/ // An ICodeGenerator provides the interface between the parser and the // interpreter. The parser constructs one of these for each // function/script, adds statements and expressions to it and then // converts it into an ICodeModule, ready for execution. class ICodeGenerator { private: InstructionStream *iCode; LabelList labels; std::vector<ICodeState *> stitcher; void markMaxRegister() \ { if (topRegister > maxRegister) maxRegister = topRegister; } void markMaxVariable(uint32 variableIndex) \ { if (variableIndex > maxVariable) maxVariable = variableIndex; } Register topRegister; Register registerBase; Register getRegister() \ { return topRegister++; } void resetTopRegister() \ { markMaxRegister(); topRegister = stitcher.empty() ? registerBase : \ stitcher.back()->registerBase; } ICodeOp getBranchOp() \ { ASSERT(!iCode->empty()); return iCode->back()->getBranchOp(); } uint32 maxRegister; uint32 maxVariable; void setLabel(Label *label); void setLabel(InstructionStream *stream, Label *label); void branch(Label *label); void branchConditional(Label *label, Register condition); public: ICodeGenerator() : topRegister(0), registerBase(0), maxRegister(0), maxVariable(0) \ { iCode = new InstructionStream(); } virtual ~ICodeGenerator() { if (iCode) delete iCode; } void mergeStream(InstructionStream *sideStream); ICodeModule *complete(); Register allocateVariable(StringAtom &name) { Register result = getRegister(); registerBase = topRegister; return result; } Formatter& print(Formatter& f); Register op(ICodeOp op, Register source); Register op(ICodeOp op, Register source1, Register source2); Register call(Register target, RegisterList args); void move(Register destination, Register source); Register compare(ICodeOp op, Register source1, Register source2); Register loadVariable(uint32 frameIndex); Register loadImmediate(double value); void saveVariable(uint32 frameIndex, Register value); Register newObject(); Register newArray(); Register loadName(StringAtom &name); void saveName(StringAtom &name, Register value); Register getProperty(Register base, StringAtom &name); void setProperty(Register base, StringAtom &name, Register value); Register getElement(Register base, Register index); void setElement(Register base, Register index, Register value); Register getRegisterBase() { return topRegister; } InstructionStream *get_iCode() { return iCode; } Label *getLabel(); // Rather than have the ICG client maniplate labels and branches, it // uses the following calls to describe the high level looping // constructs being generated. The functions listed below are // expected to be called in the order listed for each construct, // (internal error otherwise). // The ICG will enforce correct nesting and closing. // expression statements void beginStatement(uint32 /*pos*/) { resetTopRegister(); } void returnStatement() { iCode->push_back(new Return()); } void returnStatement(Register result) \ { iCode->push_back(new Return(result)); } void beginWhileStatement(uint32 pos); void endWhileExpression(Register condition); void endWhileStatement(); void beginDoStatement(uint32 pos); void endDoStatement(); void endDoExpression(Register condition); void beginIfStatement(uint32 pos, Register condition); void beginElseStatement(bool hasElse); // required, regardless of // existence of else clause void endIfStatement(); // for ( ... in ...) statements get turned into generic for // statements by the parser (ok?) void beginForStatement(uint32 pos); // for initialization is // emitted prior to this call void forCondition(Register condition); // required void forIncrement(); // required void endForStatement(); void beginSwitchStatement(uint32 pos, Register expression); void endCaseCondition(Register expression); void beginCaseStatement(); void endCaseStatement(); // optionally void beginDefaultStatement(); void endDefaultStatement(); void endSwitchStatement(); void labelStatement(const StringAtom &label); // adds to label set // for next statement, removed when that statement is finished void continueStatement(); void breakStatement(); void continueStatement(const StringAtom &label); void breakStatement(const StringAtom &label); void throwStatement(Register expression); void beginCatchStatement(); void endCatchExpression(Register expression); void endCatchStatement(); }; Formatter& operator<<(Formatter &f, ICodeGenerator &i); /* std::ostream &operator<<(std::ostream &s, ICodeGenerator &i); std::ostream &operator<<(std::ostream &s, StringAtom &str); */ class WhileCodeState : public ICodeState { public: WhileCodeState(Label *conditionLabel, Label *bodyLabel, ICodeGenerator *icg); // inline below InstructionStream *swapStream(InstructionStream *iCode) \ { InstructionStream *t = whileExpressionStream; \ whileExpressionStream = iCode; return t; } virtual Label *getBreakLabel(ICodeGenerator *icg) \ { if (breakLabel == NULL) breakLabel = icg->getLabel(); \ return breakLabel; } virtual Label *getContinueLabel(ICodeGenerator *) \ { return whileCondition; } Label *whileCondition; Label *whileBody; InstructionStream *whileExpressionStream; }; class ForCodeState : public ICodeState { public: ForCodeState(Label *conditionLabel, Label *bodyLabel, ICodeGenerator *icg); // inline below InstructionStream *swapStream(InstructionStream *iCode) \ { InstructionStream *t = forConditionStream; \ forConditionStream = iCode; return t; } InstructionStream *swapStream2(InstructionStream *iCode) \ { InstructionStream *t = forIncrementStream; \ forIncrementStream = iCode; return t; } virtual Label *getBreakLabel(ICodeGenerator *icg) \ { if (breakLabel == NULL) breakLabel = icg->getLabel(); \ return breakLabel; } virtual Label *getContinueLabel(ICodeGenerator *) \ { ASSERT(continueLabel); return continueLabel; } Label *forCondition; Label *forBody; InstructionStream *forConditionStream; InstructionStream *forIncrementStream; }; class IfCodeState : public ICodeState { public: IfCodeState(Label *a, Label *b, ICodeGenerator *icg) : ICodeState(If_state, icg), elseLabel(a), beyondElse(b) { } Label *elseLabel; Label *beyondElse; }; class DoCodeState : public ICodeState { public: DoCodeState(Label *bodyLabel, Label *conditionLabel, ICodeGenerator *icg) : ICodeState(Do_state, icg), doBody(bodyLabel), doCondition(conditionLabel) { } virtual Label *getBreakLabel(ICodeGenerator *icg) \ { if (breakLabel == NULL) breakLabel = icg->getLabel(); return breakLabel; } virtual Label *getContinueLabel(ICodeGenerator *) \ { return doCondition; } Label *doBody; Label *doCondition; }; class SwitchCodeState : public ICodeState { public: SwitchCodeState(Register control, ICodeGenerator *icg); // inline below InstructionStream *swapStream(InstructionStream *iCode) \ { InstructionStream *t = caseStatementsStream; \ caseStatementsStream = iCode; return t; } virtual Label *getBreakLabel(ICodeGenerator *icg) \ { if (breakLabel == NULL) breakLabel = icg->getLabel(); return breakLabel; } Register controlExpression; Label *defaultLabel; InstructionStream *caseStatementsStream; }; inline ICodeState::ICodeState(StateKind kind, ICodeGenerator *icg) : stateKind(kind), registerBase(icg->getRegisterBase()), breakLabel(NULL), continueLabel(NULL) { } inline SwitchCodeState::SwitchCodeState(Register control, ICodeGenerator *icg) : ICodeState(Switch_state, icg), controlExpression(control), defaultLabel(NULL), caseStatementsStream(icg->get_iCode()) {} inline WhileCodeState::WhileCodeState(Label *conditionLabel, Label *bodyLabel, ICodeGenerator *icg) : ICodeState(While_state, icg), whileCondition(conditionLabel), whileBody(bodyLabel), whileExpressionStream(icg->get_iCode()) {} inline ForCodeState::ForCodeState(Label *conditionLabel, Label *bodyLabel, ICodeGenerator *icg) : ICodeState(For_state, icg), forCondition(conditionLabel), forBody(bodyLabel), forConditionStream(icg->get_iCode()), forIncrementStream(icg->get_iCode()) {} } /* namespace IGC */ } /* namespace JavaScript */ #endif /* icodegenerator_h */