예제 #1
0
        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);
            }
        }
예제 #2
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            // If this Target was already translated, it's needed to change the current
            // state and return null to tell CompilerContext to process next untranslated
            // item.
            if (IsTranslated)
            {
                cc.RestoreState(_state);
                return null;
            }

            if (cc.Unreachable)
            {
                // If the context has "isUnreachable" flag set and there is no state then
                // it means that this code will be never called. This is a problem, because
                // we are unable to assign a state to current location so we can't allocate
                // registers for variables used inside. So instead of doing anything wrong
                // we remove the unreachable code.
                if (_state == null)
                    return RemoveUnreachableItems();

                // Assign state to the compiler context.
                cc.Unreachable = false;
                cc.AssignState(_state);
            }
            else
            {
                _state = cc.SaveState();
            }

            return Next;
        }