/// <summary>
        /// Moves a float argument to the stack
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        /// <param name="argumentIndex">The argument index</param>
        private void MoveFloatArgumentToStack(CompilationData compilationData, int argumentIndex)
        {
            var assembler      = compilationData.Assembler;
            int argStackOffset = -(1 + argumentIndex) * Assembler.RegisterSize;

            if (argumentIndex >= numRegisterArguments)
            {
                int stackArgumentIndex = this.GetStackArgumentIndex(compilationData, argumentIndex);
                int stackAlignment     = this.CalculateStackAlignment(
                    compilationData,
                    compilationData.Function.Definition.Parameters);

                assembler.Move(
                    Register.AX,
                    new MemoryOperand(
                        Register.BP,
                        Assembler.RegisterSize * (6 + stackArgumentIndex)));

                assembler.Move(new MemoryOperand(Register.BP, argStackOffset), Register.AX);
            }
            else
            {
                assembler.Move(
                    new MemoryOperand(Register.BP, argStackOffset),
                    this.floatArgumentRegisters[argumentIndex]);
            }
        }
 /// <summary>
 /// Handles the given function call arguments
 /// </summary>
 /// <param name="compilationData">The compilation data</param>
 /// <param name="toCall">The function to call</param>
 public void CallFunctionArguments(CompilationData compilationData, FunctionDefinition toCall)
 {
     for (int arg = toCall.Parameters.Count - 1; arg >= 0; arg--)
     {
         this.CallFunctionArgument(compilationData, arg, toCall.Parameters[arg], toCall);
     }
 }
        /// <summary>
        /// Adds a stack overflow check
        /// </summary>
        /// <param name="compilationData">The function compilation data</param>
        /// <param name="callStackEnd">The end of the call stack</param>
        public void AddStackOverflowCheck(CompilationData compilationData, IntPtr callStackEnd)
        {
            var assembler = compilationData.Assembler;

            //Move the end of the call stack to register
            assembler.Move(Register.CX, callStackEnd.ToInt64());

            //Compare the top and the end of the stack
            assembler.Compare(Register.AX, Register.CX);

            //Jump to handler if overflow
            assembler.Jump(JumpCondition.GreaterThanOrEqual, 0);
            compilationData.UnresolvedNativeLabels.Add(assembler.GeneratedCode.Count - 6, this.stackOverflowCheckHandler);
        }
        /// <summary>
        /// Adds an array creation check
        /// </summary>
        /// <param name="compilationData">The function compilation data</param>
        /// <param name="sizeRegister">The register where the size is stored</param>
        /// <param name="compareRegister">The register used for comparison</param>
        public void AddArrayCreationCheck(
            CompilationData compilationData,
            Register sizeRegister    = IntCallingConventions.Argument1,
            Register compareRegister = Register.R11)
        {
            var assembler = compilationData.Assembler;

            assembler.Xor(compareRegister, compareRegister); //Zero the register
            assembler.Compare(compareRegister, sizeRegister);

            //Jump to handler if invalid
            assembler.Jump(JumpCondition.GreaterThan, 0);
            compilationData.UnresolvedNativeLabels.Add(assembler.GeneratedCode.Count - 6, this.arrayCreationCheckHandler);
        }
        /// <summary>
        /// Adds a null check
        /// </summary>
        /// <param name="compilationData">The function compilation data</param>
        /// <param name="refRegister">The register where the reference is located</param>
        /// <param name="compareRegister">The register where the result of the comparison will be stored</param>
        public void AddNullCheck(
            CompilationData compilationData,
            Register refRegister     = Register.AX,
            Register compareRegister = Register.R11)
        {
            var assembler = compilationData.Assembler;

            //Compare the reference with null
            assembler.Xor(compareRegister, compareRegister); //Zero the register
            assembler.Compare(refRegister, compareRegister);

            //Jump to handler if null
            assembler.Jump(JumpCondition.Equal, 0);
            compilationData.UnresolvedNativeLabels.Add(assembler.GeneratedCode.Count - 6, this.nullCheckHandler);
        }
