mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-10 09:19:28 +00:00
Added ICodeModule to collect extra info about executable chunks.
This commit is contained in:
parent
365dd176a7
commit
4898874939
@ -37,7 +37,7 @@ namespace JavaScript {
|
||||
// ICodeGenerator
|
||||
//
|
||||
|
||||
InstructionStream *ICodeGenerator::complete()
|
||||
ICodeModule *ICodeGenerator::complete()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
ASSERT(stitcher.empty());
|
||||
@ -62,20 +62,29 @@ namespace JavaScript {
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
markMaxRegister();
|
||||
|
||||
return iCode;
|
||||
return new ICodeModule(iCode, maxRegister, maxVariable);
|
||||
}
|
||||
|
||||
/***********************************************************************************************/
|
||||
|
||||
Register ICodeGenerator::loadVariable(uint32 frameIndex)
|
||||
{
|
||||
markMaxVariable(frameIndex);
|
||||
Register dest = getRegister();
|
||||
LoadVar *instr = new LoadVar(LOAD_VAR, dest, frameIndex);
|
||||
iCode->push_back(instr);
|
||||
return dest;
|
||||
}
|
||||
|
||||
void ICodeGenerator::saveVariable(uint32 frameIndex, Register value)
|
||||
{
|
||||
markMaxVariable(frameIndex);
|
||||
SaveVar *instr = new SaveVar(SAVE_VAR, frameIndex, value);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
Register ICodeGenerator::loadImmediate(double value)
|
||||
{
|
||||
Register dest = getRegister();
|
||||
@ -120,12 +129,6 @@ namespace JavaScript {
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::saveVariable(uint32 frameIndex, Register value)
|
||||
{
|
||||
SaveVar *instr = new SaveVar(SAVE_VAR, frameIndex, value);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
Register ICodeGenerator::op(ICodeOp op, Register source)
|
||||
{
|
||||
Register dest = getRegister();
|
||||
@ -585,7 +588,7 @@ namespace JavaScript {
|
||||
for (InstructionIterator i = iCode->begin(); i != iCode->end(); i++) {
|
||||
|
||||
for (LabelList::iterator k = labels.begin(); k != labels.end(); k++)
|
||||
if ((*k)->itsOffset == (i - iCode->begin())) {
|
||||
if ((*k)->itsOffset == (ptrdiff_t)(i - iCode->begin())) {
|
||||
//s << "label #" << (k - labels.begin()) << ":\n";
|
||||
s << "#" << (i - iCode->begin());
|
||||
break;
|
||||
@ -691,7 +694,7 @@ namespace JavaScript {
|
||||
s << "\n";
|
||||
}
|
||||
for (LabelList::iterator k = labels.begin(); k != labels.end(); k++)
|
||||
if ((*k)->itsOffset == (iCode->end() - iCode->begin())) {
|
||||
if ((*k)->itsOffset == (ptrdiff_t)(iCode->end() - iCode->begin())) {
|
||||
// s << "label #" << (k - labels.begin()) << ":\n";
|
||||
// s << "#" << (i - iCode->begin());
|
||||
}
|
||||
|
@ -31,50 +31,54 @@ namespace JavaScript {
|
||||
|
||||
typedef uint32 Register;
|
||||
|
||||
typedef std::vector<Register> RegisterList;
|
||||
|
||||
enum ICodeOp {
|
||||
// Operand1 Operand2 Operand3
|
||||
// Operand1 Operand2 Operand3
|
||||
NOP,
|
||||
|
||||
MOVE_TO, // Destination Register Source Register
|
||||
MOVE_TO, // Destination Register Source Register
|
||||
|
||||
LOAD_VAR, // Destination Register index of frame slot
|
||||
SAVE_VAR, // index of frame slot Source Register
|
||||
LOAD_VAR, // Destination Register index of frame slot
|
||||
SAVE_VAR, // index of frame slot Source Register
|
||||
|
||||
LOAD_IMMEDIATE, // Destination Register immediate (double)
|
||||
LOAD_IMMEDIATE, // Destination Register immediate (double)
|
||||
|
||||
LOAD_NAME, // Destination Register StringAtom &
|
||||
SAVE_NAME, // StringAtom & Source Register
|
||||
LOAD_NAME, // Destination Register StringAtom &
|
||||
SAVE_NAME, // StringAtom & Source Register
|
||||
|
||||
NEW_OBJECT, // Destination Register
|
||||
|
||||
GET_PROP, // Destination Register StringAtom & Base Register
|
||||
SET_PROP, // StringAtom & Base Register Source Register
|
||||
GET_PROP, // Destination Register StringAtom & Base Register
|
||||
SET_PROP, // StringAtom & Base Register Source Register
|
||||
|
||||
ADD, // Destination Register Source Register 1 Source Register 2
|
||||
ADD, // Destination Register Source Register 1 Source Register 2
|
||||
SUBTRACT,
|
||||
MULTIPLY,
|
||||
DIVIDE,
|
||||
|
||||
// maintain contiguity
|
||||
COMPARE_LT, // Destination Register Source Register 1 Source Register 2
|
||||
COMPARE_LT, // Destination Register Source Register 1 Source Register 2
|
||||
COMPARE_LE,
|
||||
COMPARE_EQ,
|
||||
COMPARE_NE,
|
||||
COMPARE_GE,
|
||||
COMPARE_GT,
|
||||
|
||||
NOT, // Destination Register Source Register
|
||||
NOT, // Destination Register Source Register
|
||||
|
||||
BRANCH, // Target label
|
||||
|
||||
BRANCH_LT, // Target label Condition Register
|
||||
BRANCH_LT, // Target label Condition Register
|
||||
BRANCH_LE,
|
||||
BRANCH_EQ,
|
||||
BRANCH_NE,
|
||||
BRANCH_GE,
|
||||
BRANCH_GT,
|
||||
|
||||
RETURN // Source Register
|
||||
RETURN, // Source Register
|
||||
|
||||
CALL, // Destination Register Target Register Arguments
|
||||
};
|
||||
|
||||
class Instruction {
|
||||
@ -185,6 +189,12 @@ namespace JavaScript {
|
||||
: Instruction_2<uint32, Register>(op, offset, condition) { }
|
||||
};
|
||||
|
||||
class Call : public Instruction_3<Register, Register, RegisterList> {
|
||||
public:
|
||||
Call(Register result, Register target, RegisterList args)
|
||||
: Instruction_3<Register, Register, RegisterList>(CALL, result, target, args) { }
|
||||
|
||||
};
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
@ -206,6 +216,16 @@ namespace JavaScript {
|
||||
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.
|
||||
@ -220,15 +240,21 @@ namespace JavaScript {
|
||||
|
||||
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() { topRegister = stitcher.empty() ? 0 : stitcher.back()->registerBase; }
|
||||
void resetTopRegister() { markMaxRegister(); topRegister = stitcher.empty() ? 0 : stitcher.back()->registerBase; }
|
||||
|
||||
ICodeOp getBranchOp() { ASSERT(!iCode->empty()); return iCode->back()->getBranchOp(); }
|
||||
|
||||
public:
|
||||
Label *getLabel();
|
||||
private:
|
||||
uint32 maxRegister;
|
||||
uint32 maxVariable;
|
||||
|
||||
|
||||
|
||||
void setLabel(Label *label);
|
||||
void setLabel(InstructionStream *stream, Label *label);
|
||||
|
||||
@ -236,11 +262,12 @@ namespace JavaScript {
|
||||
void branchConditional(Label *label, Register condition);
|
||||
|
||||
public:
|
||||
ICodeGenerator() : topRegister(0) { iCode = new InstructionStream(); }
|
||||
ICodeGenerator() : topRegister(0), maxRegister(0), maxVariable(0) { iCode = new InstructionStream(); }
|
||||
virtual ~ICodeGenerator() { if (iCode) delete iCode; }
|
||||
|
||||
void mergeStream(InstructionStream *sideStream);
|
||||
|
||||
InstructionStream *complete();
|
||||
ICodeModule *complete();
|
||||
|
||||
std::ostream &print(std::ostream &s);
|
||||
|
||||
@ -265,6 +292,8 @@ namespace JavaScript {
|
||||
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
|
||||
|
@ -63,15 +63,17 @@ gc_allocator<JSObject> JSObject::alloc;
|
||||
#define op2(i) (i->itsOperand2)
|
||||
#define op3(i) (i->itsOperand3)
|
||||
|
||||
JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
JSValue interpret(ICodeModule *iCode, const JSValues& args)
|
||||
{
|
||||
JSValue result;
|
||||
JSValues frame(args);
|
||||
JSValues registers(32);
|
||||
JSValues registers(iCode->itsMaxRegister + 1);
|
||||
static JSObject globals;
|
||||
|
||||
InstructionIterator pc = iCode.begin();
|
||||
while (pc != iCode.end()) {
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator end_pc = iCode->its_iCode->end();
|
||||
InstructionIterator pc = begin_pc;
|
||||
while (pc != end_pc) {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->opcode()) {
|
||||
case MOVE_TO:
|
||||
@ -133,7 +135,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
case BRANCH:
|
||||
{
|
||||
ResolvedBranch* bra = static_cast<ResolvedBranch*>(instruction);
|
||||
pc = iCode.begin() + op1(bra);
|
||||
pc = begin_pc + op1(bra);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -141,7 +143,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 < 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -150,7 +152,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 <= 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -159,7 +161,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 == 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -168,7 +170,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 != 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -177,7 +179,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 >= 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -186,7 +188,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 > 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace JavaScript {
|
||||
|
||||
typedef vector<JSValue, gc_allocator<JSValue> > JSValues;
|
||||
|
||||
JSValue interpret(InstructionStream& iCode, const JSValues& args);
|
||||
JSValue interpret(ICodeModule *iCode, const JSValues& args);
|
||||
}
|
||||
|
||||
#endif /* interpreter_h */
|
||||
|
@ -342,9 +342,24 @@ static void testICG(World &world)
|
||||
icg.saveVariable(0, icg.loadImmediate(99));
|
||||
icg.endForStatement();
|
||||
|
||||
InstructionStream *iCode = icg.complete();
|
||||
ICodeModule *icm = icg.complete();
|
||||
|
||||
std::cout << icg;
|
||||
|
||||
delete icm;
|
||||
}
|
||||
|
||||
static float64 testFunctionCall(float64 n)
|
||||
{
|
||||
uint32 position = 0;
|
||||
ICodeGenerator icg;
|
||||
|
||||
// function sum(n) { if (n > 1) return 1 + sum(n - 1); else return 1; }
|
||||
// n is bound to var #0.
|
||||
icg.beginStatement(position);
|
||||
icg.loadVariable(0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static float64 testFactorial(float64 n)
|
||||
@ -384,15 +399,17 @@ static float64 testFactorial(float64 n)
|
||||
|
||||
// return result;
|
||||
icg.returnStatement(icg.loadVariable(1));
|
||||
InstructionStream *iCode = icg.complete();
|
||||
// std::cout << icg;
|
||||
ICodeModule *icm = icg.complete();
|
||||
std::cout << icg;
|
||||
|
||||
// test the iCode interpreter.
|
||||
JSValues args(32);
|
||||
args[0] = JSValue(n);
|
||||
JSValue result = interpret(*iCode, args);
|
||||
JSValue result = interpret(icm, args);
|
||||
std::cout << "fact(" << n << ") = " << result.f64 << std::endl;
|
||||
|
||||
delete icm;
|
||||
|
||||
return result.f64;
|
||||
}
|
||||
|
||||
@ -412,7 +429,7 @@ static float64 testObjects(World &world, int32 n)
|
||||
initCG.beginStatement(position);
|
||||
initCG.setProperty(counter, initCG.loadName(global), initCG.loadImmediate(0.0));
|
||||
|
||||
InstructionStream* initCode = initCG.complete();
|
||||
ICodeModule* initCode = initCG.complete();
|
||||
|
||||
std::cout << initCG;
|
||||
|
||||
@ -428,21 +445,24 @@ static float64 testObjects(World &world, int32 n)
|
||||
incrCG.setProperty(counter, robject, rvalue);
|
||||
incrCG.returnStatement(rvalue);
|
||||
|
||||
InstructionStream* incrCode = incrCG.complete();
|
||||
ICodeModule* incrCode = incrCG.complete();
|
||||
|
||||
std::cout << incrCG;
|
||||
|
||||
// run initialization code.
|
||||
JSValues args(32);
|
||||
interpret(*initCode, args);
|
||||
interpret(initCode, args);
|
||||
|
||||
// call the increment function some number of times.
|
||||
JSValue result;
|
||||
while (n-- > 0)
|
||||
result = interpret(*incrCode, args);
|
||||
result = interpret(incrCode, args);
|
||||
|
||||
std::cout << "result = " << result.f64 << std::endl;
|
||||
|
||||
delete initCode;
|
||||
delete incrCode;
|
||||
|
||||
return result.f64;
|
||||
}
|
||||
|
||||
@ -452,7 +472,7 @@ int main(int argc, char **argv)
|
||||
initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv);
|
||||
#endif
|
||||
World world;
|
||||
#if 0
|
||||
#if 1
|
||||
assert(testFactorial(5) == 120);
|
||||
assert(testObjects(world, 5) == 5);
|
||||
testICG(world);
|
||||
|
@ -37,7 +37,7 @@ namespace JavaScript {
|
||||
// ICodeGenerator
|
||||
//
|
||||
|
||||
InstructionStream *ICodeGenerator::complete()
|
||||
ICodeModule *ICodeGenerator::complete()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
ASSERT(stitcher.empty());
|
||||
@ -62,20 +62,29 @@ namespace JavaScript {
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
markMaxRegister();
|
||||
|
||||
return iCode;
|
||||
return new ICodeModule(iCode, maxRegister, maxVariable);
|
||||
}
|
||||
|
||||
/***********************************************************************************************/
|
||||
|
||||
Register ICodeGenerator::loadVariable(uint32 frameIndex)
|
||||
{
|
||||
markMaxVariable(frameIndex);
|
||||
Register dest = getRegister();
|
||||
LoadVar *instr = new LoadVar(LOAD_VAR, dest, frameIndex);
|
||||
iCode->push_back(instr);
|
||||
return dest;
|
||||
}
|
||||
|
||||
void ICodeGenerator::saveVariable(uint32 frameIndex, Register value)
|
||||
{
|
||||
markMaxVariable(frameIndex);
|
||||
SaveVar *instr = new SaveVar(SAVE_VAR, frameIndex, value);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
Register ICodeGenerator::loadImmediate(double value)
|
||||
{
|
||||
Register dest = getRegister();
|
||||
@ -120,12 +129,6 @@ namespace JavaScript {
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::saveVariable(uint32 frameIndex, Register value)
|
||||
{
|
||||
SaveVar *instr = new SaveVar(SAVE_VAR, frameIndex, value);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
Register ICodeGenerator::op(ICodeOp op, Register source)
|
||||
{
|
||||
Register dest = getRegister();
|
||||
@ -585,7 +588,7 @@ namespace JavaScript {
|
||||
for (InstructionIterator i = iCode->begin(); i != iCode->end(); i++) {
|
||||
|
||||
for (LabelList::iterator k = labels.begin(); k != labels.end(); k++)
|
||||
if ((*k)->itsOffset == (i - iCode->begin())) {
|
||||
if ((*k)->itsOffset == (ptrdiff_t)(i - iCode->begin())) {
|
||||
//s << "label #" << (k - labels.begin()) << ":\n";
|
||||
s << "#" << (i - iCode->begin());
|
||||
break;
|
||||
@ -691,7 +694,7 @@ namespace JavaScript {
|
||||
s << "\n";
|
||||
}
|
||||
for (LabelList::iterator k = labels.begin(); k != labels.end(); k++)
|
||||
if ((*k)->itsOffset == (iCode->end() - iCode->begin())) {
|
||||
if ((*k)->itsOffset == (ptrdiff_t)(iCode->end() - iCode->begin())) {
|
||||
// s << "label #" << (k - labels.begin()) << ":\n";
|
||||
// s << "#" << (i - iCode->begin());
|
||||
}
|
||||
|
@ -31,50 +31,54 @@ namespace JavaScript {
|
||||
|
||||
typedef uint32 Register;
|
||||
|
||||
typedef std::vector<Register> RegisterList;
|
||||
|
||||
enum ICodeOp {
|
||||
// Operand1 Operand2 Operand3
|
||||
// Operand1 Operand2 Operand3
|
||||
NOP,
|
||||
|
||||
MOVE_TO, // Destination Register Source Register
|
||||
MOVE_TO, // Destination Register Source Register
|
||||
|
||||
LOAD_VAR, // Destination Register index of frame slot
|
||||
SAVE_VAR, // index of frame slot Source Register
|
||||
LOAD_VAR, // Destination Register index of frame slot
|
||||
SAVE_VAR, // index of frame slot Source Register
|
||||
|
||||
LOAD_IMMEDIATE, // Destination Register immediate (double)
|
||||
LOAD_IMMEDIATE, // Destination Register immediate (double)
|
||||
|
||||
LOAD_NAME, // Destination Register StringAtom &
|
||||
SAVE_NAME, // StringAtom & Source Register
|
||||
LOAD_NAME, // Destination Register StringAtom &
|
||||
SAVE_NAME, // StringAtom & Source Register
|
||||
|
||||
NEW_OBJECT, // Destination Register
|
||||
|
||||
GET_PROP, // Destination Register StringAtom & Base Register
|
||||
SET_PROP, // StringAtom & Base Register Source Register
|
||||
GET_PROP, // Destination Register StringAtom & Base Register
|
||||
SET_PROP, // StringAtom & Base Register Source Register
|
||||
|
||||
ADD, // Destination Register Source Register 1 Source Register 2
|
||||
ADD, // Destination Register Source Register 1 Source Register 2
|
||||
SUBTRACT,
|
||||
MULTIPLY,
|
||||
DIVIDE,
|
||||
|
||||
// maintain contiguity
|
||||
COMPARE_LT, // Destination Register Source Register 1 Source Register 2
|
||||
COMPARE_LT, // Destination Register Source Register 1 Source Register 2
|
||||
COMPARE_LE,
|
||||
COMPARE_EQ,
|
||||
COMPARE_NE,
|
||||
COMPARE_GE,
|
||||
COMPARE_GT,
|
||||
|
||||
NOT, // Destination Register Source Register
|
||||
NOT, // Destination Register Source Register
|
||||
|
||||
BRANCH, // Target label
|
||||
|
||||
BRANCH_LT, // Target label Condition Register
|
||||
BRANCH_LT, // Target label Condition Register
|
||||
BRANCH_LE,
|
||||
BRANCH_EQ,
|
||||
BRANCH_NE,
|
||||
BRANCH_GE,
|
||||
BRANCH_GT,
|
||||
|
||||
RETURN // Source Register
|
||||
RETURN, // Source Register
|
||||
|
||||
CALL, // Destination Register Target Register Arguments
|
||||
};
|
||||
|
||||
class Instruction {
|
||||
@ -185,6 +189,12 @@ namespace JavaScript {
|
||||
: Instruction_2<uint32, Register>(op, offset, condition) { }
|
||||
};
|
||||
|
||||
class Call : public Instruction_3<Register, Register, RegisterList> {
|
||||
public:
|
||||
Call(Register result, Register target, RegisterList args)
|
||||
: Instruction_3<Register, Register, RegisterList>(CALL, result, target, args) { }
|
||||
|
||||
};
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
@ -206,6 +216,16 @@ namespace JavaScript {
|
||||
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.
|
||||
@ -220,15 +240,21 @@ namespace JavaScript {
|
||||
|
||||
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() { topRegister = stitcher.empty() ? 0 : stitcher.back()->registerBase; }
|
||||
void resetTopRegister() { markMaxRegister(); topRegister = stitcher.empty() ? 0 : stitcher.back()->registerBase; }
|
||||
|
||||
ICodeOp getBranchOp() { ASSERT(!iCode->empty()); return iCode->back()->getBranchOp(); }
|
||||
|
||||
public:
|
||||
Label *getLabel();
|
||||
private:
|
||||
uint32 maxRegister;
|
||||
uint32 maxVariable;
|
||||
|
||||
|
||||
|
||||
void setLabel(Label *label);
|
||||
void setLabel(InstructionStream *stream, Label *label);
|
||||
|
||||
@ -236,11 +262,12 @@ namespace JavaScript {
|
||||
void branchConditional(Label *label, Register condition);
|
||||
|
||||
public:
|
||||
ICodeGenerator() : topRegister(0) { iCode = new InstructionStream(); }
|
||||
ICodeGenerator() : topRegister(0), maxRegister(0), maxVariable(0) { iCode = new InstructionStream(); }
|
||||
virtual ~ICodeGenerator() { if (iCode) delete iCode; }
|
||||
|
||||
void mergeStream(InstructionStream *sideStream);
|
||||
|
||||
InstructionStream *complete();
|
||||
ICodeModule *complete();
|
||||
|
||||
std::ostream &print(std::ostream &s);
|
||||
|
||||
@ -265,6 +292,8 @@ namespace JavaScript {
|
||||
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
|
||||
|
@ -63,15 +63,17 @@ gc_allocator<JSObject> JSObject::alloc;
|
||||
#define op2(i) (i->itsOperand2)
|
||||
#define op3(i) (i->itsOperand3)
|
||||
|
||||
JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
JSValue interpret(ICodeModule *iCode, const JSValues& args)
|
||||
{
|
||||
JSValue result;
|
||||
JSValues frame(args);
|
||||
JSValues registers(32);
|
||||
JSValues registers(iCode->itsMaxRegister + 1);
|
||||
static JSObject globals;
|
||||
|
||||
InstructionIterator pc = iCode.begin();
|
||||
while (pc != iCode.end()) {
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator end_pc = iCode->its_iCode->end();
|
||||
InstructionIterator pc = begin_pc;
|
||||
while (pc != end_pc) {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->opcode()) {
|
||||
case MOVE_TO:
|
||||
@ -133,7 +135,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
case BRANCH:
|
||||
{
|
||||
ResolvedBranch* bra = static_cast<ResolvedBranch*>(instruction);
|
||||
pc = iCode.begin() + op1(bra);
|
||||
pc = begin_pc + op1(bra);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -141,7 +143,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 < 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -150,7 +152,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 <= 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -159,7 +161,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 == 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -168,7 +170,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 != 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -177,7 +179,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 >= 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -186,7 +188,7 @@ JSValue interpret(InstructionStream& iCode, const JSValues& args)
|
||||
{
|
||||
ResolvedBranchCond* bc = static_cast<ResolvedBranchCond*>(instruction);
|
||||
if (registers[op2(bc)].i32 > 0) {
|
||||
pc = iCode.begin() + op1(bc);
|
||||
pc = begin_pc + op1(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace JavaScript {
|
||||
|
||||
typedef vector<JSValue, gc_allocator<JSValue> > JSValues;
|
||||
|
||||
JSValue interpret(InstructionStream& iCode, const JSValues& args);
|
||||
JSValue interpret(ICodeModule *iCode, const JSValues& args);
|
||||
}
|
||||
|
||||
#endif /* interpreter_h */
|
||||
|
@ -342,9 +342,24 @@ static void testICG(World &world)
|
||||
icg.saveVariable(0, icg.loadImmediate(99));
|
||||
icg.endForStatement();
|
||||
|
||||
InstructionStream *iCode = icg.complete();
|
||||
ICodeModule *icm = icg.complete();
|
||||
|
||||
std::cout << icg;
|
||||
|
||||
delete icm;
|
||||
}
|
||||
|
||||
static float64 testFunctionCall(float64 n)
|
||||
{
|
||||
uint32 position = 0;
|
||||
ICodeGenerator icg;
|
||||
|
||||
// function sum(n) { if (n > 1) return 1 + sum(n - 1); else return 1; }
|
||||
// n is bound to var #0.
|
||||
icg.beginStatement(position);
|
||||
icg.loadVariable(0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static float64 testFactorial(float64 n)
|
||||
@ -384,15 +399,17 @@ static float64 testFactorial(float64 n)
|
||||
|
||||
// return result;
|
||||
icg.returnStatement(icg.loadVariable(1));
|
||||
InstructionStream *iCode = icg.complete();
|
||||
// std::cout << icg;
|
||||
ICodeModule *icm = icg.complete();
|
||||
std::cout << icg;
|
||||
|
||||
// test the iCode interpreter.
|
||||
JSValues args(32);
|
||||
args[0] = JSValue(n);
|
||||
JSValue result = interpret(*iCode, args);
|
||||
JSValue result = interpret(icm, args);
|
||||
std::cout << "fact(" << n << ") = " << result.f64 << std::endl;
|
||||
|
||||
delete icm;
|
||||
|
||||
return result.f64;
|
||||
}
|
||||
|
||||
@ -412,7 +429,7 @@ static float64 testObjects(World &world, int32 n)
|
||||
initCG.beginStatement(position);
|
||||
initCG.setProperty(counter, initCG.loadName(global), initCG.loadImmediate(0.0));
|
||||
|
||||
InstructionStream* initCode = initCG.complete();
|
||||
ICodeModule* initCode = initCG.complete();
|
||||
|
||||
std::cout << initCG;
|
||||
|
||||
@ -428,21 +445,24 @@ static float64 testObjects(World &world, int32 n)
|
||||
incrCG.setProperty(counter, robject, rvalue);
|
||||
incrCG.returnStatement(rvalue);
|
||||
|
||||
InstructionStream* incrCode = incrCG.complete();
|
||||
ICodeModule* incrCode = incrCG.complete();
|
||||
|
||||
std::cout << incrCG;
|
||||
|
||||
// run initialization code.
|
||||
JSValues args(32);
|
||||
interpret(*initCode, args);
|
||||
interpret(initCode, args);
|
||||
|
||||
// call the increment function some number of times.
|
||||
JSValue result;
|
||||
while (n-- > 0)
|
||||
result = interpret(*incrCode, args);
|
||||
result = interpret(incrCode, args);
|
||||
|
||||
std::cout << "result = " << result.f64 << std::endl;
|
||||
|
||||
delete initCode;
|
||||
delete incrCode;
|
||||
|
||||
return result.f64;
|
||||
}
|
||||
|
||||
@ -452,7 +472,7 @@ int main(int argc, char **argv)
|
||||
initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv);
|
||||
#endif
|
||||
World world;
|
||||
#if 0
|
||||
#if 1
|
||||
assert(testFactorial(5) == 120);
|
||||
assert(testObjects(world, 5) == 5);
|
||||
testICG(world);
|
||||
|
Loading…
x
Reference in New Issue
Block a user