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;
}
示例#4
0
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
}
示例#5
0
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;
}
示例#7
0
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;
}