示例#6
0
        /// <summary>
        /// Compiles the given function
        /// </summary>
        /// <param name="function">The function to compile</param>
        /// <returns>A pointer to the start of the compiled function</returns>
        public IntPtr Compile(ManagedFunction function)
        {
            //Compile the function
            var compilationData = new CompilationData(function);

            this.compiledFunctions.Add(function, compilationData);
            this.codeGenerator.CompileFunction(compilationData);

            //Allocate native memory. The instructions will be copied later when all symbols has been resolved.
            var memory = this.MemoryManager.AllocateCode(function.GeneratedCode.Count);

            function.Definition.SetEntryPoint(memory);

            return(memory);
        }
        /// <summary>
        /// Makes the return value for a function
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        public void MakeReturnValue(CompilationData compilationData)
        {
            var def = compilationData.Function.Definition;

            if (!def.ReturnType.IsPrimitiveType(PrimitiveTypes.Void))
            {
                if (def.ReturnType.IsPrimitiveType(PrimitiveTypes.Float))
                {
                    compilationData.OperandStack.PopRegister(FloatCallingConventions.ReturnValue);
                }
                else
                {
                    compilationData.OperandStack.PopRegister(IntCallingConventions.ReturnValue);
                }
            }
        }
        /// <summary>
        /// Adds an array bounds check
        /// </summary>
        /// <param name="compilationData">The function compilation data</param>
        /// <param name="refRegister">The register where the array is stored</param>
        /// <param name="indexRegister">The register where the index is stored</param>
        /// <param name="compareRegister">The register used for comparison</param>
        public void AddArrayBoundsCheck(
            CompilationData compilationData,
            Register refRegister     = Register.AX,
            Register indexRegister   = Register.R10,
            Register compareRegister = Register.CX)
        {
            var assembler = compilationData.Assembler;

            //Get the size of the array (an int)
            assembler.Move(compareRegister, new MemoryOperand(refRegister), DataSize.Size32);

            //Compare the index and size
            assembler.Compare(indexRegister, compareRegister);

            //Jump to handler if out of bounds. By using an unsigned comparison, we only need one check.
            assembler.Jump(JumpCondition.GreaterThanOrEqual, 0, true);
            compilationData.UnresolvedNativeLabels.Add(assembler.GeneratedCode.Count - 6, this.arrayBoundsCheckHandler);
        }
示例#9
0
        /// <summary>
        /// Resolves the branches for the given function
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        private void ResolveBranches(CompilationData compilationData)
        {
            foreach (var branch in compilationData.UnresolvedBranches)
            {
                int source       = branch.Key;
                var branchTarget = branch.Value;

                int nativeTarget = compilationData.InstructionMapping[branchTarget.Target];

                //Calculate the native jump location
                int target = nativeTarget - source - branchTarget.InstructionSize;

                //Update the source with the native target
                int sourceOffset = source + branchTarget.InstructionSize - sizeof(int);
                NativeHelpers.SetInt(compilationData.Function.GeneratedCode, sourceOffset, target);
            }

            compilationData.UnresolvedBranches.Clear();
        }
示例#10
0
        /// <summary>
        /// Resolves the native labels for the given function
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        private void ResolveNativeLabels(CompilationData compilationData)
        {
            var generatedCode = compilationData.Function.GeneratedCode;
            var entryPoint    = compilationData.Function.Definition.EntryPoint.ToInt64();

            foreach (var nativeLabel in compilationData.UnresolvedNativeLabels)
            {
                var source = nativeLabel.Key;
                var target = nativeLabel.Value.ToInt64();

                //Calculate the native jump location
                var nativeTarget = (int)(target - (entryPoint + source) - 6);

                //Update the source with the native target
                var sourceOffset = source + 6 - sizeof(int);
                NativeHelpers.SetInt(generatedCode, sourceOffset, nativeTarget);
            }

            compilationData.UnresolvedNativeLabels.Clear();
        }
示例#11
0
        /// <summary>
        /// Moves the argument to the stack
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        public void MoveArgumentsToStack(CompilationData compilationData)
        {
            var function       = compilationData.Function;
            var parameterTypes = function.Definition.Parameters;

            for (int argumentIndex = parameterTypes.Count - 1; argumentIndex >= 0; argumentIndex--)
            {
                if (parameterTypes[argumentIndex].IsPrimitiveType(PrimitiveTypes.Float))
                {
                    this.MoveFloatArgumentToStack(
                        compilationData,
                        argumentIndex);
                }
                else
                {
                    this.MoveNoneFloatArgumentToStack(
                        compilationData,
                        argumentIndex);
                }
            }
        }
