Example #1
0
        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);
            }
        }