private CompilerFunction(Compiler compiler, FunctionDeclaration prototype) : base(compiler) { Contract.Requires(compiler != null); Contract.Requires(prototype != null); _functionPrototype = prototype; _entryLabel = compiler.DefineLabel(); _exitLabel = compiler.DefineLabel(); _entryTarget = compiler.GetTarget(_entryLabel.Id); _exitTarget = compiler.GetTarget(_exitLabel.Id); _end = new CompilerFunctionEnd(compiler, this); }
public CompilerJmpInstruction(Compiler compiler, InstructionCode code, Operand[] operands) : base(compiler, code, operands) { if (code < InstructionDescription.JumpBegin || code > InstructionDescription.JumpEnd) throw new ArgumentException("The specified instruction code is not a valid jump."); Contract.Requires(compiler != null); Contract.Requires(operands != null); Contract.EndContractBlock(); _jumpTarget = compiler.GetTarget(Operands[0].Id); _jumpTarget.JumpsCount++; _jumpNext = _jumpTarget.From; _jumpTarget.From = this; _isTaken = Code == InstructionCode.Jmp || (Operands.Length > 1 && Operands[1].IsImm && ((Imm)Operands[1]).Value == (IntPtr)Hint.Taken); }
internal void DoJump(CompilerContext cc) { Contract.Requires(cc != null); // The state have to be already known. The _doJump() method is called by // translate() or by Compiler in case that it's forward jump. if (_jumpTarget.State == null) throw new CompilerException("Cannot jump to a target without knowing its state."); if ((Code == InstructionCode.Jmp) || (IsTaken && _jumpTarget.Offset < Offset)) { // Instruction type is JMP or conditional jump that should be taken (likely). // We can set state here instead of jumping out, setting state and jumping // to _jumpTarget. // // NOTE: We can't use this technique if instruction is forward conditional // jump. The reason is that when generating code we can't change state here, // because the next instruction depends on it. cc.RestoreState(_jumpTarget.State, _jumpTarget.Offset); } else { // Instruction type is JMP or conditional jump that should be not normally // taken. If we need add code that will switch between different states we // add it after the end of function body (after epilog, using 'ExtraBlock'). Compiler compiler = cc.Compiler; CompilerItem ext = cc.ExtraBlock; CompilerItem old = compiler.CurrentItem; compiler.CurrentItem = ext; cc.RestoreState(_jumpTarget.State, _jumpTarget.Offset); if (compiler.CurrentItem != ext) { // Add the jump to the target. compiler.Jmp(_jumpTarget.Label); ext = compiler.CurrentItem; // The cc._restoreState() method emitted some instructions so we need to // patch the jump. Label L = compiler.DefineLabel(); compiler.CurrentItem = cc.ExtraBlock; compiler.MarkLabel(L); // Finally, patch the jump target. if (Operands.Length == 0) throw new CompilerException(); Operands[0] = L; // Operand part (Label). _jumpTarget = compiler.GetTarget(L.Id); // Item part (ETarget). } cc.ExtraBlock = ext; compiler.CurrentItem = old; // Assign state back. cc.AssignState(_state); } }