зеркало из https://github.com/mozilla/pjs.git
formatting changes. use only one tab regardless of nested namespaces
This commit is contained in:
Родитель
0f465e4756
Коммит
3a06b96f97
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -42,304 +42,306 @@
|
|||
#include "parser.h"
|
||||
#include "vmtypes.h"
|
||||
|
||||
|
||||
#define NS_JSICG JavaScript::IGC
|
||||
|
||||
namespace JavaScript {
|
||||
namespace ICG {
|
||||
|
||||
using namespace VM;
|
||||
|
||||
class ICodeGenerator; // forward declaration
|
||||
namespace ICG {
|
||||
|
||||
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 getRegister() \
|
||||
{ return topRegister++; }
|
||||
void resetTopRegister() \
|
||||
{ markMaxRegister(); topRegister = stitcher.empty() ? 0 : \
|
||||
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);
|
||||
using namespace VM;
|
||||
|
||||
public:
|
||||
ICodeGenerator() : topRegister(0), maxRegister(0),
|
||||
maxVariable(0) \
|
||||
{ iCode = new InstructionStream(); }
|
||||
|
||||
virtual ~ICodeGenerator() { if (iCode) delete iCode; }
|
||||
|
||||
void mergeStream(InstructionStream *sideStream);
|
||||
|
||||
ICodeModule *complete();
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
Register op(ICodeOp op, Register source);
|
||||
Register op(ICodeOp op, Register source1, Register source2);
|
||||
Register call(Register target, RegisterList args);
|
||||
|
||||
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(); }
|
||||
class ICodeGenerator; // forward declaration
|
||||
|
||||
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);
|
||||
enum StateKind {
|
||||
While_state,
|
||||
If_state,
|
||||
Do_state,
|
||||
Switch_state,
|
||||
For_state
|
||||
};
|
||||
|
||||
void beginCaseStatement();
|
||||
void endCaseStatement();
|
||||
class ICodeState {
|
||||
public :
|
||||
ICodeState(StateKind kind, ICodeGenerator *icg); // inline below
|
||||
virtual ~ICodeState() { }
|
||||
|
||||
// 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 *) \
|
||||
{ ASSERT(false); return NULL; }
|
||||
virtual Label *getContinueLabel(ICodeGenerator *) \
|
||||
{ ASSERT(false); return NULL;}
|
||||
|
||||
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 */
|
||||
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 getRegister() \
|
||||
{ return topRegister++; }
|
||||
void resetTopRegister() \
|
||||
{ markMaxRegister(); topRegister = stitcher.empty() ? 0 : \
|
||||
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), maxRegister(0),
|
||||
maxVariable(0) \
|
||||
{ iCode = new InstructionStream(); }
|
||||
|
||||
virtual ~ICodeGenerator() { if (iCode) delete iCode; }
|
||||
|
||||
void mergeStream(InstructionStream *sideStream);
|
||||
|
||||
ICodeModule *complete();
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
Register op(ICodeOp op, Register source);
|
||||
Register op(ICodeOp op, Register source1, Register source2);
|
||||
Register call(Register target, RegisterList args);
|
||||
|
||||
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 */
|
||||
|
|
|
@ -22,280 +22,293 @@
|
|||
#include "vmtypes.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace Interpreter {
|
||||
namespace Interpreter {
|
||||
|
||||
using namespace JSTypes;
|
||||
// operand access macros.
|
||||
using namespace JSTypes;
|
||||
|
||||
// operand access macros.
|
||||
#define op1(i) (i->o1())
|
||||
#define op2(i) (i->o2())
|
||||
#define op3(i) (i->o3())
|
||||
|
||||
// mnemonic names for operands.
|
||||
// mnemonic names for operands.
|
||||
#define dst(i) op1(i)
|
||||
#define src1(i) op2(i)
|
||||
#define src2(i) op3(i)
|
||||
#define ofs(i) (i->getOffset())
|
||||
|
||||
static JSObject globals;
|
||||
static JSObject globals;
|
||||
|
||||
JSValue& defineGlobalProperty(const String& name, const JSValue& value)
|
||||
{
|
||||
return (globals[name] = value);
|
||||
}
|
||||
JSValue& defineGlobalProperty(const String& name, const JSValue& value)
|
||||
{
|
||||
return (globals[name] = value);
|
||||
}
|
||||
|
||||
// FIXME: need to copy the ICodeModule's instruction stream.
|
||||
// FIXME: need to copy the ICodeModule's instruction stream.
|
||||
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode)
|
||||
{
|
||||
JSValue value;
|
||||
value.function = new JSFunction(iCode);
|
||||
return defineGlobalProperty(name, value);
|
||||
}
|
||||
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode)
|
||||
{
|
||||
JSValue value;
|
||||
value.function = new JSFunction(iCode);
|
||||
return defineGlobalProperty(name, value);
|
||||
}
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args)
|
||||
{
|
||||
// stack of JSFrames.
|
||||
// XXX is a linked list of activation's sufficient?
|
||||
JSFrameStack frames;
|
||||
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args)
|
||||
{
|
||||
// stack of JSFrames.
|
||||
// XXX is a linked list of activation's sufficient?
|
||||
JSFrameStack frames;
|
||||
// initial activation.
|
||||
JSActivation* activation = new JSActivation(iCode, args);
|
||||
JSValues* locals = &activation->mLocals;
|
||||
JSValues* registers = &activation->mRegisters;
|
||||
|
||||
// initial activation.
|
||||
JSActivation* activation = new JSActivation(iCode, args);
|
||||
JSValues* locals = &activation->mLocals;
|
||||
JSValues* registers = &activation->mRegisters;
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
|
||||
while (true) {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->op()) {
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
frames.push(new JSFrame(++pc, begin_pc, activation, op1(call)));
|
||||
ICodeModule* target = (*registers)[op2(call)].function->getICode();
|
||||
activation = new JSActivation(target, activation, op3(call));
|
||||
locals = &activation->mLocals;
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pc = target->its_iCode->begin();
|
||||
}
|
||||
while (true) {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->op()) {
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
frames.push(new JSFrame(++pc, begin_pc, activation,
|
||||
op1(call)));
|
||||
ICodeModule* target =
|
||||
(*registers)[op2(call)].function->getICode();
|
||||
activation = new JSActivation(target, activation, op3(call));
|
||||
locals = &activation->mLocals;
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pc = target->its_iCode->begin();
|
||||
}
|
||||
continue;
|
||||
case RETURN:
|
||||
{
|
||||
Return* ret = static_cast<Return*>(instruction);
|
||||
JSValue result;
|
||||
if (op1(ret) != NotARegister)
|
||||
result = (*registers)[op1(ret)];
|
||||
if (frames.empty())
|
||||
return result;
|
||||
JSFrame *frame = frames.top();
|
||||
frames.pop();
|
||||
activation = frame->itsActivation;
|
||||
registers = &activation->mRegisters;
|
||||
locals = &activation->mLocals;
|
||||
(*registers)[frame->itsResult] = result;
|
||||
pc = frame->itsReturnPC;
|
||||
begin_pc = frame->itsBasePC;
|
||||
}
|
||||
continue;
|
||||
case MOVE:
|
||||
{
|
||||
Move* mov = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(mov)] = (*registers)[src1(mov)];
|
||||
}
|
||||
break;
|
||||
case LOAD_NAME:
|
||||
{
|
||||
LoadName* ln = static_cast<LoadName*>(instruction);
|
||||
(*registers)[dst(ln)] = globals[*src1(ln)];
|
||||
}
|
||||
break;
|
||||
case SAVE_NAME:
|
||||
{
|
||||
SaveName* sn = static_cast<SaveName*>(instruction);
|
||||
globals[*dst(sn)] = (*registers)[src1(sn)];
|
||||
}
|
||||
break;
|
||||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
(*registers)[dst(no)].object = new JSObject();
|
||||
}
|
||||
break;
|
||||
case NEW_ARRAY:
|
||||
{
|
||||
NewArray* na = static_cast<NewArray*>(instruction);
|
||||
(*registers)[dst(na)].array = new JSArray();
|
||||
}
|
||||
break;
|
||||
case GET_PROP:
|
||||
{
|
||||
GetProp* gp = static_cast<GetProp*>(instruction);
|
||||
JSObject* object = (*registers)[src1(gp)].object;
|
||||
(*registers)[dst(gp)] = (*object)[*src2(gp)];
|
||||
}
|
||||
break;
|
||||
case SET_PROP:
|
||||
{
|
||||
SetProp* sp = static_cast<SetProp*>(instruction);
|
||||
JSObject* object = (*registers)[dst(sp)].object;
|
||||
(*object)[*src1(sp)] = (*registers)[src2(sp)];
|
||||
}
|
||||
break;
|
||||
case GET_ELEMENT:
|
||||
{
|
||||
GetElement* ge = static_cast<GetElement*>(instruction);
|
||||
JSArray* array = (*registers)[src1(ge)].array;
|
||||
(*registers)[dst(ge)] = (*array)[(*registers)[src2(ge)]];
|
||||
}
|
||||
break;
|
||||
case SET_ELEMENT:
|
||||
{
|
||||
SetElement* se = static_cast<SetElement*>(instruction);
|
||||
JSArray* array = (*registers)[dst(se)].array;
|
||||
(*array)[(*registers)[src1(se)]] = (*registers)[src2(se)];
|
||||
}
|
||||
break;
|
||||
case LOAD_IMMEDIATE:
|
||||
{
|
||||
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case LOAD_VAR:
|
||||
{
|
||||
LoadVar* lv = static_cast<LoadVar*>(instruction);
|
||||
(*registers)[dst(lv)] = (*locals)[src1(lv)];
|
||||
}
|
||||
break;
|
||||
case SAVE_VAR:
|
||||
{
|
||||
SaveVar* sv = static_cast<SaveVar*>(instruction);
|
||||
(*locals)[dst(sv)] = (*registers)[src1(sv)];
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
pc = begin_pc + ofs(bra);
|
||||
continue;
|
||||
case RETURN:
|
||||
{
|
||||
Return* ret = static_cast<Return*>(instruction);
|
||||
JSValue result;
|
||||
if (op1(ret) != NotARegister)
|
||||
result = (*registers)[op1(ret)];
|
||||
if (frames.empty())
|
||||
return result;
|
||||
JSFrame *frame = frames.top();
|
||||
frames.pop();
|
||||
activation = frame->itsActivation;
|
||||
registers = &activation->mRegisters;
|
||||
locals = &activation->mLocals;
|
||||
(*registers)[frame->itsResult] = result;
|
||||
pc = frame->itsReturnPC;
|
||||
begin_pc = frame->itsBasePC;
|
||||
}
|
||||
continue;
|
||||
case MOVE:
|
||||
{
|
||||
Move* mov = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(mov)] = (*registers)[src1(mov)];
|
||||
}
|
||||
break;
|
||||
case LOAD_NAME:
|
||||
{
|
||||
LoadName* ln = static_cast<LoadName*>(instruction);
|
||||
(*registers)[dst(ln)] = globals[*src1(ln)];
|
||||
}
|
||||
break;
|
||||
case SAVE_NAME:
|
||||
{
|
||||
SaveName* sn = static_cast<SaveName*>(instruction);
|
||||
globals[*dst(sn)] = (*registers)[src1(sn)];
|
||||
}
|
||||
break;
|
||||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
(*registers)[dst(no)].object = new JSObject();
|
||||
}
|
||||
break;
|
||||
case NEW_ARRAY:
|
||||
{
|
||||
NewArray* na = static_cast<NewArray*>(instruction);
|
||||
(*registers)[dst(na)].array = new JSArray();
|
||||
}
|
||||
break;
|
||||
case GET_PROP:
|
||||
{
|
||||
GetProp* gp = static_cast<GetProp*>(instruction);
|
||||
JSObject* object = (*registers)[src1(gp)].object;
|
||||
(*registers)[dst(gp)] = (*object)[*src2(gp)];
|
||||
}
|
||||
break;
|
||||
case SET_PROP:
|
||||
{
|
||||
SetProp* sp = static_cast<SetProp*>(instruction);
|
||||
JSObject* object = (*registers)[dst(sp)].object;
|
||||
(*object)[*src1(sp)] = (*registers)[src2(sp)];
|
||||
}
|
||||
break;
|
||||
case GET_ELEMENT:
|
||||
{
|
||||
GetElement* ge = static_cast<GetElement*>(instruction);
|
||||
JSArray* array = (*registers)[src1(ge)].array;
|
||||
(*registers)[dst(ge)] = (*array)[(*registers)[src2(ge)]];
|
||||
}
|
||||
break;
|
||||
case SET_ELEMENT:
|
||||
{
|
||||
SetElement* se = static_cast<SetElement*>(instruction);
|
||||
JSArray* array = (*registers)[dst(se)].array;
|
||||
(*array)[(*registers)[src1(se)]] = (*registers)[src2(se)];
|
||||
}
|
||||
break;
|
||||
case LOAD_IMMEDIATE:
|
||||
{
|
||||
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case LOAD_VAR:
|
||||
{
|
||||
LoadVar* lv = static_cast<LoadVar*>(instruction);
|
||||
(*registers)[dst(lv)] = (*locals)[src1(lv)];
|
||||
}
|
||||
break;
|
||||
case SAVE_VAR:
|
||||
{
|
||||
SaveVar* sv = static_cast<SaveVar*>(instruction);
|
||||
(*locals)[dst(sv)] = (*registers)[src1(sv)];
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
pc = begin_pc + ofs(bra);
|
||||
}
|
||||
break;
|
||||
case BRANCH_LT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 < 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case BRANCH_LT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 < 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_LE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 <= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_EQ:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 == 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_NE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 != 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 >= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 > 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] = JSValue((*registers)[src1(add)].f64 + (*registers)[src2(add)].f64);
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
{
|
||||
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(sub)] = JSValue((*registers)[src1(sub)].f64 - (*registers)[src2(sub)].f64);
|
||||
}
|
||||
break;
|
||||
case MULTIPLY:
|
||||
{
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(mul)] = JSValue((*registers)[src1(mul)].f64 * (*registers)[src2(mul)].f64);
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
{
|
||||
Arithmetic* div = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(div)] = JSValue((*registers)[src1(div)].f64 / (*registers)[src2(div)].f64);
|
||||
}
|
||||
break;
|
||||
case COMPARE_LT:
|
||||
case COMPARE_LE:
|
||||
case COMPARE_EQ:
|
||||
case COMPARE_NE:
|
||||
case COMPARE_GT:
|
||||
case COMPARE_GE:
|
||||
{
|
||||
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
|
||||
float64 diff = ((*registers)[src1(cmp)].f64 - (*registers)[src2(cmp)].f64);
|
||||
(*registers)[dst(cmp)].i32 = (diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Move* nt = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
break;
|
||||
case BRANCH_LE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 <= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_EQ:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 == 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_NE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 != 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 >= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 > 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] =
|
||||
JSValue((*registers)[src1(add)].f64 +
|
||||
(*registers)[src2(add)].f64);
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
{
|
||||
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(sub)] =
|
||||
JSValue((*registers)[src1(sub)].f64 -
|
||||
(*registers)[src2(sub)].f64);
|
||||
}
|
||||
break;
|
||||
case MULTIPLY:
|
||||
{
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(mul)] =
|
||||
JSValue((*registers)[src1(mul)].f64 *
|
||||
(*registers)[src2(mul)].f64);
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
{
|
||||
Arithmetic* div = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(div)] =
|
||||
JSValue((*registers)[src1(div)].f64 /
|
||||
(*registers)[src2(div)].f64);
|
||||
}
|
||||
break;
|
||||
case COMPARE_LT:
|
||||
case COMPARE_LE:
|
||||
case COMPARE_EQ:
|
||||
case COMPARE_NE:
|
||||
case COMPARE_GT:
|
||||
case COMPARE_GE:
|
||||
{
|
||||
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
|
||||
float64 diff =
|
||||
((*registers)[src1(cmp)].f64 -
|
||||
(*registers)[src2(cmp)].f64);
|
||||
(*registers)[dst(cmp)].i32 =
|
||||
(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Move* nt = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
|
||||
} /* interpret */
|
||||
} /* interpret */
|
||||
|
||||
} /* namespace Interpreter */
|
||||
|
||||
} /* namespace Interpreter */
|
||||
} /* namespace JavaScript */
|
||||
|
|
|
@ -25,18 +25,18 @@
|
|||
#include "icodegenerator.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace Interpreter {
|
||||
using namespace ICG;
|
||||
using namespace JSTypes;
|
||||
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
namespace Interpreter {
|
||||
|
||||
JSValue& defineGlobalProperty(const String& name,
|
||||
const JSValue& value);
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode);
|
||||
};
|
||||
using namespace ICG;
|
||||
using namespace JSTypes;
|
||||
|
||||
};
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
|
||||
JSValue& defineGlobalProperty(const String& name,
|
||||
const JSValue& value);
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode);
|
||||
|
||||
} /* namespace Interpreter */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
#endif /* interpreter_h */
|
||||
|
|
277
js/js2/jstypes.h
277
js/js2/jstypes.h
|
@ -44,183 +44,188 @@
|
|||
#include "icodegenerator.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace JSTypes {
|
||||
using namespace VM;
|
||||
using namespace ICG;
|
||||
namespace JSTypes {
|
||||
using namespace VM;
|
||||
using namespace ICG;
|
||||
|
||||
class JSObject;
|
||||
class JSArray;
|
||||
class JSFunction;
|
||||
|
||||
/**
|
||||
* All JavaScript data types.
|
||||
*/
|
||||
union JSValue {
|
||||
int8 i8;
|
||||
uint8 u8;
|
||||
int16 i16;
|
||||
uint16 u16;
|
||||
int32 i32;
|
||||
uint32 u32;
|
||||
int64 i64;
|
||||
uint64 u64;
|
||||
float32 f32;
|
||||
float64 f64;
|
||||
JSObject* object;
|
||||
JSArray* array;
|
||||
JSFunction *function;
|
||||
|
||||
class JSObject;
|
||||
class JSArray;
|
||||
class JSFunction;
|
||||
|
||||
/**
|
||||
* All JavaScript data types.
|
||||
*/
|
||||
union JSValue {
|
||||
int8 i8;
|
||||
uint8 u8;
|
||||
int16 i16;
|
||||
uint16 u16;
|
||||
int32 i32;
|
||||
uint32 u32;
|
||||
int64 i64;
|
||||
uint64 u64;
|
||||
float32 f32;
|
||||
float64 f64;
|
||||
JSObject* object;
|
||||
JSArray* array;
|
||||
JSFunction *function;
|
||||
JSValue() : f64(0.0) {}
|
||||
|
||||
JSValue() : f64(0.0) {}
|
||||
|
||||
explicit JSValue(float64 f64) : f64(f64) {}
|
||||
};
|
||||
explicit JSValue(float64 f64) : f64(f64) {}
|
||||
};
|
||||
|
||||
#if defined(XP_MAC)
|
||||
// copied from default template parameters in map.
|
||||
typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
|
||||
// copied from default template parameters in map.
|
||||
typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
|
||||
#elif defined(XP_UNIX)
|
||||
// FIXME: in libg++, they assume the map's allocator is a byte allocator,
|
||||
// which is wrapped in a simple_allocator. this is crap.
|
||||
typedef char _Char[1];
|
||||
typedef gc_allocator<_Char> gc_map_allocator;
|
||||
// FIXME: in libg++, they assume the map's allocator is a byte allocator,
|
||||
// which is wrapped in a simple_allocator. this is crap.
|
||||
typedef char _Char[1];
|
||||
typedef gc_allocator<_Char> gc_map_allocator;
|
||||
#elif defined(_WIN32)
|
||||
// FIXME: MSVC++'s notion. this is why we had to add _Charalloc().
|
||||
typedef gc_allocator<JSValue> gc_map_allocator;
|
||||
// FIXME: MSVC++'s notion. this is why we had to add _Charalloc().
|
||||
typedef gc_allocator<JSValue> gc_map_allocator;
|
||||
#endif
|
||||
|
||||
/**
|
||||
/**
|
||||
* GC-scannable array of values.
|
||||
*/
|
||||
typedef std::vector<JSValue, gc_allocator<JSValue> > JSValues;
|
||||
typedef std::vector<JSValue, gc_allocator<JSValue> > JSValues;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Basic behavior of all JS objects, mapping a name to a value.
|
||||
* This is provided mainly to avoid having an awkward implementation
|
||||
* of JSObject & JSArray, which must each define its own
|
||||
* gc_allocator. This is all in flux.
|
||||
*/
|
||||
class JSMap : public gc_base {
|
||||
std::map<String, JSValue, std::less<String>, gc_map_allocator> properties;
|
||||
public:
|
||||
JSValue& operator[](const String& name)
|
||||
{
|
||||
return properties[name];
|
||||
}
|
||||
};
|
||||
class JSMap : public gc_base {
|
||||
std::map<String, JSValue, std::less<String>,
|
||||
gc_map_allocator> properties;
|
||||
public:
|
||||
JSValue& operator[](const String& name)
|
||||
{
|
||||
return properties[name];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Private representation of a JavaScript object.
|
||||
* This will change over time, so it is treated as an opaque
|
||||
* type everywhere else but here.
|
||||
*/
|
||||
class JSObject : public JSMap {};
|
||||
class JSObject : public JSMap {};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Private representation of a JavaScript array.
|
||||
*/
|
||||
class JSArray : public JSMap {
|
||||
JSValues elements;
|
||||
public:
|
||||
JSArray() : elements(1) {}
|
||||
JSArray(uint32 size) : elements(size) {}
|
||||
JSArray(const JSValues &v) : elements(v) {}
|
||||
class JSArray : public JSMap {
|
||||
JSValues elements;
|
||||
public:
|
||||
JSArray() : elements(1) {}
|
||||
JSArray(uint32 size) : elements(size) {}
|
||||
JSArray(const JSValues &v) : elements(v) {}
|
||||
|
||||
uint32 length()
|
||||
{
|
||||
return elements.size();
|
||||
}
|
||||
uint32 length()
|
||||
{
|
||||
return elements.size();
|
||||
}
|
||||
|
||||
JSValue& operator[](const JSValue& index)
|
||||
{
|
||||
// for now, we can only handle f64 index values.
|
||||
uint32 n = (uint32)index.f64;
|
||||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
return elements[n];
|
||||
}
|
||||
JSValue& operator[](const JSValue& index)
|
||||
{
|
||||
// for now, we can only handle f64 index values.
|
||||
uint32 n = (uint32)index.f64;
|
||||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
return elements[n];
|
||||
}
|
||||
|
||||
JSValue& operator[](uint32 n)
|
||||
{
|
||||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
return elements[n];
|
||||
}
|
||||
JSValue& operator[](uint32 n)
|
||||
{
|
||||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
return elements[n];
|
||||
}
|
||||
|
||||
void resize(uint32 size)
|
||||
{
|
||||
elements.resize(size);
|
||||
}
|
||||
void resize(uint32 size)
|
||||
{
|
||||
elements.resize(size);
|
||||
}
|
||||
|
||||
private:
|
||||
void expand(uint32 n, uint32 size)
|
||||
{
|
||||
do {
|
||||
size *= 2;
|
||||
} while (n >= size);
|
||||
elements.resize(size);
|
||||
}
|
||||
};
|
||||
private:
|
||||
void expand(uint32 n, uint32 size)
|
||||
{
|
||||
do {
|
||||
size *= 2;
|
||||
} while (n >= size);
|
||||
elements.resize(size);
|
||||
}
|
||||
};
|
||||
|
||||
class JSFunction : public JSMap {
|
||||
ICodeModule* mICode;
|
||||
public:
|
||||
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
|
||||
ICodeModule* getICode() { return mICode; }
|
||||
};
|
||||
class JSFunction : public JSMap {
|
||||
ICodeModule* mICode;
|
||||
public:
|
||||
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
|
||||
ICodeModule* getICode() { return mICode; }
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Represents the current function's invocation state.
|
||||
*/
|
||||
struct JSActivation : public gc_base {
|
||||
JSValues mRegisters;
|
||||
JSValues mLocals;
|
||||
struct JSActivation : public gc_base {
|
||||
JSValues mRegisters;
|
||||
JSValues mLocals;
|
||||
|
||||
JSActivation(ICodeModule* iCode, const JSValues& args)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mLocals(args)
|
||||
{
|
||||
// ensure that locals array is large enough.
|
||||
uint32 localsSize = iCode->itsMaxVariable + 1;
|
||||
if (localsSize > mLocals.size())
|
||||
mLocals.resize(localsSize);
|
||||
}
|
||||
JSActivation(ICodeModule* iCode, const JSValues& args)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mLocals(args)
|
||||
{
|
||||
// ensure that locals array is large enough.
|
||||
uint32 localsSize = iCode->itsMaxVariable + 1;
|
||||
if (localsSize > mLocals.size())
|
||||
mLocals.resize(localsSize);
|
||||
}
|
||||
|
||||
JSActivation(ICodeModule* iCode, JSActivation* caller, const RegisterList& list)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mLocals(iCode->itsMaxVariable + 1)
|
||||
{
|
||||
// copy caller's parameter list in to locals.
|
||||
JSValues::iterator dest = mLocals.begin();
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (RegisterList::const_iterator src = list.begin(), end = list.end(); src != end; ++src, ++dest) {
|
||||
*dest = params[*src];
|
||||
}
|
||||
JSActivation(ICodeModule* iCode, JSActivation* caller,
|
||||
const RegisterList& list)
|
||||
: mRegisters(iCode->itsMaxRegister + 1),
|
||||
mLocals(iCode->itsMaxVariable + 1)
|
||||
{
|
||||
// copy caller's parameter list in to locals.
|
||||
JSValues::iterator dest = mLocals.begin();
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (RegisterList::const_iterator src = list.begin(),
|
||||
end = list.end(); src != end; ++src, ++dest) {
|
||||
*dest = params[*src];
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores saved state from the *previous* activation, the current activation is alive
|
||||
* and well in locals of the interpreter loop.
|
||||
/**
|
||||
* Stores saved state from the *previous* activation, the current activation is
|
||||
* alive and well in locals of the interpreter loop.
|
||||
*/
|
||||
struct JSFrame : public gc_base {
|
||||
JSFrame(InstructionIterator returnPC, InstructionIterator basePC,
|
||||
JSActivation* activation, Register result)
|
||||
: itsReturnPC(returnPC), itsBasePC(basePC),
|
||||
itsActivation(activation),
|
||||
itsResult(result)
|
||||
{
|
||||
}
|
||||
struct JSFrame : public gc_base {
|
||||
JSFrame(InstructionIterator returnPC, InstructionIterator basePC,
|
||||
JSActivation* activation, Register result)
|
||||
: itsReturnPC(returnPC), itsBasePC(basePC),
|
||||
itsActivation(activation),
|
||||
itsResult(result)
|
||||
{
|
||||
}
|
||||
|
||||
InstructionIterator itsReturnPC;
|
||||
InstructionIterator itsBasePC;
|
||||
JSActivation* itsActivation; // caller's activation.
|
||||
Register itsResult; // the desired target register for the return value
|
||||
};
|
||||
InstructionIterator itsReturnPC;
|
||||
InstructionIterator itsBasePC;
|
||||
JSActivation* itsActivation; // caller's activation.
|
||||
// the desired target register for the return value
|
||||
Register itsResult;
|
||||
};
|
||||
|
||||
// a stack of JSFrames.
|
||||
typedef std::stack<JSFrame*, std::vector<JSFrame*, gc_allocator<JSFrame*> > > JSFrameStack;
|
||||
// a stack of JSFrames.
|
||||
typedef std::stack<JSFrame*, std::vector<JSFrame*, gc_allocator<JSFrame*> > > JSFrameStack;
|
||||
|
||||
} /* namespace JSTypes */
|
||||
} /* namespace JSTypes */
|
||||
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use strict;
|
||||
|
||||
my $tab = " ";
|
||||
my $tab2 = " ";
|
||||
my $init_tab = $tab;
|
||||
my $enum_decs = "";
|
||||
my $class_decs = "";
|
||||
my @name_array;
|
||||
|
@ -186,20 +186,21 @@ sub collect {
|
|||
}
|
||||
|
||||
push (@name_array, $opname);
|
||||
$enum_decs .= "$tab2$tab$opname, /* $rem */\n";
|
||||
$class_decs .= ($tab2 . "class $cname : public $super {\n" .
|
||||
$tab2 . "public:\n" .
|
||||
$tab2 . $tab . "/* $rem */\n" .
|
||||
$tab2 . $tab . "$cname ($dec_list) :\n" .
|
||||
$tab2 . $tab . $tab . "$super\n$tab2$tab$tab($params) " .
|
||||
$enum_decs .= "$init_tab$tab$opname, /* $rem */\n";
|
||||
$class_decs .= ($init_tab . "class $cname : public $super {\n" .
|
||||
$init_tab . "public:\n" .
|
||||
$init_tab . $tab . "/* $rem */\n" .
|
||||
$init_tab . $tab . "$cname ($dec_list) :\n" .
|
||||
$init_tab . $tab . $tab . "$super\n" .
|
||||
"$init_tab$tab$tab($params) " .
|
||||
"{};\n" .
|
||||
$tab2 . $tab .
|
||||
$init_tab . $tab .
|
||||
"virtual Formatter& print (Formatter& f) {\n" .
|
||||
$tab2 . $tab . $tab . "f << opcodeNames[$opname];\n" .
|
||||
$init_tab . $tab . $tab . "f << opcodeNames[$opname];\n" .
|
||||
$printbody .
|
||||
$tab2 . $tab . $tab . "return f;\n" .
|
||||
$tab2 . $tab . "}\n" .
|
||||
$tab2 . "};\n\n");
|
||||
$init_tab . $tab . $tab . "return f;\n" .
|
||||
$init_tab . $tab . "}\n" .
|
||||
$init_tab . "};\n\n");
|
||||
}
|
||||
|
||||
sub spew {
|
||||
|
@ -274,7 +275,7 @@ sub get_printbody {
|
|||
my $type;
|
||||
my @oplist;
|
||||
my $op = 1;
|
||||
my $in = $tab2 . $tab . $tab;
|
||||
my $in = $init_tab . $tab . $tab;
|
||||
|
||||
for $type (@types) {
|
||||
print "type $type\n";
|
||||
|
|
|
@ -35,29 +35,28 @@
|
|||
#include "vmtypes.h"
|
||||
|
||||
namespace JavaScript {
|
||||
|
||||
namespace VM {
|
||||
namespace VM {
|
||||
|
||||
Formatter& operator<< (Formatter& f, Instruction& i)
|
||||
{
|
||||
return i.print(f);
|
||||
Formatter& operator<< (Formatter& f, Instruction& i)
|
||||
{
|
||||
return i.print(f);
|
||||
}
|
||||
|
||||
Formatter& operator<< (Formatter& f, RegisterList& rl)
|
||||
{
|
||||
Register* e = rl.end();
|
||||
|
||||
f << "(";
|
||||
for (RegisterList::iterator r = rl.begin(); r != e; r++) {
|
||||
f << "R" << (*r);
|
||||
if ((r + 1) != e)
|
||||
f << ", ";
|
||||
}
|
||||
|
||||
Formatter& operator<< (Formatter& f, RegisterList& rl)
|
||||
{
|
||||
Register* e = rl.end();
|
||||
|
||||
f << "(";
|
||||
for (RegisterList::iterator r = rl.begin(); r != e; r++) {
|
||||
f << "R" << (*r);
|
||||
if ((r + 1) != e)
|
||||
f << ", ";
|
||||
}
|
||||
f << ")";
|
||||
|
||||
return f;
|
||||
}
|
||||
};
|
||||
};
|
||||
f << ")";
|
||||
|
||||
return f;
|
||||
}
|
||||
} /* namespace VM */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
||||
|
|
1847
js/js2/vmtypes.h
1847
js/js2/vmtypes.h
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -42,304 +42,306 @@
|
|||
#include "parser.h"
|
||||
#include "vmtypes.h"
|
||||
|
||||
|
||||
#define NS_JSICG JavaScript::IGC
|
||||
|
||||
namespace JavaScript {
|
||||
namespace ICG {
|
||||
|
||||
using namespace VM;
|
||||
|
||||
class ICodeGenerator; // forward declaration
|
||||
namespace ICG {
|
||||
|
||||
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 getRegister() \
|
||||
{ return topRegister++; }
|
||||
void resetTopRegister() \
|
||||
{ markMaxRegister(); topRegister = stitcher.empty() ? 0 : \
|
||||
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);
|
||||
using namespace VM;
|
||||
|
||||
public:
|
||||
ICodeGenerator() : topRegister(0), maxRegister(0),
|
||||
maxVariable(0) \
|
||||
{ iCode = new InstructionStream(); }
|
||||
|
||||
virtual ~ICodeGenerator() { if (iCode) delete iCode; }
|
||||
|
||||
void mergeStream(InstructionStream *sideStream);
|
||||
|
||||
ICodeModule *complete();
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
Register op(ICodeOp op, Register source);
|
||||
Register op(ICodeOp op, Register source1, Register source2);
|
||||
Register call(Register target, RegisterList args);
|
||||
|
||||
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(); }
|
||||
class ICodeGenerator; // forward declaration
|
||||
|
||||
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);
|
||||
enum StateKind {
|
||||
While_state,
|
||||
If_state,
|
||||
Do_state,
|
||||
Switch_state,
|
||||
For_state
|
||||
};
|
||||
|
||||
void beginCaseStatement();
|
||||
void endCaseStatement();
|
||||
class ICodeState {
|
||||
public :
|
||||
ICodeState(StateKind kind, ICodeGenerator *icg); // inline below
|
||||
virtual ~ICodeState() { }
|
||||
|
||||
// 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 *) \
|
||||
{ ASSERT(false); return NULL; }
|
||||
virtual Label *getContinueLabel(ICodeGenerator *) \
|
||||
{ ASSERT(false); return NULL;}
|
||||
|
||||
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 */
|
||||
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 getRegister() \
|
||||
{ return topRegister++; }
|
||||
void resetTopRegister() \
|
||||
{ markMaxRegister(); topRegister = stitcher.empty() ? 0 : \
|
||||
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), maxRegister(0),
|
||||
maxVariable(0) \
|
||||
{ iCode = new InstructionStream(); }
|
||||
|
||||
virtual ~ICodeGenerator() { if (iCode) delete iCode; }
|
||||
|
||||
void mergeStream(InstructionStream *sideStream);
|
||||
|
||||
ICodeModule *complete();
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
Register op(ICodeOp op, Register source);
|
||||
Register op(ICodeOp op, Register source1, Register source2);
|
||||
Register call(Register target, RegisterList args);
|
||||
|
||||
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 */
|
||||
|
|
|
@ -22,280 +22,293 @@
|
|||
#include "vmtypes.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace Interpreter {
|
||||
namespace Interpreter {
|
||||
|
||||
using namespace JSTypes;
|
||||
// operand access macros.
|
||||
using namespace JSTypes;
|
||||
|
||||
// operand access macros.
|
||||
#define op1(i) (i->o1())
|
||||
#define op2(i) (i->o2())
|
||||
#define op3(i) (i->o3())
|
||||
|
||||
// mnemonic names for operands.
|
||||
// mnemonic names for operands.
|
||||
#define dst(i) op1(i)
|
||||
#define src1(i) op2(i)
|
||||
#define src2(i) op3(i)
|
||||
#define ofs(i) (i->getOffset())
|
||||
|
||||
static JSObject globals;
|
||||
static JSObject globals;
|
||||
|
||||
JSValue& defineGlobalProperty(const String& name, const JSValue& value)
|
||||
{
|
||||
return (globals[name] = value);
|
||||
}
|
||||
JSValue& defineGlobalProperty(const String& name, const JSValue& value)
|
||||
{
|
||||
return (globals[name] = value);
|
||||
}
|
||||
|
||||
// FIXME: need to copy the ICodeModule's instruction stream.
|
||||
// FIXME: need to copy the ICodeModule's instruction stream.
|
||||
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode)
|
||||
{
|
||||
JSValue value;
|
||||
value.function = new JSFunction(iCode);
|
||||
return defineGlobalProperty(name, value);
|
||||
}
|
||||
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode)
|
||||
{
|
||||
JSValue value;
|
||||
value.function = new JSFunction(iCode);
|
||||
return defineGlobalProperty(name, value);
|
||||
}
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args)
|
||||
{
|
||||
// stack of JSFrames.
|
||||
// XXX is a linked list of activation's sufficient?
|
||||
JSFrameStack frames;
|
||||
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args)
|
||||
{
|
||||
// stack of JSFrames.
|
||||
// XXX is a linked list of activation's sufficient?
|
||||
JSFrameStack frames;
|
||||
// initial activation.
|
||||
JSActivation* activation = new JSActivation(iCode, args);
|
||||
JSValues* locals = &activation->mLocals;
|
||||
JSValues* registers = &activation->mRegisters;
|
||||
|
||||
// initial activation.
|
||||
JSActivation* activation = new JSActivation(iCode, args);
|
||||
JSValues* locals = &activation->mLocals;
|
||||
JSValues* registers = &activation->mRegisters;
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
|
||||
while (true) {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->op()) {
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
frames.push(new JSFrame(++pc, begin_pc, activation, op1(call)));
|
||||
ICodeModule* target = (*registers)[op2(call)].function->getICode();
|
||||
activation = new JSActivation(target, activation, op3(call));
|
||||
locals = &activation->mLocals;
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pc = target->its_iCode->begin();
|
||||
}
|
||||
while (true) {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->op()) {
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
frames.push(new JSFrame(++pc, begin_pc, activation,
|
||||
op1(call)));
|
||||
ICodeModule* target =
|
||||
(*registers)[op2(call)].function->getICode();
|
||||
activation = new JSActivation(target, activation, op3(call));
|
||||
locals = &activation->mLocals;
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pc = target->its_iCode->begin();
|
||||
}
|
||||
continue;
|
||||
case RETURN:
|
||||
{
|
||||
Return* ret = static_cast<Return*>(instruction);
|
||||
JSValue result;
|
||||
if (op1(ret) != NotARegister)
|
||||
result = (*registers)[op1(ret)];
|
||||
if (frames.empty())
|
||||
return result;
|
||||
JSFrame *frame = frames.top();
|
||||
frames.pop();
|
||||
activation = frame->itsActivation;
|
||||
registers = &activation->mRegisters;
|
||||
locals = &activation->mLocals;
|
||||
(*registers)[frame->itsResult] = result;
|
||||
pc = frame->itsReturnPC;
|
||||
begin_pc = frame->itsBasePC;
|
||||
}
|
||||
continue;
|
||||
case MOVE:
|
||||
{
|
||||
Move* mov = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(mov)] = (*registers)[src1(mov)];
|
||||
}
|
||||
break;
|
||||
case LOAD_NAME:
|
||||
{
|
||||
LoadName* ln = static_cast<LoadName*>(instruction);
|
||||
(*registers)[dst(ln)] = globals[*src1(ln)];
|
||||
}
|
||||
break;
|
||||
case SAVE_NAME:
|
||||
{
|
||||
SaveName* sn = static_cast<SaveName*>(instruction);
|
||||
globals[*dst(sn)] = (*registers)[src1(sn)];
|
||||
}
|
||||
break;
|
||||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
(*registers)[dst(no)].object = new JSObject();
|
||||
}
|
||||
break;
|
||||
case NEW_ARRAY:
|
||||
{
|
||||
NewArray* na = static_cast<NewArray*>(instruction);
|
||||
(*registers)[dst(na)].array = new JSArray();
|
||||
}
|
||||
break;
|
||||
case GET_PROP:
|
||||
{
|
||||
GetProp* gp = static_cast<GetProp*>(instruction);
|
||||
JSObject* object = (*registers)[src1(gp)].object;
|
||||
(*registers)[dst(gp)] = (*object)[*src2(gp)];
|
||||
}
|
||||
break;
|
||||
case SET_PROP:
|
||||
{
|
||||
SetProp* sp = static_cast<SetProp*>(instruction);
|
||||
JSObject* object = (*registers)[dst(sp)].object;
|
||||
(*object)[*src1(sp)] = (*registers)[src2(sp)];
|
||||
}
|
||||
break;
|
||||
case GET_ELEMENT:
|
||||
{
|
||||
GetElement* ge = static_cast<GetElement*>(instruction);
|
||||
JSArray* array = (*registers)[src1(ge)].array;
|
||||
(*registers)[dst(ge)] = (*array)[(*registers)[src2(ge)]];
|
||||
}
|
||||
break;
|
||||
case SET_ELEMENT:
|
||||
{
|
||||
SetElement* se = static_cast<SetElement*>(instruction);
|
||||
JSArray* array = (*registers)[dst(se)].array;
|
||||
(*array)[(*registers)[src1(se)]] = (*registers)[src2(se)];
|
||||
}
|
||||
break;
|
||||
case LOAD_IMMEDIATE:
|
||||
{
|
||||
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case LOAD_VAR:
|
||||
{
|
||||
LoadVar* lv = static_cast<LoadVar*>(instruction);
|
||||
(*registers)[dst(lv)] = (*locals)[src1(lv)];
|
||||
}
|
||||
break;
|
||||
case SAVE_VAR:
|
||||
{
|
||||
SaveVar* sv = static_cast<SaveVar*>(instruction);
|
||||
(*locals)[dst(sv)] = (*registers)[src1(sv)];
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
pc = begin_pc + ofs(bra);
|
||||
continue;
|
||||
case RETURN:
|
||||
{
|
||||
Return* ret = static_cast<Return*>(instruction);
|
||||
JSValue result;
|
||||
if (op1(ret) != NotARegister)
|
||||
result = (*registers)[op1(ret)];
|
||||
if (frames.empty())
|
||||
return result;
|
||||
JSFrame *frame = frames.top();
|
||||
frames.pop();
|
||||
activation = frame->itsActivation;
|
||||
registers = &activation->mRegisters;
|
||||
locals = &activation->mLocals;
|
||||
(*registers)[frame->itsResult] = result;
|
||||
pc = frame->itsReturnPC;
|
||||
begin_pc = frame->itsBasePC;
|
||||
}
|
||||
continue;
|
||||
case MOVE:
|
||||
{
|
||||
Move* mov = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(mov)] = (*registers)[src1(mov)];
|
||||
}
|
||||
break;
|
||||
case LOAD_NAME:
|
||||
{
|
||||
LoadName* ln = static_cast<LoadName*>(instruction);
|
||||
(*registers)[dst(ln)] = globals[*src1(ln)];
|
||||
}
|
||||
break;
|
||||
case SAVE_NAME:
|
||||
{
|
||||
SaveName* sn = static_cast<SaveName*>(instruction);
|
||||
globals[*dst(sn)] = (*registers)[src1(sn)];
|
||||
}
|
||||
break;
|
||||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
(*registers)[dst(no)].object = new JSObject();
|
||||
}
|
||||
break;
|
||||
case NEW_ARRAY:
|
||||
{
|
||||
NewArray* na = static_cast<NewArray*>(instruction);
|
||||
(*registers)[dst(na)].array = new JSArray();
|
||||
}
|
||||
break;
|
||||
case GET_PROP:
|
||||
{
|
||||
GetProp* gp = static_cast<GetProp*>(instruction);
|
||||
JSObject* object = (*registers)[src1(gp)].object;
|
||||
(*registers)[dst(gp)] = (*object)[*src2(gp)];
|
||||
}
|
||||
break;
|
||||
case SET_PROP:
|
||||
{
|
||||
SetProp* sp = static_cast<SetProp*>(instruction);
|
||||
JSObject* object = (*registers)[dst(sp)].object;
|
||||
(*object)[*src1(sp)] = (*registers)[src2(sp)];
|
||||
}
|
||||
break;
|
||||
case GET_ELEMENT:
|
||||
{
|
||||
GetElement* ge = static_cast<GetElement*>(instruction);
|
||||
JSArray* array = (*registers)[src1(ge)].array;
|
||||
(*registers)[dst(ge)] = (*array)[(*registers)[src2(ge)]];
|
||||
}
|
||||
break;
|
||||
case SET_ELEMENT:
|
||||
{
|
||||
SetElement* se = static_cast<SetElement*>(instruction);
|
||||
JSArray* array = (*registers)[dst(se)].array;
|
||||
(*array)[(*registers)[src1(se)]] = (*registers)[src2(se)];
|
||||
}
|
||||
break;
|
||||
case LOAD_IMMEDIATE:
|
||||
{
|
||||
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case LOAD_VAR:
|
||||
{
|
||||
LoadVar* lv = static_cast<LoadVar*>(instruction);
|
||||
(*registers)[dst(lv)] = (*locals)[src1(lv)];
|
||||
}
|
||||
break;
|
||||
case SAVE_VAR:
|
||||
{
|
||||
SaveVar* sv = static_cast<SaveVar*>(instruction);
|
||||
(*locals)[dst(sv)] = (*registers)[src1(sv)];
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
pc = begin_pc + ofs(bra);
|
||||
}
|
||||
break;
|
||||
case BRANCH_LT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 < 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case BRANCH_LT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 < 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_LE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 <= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_EQ:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 == 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_NE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 != 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 >= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 > 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] = JSValue((*registers)[src1(add)].f64 + (*registers)[src2(add)].f64);
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
{
|
||||
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(sub)] = JSValue((*registers)[src1(sub)].f64 - (*registers)[src2(sub)].f64);
|
||||
}
|
||||
break;
|
||||
case MULTIPLY:
|
||||
{
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(mul)] = JSValue((*registers)[src1(mul)].f64 * (*registers)[src2(mul)].f64);
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
{
|
||||
Arithmetic* div = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(div)] = JSValue((*registers)[src1(div)].f64 / (*registers)[src2(div)].f64);
|
||||
}
|
||||
break;
|
||||
case COMPARE_LT:
|
||||
case COMPARE_LE:
|
||||
case COMPARE_EQ:
|
||||
case COMPARE_NE:
|
||||
case COMPARE_GT:
|
||||
case COMPARE_GE:
|
||||
{
|
||||
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
|
||||
float64 diff = ((*registers)[src1(cmp)].f64 - (*registers)[src2(cmp)].f64);
|
||||
(*registers)[dst(cmp)].i32 = (diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Move* nt = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
break;
|
||||
case BRANCH_LE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 <= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_EQ:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 == 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_NE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 != 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 >= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 > 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] =
|
||||
JSValue((*registers)[src1(add)].f64 +
|
||||
(*registers)[src2(add)].f64);
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
{
|
||||
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(sub)] =
|
||||
JSValue((*registers)[src1(sub)].f64 -
|
||||
(*registers)[src2(sub)].f64);
|
||||
}
|
||||
break;
|
||||
case MULTIPLY:
|
||||
{
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(mul)] =
|
||||
JSValue((*registers)[src1(mul)].f64 *
|
||||
(*registers)[src2(mul)].f64);
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
{
|
||||
Arithmetic* div = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(div)] =
|
||||
JSValue((*registers)[src1(div)].f64 /
|
||||
(*registers)[src2(div)].f64);
|
||||
}
|
||||
break;
|
||||
case COMPARE_LT:
|
||||
case COMPARE_LE:
|
||||
case COMPARE_EQ:
|
||||
case COMPARE_NE:
|
||||
case COMPARE_GT:
|
||||
case COMPARE_GE:
|
||||
{
|
||||
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
|
||||
float64 diff =
|
||||
((*registers)[src1(cmp)].f64 -
|
||||
(*registers)[src2(cmp)].f64);
|
||||
(*registers)[dst(cmp)].i32 =
|
||||
(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Move* nt = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
|
||||
} /* interpret */
|
||||
} /* interpret */
|
||||
|
||||
} /* namespace Interpreter */
|
||||
|
||||
} /* namespace Interpreter */
|
||||
} /* namespace JavaScript */
|
||||
|
|
|
@ -25,18 +25,18 @@
|
|||
#include "icodegenerator.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace Interpreter {
|
||||
using namespace ICG;
|
||||
using namespace JSTypes;
|
||||
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
namespace Interpreter {
|
||||
|
||||
JSValue& defineGlobalProperty(const String& name,
|
||||
const JSValue& value);
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode);
|
||||
};
|
||||
using namespace ICG;
|
||||
using namespace JSTypes;
|
||||
|
||||
};
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
|
||||
JSValue& defineGlobalProperty(const String& name,
|
||||
const JSValue& value);
|
||||
JSValue& defineFunction(const String& name, ICodeModule* iCode);
|
||||
|
||||
} /* namespace Interpreter */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
#endif /* interpreter_h */
|
||||
|
|
|
@ -44,183 +44,188 @@
|
|||
#include "icodegenerator.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace JSTypes {
|
||||
using namespace VM;
|
||||
using namespace ICG;
|
||||
namespace JSTypes {
|
||||
using namespace VM;
|
||||
using namespace ICG;
|
||||
|
||||
class JSObject;
|
||||
class JSArray;
|
||||
class JSFunction;
|
||||
|
||||
/**
|
||||
* All JavaScript data types.
|
||||
*/
|
||||
union JSValue {
|
||||
int8 i8;
|
||||
uint8 u8;
|
||||
int16 i16;
|
||||
uint16 u16;
|
||||
int32 i32;
|
||||
uint32 u32;
|
||||
int64 i64;
|
||||
uint64 u64;
|
||||
float32 f32;
|
||||
float64 f64;
|
||||
JSObject* object;
|
||||
JSArray* array;
|
||||
JSFunction *function;
|
||||
|
||||
class JSObject;
|
||||
class JSArray;
|
||||
class JSFunction;
|
||||
|
||||
/**
|
||||
* All JavaScript data types.
|
||||
*/
|
||||
union JSValue {
|
||||
int8 i8;
|
||||
uint8 u8;
|
||||
int16 i16;
|
||||
uint16 u16;
|
||||
int32 i32;
|
||||
uint32 u32;
|
||||
int64 i64;
|
||||
uint64 u64;
|
||||
float32 f32;
|
||||
float64 f64;
|
||||
JSObject* object;
|
||||
JSArray* array;
|
||||
JSFunction *function;
|
||||
JSValue() : f64(0.0) {}
|
||||
|
||||
JSValue() : f64(0.0) {}
|
||||
|
||||
explicit JSValue(float64 f64) : f64(f64) {}
|
||||
};
|
||||
explicit JSValue(float64 f64) : f64(f64) {}
|
||||
};
|
||||
|
||||
#if defined(XP_MAC)
|
||||
// copied from default template parameters in map.
|
||||
typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
|
||||
// copied from default template parameters in map.
|
||||
typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
|
||||
#elif defined(XP_UNIX)
|
||||
// FIXME: in libg++, they assume the map's allocator is a byte allocator,
|
||||
// which is wrapped in a simple_allocator. this is crap.
|
||||
typedef char _Char[1];
|
||||
typedef gc_allocator<_Char> gc_map_allocator;
|
||||
// FIXME: in libg++, they assume the map's allocator is a byte allocator,
|
||||
// which is wrapped in a simple_allocator. this is crap.
|
||||
typedef char _Char[1];
|
||||
typedef gc_allocator<_Char> gc_map_allocator;
|
||||
#elif defined(_WIN32)
|
||||
// FIXME: MSVC++'s notion. this is why we had to add _Charalloc().
|
||||
typedef gc_allocator<JSValue> gc_map_allocator;
|
||||
// FIXME: MSVC++'s notion. this is why we had to add _Charalloc().
|
||||
typedef gc_allocator<JSValue> gc_map_allocator;
|
||||
#endif
|
||||
|
||||
/**
|
||||
/**
|
||||
* GC-scannable array of values.
|
||||
*/
|
||||
typedef std::vector<JSValue, gc_allocator<JSValue> > JSValues;
|
||||
typedef std::vector<JSValue, gc_allocator<JSValue> > JSValues;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Basic behavior of all JS objects, mapping a name to a value.
|
||||
* This is provided mainly to avoid having an awkward implementation
|
||||
* of JSObject & JSArray, which must each define its own
|
||||
* gc_allocator. This is all in flux.
|
||||
*/
|
||||
class JSMap : public gc_base {
|
||||
std::map<String, JSValue, std::less<String>, gc_map_allocator> properties;
|
||||
public:
|
||||
JSValue& operator[](const String& name)
|
||||
{
|
||||
return properties[name];
|
||||
}
|
||||
};
|
||||
class JSMap : public gc_base {
|
||||
std::map<String, JSValue, std::less<String>,
|
||||
gc_map_allocator> properties;
|
||||
public:
|
||||
JSValue& operator[](const String& name)
|
||||
{
|
||||
return properties[name];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Private representation of a JavaScript object.
|
||||
* This will change over time, so it is treated as an opaque
|
||||
* type everywhere else but here.
|
||||
*/
|
||||
class JSObject : public JSMap {};
|
||||
class JSObject : public JSMap {};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Private representation of a JavaScript array.
|
||||
*/
|
||||
class JSArray : public JSMap {
|
||||
JSValues elements;
|
||||
public:
|
||||
JSArray() : elements(1) {}
|
||||
JSArray(uint32 size) : elements(size) {}
|
||||
JSArray(const JSValues &v) : elements(v) {}
|
||||
class JSArray : public JSMap {
|
||||
JSValues elements;
|
||||
public:
|
||||
JSArray() : elements(1) {}
|
||||
JSArray(uint32 size) : elements(size) {}
|
||||
JSArray(const JSValues &v) : elements(v) {}
|
||||
|
||||
uint32 length()
|
||||
{
|
||||
return elements.size();
|
||||
}
|
||||
uint32 length()
|
||||
{
|
||||
return elements.size();
|
||||
}
|
||||
|
||||
JSValue& operator[](const JSValue& index)
|
||||
{
|
||||
// for now, we can only handle f64 index values.
|
||||
uint32 n = (uint32)index.f64;
|
||||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
return elements[n];
|
||||
}
|
||||
JSValue& operator[](const JSValue& index)
|
||||
{
|
||||
// for now, we can only handle f64 index values.
|
||||
uint32 n = (uint32)index.f64;
|
||||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
return elements[n];
|
||||
}
|
||||
|
||||
JSValue& operator[](uint32 n)
|
||||
{
|
||||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
return elements[n];
|
||||
}
|
||||
JSValue& operator[](uint32 n)
|
||||
{
|
||||
// obviously, a sparse representation might be better.
|
||||
uint32 size = elements.size();
|
||||
if (n >= size) expand(n, size);
|
||||
return elements[n];
|
||||
}
|
||||
|
||||
void resize(uint32 size)
|
||||
{
|
||||
elements.resize(size);
|
||||
}
|
||||
void resize(uint32 size)
|
||||
{
|
||||
elements.resize(size);
|
||||
}
|
||||
|
||||
private:
|
||||
void expand(uint32 n, uint32 size)
|
||||
{
|
||||
do {
|
||||
size *= 2;
|
||||
} while (n >= size);
|
||||
elements.resize(size);
|
||||
}
|
||||
};
|
||||
private:
|
||||
void expand(uint32 n, uint32 size)
|
||||
{
|
||||
do {
|
||||
size *= 2;
|
||||
} while (n >= size);
|
||||
elements.resize(size);
|
||||
}
|
||||
};
|
||||
|
||||
class JSFunction : public JSMap {
|
||||
ICodeModule* mICode;
|
||||
public:
|
||||
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
|
||||
ICodeModule* getICode() { return mICode; }
|
||||
};
|
||||
class JSFunction : public JSMap {
|
||||
ICodeModule* mICode;
|
||||
public:
|
||||
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
|
||||
ICodeModule* getICode() { return mICode; }
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Represents the current function's invocation state.
|
||||
*/
|
||||
struct JSActivation : public gc_base {
|
||||
JSValues mRegisters;
|
||||
JSValues mLocals;
|
||||
struct JSActivation : public gc_base {
|
||||
JSValues mRegisters;
|
||||
JSValues mLocals;
|
||||
|
||||
JSActivation(ICodeModule* iCode, const JSValues& args)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mLocals(args)
|
||||
{
|
||||
// ensure that locals array is large enough.
|
||||
uint32 localsSize = iCode->itsMaxVariable + 1;
|
||||
if (localsSize > mLocals.size())
|
||||
mLocals.resize(localsSize);
|
||||
}
|
||||
JSActivation(ICodeModule* iCode, const JSValues& args)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mLocals(args)
|
||||
{
|
||||
// ensure that locals array is large enough.
|
||||
uint32 localsSize = iCode->itsMaxVariable + 1;
|
||||
if (localsSize > mLocals.size())
|
||||
mLocals.resize(localsSize);
|
||||
}
|
||||
|
||||
JSActivation(ICodeModule* iCode, JSActivation* caller, const RegisterList& list)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mLocals(iCode->itsMaxVariable + 1)
|
||||
{
|
||||
// copy caller's parameter list in to locals.
|
||||
JSValues::iterator dest = mLocals.begin();
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (RegisterList::const_iterator src = list.begin(), end = list.end(); src != end; ++src, ++dest) {
|
||||
*dest = params[*src];
|
||||
}
|
||||
JSActivation(ICodeModule* iCode, JSActivation* caller,
|
||||
const RegisterList& list)
|
||||
: mRegisters(iCode->itsMaxRegister + 1),
|
||||
mLocals(iCode->itsMaxVariable + 1)
|
||||
{
|
||||
// copy caller's parameter list in to locals.
|
||||
JSValues::iterator dest = mLocals.begin();
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (RegisterList::const_iterator src = list.begin(),
|
||||
end = list.end(); src != end; ++src, ++dest) {
|
||||
*dest = params[*src];
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores saved state from the *previous* activation, the current activation is alive
|
||||
* and well in locals of the interpreter loop.
|
||||
/**
|
||||
* Stores saved state from the *previous* activation, the current activation is
|
||||
* alive and well in locals of the interpreter loop.
|
||||
*/
|
||||
struct JSFrame : public gc_base {
|
||||
JSFrame(InstructionIterator returnPC, InstructionIterator basePC,
|
||||
JSActivation* activation, Register result)
|
||||
: itsReturnPC(returnPC), itsBasePC(basePC),
|
||||
itsActivation(activation),
|
||||
itsResult(result)
|
||||
{
|
||||
}
|
||||
struct JSFrame : public gc_base {
|
||||
JSFrame(InstructionIterator returnPC, InstructionIterator basePC,
|
||||
JSActivation* activation, Register result)
|
||||
: itsReturnPC(returnPC), itsBasePC(basePC),
|
||||
itsActivation(activation),
|
||||
itsResult(result)
|
||||
{
|
||||
}
|
||||
|
||||
InstructionIterator itsReturnPC;
|
||||
InstructionIterator itsBasePC;
|
||||
JSActivation* itsActivation; // caller's activation.
|
||||
Register itsResult; // the desired target register for the return value
|
||||
};
|
||||
InstructionIterator itsReturnPC;
|
||||
InstructionIterator itsBasePC;
|
||||
JSActivation* itsActivation; // caller's activation.
|
||||
// the desired target register for the return value
|
||||
Register itsResult;
|
||||
};
|
||||
|
||||
// a stack of JSFrames.
|
||||
typedef std::stack<JSFrame*, std::vector<JSFrame*, gc_allocator<JSFrame*> > > JSFrameStack;
|
||||
// a stack of JSFrames.
|
||||
typedef std::stack<JSFrame*, std::vector<JSFrame*, gc_allocator<JSFrame*> > > JSFrameStack;
|
||||
|
||||
} /* namespace JSTypes */
|
||||
} /* namespace JSTypes */
|
||||
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
|
|
@ -35,29 +35,28 @@
|
|||
#include "vmtypes.h"
|
||||
|
||||
namespace JavaScript {
|
||||
|
||||
namespace VM {
|
||||
namespace VM {
|
||||
|
||||
Formatter& operator<< (Formatter& f, Instruction& i)
|
||||
{
|
||||
return i.print(f);
|
||||
Formatter& operator<< (Formatter& f, Instruction& i)
|
||||
{
|
||||
return i.print(f);
|
||||
}
|
||||
|
||||
Formatter& operator<< (Formatter& f, RegisterList& rl)
|
||||
{
|
||||
Register* e = rl.end();
|
||||
|
||||
f << "(";
|
||||
for (RegisterList::iterator r = rl.begin(); r != e; r++) {
|
||||
f << "R" << (*r);
|
||||
if ((r + 1) != e)
|
||||
f << ", ";
|
||||
}
|
||||
|
||||
Formatter& operator<< (Formatter& f, RegisterList& rl)
|
||||
{
|
||||
Register* e = rl.end();
|
||||
|
||||
f << "(";
|
||||
for (RegisterList::iterator r = rl.begin(); r != e; r++) {
|
||||
f << "R" << (*r);
|
||||
if ((r + 1) != e)
|
||||
f << ", ";
|
||||
}
|
||||
f << ")";
|
||||
|
||||
return f;
|
||||
}
|
||||
};
|
||||
};
|
||||
f << ")";
|
||||
|
||||
return f;
|
||||
}
|
||||
} /* namespace VM */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
||||
|
|
1847
js2/src/vmtypes.h
1847
js2/src/vmtypes.h
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,7 +1,7 @@
|
|||
use strict;
|
||||
|
||||
my $tab = " ";
|
||||
my $tab2 = " ";
|
||||
my $init_tab = $tab;
|
||||
my $enum_decs = "";
|
||||
my $class_decs = "";
|
||||
my @name_array;
|
||||
|
@ -186,20 +186,21 @@ sub collect {
|
|||
}
|
||||
|
||||
push (@name_array, $opname);
|
||||
$enum_decs .= "$tab2$tab$opname, /* $rem */\n";
|
||||
$class_decs .= ($tab2 . "class $cname : public $super {\n" .
|
||||
$tab2 . "public:\n" .
|
||||
$tab2 . $tab . "/* $rem */\n" .
|
||||
$tab2 . $tab . "$cname ($dec_list) :\n" .
|
||||
$tab2 . $tab . $tab . "$super\n$tab2$tab$tab($params) " .
|
||||
$enum_decs .= "$init_tab$tab$opname, /* $rem */\n";
|
||||
$class_decs .= ($init_tab . "class $cname : public $super {\n" .
|
||||
$init_tab . "public:\n" .
|
||||
$init_tab . $tab . "/* $rem */\n" .
|
||||
$init_tab . $tab . "$cname ($dec_list) :\n" .
|
||||
$init_tab . $tab . $tab . "$super\n" .
|
||||
"$init_tab$tab$tab($params) " .
|
||||
"{};\n" .
|
||||
$tab2 . $tab .
|
||||
$init_tab . $tab .
|
||||
"virtual Formatter& print (Formatter& f) {\n" .
|
||||
$tab2 . $tab . $tab . "f << opcodeNames[$opname];\n" .
|
||||
$init_tab . $tab . $tab . "f << opcodeNames[$opname];\n" .
|
||||
$printbody .
|
||||
$tab2 . $tab . $tab . "return f;\n" .
|
||||
$tab2 . $tab . "}\n" .
|
||||
$tab2 . "};\n\n");
|
||||
$init_tab . $tab . $tab . "return f;\n" .
|
||||
$init_tab . $tab . "}\n" .
|
||||
$init_tab . "};\n\n");
|
||||
}
|
||||
|
||||
sub spew {
|
||||
|
@ -274,7 +275,7 @@ sub get_printbody {
|
|||
my $type;
|
||||
my @oplist;
|
||||
my $op = 1;
|
||||
my $in = $tab2 . $tab . $tab;
|
||||
my $in = $init_tab . $tab . $tab;
|
||||
|
||||
for $type (@types) {
|
||||
print "type $type\n";
|
||||
|
|
Загрузка…
Ссылка в новой задаче