Пример #1
0
        public void Compile(
            If statement,
            ICompilationContext context
            )
        {
            var preferredRegisterCondition = new PreferredRegister(Register64.RAX);
            var ifConditionResult          = context.CompileExpression(statement.Condition, preferredRegisterCondition);

            ifConditionResult.GenerateMoveTo(preferredRegisterCondition.MakeFor(Constants.BoolType), context.Generator, context.Linking);
            context.Generator.Test(Register8.AL, Register8.AL);

            var ifBody   = context.CreateChildContext();
            var elseBody = context.CreateChildContext();

            if (statement.ElseInstruction != null)
            {
                elseBody.CompileStatement(statement.ElseInstruction.StatementAsBlock());
            }

            ifBody.CompileStatement(statement.Instruction.StatementAsBlock());

            var elseBodySpan = elseBody.Generator.GetBufferSpan();

            if (elseBodySpan.Length > 0)
            {
                if (elseBodySpan.Length <= sbyte.MaxValue)
                {
                    ifBody.Generator.Jmp((sbyte)elseBodySpan.Length);
                }
                else
                {
                    ifBody.Generator.Jmp(elseBodySpan.Length);
                }
            }

            var ifBodySpan = ifBody.Generator.GetBufferSpan();

            if (ifBodySpan.Length <= sbyte.MaxValue)
            {
                context.Generator.Je((sbyte)ifBodySpan.Length);
            }
            else
            {
                context.Generator.Je(ifBodySpan.Length);
            }

            ifBody.CopyToContext(context);
            elseBody.CopyToContext(context);
        }
Пример #2
0
        public void Compile(
            While statement,
            ICompilationContext context
            )
        {
            var codeGen                = context.Generator;
            var conditionStart         = codeGen.StreamPosition;
            var whileConditionResult   = context.CompileExpression(statement.Condition, new PreferredRegister(Register64.RAX));
            var whileConditionRegister = whileConditionResult.GetOccupiedOrVolatile(Constants.BoolType);

            whileConditionResult.GenerateMoveTo(whileConditionRegister, Constants.BoolType, codeGen, context.Linking);

            codeGen.Test(whileConditionRegister, whileConditionRegister);

            var childContext = context.CreateChildContext();

            childContext.CompileStatement(statement.Instruction.StatementAsBlock());

            var bodySpan   = childContext.Generator.GetBufferSpan();
            var bodyLength = bodySpan.Length + JmpIntSize; // assume far jmp will be generated

            if (bodyLength <= sbyte.MaxValue)
            {
                codeGen.Je((sbyte)bodyLength);
            }
            else
            {
                codeGen.Je(bodyLength);
            }
            var farJmpGuessPos = codeGen.StreamPosition;

            childContext.CopyToContext(context);

            var offsetToStart = conditionStart - codeGen.StreamPosition;

            if (offsetToStart >= sbyte.MinValue)
            {
                codeGen.Jmp((sbyte)(offsetToStart - JmpSbyteSize));

                // near jmp has been generated, but we assume a far jmp above
                // if this is a near jmp, the other has to be too
                // so it's safe to say, we just need to edit the byte.
                // The new value has to fit, because the jmp becomes even nearer.
                codeGen.GetBufferSpan().Slice((int)farJmpGuessPos - 1, 1)[0] -= (byte)(JmpIntSize - JmpSbyteSize);
            }
            else
            {
                codeGen.Jmp((int)(offsetToStart - JmpIntSize));
            }
        }