在控制语句的指令生成过程中, 语句无法知道外界指令结构, 不能贸然将跳出语句定向到外部指令, 因此使用了 NOP 指令缓冲了这些跳转. 然而, 在全部指令生成结束后, 跳转指令就可以根据上下文选择正确的目标了, 那么 NOP 指令只是影响性能的冗余指令了. 本着兔死狗烹的原则, 现在去掉这些指令.
static void cleanNop(struct List* instructions);
具体的做法是, 为每个 NOP 指令记录它之后的第一条非 NOP 指令, 然后扫描指令序列, 重定向它们的目标, 然后删去全部 NOP 指令. 现在先给指令数据结构增加一个索引域
/* 增加 index 域 */ #define memberAbstractInstruction \ int segOffset; \ int index; \ InstructionCode code; /*******/ struct AbstractInstruction { memberAbstractInstruction };
对于非 NOP 指令, 它的索引域等于它自己的位置索引, 而 NOP 指令的索引域等于该指令之后第一条非 NOP 指令的索引.
对整个指令序列进行一次逆向遍历, 计算它们的索引值
int index = instructions->count(instructions) - 1; int lastOpInd; struct AbstractInstruction* ins; for (; index >=0; --index) { ins = (struct AbstractInstruction*) (instructions->elementAt(instructions, index)); if (NOP != ins->code) { lastOpInd = index; } ins->index = lastOpInd; }
扫描并重定向全部的跳转指令
struct Iterator* iterator; for_each (iterator, instructions) { ins = (struct AbstractInstruction*)(iterator->current(iterator)); if (isJump(ins->code)) { struct JumpInstruction* jmp = (struct JumpInstruction*)ins; jmp->targetIns = instructions->elementAt(instructions, jmp->targetIns->index); } }
删除 NOP 指令. 任务完成.
for_each (iterator, instructions) { if (NOP == ((struct AbstractInstruction*) (iterator->current(iterator)))->code) { revert(iterator->current(iterator)); iterator->remove(iterator); } }
现在的修改版本中, 输出指令的代码被移入新文件, 减少了 jerry-compiler.c 的混乱程度.
void fakeDefaultAnalyserConsumeNT(void* self, struct AbstractSyntaxNode* node) { if (NULL == node) { return; } node = (struct AbstractSyntaxNode*)newBasicBlockNode(node); initStack(&loopStack); initialSymTabManager(); struct List* insList = node->createInstruction(node); node->delNode(node); finalizeSymTabManager(); loopStack.finalize(&loopStack); if (isFailed()) { while (0 != insList->count(insList)) { revert(insList->popElementAt(insList, 0)); } cresult = ERROR_IN_SRC; return; } struct NoParamInstruction* endProg = (struct NoParamInstruction*) allocate(sizeof(struct NoParamInstruction)); endProg->code = END_PROGRAM; insList->addTo(insList, endProg, insList->count(insList)); /* 原先在这里的代码, 以及 writeInstruction 函数被移入了 instruction-process.cpp / instruction-process.h */ ErrMsg err = processIns(insList, treeout); if (NULL != err) { fputs(err, stderr); cresult = IO_ERROR; } insList->finalize(insList); }
编译器/解释器构造到此结束, 也许我还会改改 Jerry, 不过不保证, 哈~