formatting changes. use only one tab regardless of nested namespaces

This commit is contained in:
rginda%netscape.com 2000-04-18 21:51:45 +00:00
Родитель 0f465e4756
Коммит 3a06b96f97
16 изменённых файлов: 4350 добавлений и 4248 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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 */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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 */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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";