bool Compiler::ParseOrCondition(const TEXTRANGE& messageRange) { POTE oteSelector = AddSymbolToFrame("or:", messageRange); if (!ThisTokenIsBinary('[')) { Warning(CWarnExpectNiladicBlockArg, (Oop)oteSelector); return false; } // Note "reordering" to allow us to use the smaller // jump on false instruction. In the case of #or: this // seems to be worth doing, even if it isn't for #ifFalse:. It does // result in a small overall size reduction. Which has a speed // advantage is difficult to say. // int branchMark = GenJumpInstruction(LongJumpIfFalse); AddTextMap(branchMark, messageRange); GenInstruction(ShortPushTrue); int jumpOutMark = GenJumpInstruction(LongJump); int ifFalse = m_codePointer; ParseZeroArgOptimizedBlock(); if (m_ok) { SetJumpTarget(branchMark, ifFalse); SetJumpTarget(jumpOutMark, GenNop()); } return true; }
bool Compiler::ParseAndCondition(const TEXTRANGE& messageRange) { POTE oteSelector = AddSymbolToFrame("and:", messageRange); // Assume we can reorder blocks to allow us to use the smaller // jump on false instruction. // int popAndJumpInstruction=LongJumpIfFalse; if (!ThisTokenIsBinary('[')) { Warning(CWarnExpectNiladicBlockArg, (Oop)oteSelector); return false; } // If the receiver is false, then the whole expression is false, so // jump over (shortcut) the block argument int branchMark = GenJumpInstruction(LongJumpIfFalse); AddTextMap(branchMark, messageRange); ParseZeroArgOptimizedBlock(); int jumpOutMark = GenJumpInstruction(LongJump); SetJumpTarget(branchMark, GenInstruction(ShortPushFalse)); SetJumpTarget(jumpOutMark, GenNop()); return true; }
bool Compiler::ParseIfFalse(const TEXTRANGE& messageRange) { if (!ThisTokenIsBinary('[')) { Warning(CWarnExpectNiladicBlockArg, (Oop)InternSymbol("ifFalse:")); return false; } int condJumpMark = GenJumpInstruction(LongJumpIfTrue); AddTextMap(condJumpMark, messageRange); ParseZeroArgOptimizedBlock(); // Need to jump over the false block at end of true block int jumpOutMark = GenJumpInstruction(LongJump); int elseMark = m_codePointer; if (strcmp(ThisTokenText(), "ifTrue:") == 0) { // An else block exists POTE oteSelector = AddSymbolToFrame("ifFalse:ifTrue:", messageRange); NextToken(); ParseZeroArgOptimizedBlock(); } else { // When ifTrue: branch is missing, value of expression if condition false is nil POTE oteSelector = AddSymbolToFrame("ifFalse:", messageRange); // N.B. We used (pre 5.5) to reorder the "blocks" to take advantage of the shorter jump on false // instruction (i.e. we put the empty true block first), but it turns out that this // apparent optimization is actually a bad idea since it seems to reduce the effectiveness // of the peephole optimizer. Here are some stats from an image with 34319 methods: // // Methods affected: 1276 // Shorter with inversion: 182 // Shorter without inversion: 849 (1) // Size of bytecodes with: 60268 // Size of bytecodes without: 58564 (2) // // i.e. more methods are lengthened by the apparent optimization than without it (1), and // the overall size of the methods is actually increased in most cases (2). GenInstruction(ShortPushNil); } SetJumpTarget(jumpOutMark, GenNop()); // Now the jump on condition SetJumpTarget(condJumpMark, elseMark); return true; }
void GenPrintInstr1Operand(int instr, int instrval, int operand, int operandval) { GenPrintInstr(instr, instrval); GenPrintOperand(operand, operandval); GenPrintNewLine(); #ifndef NO_REORDER_WORKAROUND if (instr == MipsInstrJ || instr == MipsInstrJAL) GenNop(); #endif }
void GenFin(void) { if (StructCpyLabel) { char s[1 + 2 + (2 + CHAR_BIT * sizeof StructCpyLabel) / 3]; char *p = s + sizeof s; int lbl = LabelCnt++; *--p = '\0'; p = lab2str(p, StructCpyLabel); *--p = '_'; *--p = '_'; if (OutputFormat != FormatFlat) puts2(CodeHeader); GenLabel(p, 1); puts2("\tmove\t$2, $6\n" "\tmove\t$3, $6"); GenNumLabel(lbl); puts2("\tlbu\t$6, 0($5)\n" "\taddiu\t$5, $5, 1\n" "\taddiu\t$4, $4, -1\n" "\tsb\t$6, 0($3)\n" "\taddiu\t$3, $3, 1"); printf2("\tbne\t$4, $0, "); GenPrintNumLabel(lbl); puts2(""); #ifndef NO_REORDER_WORKAROUND GenNop(); #endif puts2("\tj\t$31"); #ifndef NO_REORDER_WORKAROUND GenNop(); #endif if (OutputFormat != FormatFlat) puts2(CodeFooter); } }
bool Compiler::ParseIfTrue(const TEXTRANGE& messageRange) { if (!ThisTokenIsBinary('[')) { Warning(CWarnExpectNiladicBlockArg, (Oop)InternSymbol("ifTrue:")); return false; } int condJumpMark = GenJumpInstruction(LongJumpIfFalse); AddTextMap(condJumpMark, messageRange); ParseZeroArgOptimizedBlock(); // Need to jump over the false block at end of true block int jumpOutMark = GenJumpInstruction(LongJump); int elseMark = m_codePointer; if (strcmp(ThisTokenText(), "ifFalse:") == 0) { // An else block exists POTE oteSelector = AddSymbolToFrame("ifTrue:ifFalse:", messageRange); NextToken(); ParseZeroArgOptimizedBlock(); } else { // When #ifFalse: branch is missing, value of expression if condition false is nil POTE oteSelector = AddSymbolToFrame("ifTrue:", messageRange); GenInstruction(ShortPushNil); } SetJumpTarget(jumpOutMark, GenNop()); // Now the jump on condition SetJumpTarget(condJumpMark, elseMark); return true; }
void GenPrintInstr3Operands(int instr, int instrval, int operand1, int operand1val, int operand2, int operand2val, int operand3, int operand3val) { if (operand3 == MipsOpConst && operand3val == 0 && (instr == MipsInstrAddU || instr == MipsInstrSubU)) return; GenPrintInstr(instr, instrval); GenPrintOperand(operand1, operand1val); GenPrintOperandSeparator(); GenPrintOperand(operand2, operand2val); GenPrintOperandSeparator(); GenPrintOperand(operand3, operand3val); GenPrintNewLine(); #ifndef NO_REORDER_WORKAROUND if (instr == MipsInstrBEQ || instr == MipsInstrBNE) GenNop(); #endif }
bool Compiler::ParseIfNotNil(const TEXTRANGE& messageRange, int exprStartPos) { if (!ThisTokenIsBinary('[')) { Warning(CWarnExpectMonadicOrNiladicBlockArg, (Oop)InternSymbol("ifNotNil:")); return false; } int dupMark = GenDup(); BreakPoint(); const int sendIsNil = GenInstruction(SpecialSendIsNil); AddTextMap(sendIsNil, exprStartPos, LastTokenRange().m_stop); // We're going to add a pop and jump on condition instruction here // Its a forward jump, so we need to patch up the target later const int popAndJumpMark = GenJumpInstruction(LongJumpIfTrue); int argc = ParseIfNotNilBlock(); // If the ifNotNil: block did not have any arguments, then we do not need the Dup, and we also // need to patch out the corresponding pop. if (!argc) { UngenInstruction(dupMark); UngenInstruction(popAndJumpMark + lengthOfByteCode(LongJumpIfTrue)); } int ifNilMark; // Has an #ifNil: branch? if (strcmp(ThisTokenText(), "ifNil:") == 0) { POTE oteSelector = AddSymbolToFrame("ifNotNil:ifNil:", messageRange); // Generate the jump out instruction (forward jump, so target not yet known) int jumpOutMark = GenJumpInstruction(LongJump); // Mark first instruction of the "else" branch ifNilMark = m_codePointer; // ifNotNil:ifNil: form NextToken(); ParseIfNilBlock(!argc); SetJumpTarget(jumpOutMark, GenNop()); } else { // No "ifNil:" branch POTE oteSelector = AddSymbolToFrame("ifNotNil:", messageRange); if (!argc) { // Since we've removed the Dup if the ifNotNil: block had no args, we need to ensure there is nil atop the stack // This should normally get optimized away later if the expression value is not used. // Generate the jump out instruction int jumpOutMark = GenJumpInstruction(LongJump); ifNilMark = GenInstruction(ShortPushNil); SetJumpTarget(jumpOutMark, GenNop()); } else { ifNilMark = GenNop(); } } SetJumpTarget(popAndJumpMark, ifNilMark); return true; }
bool Compiler::ParseIfNil(const TEXTRANGE& messageRange, int exprStartPos) { if (!ThisTokenIsBinary('[')) { Warning(CWarnExpectNiladicBlockArg, (Oop)InternSymbol("ifNil:")); return false; } int dupMark = GenDup(); BreakPoint(); const int sendIsNil = GenInstruction(SpecialSendIsNil); const int mapEntry = AddTextMap(sendIsNil, exprStartPos, LastTokenRange().m_stop); // We're going to add a pop and jump on condition instruction here // Its a forward jump, so we need to patch up the target later const int popAndJumpMark = GenJumpInstruction(LongJumpIfFalse); ParseIfNilBlock(false); int ifNotNilMark; if (strcmp(ThisTokenText(), "ifNotNil:") == 0) { POTE oteSelector = AddSymbolToFrame("ifNil:ifNotNil:", messageRange); // Generate the jump out instruction (forward jump, so target not yet known) int jumpOutMark = GenJumpInstruction(LongJump); // Mark first instruction of the "else" branch ifNotNilMark = m_codePointer; // #ifNil:ifNotNil: form NextToken(); int argc = ParseIfNotNilBlock(); // Be careful, may not actually be a literal block there if (m_ok) { // If the ifNotNil: block does not need an argument, we can patch out the Dup // and corresponding pop if (!argc) { UngenInstruction(dupMark); _ASSERTE(m_bytecodes[popAndJumpMark + lengthOfByteCode(LongJumpIfFalse)].byte == PopStackTop); UngenInstruction(popAndJumpMark + lengthOfByteCode(LongJumpIfFalse)); _ASSERTE(m_bytecodes[ifNotNilMark].byte == PopStackTop); UngenInstruction(ifNotNilMark); } // Set unconditional jump at the end of the ifNil to jump over the "else" branch to a Nop SetJumpTarget(jumpOutMark, GenNop()); } } else { POTE oteSelector = AddSymbolToFrame("ifNil:", messageRange); // No "else" branch, but we still need an instruction to jump to ifNotNilMark = GenNop(); } if (m_ok) { // Conditional jump to the "else" branch (or the Nop if no else branch) SetJumpTarget(popAndJumpMark, ifNotNilMark); if (mapEntry >= 0) m_textMaps[mapEntry].stop = LastTokenRange().m_stop; } return true; }