зеркало из https://github.com/mozilla/pjs.git
For statements.
This commit is contained in:
Родитель
a319d852b3
Коммит
3714722cf4
|
@ -161,19 +161,19 @@ void ICodeGenerator::setLabel(InstructionStream *stream, int32 label)
|
|||
|
||||
/***********************************************************************************************/
|
||||
|
||||
void MultiPathICodeState::mergeStream(InstructionStream *mainStream, LabelList &labels)
|
||||
void MultiPathICodeState::mergeStream(InstructionStream *sideStream, InstructionStream *mainStream, LabelList &labels)
|
||||
{
|
||||
// change InstructionStream to be a class that also remembers
|
||||
// if it contains any labels (maybe even remembers the labels
|
||||
// themselves?) in order to avoid running this loop unnecessarily.
|
||||
for (LabelList::iterator i = labels.begin(); i != labels.end(); i++) {
|
||||
if ((*i)->itsBase == its_iCode) {
|
||||
if ((*i)->itsBase == sideStream) {
|
||||
(*i)->itsBase = mainStream;
|
||||
(*i)->itsOffset += mainStream->size();
|
||||
}
|
||||
}
|
||||
|
||||
for (InstructionIterator ii = its_iCode->begin(); ii != its_iCode->end(); ii++)
|
||||
for (InstructionIterator ii = sideStream->begin(); ii != sideStream->end(); ii++)
|
||||
mainStream->push_back(*ii);
|
||||
|
||||
}
|
||||
|
@ -231,6 +231,66 @@ void ICodeGenerator::endWhileStatement()
|
|||
|
||||
/***********************************************************************************************/
|
||||
|
||||
void ICodeGenerator::beginForStatement(const SourcePosition &pos)
|
||||
{
|
||||
int32 forCondition = getLabel();
|
||||
|
||||
ForCodeState *ics = new ForCodeState(forCondition, getLabel(), this);
|
||||
ics->continueLabel = getLabel();
|
||||
|
||||
branch(forCondition);
|
||||
|
||||
stitcher.push_back(ics);
|
||||
|
||||
iCode = new InstructionStream(); // begin the stream for collecting the test expression
|
||||
setLabel(forCondition);
|
||||
|
||||
resetTopRegister();
|
||||
}
|
||||
|
||||
void ICodeGenerator::forCondition(Register condition)
|
||||
{
|
||||
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == For_state);
|
||||
|
||||
// finsh off the test expression by adding the branch to the body
|
||||
branchConditional(ics->forBody, condition);
|
||||
|
||||
iCode = ics->swapStream(iCode); // switch back to main stream
|
||||
iCode = new InstructionStream(); // begin the stream for collecting the increment expression
|
||||
|
||||
setLabel(ics->continueLabel); // which is where continues will target
|
||||
resetTopRegister();
|
||||
}
|
||||
|
||||
void ICodeGenerator::forIncrement()
|
||||
{
|
||||
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == For_state);
|
||||
|
||||
// now switch back to the main stream
|
||||
iCode = ics->swapStream2(iCode);
|
||||
setLabel(ics->forBody);
|
||||
|
||||
resetTopRegister();
|
||||
}
|
||||
|
||||
void ICodeGenerator::endForStatement()
|
||||
{
|
||||
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == For_state);
|
||||
|
||||
ics->mergeStream2(iCode, labels); // merges the increment sequence
|
||||
ics->mergeStream(iCode, labels); // merges the test sequence
|
||||
|
||||
if (ics->breakLabel != -1)
|
||||
setLabel(ics->breakLabel);
|
||||
|
||||
delete ics;
|
||||
}
|
||||
|
||||
/***********************************************************************************************/
|
||||
|
||||
void ICodeGenerator::beginDoStatement(const SourcePosition &pos)
|
||||
{
|
||||
resetTopRegister();
|
||||
|
@ -279,12 +339,12 @@ void ICodeGenerator::beginSwitchStatement(const SourcePosition &pos, Register ex
|
|||
{
|
||||
// stash the control expression value
|
||||
resetTopRegister();
|
||||
op(MOVE_TO, getRegister(), expression);
|
||||
Register control = op(MOVE_TO, expression);
|
||||
// build an instruction stream for the case statements, the case
|
||||
// expressions are generated into the main stream directly, the
|
||||
// case statements are then added back in afterwards.
|
||||
InstructionStream *x = new InstructionStream();
|
||||
SwitchCodeState *ics = new SwitchCodeState(expression, this);
|
||||
SwitchCodeState *ics = new SwitchCodeState(control, this);
|
||||
ics->swapStream(x);
|
||||
stitcher.push_back(ics);
|
||||
}
|
||||
|
|
|
@ -131,7 +131,9 @@ namespace JavaScript {
|
|||
|
||||
InstructionStream *its_iCode;
|
||||
|
||||
void mergeStream(InstructionStream *mainStream, LabelList &labels);
|
||||
static void mergeStream(InstructionStream *sideStream, InstructionStream *mainStream, LabelList &labels);
|
||||
|
||||
void mergeStream(InstructionStream *mainStream, LabelList &labels) { mergeStream(its_iCode, mainStream, labels); }
|
||||
};
|
||||
|
||||
class WhileCodeState : public MultiPathICodeState {
|
||||
|
@ -142,6 +144,16 @@ namespace JavaScript {
|
|||
int32 whileBody;
|
||||
};
|
||||
|
||||
class ForCodeState : public MultiPathICodeState {
|
||||
public:
|
||||
ForCodeState(int32 conditionLabel, int32 bodyLabel, ICodeGenerator *icg); // inline below
|
||||
InstructionStream *swapStream2(InstructionStream *iCode) { InstructionStream *t = its_iCode_2; its_iCode_2 = iCode; return t; }
|
||||
void mergeStream2(InstructionStream *mainStream, LabelList &labels) { mergeStream(its_iCode_2, mainStream, labels); }
|
||||
int32 forCondition;
|
||||
int32 forBody;
|
||||
InstructionStream *its_iCode_2;
|
||||
};
|
||||
|
||||
class IfCodeState : public ICodeState {
|
||||
public:
|
||||
IfCodeState(int32 a, int32 b, ICodeGenerator *icg)
|
||||
|
@ -241,9 +253,9 @@ namespace JavaScript {
|
|||
|
||||
|
||||
// for ( ... in ...) statements get turned into generic for statements by the parser (ok?)
|
||||
void beginForStatement(); // for initialization is emitted prior to this call
|
||||
void forCondition(Register condition); // required with optional <operand>
|
||||
void forIncrement(Register expression); // required with optional <operand>
|
||||
void beginForStatement(const SourcePosition &pos); // for initialization is emitted prior to this call
|
||||
void forCondition(Register condition); // required
|
||||
void forIncrement(); // required
|
||||
void endForStatement();
|
||||
|
||||
|
||||
|
@ -290,5 +302,8 @@ namespace JavaScript {
|
|||
|
||||
inline MultiPathICodeState::MultiPathICodeState(StateKind kind, ICodeGenerator *icg)
|
||||
: ICodeState(kind, icg), its_iCode(icg->get_iCode()) {}
|
||||
|
||||
inline ForCodeState::ForCodeState(int32 conditionLabel, int32 bodyLabel, ICodeGenerator *icg)
|
||||
: MultiPathICodeState(For_state, icg), forCondition(conditionLabel), forBody(bodyLabel), its_iCode_2(icg->get_iCode()) { }
|
||||
}
|
||||
#endif
|
|
@ -400,6 +400,17 @@ void testICG(World &world)
|
|||
icg.endDefaultStatement();
|
||||
icg.endSwitchStatement();
|
||||
|
||||
// for ( ; i; i + 1 ) j = 99;
|
||||
icg.beginForStatement(pos);
|
||||
r1 = icg.loadVariable(0);
|
||||
icg.forCondition(r1);
|
||||
icg.saveVariable(0, icg.op(ADD, icg.loadVariable(0), icg.loadImmediate(1)));
|
||||
icg.forIncrement();
|
||||
icg.saveVariable(0, icg.loadImmediate(99));
|
||||
icg.endForStatement();
|
||||
|
||||
|
||||
|
||||
InstructionStream *iCode = icg.complete();
|
||||
|
||||
std::cout << icg;
|
||||
|
|
|
@ -161,19 +161,19 @@ void ICodeGenerator::setLabel(InstructionStream *stream, int32 label)
|
|||
|
||||
/***********************************************************************************************/
|
||||
|
||||
void MultiPathICodeState::mergeStream(InstructionStream *mainStream, LabelList &labels)
|
||||
void MultiPathICodeState::mergeStream(InstructionStream *sideStream, InstructionStream *mainStream, LabelList &labels)
|
||||
{
|
||||
// change InstructionStream to be a class that also remembers
|
||||
// if it contains any labels (maybe even remembers the labels
|
||||
// themselves?) in order to avoid running this loop unnecessarily.
|
||||
for (LabelList::iterator i = labels.begin(); i != labels.end(); i++) {
|
||||
if ((*i)->itsBase == its_iCode) {
|
||||
if ((*i)->itsBase == sideStream) {
|
||||
(*i)->itsBase = mainStream;
|
||||
(*i)->itsOffset += mainStream->size();
|
||||
}
|
||||
}
|
||||
|
||||
for (InstructionIterator ii = its_iCode->begin(); ii != its_iCode->end(); ii++)
|
||||
for (InstructionIterator ii = sideStream->begin(); ii != sideStream->end(); ii++)
|
||||
mainStream->push_back(*ii);
|
||||
|
||||
}
|
||||
|
@ -231,6 +231,66 @@ void ICodeGenerator::endWhileStatement()
|
|||
|
||||
/***********************************************************************************************/
|
||||
|
||||
void ICodeGenerator::beginForStatement(const SourcePosition &pos)
|
||||
{
|
||||
int32 forCondition = getLabel();
|
||||
|
||||
ForCodeState *ics = new ForCodeState(forCondition, getLabel(), this);
|
||||
ics->continueLabel = getLabel();
|
||||
|
||||
branch(forCondition);
|
||||
|
||||
stitcher.push_back(ics);
|
||||
|
||||
iCode = new InstructionStream(); // begin the stream for collecting the test expression
|
||||
setLabel(forCondition);
|
||||
|
||||
resetTopRegister();
|
||||
}
|
||||
|
||||
void ICodeGenerator::forCondition(Register condition)
|
||||
{
|
||||
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == For_state);
|
||||
|
||||
// finsh off the test expression by adding the branch to the body
|
||||
branchConditional(ics->forBody, condition);
|
||||
|
||||
iCode = ics->swapStream(iCode); // switch back to main stream
|
||||
iCode = new InstructionStream(); // begin the stream for collecting the increment expression
|
||||
|
||||
setLabel(ics->continueLabel); // which is where continues will target
|
||||
resetTopRegister();
|
||||
}
|
||||
|
||||
void ICodeGenerator::forIncrement()
|
||||
{
|
||||
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == For_state);
|
||||
|
||||
// now switch back to the main stream
|
||||
iCode = ics->swapStream2(iCode);
|
||||
setLabel(ics->forBody);
|
||||
|
||||
resetTopRegister();
|
||||
}
|
||||
|
||||
void ICodeGenerator::endForStatement()
|
||||
{
|
||||
ForCodeState *ics = static_cast<ForCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == For_state);
|
||||
|
||||
ics->mergeStream2(iCode, labels); // merges the increment sequence
|
||||
ics->mergeStream(iCode, labels); // merges the test sequence
|
||||
|
||||
if (ics->breakLabel != -1)
|
||||
setLabel(ics->breakLabel);
|
||||
|
||||
delete ics;
|
||||
}
|
||||
|
||||
/***********************************************************************************************/
|
||||
|
||||
void ICodeGenerator::beginDoStatement(const SourcePosition &pos)
|
||||
{
|
||||
resetTopRegister();
|
||||
|
@ -279,12 +339,12 @@ void ICodeGenerator::beginSwitchStatement(const SourcePosition &pos, Register ex
|
|||
{
|
||||
// stash the control expression value
|
||||
resetTopRegister();
|
||||
op(MOVE_TO, getRegister(), expression);
|
||||
Register control = op(MOVE_TO, expression);
|
||||
// build an instruction stream for the case statements, the case
|
||||
// expressions are generated into the main stream directly, the
|
||||
// case statements are then added back in afterwards.
|
||||
InstructionStream *x = new InstructionStream();
|
||||
SwitchCodeState *ics = new SwitchCodeState(expression, this);
|
||||
SwitchCodeState *ics = new SwitchCodeState(control, this);
|
||||
ics->swapStream(x);
|
||||
stitcher.push_back(ics);
|
||||
}
|
||||
|
|
|
@ -131,7 +131,9 @@ namespace JavaScript {
|
|||
|
||||
InstructionStream *its_iCode;
|
||||
|
||||
void mergeStream(InstructionStream *mainStream, LabelList &labels);
|
||||
static void mergeStream(InstructionStream *sideStream, InstructionStream *mainStream, LabelList &labels);
|
||||
|
||||
void mergeStream(InstructionStream *mainStream, LabelList &labels) { mergeStream(its_iCode, mainStream, labels); }
|
||||
};
|
||||
|
||||
class WhileCodeState : public MultiPathICodeState {
|
||||
|
@ -142,6 +144,16 @@ namespace JavaScript {
|
|||
int32 whileBody;
|
||||
};
|
||||
|
||||
class ForCodeState : public MultiPathICodeState {
|
||||
public:
|
||||
ForCodeState(int32 conditionLabel, int32 bodyLabel, ICodeGenerator *icg); // inline below
|
||||
InstructionStream *swapStream2(InstructionStream *iCode) { InstructionStream *t = its_iCode_2; its_iCode_2 = iCode; return t; }
|
||||
void mergeStream2(InstructionStream *mainStream, LabelList &labels) { mergeStream(its_iCode_2, mainStream, labels); }
|
||||
int32 forCondition;
|
||||
int32 forBody;
|
||||
InstructionStream *its_iCode_2;
|
||||
};
|
||||
|
||||
class IfCodeState : public ICodeState {
|
||||
public:
|
||||
IfCodeState(int32 a, int32 b, ICodeGenerator *icg)
|
||||
|
@ -241,9 +253,9 @@ namespace JavaScript {
|
|||
|
||||
|
||||
// for ( ... in ...) statements get turned into generic for statements by the parser (ok?)
|
||||
void beginForStatement(); // for initialization is emitted prior to this call
|
||||
void forCondition(Register condition); // required with optional <operand>
|
||||
void forIncrement(Register expression); // required with optional <operand>
|
||||
void beginForStatement(const SourcePosition &pos); // for initialization is emitted prior to this call
|
||||
void forCondition(Register condition); // required
|
||||
void forIncrement(); // required
|
||||
void endForStatement();
|
||||
|
||||
|
||||
|
@ -290,5 +302,8 @@ namespace JavaScript {
|
|||
|
||||
inline MultiPathICodeState::MultiPathICodeState(StateKind kind, ICodeGenerator *icg)
|
||||
: ICodeState(kind, icg), its_iCode(icg->get_iCode()) {}
|
||||
|
||||
inline ForCodeState::ForCodeState(int32 conditionLabel, int32 bodyLabel, ICodeGenerator *icg)
|
||||
: MultiPathICodeState(For_state, icg), forCondition(conditionLabel), forBody(bodyLabel), its_iCode_2(icg->get_iCode()) { }
|
||||
}
|
||||
#endif
|
|
@ -400,6 +400,17 @@ void testICG(World &world)
|
|||
icg.endDefaultStatement();
|
||||
icg.endSwitchStatement();
|
||||
|
||||
// for ( ; i; i + 1 ) j = 99;
|
||||
icg.beginForStatement(pos);
|
||||
r1 = icg.loadVariable(0);
|
||||
icg.forCondition(r1);
|
||||
icg.saveVariable(0, icg.op(ADD, icg.loadVariable(0), icg.loadImmediate(1)));
|
||||
icg.forIncrement();
|
||||
icg.saveVariable(0, icg.loadImmediate(99));
|
||||
icg.endForStatement();
|
||||
|
||||
|
||||
|
||||
InstructionStream *iCode = icg.complete();
|
||||
|
||||
std::cout << icg;
|
||||
|
|
Загрузка…
Ссылка в новой задаче