示例#12
0
        /// <summary>
        /// Handles the given function call argument
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        /// <param name="argumentIndex">The index of the argument</param>
        /// <param name="argumentType">The type of the argument</param>
        /// <param name="toCall">The function to call</param>
        public void CallFunctionArgument(CompilationData compilationData, int argumentIndex, BaseType argumentType, FunctionDefinition toCall)
        {
            var operandStack = compilationData.OperandStack;

            //Check if to pass argument by via stack
            if (argumentIndex >= numRegisterArguments)
            {
                //Move from the operand stack to the normal stack
                operandStack.PopRegister(Register.AX);
                compilationData.Assembler.Push(Register.AX);
            }
            else
            {
                if (argumentType.IsPrimitiveType(PrimitiveTypes.Float))
                {
                    operandStack.PopRegister(this.floatArgumentRegisters[argumentIndex]);
                }
                else
                {
                    operandStack.PopRegister(this.intArgumentRegisters[argumentIndex]);
                }
            }
        }
示例#13
0
        /// <summary>
        /// Resolves the call target for the given function
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        private void ResolveCallTargets(CompilationData compilationData)
        {
            var generatedCode = compilationData.Function.GeneratedCode;
            var entryPoint    = compilationData.Function.Definition.EntryPoint.ToInt64();

            foreach (var unresolvedCall in compilationData.UnresolvedFunctionCalls)
            {
                var toCallAddress = unresolvedCall.Function.EntryPoint.ToInt64();

                //Update the call target
                if (unresolvedCall.AddressMode == FunctionCallAddressMode.Absolute)
                {
                    NativeHelpers.SetLong(generatedCode, unresolvedCall.CallSiteOffset + 2, toCallAddress);
                }
                else
                {
                    int target = (int)(toCallAddress - (entryPoint + unresolvedCall.CallSiteOffset + 5));
                    NativeHelpers.SetInt(generatedCode, unresolvedCall.CallSiteOffset + 1, target);
                }
            }

            compilationData.UnresolvedFunctionCalls.Clear();
        }
示例#14
0
        /// <summary>
        /// Handles the return value from a function
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        /// <param name="toCall">The function to call</param>
        public void HandleReturnValue(CompilationData compilationData, FunctionDefinition toCall)
        {
            //If we have passed arguments via the stack, adjust the stack pointer.
            int numStackArgs = this.CalculateStackArguments(toCall.Parameters);

            if (numStackArgs > 0)
            {
                compilationData.Assembler.Add(
                    Register.SP,
                    numStackArgs * Assembler.RegisterSize);
            }

            if (!toCall.ReturnType.IsPrimitiveType(PrimitiveTypes.Void))
            {
                if (toCall.ReturnType.IsPrimitiveType(PrimitiveTypes.Float))
                {
                    compilationData.OperandStack.PushRegister(FloatCallingConventions.ReturnValue);
                }
                else
                {
                    compilationData.OperandStack.PushRegister(IntCallingConventions.ReturnValue);
                }
            }
        }
示例#15
0
        /// <summary>
        /// Returns the stack argument index for the argument
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        /// <param name="argumentIndex">The argument index</param>
        private int GetStackArgumentIndex(CompilationData compilationData, int argumentIndex)
        {
            int stackArgIndex  = 0;
            var parameterTypes = compilationData.Function.Definition.Parameters;

            int index = 0;

            foreach (var parameterType in parameterTypes)
            {
                if (index == argumentIndex)
                {
                    break;
                }

                if (index >= numRegisterArguments)
                {
                    stackArgIndex++;
                }

                index++;
            }

            return(stackArgIndex);
        }
示例#16
0
        /// <summary>
        /// Calculates the stack alignment
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        /// <param name="parameters">The parameters of the function to call</param>
        public int CalculateStackAlignment(CompilationData compilationData, IReadOnlyList <BaseType> parameterTypes)
        {
            int numStackArgs = this.CalculateStackArguments(parameterTypes);

            return((numStackArgs % 2) * Assembler.RegisterSize);
        }