diff --git a/ARMeilleure/CodeGen/X86/CallConvName.cs b/ARMeilleure/CodeGen/X86/CallConvName.cs new file mode 100644 index 0000000000..be36762820 --- /dev/null +++ b/ARMeilleure/CodeGen/X86/CallConvName.cs @@ -0,0 +1,8 @@ +namespace ARMeilleure.CodeGen.X86 +{ + enum CallConvName + { + SystemV, + Windows + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/CallingConvention.cs b/ARMeilleure/CodeGen/X86/CallingConvention.cs index 65cdf0a38a..2769fd93e1 100644 --- a/ARMeilleure/CodeGen/X86/CallingConvention.cs +++ b/ARMeilleure/CodeGen/X86/CallingConvention.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.InteropServices; namespace ARMeilleure.CodeGen.X86 { @@ -18,23 +19,45 @@ namespace ARMeilleure.CodeGen.X86 public static int GetIntCallerSavedRegisters() { - return (1 << (int)X86Register.Rax) | - (1 << (int)X86Register.Rdx) | - (1 << (int)X86Register.Rcx) | - (1 << (int)X86Register.R8) | - (1 << (int)X86Register.R9) | - (1 << (int)X86Register.R10) | - (1 << (int)X86Register.R11); + if (GetCurrentCallConv() == CallConvName.Windows) + { + return (1 << (int)X86Register.Rax) | + (1 << (int)X86Register.Rcx) | + (1 << (int)X86Register.Rdx) | + (1 << (int)X86Register.R8) | + (1 << (int)X86Register.R9) | + (1 << (int)X86Register.R10) | + (1 << (int)X86Register.R11); + } + else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ + { + return (1 << (int)X86Register.Rax) | + (1 << (int)X86Register.Rcx) | + (1 << (int)X86Register.Rdx) | + (1 << (int)X86Register.Rsi) | + (1 << (int)X86Register.Rdi) | + (1 << (int)X86Register.R8) | + (1 << (int)X86Register.R9) | + (1 << (int)X86Register.R10) | + (1 << (int)X86Register.R11); + } } public static int GetVecCallerSavedRegisters() { - return (1 << (int)X86Register.Xmm0) | - (1 << (int)X86Register.Xmm1) | - (1 << (int)X86Register.Xmm2) | - (1 << (int)X86Register.Xmm3) | - (1 << (int)X86Register.Xmm4) | - (1 << (int)X86Register.Xmm5); + if (GetCurrentCallConv() == CallConvName.Windows) + { + return (1 << (int)X86Register.Xmm0) | + (1 << (int)X86Register.Xmm1) | + (1 << (int)X86Register.Xmm2) | + (1 << (int)X86Register.Xmm3) | + (1 << (int)X86Register.Xmm4) | + (1 << (int)X86Register.Xmm5); + } + else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ + { + return RegistersMask; + } } public static int GetIntCalleeSavedRegisters() @@ -52,14 +75,39 @@ namespace ARMeilleure.CodeGen.X86 return 4; } + public static int GetIntArgumentsOnRegsCount() + { + return 6; + } + + public static int GetVecArgumentsOnRegsCount() + { + return 8; + } + public static X86Register GetIntArgumentRegister(int index) { - switch (index) + if (GetCurrentCallConv() == CallConvName.Windows) { - case 0: return X86Register.Rcx; - case 1: return X86Register.Rdx; - case 2: return X86Register.R8; - case 3: return X86Register.R9; + switch (index) + { + case 0: return X86Register.Rcx; + case 1: return X86Register.Rdx; + case 2: return X86Register.R8; + case 3: return X86Register.R9; + } + } + else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ + { + switch (index) + { + case 0: return X86Register.Rdi; + case 1: return X86Register.Rsi; + case 2: return X86Register.Rdx; + case 3: return X86Register.Rcx; + case 4: return X86Register.R8; + case 5: return X86Register.R9; + } } throw new ArgumentOutOfRangeException(nameof(index)); @@ -67,12 +115,20 @@ namespace ARMeilleure.CodeGen.X86 public static X86Register GetVecArgumentRegister(int index) { - switch (index) + int count; + + if (GetCurrentCallConv() == CallConvName.Windows) { - case 0: return X86Register.Xmm0; - case 1: return X86Register.Xmm1; - case 2: return X86Register.Xmm2; - case 3: return X86Register.Xmm3; + count = 4; + } + else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ + { + count = 8; + } + + if ((uint)index < count) + { + return X86Register.Xmm0 + index; } throw new ArgumentOutOfRangeException(nameof(index)); @@ -83,9 +139,21 @@ namespace ARMeilleure.CodeGen.X86 return X86Register.Rax; } + public static X86Register GetIntReturnRegisterHigh() + { + return X86Register.Rdx; + } + public static X86Register GetVecReturnRegister() { return X86Register.Xmm0; } + + public static CallConvName GetCurrentCallConv() + { + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? CallConvName.Windows + : CallConvName.SystemV; + } } } \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/CodeGenContext.cs b/ARMeilleure/CodeGen/X86/CodeGenContext.cs index 1f6453ed1f..f894b53031 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenContext.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenContext.cs @@ -116,7 +116,7 @@ namespace ARMeilleure.CodeGen.X86 int frameSize = calleeSaveRegionSize + allocResult.SpillRegionSize; - int callArgsAndFrameSize = frameSize + argsCount * 8; + int callArgsAndFrameSize = frameSize + argsCount * 16; //FIXME * 16 => calc //Ensure that the Stack Pointer will be aligned to 16 bytes. callArgsAndFrameSize = (callArgsAndFrameSize + 0xf) & ~0xf; diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs index dbc811f6f1..866576a7da 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -117,7 +117,7 @@ namespace ARMeilleure.CodeGen.X86 Logger.StartPass(PassName.RegisterAllocation); - FastLinearScan regAlloc = new FastLinearScan(); + LinearScan regAlloc = new LinearScan(); RegisterMasks regMasks = new RegisterMasks( CallingConvention.GetIntAvailableRegisters(), @@ -1607,7 +1607,7 @@ namespace ARMeilleure.CodeGen.X86 size = (size + pageMask) & ~pageMask; Operand rsp = Register(X86Register.Rsp); - Operand temp = Register(CallingConvention.GetIntReturnRegister()); + Operand temp = Register(CallingConvention.GetIntReturnRegister()); for (int offset = PageSize; offset < size; offset += PageSize) { diff --git a/ARMeilleure/CodeGen/X86/HardwareCapabilities.cs b/ARMeilleure/CodeGen/X86/HardwareCapabilities.cs index 54dd4be97f..a5951de734 100644 --- a/ARMeilleure/CodeGen/X86/HardwareCapabilities.cs +++ b/ARMeilleure/CodeGen/X86/HardwareCapabilities.cs @@ -38,7 +38,9 @@ namespace ARMeilleure.CodeGen.X86 ControlFlowGraph cfg = context.GetControlFlowGraph(); - GetFeatureInfo getFeatureInfo = Compiler.Compile(cfg, OperandType.I64); + OperandType[] argTypes = new OperandType[0]; + + GetFeatureInfo getFeatureInfo = Compiler.Compile(cfg, argTypes, OperandType.I64); _featureInfo = getFeatureInfo(); } diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs index 61688e1719..2f83e3ed60 100644 --- a/ARMeilleure/CodeGen/X86/PreAllocator.cs +++ b/ARMeilleure/CodeGen/X86/PreAllocator.cs @@ -16,6 +16,8 @@ namespace ARMeilleure.CodeGen.X86 { maxCallArgs = -1; + CallConvName callConv = CallingConvention.GetCurrentCallConv(); + Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()]; foreach (BasicBlock block in cctx.Cfg.Blocks) @@ -58,7 +60,14 @@ namespace ARMeilleure.CodeGen.X86 // Copy values to registers expected by the function // being called, as mandated by the ABI. - node = HandleCallWindowsAbi(stackAlloc, node, operation); + if (callConv == CallConvName.Windows) + { + node = HandleCallWindowsAbi(stackAlloc, node, operation); + } + else /* if (callConv == CallConvName.SystemV) */ + { + node = HandleCallSystemVAbi(node, operation); + } break; case Instruction.ConvertToFPUI: @@ -66,7 +75,14 @@ namespace ARMeilleure.CodeGen.X86 break; case Instruction.LoadArgument: - HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation); + if (callConv == CallConvName.Windows) + { + HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation); + } + else + { + HandleLoadArgumentSystemVAbi(cctx, node, preservedArgs, operation); + } break; case Instruction.Negate: @@ -77,7 +93,14 @@ namespace ARMeilleure.CodeGen.X86 break; case Instruction.Return: - HandleReturnWindowsAbi(cctx, node, preservedArgs, operation); + if (callConv == CallConvName.Windows) + { + HandleReturnWindowsAbi(cctx, node, preservedArgs, operation); + } + else /* if (callConv == CallConvName.SystemV) */ + { + HandleReturnSystemVAbi(node, operation); + } break; case Instruction.VectorInsert8: @@ -612,9 +635,9 @@ namespace ARMeilleure.CodeGen.X86 argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type); } - Operation srcCopyOp = new Operation(Instruction.Copy, argReg, source); + Operation copyOp = new Operation(Instruction.Copy, argReg, source); - HandleConstantCopy(nodes.AddBefore(node, srcCopyOp), srcCopyOp); + HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp); operation.SetSource(index + 1, argReg); } @@ -656,20 +679,120 @@ namespace ARMeilleure.CodeGen.X86 { RegisterType regType = dest.Type.ToRegisterType(); - Operand retReg; + Operand retReg = regType == RegisterType.Integer + ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type) + : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type); - if (regType == RegisterType.Integer) - { - retReg = Gpr(CallingConvention.GetIntReturnRegister(), dest.Type); - } - else /* if (regType == RegisterType.Vector) */ - { - retReg = Xmm(CallingConvention.GetVecReturnRegister(), dest.Type); - } + Operation copyOp = new Operation(Instruction.Copy, dest, retReg); - Operation destCopyOp = new Operation(Instruction.Copy, dest, retReg); + node = nodes.AddAfter(node, copyOp); - node = nodes.AddAfter(node, destCopyOp); + operation.Dest = retReg; + } + } + + return node; + } + + private static LLNode HandleCallSystemVAbi(LLNode node, Operation operation) + { + Operand dest = operation.Dest; + + LinkedList nodes = node.List; + + // Handle arguments passed on registers. + int argsCount = operation.SourcesCount - 1; + + int intMax = CallingConvention.GetIntArgumentsOnRegsCount(); + int vecMax = CallingConvention.GetVecArgumentsOnRegsCount(); + + int intCount = 0; + int vecCount = 0; + + int stackOffset = 0; + + for (int index = 0; index < argsCount; index++) + { + Operand source = operation.GetSource(index + 1); + + bool passOnReg; + + if (source.Type.IsInteger()) + { + passOnReg = intCount < intMax; + } + else if (source.Type == OperandType.V128) + { + passOnReg = intCount + 1 < intMax; + } + else + { + passOnReg = vecCount < vecMax; + } + + if (source.Type == OperandType.V128 && passOnReg) + { + // V128 is a struct, we pass each half on a GPR if possible. + Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); + Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); + + nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg, source, Const(0))); + nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1))); + + operation.SetSource(index + 1, Undef()); + + continue; + } + + if (passOnReg) + { + Operand argReg = source.Type.IsInteger() + ? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type) + : Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type); + + Operation copyOp = new Operation(Instruction.Copy, argReg, source); + + HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp); + + operation.SetSource(index + 1, argReg); + } + else + { + Operand offset = new Operand(stackOffset); + + Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source); + + HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp); + + stackOffset += source.Type.GetSizeInBytes(); + + operation.SetSource(index + 1, Undef()); + } + } + + if (dest != null) + { + if (dest.Type == OperandType.V128) + { + Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); + Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64); + + node = nodes.AddAfter(node, new Operation(Instruction.VectorCreateScalar, dest, retLReg)); + node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1))); + + operation.Dest = null; + } + else + { + RegisterType regType = dest.Type.ToRegisterType(); + + Operand retReg = regType == RegisterType.Integer + ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type) + : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type); + + Operation copyOp = new Operation(Instruction.Copy, dest, retReg); + + node = nodes.AddAfter(node, copyOp); operation.Dest = retReg; } @@ -698,44 +821,144 @@ namespace ARMeilleure.CodeGen.X86 if (preservedArgs[index] == null) { - Operand preservedArg; - - Operand argReg; + Operand argReg, pArg; if (dest.Type.IsInteger()) { argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type); - preservedArg = Local(dest.Type); + pArg = Local(dest.Type); } else if (dest.Type == OperandType.V128) { argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64); - preservedArg = Local(OperandType.I64); + pArg = Local(OperandType.I64); } - else /* if (regType == RegisterType.Vector) */ + else { argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type); - preservedArg = Local(dest.Type); + pArg = Local(dest.Type); } - Operation copyOp = new Operation(Instruction.Copy, preservedArg, argReg); + Operation copyOp = new Operation(Instruction.Copy, pArg, argReg); cctx.Cfg.Entry.Operations.AddFirst(copyOp); - preservedArgs[index] = preservedArg; + preservedArgs[index] = pArg; } - Operation loadArgOp = new Operation(dest.Type == OperandType.V128 + Operation argCopyOp = new Operation(dest.Type == OperandType.V128 ? Instruction.Load : Instruction.Copy, dest, preservedArgs[index]); - node.List.AddBefore(node, loadArgOp); + node.List.AddBefore(node, argCopyOp); Delete(node, operation); } + else + { + // TODO: Pass on stack. + } + } + + private static void HandleLoadArgumentSystemVAbi( + CompilerContext cctx, + LLNode node, + Operand[] preservedArgs, + Operation operation) + { + Operand source = operation.GetSource(0); + + Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind."); + + int index = source.AsInt32(); + + int intCount = 0; + int vecCount = 0; + + for (int cIndex = 0; cIndex < index; cIndex++) + { + OperandType argType = cctx.FuncArgTypes[cIndex]; + + if (argType.IsInteger()) + { + intCount++; + } + else if (argType == OperandType.V128) + { + intCount += 2; + } + else + { + vecCount++; + } + } + + bool passOnReg; + + if (source.Type.IsInteger()) + { + passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount(); + } + else if (source.Type == OperandType.V128) + { + passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount(); + } + else + { + passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount(); + } + + if (passOnReg) + { + Operand dest = operation.Dest; + + if (preservedArgs[index] == null) + { + if (dest.Type == OperandType.V128) + { + // V128 is a struct, we pass each half on a GPR if possible. + Operand pArg = Local(OperandType.V128); + + Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64); + Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64); + + Operation copyL = new Operation(Instruction.VectorCreateScalar, pArg, argLReg); + Operation copyH = new Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1)); + + cctx.Cfg.Entry.Operations.AddFirst(copyH); + cctx.Cfg.Entry.Operations.AddFirst(copyL); + + preservedArgs[index] = pArg; + } + else + { + Operand pArg = Local(dest.Type); + + Operand argReg = dest.Type.IsInteger() + ? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type) + : Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type); + + Operation copyOp = new Operation(Instruction.Copy, pArg, argReg); + + cctx.Cfg.Entry.Operations.AddFirst(copyOp); + + preservedArgs[index] = pArg; + } + } + + Operation argCopyOp = new Operation(Instruction.Copy, dest, preservedArgs[index]); + + node.List.AddBefore(node, argCopyOp); + + Delete(node, operation); + } + else + { + // TODO: Pass on stack. + } } private static void HandleReturnWindowsAbi( @@ -774,7 +997,7 @@ namespace ARMeilleure.CodeGen.X86 retReg = preservedArgs[0]; } - else /* if (regType == RegisterType.Vector) */ + else { retReg = Xmm(CallingConvention.GetVecReturnRegister(), source.Type); } @@ -793,6 +1016,35 @@ namespace ARMeilleure.CodeGen.X86 } } + private static void HandleReturnSystemVAbi(LLNode node, Operation operation) + { + if (operation.SourcesCount == 0) + { + return; + } + + Operand source = operation.GetSource(0); + + if (source.Type == OperandType.V128) + { + Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); + Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64); + + node.List.AddBefore(node, new Operation(Instruction.VectorExtract, retLReg, source, Const(0))); + node.List.AddBefore(node, new Operation(Instruction.VectorExtract, retHReg, source, Const(1))); + } + else + { + Operand retReg = source.Type.IsInteger() + ? Gpr(CallingConvention.GetIntReturnRegister(), source.Type) + : Xmm(CallingConvention.GetVecReturnRegister(), source.Type); + + Operation retCopyOp = new Operation(Instruction.Copy, retReg, source); + + node.List.AddBefore(node, retCopyOp); + } + } + private static Operand AddXmmCopy(LLNode node, Operand source) { Operand temp = Local(source.Type); diff --git a/ARMeilleure/Memory/MemoryManagerPal.cs b/ARMeilleure/Memory/MemoryManagerPal.cs index b318da8648..cda7f6dbce 100644 --- a/ARMeilleure/Memory/MemoryManagerPal.cs +++ b/ARMeilleure/Memory/MemoryManagerPal.cs @@ -59,7 +59,14 @@ namespace ARMeilleure.Memory ControlFlowGraph cfg = context.GetControlFlowGraph(); - _compareExchange128 = Compiler.Compile(cfg, OperandType.V128); + OperandType[] argTypes = new OperandType[] + { + OperandType.I64, + OperandType.V128, + OperandType.V128 + }; + + _compareExchange128 = Compiler.Compile(cfg, argTypes, OperandType.V128); } } } diff --git a/ARMeilleure/Translation/Compiler.cs b/ARMeilleure/Translation/Compiler.cs index 79ceafe831..16e9d4004e 100644 --- a/ARMeilleure/Translation/Compiler.cs +++ b/ARMeilleure/Translation/Compiler.cs @@ -9,9 +9,12 @@ namespace ARMeilleure.Translation { static class Compiler { - public static T Compile(ControlFlowGraph cfg, OperandType funcReturnType) + public static T Compile( + ControlFlowGraph cfg, + OperandType[] funcArgTypes, + OperandType funcReturnType) { - CompilerContext cctx = GetCompilerContext(cfg, funcReturnType); + CompilerContext cctx = GetCompilerContext(cfg, funcArgTypes, funcReturnType); CompiledFunction func = CodeGenerator.Generate(cctx); @@ -20,7 +23,10 @@ namespace ARMeilleure.Translation return Marshal.GetDelegateForFunctionPointer(codePtr); } - private static CompilerContext GetCompilerContext(ControlFlowGraph cfg, OperandType funcReturnType) + private static CompilerContext GetCompilerContext( + ControlFlowGraph cfg, + OperandType[] funcArgTypes, + OperandType funcReturnType) { Logger.StartPass(PassName.Dominance); @@ -35,7 +41,7 @@ namespace ARMeilleure.Translation Logger.EndPass(PassName.SsaConstruction, cfg); - return new CompilerContext(cfg, funcReturnType); + return new CompilerContext(cfg, funcArgTypes, funcReturnType); } } } \ No newline at end of file diff --git a/ARMeilleure/Translation/CompilerContext.cs b/ARMeilleure/Translation/CompilerContext.cs index 3afa51bc0b..82bbd302e2 100644 --- a/ARMeilleure/Translation/CompilerContext.cs +++ b/ARMeilleure/Translation/CompilerContext.cs @@ -6,11 +6,16 @@ namespace ARMeilleure.Translation { public ControlFlowGraph Cfg { get; } - public OperandType FuncReturnType { get; } + public OperandType[] FuncArgTypes { get; } + public OperandType FuncReturnType { get; } - public CompilerContext(ControlFlowGraph cfg, OperandType funcReturnType) + public CompilerContext( + ControlFlowGraph cfg, + OperandType[] funcArgTypes, + OperandType funcReturnType) { Cfg = cfg; + FuncArgTypes = funcArgTypes; FuncReturnType = funcReturnType; } } diff --git a/ARMeilleure/Translation/JitCache.cs b/ARMeilleure/Translation/JitCache.cs index cc7e41bf45..f3d21c72d2 100644 --- a/ARMeilleure/Translation/JitCache.cs +++ b/ARMeilleure/Translation/JitCache.cs @@ -2,6 +2,7 @@ using ARMeilleure.CodeGen; using ARMeilleure.Memory; using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading; namespace ARMeilleure.Translation @@ -25,10 +26,13 @@ namespace ARMeilleure.Translation { _basePointer = MemoryManagement.Allocate(CacheSize); - JitUnwindWindows.InstallFunctionTableHandler(_basePointer, CacheSize); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + JitUnwindWindows.InstallFunctionTableHandler(_basePointer, CacheSize); - //The first page is used for the table based SEH structs. - _offset = PageSize; + // The first page is used for the table based SEH structs. + _offset = PageSize; + } _cacheEntries = new List(); } @@ -41,26 +45,44 @@ namespace ARMeilleure.Translation IntPtr funcPtr = _basePointer + funcOffset; - unsafe - { - fixed (byte* codePtr = code) - { - byte* dest = (byte*)funcPtr; + Marshal.Copy(code, 0, funcPtr, code.Length); - long size = (long)code.Length; - - Buffer.MemoryCopy(codePtr, dest, size, size); - } - } - - //TODO: W^X. - MemoryManagement.Reprotect(funcPtr, (ulong)code.Length, MemoryProtection.ReadWriteExecute); + ReprotectRange(funcOffset, code.Length); Add(new JitCacheEntry(funcOffset, code.Length, func.UnwindInfo)); return funcPtr; } + private static void ReprotectRange(int offset, int size) + { + // Map pages that are already full as RX. + // Map pages that are not full yet as RWX. + // On unix, the address and size must be page aligned. + int endOffs = offset + size; + + int pageStart = offset & ~PageMask; + int pageEnd = endOffs & ~PageMask; + + int fullPagesSize = pageEnd - pageStart; + + if (fullPagesSize != 0) + { + IntPtr funcPtr = _basePointer + pageStart; + + MemoryManagement.Reprotect(funcPtr, (ulong)fullPagesSize, MemoryProtection.ReadAndExecute); + } + + int remaining = endOffs - pageEnd; + + if (remaining != 0) + { + IntPtr funcPtr = _basePointer + pageEnd; + + MemoryManagement.Reprotect(funcPtr, (ulong)remaining, MemoryProtection.ReadWriteExecute); + } + } + private static int Allocate(int codeSize) { codeSize = checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1); @@ -79,7 +101,7 @@ namespace ARMeilleure.Translation private static void Add(JitCacheEntry entry) { - //TODO: Use concurrent collection. + // TODO: Use concurrent collection. lock (_cacheEntries) { _cacheEntries.Add(entry); diff --git a/ARMeilleure/Translation/JitUnwindWindows.cs b/ARMeilleure/Translation/JitUnwindWindows.cs index 100525b185..8c1bcbb39c 100644 --- a/ARMeilleure/Translation/JitUnwindWindows.cs +++ b/ARMeilleure/Translation/JitUnwindWindows.cs @@ -1,5 +1,4 @@ using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Memory; using System; using System.Runtime.InteropServices; diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs index df28745b2b..9d36aba5da 100644 --- a/ARMeilleure/Translation/Translator.cs +++ b/ARMeilleure/Translation/Translator.cs @@ -93,7 +93,9 @@ namespace ARMeilleure.Translation Logger.EndPass(PassName.RegisterUsage); - GuestFunction func = Compiler.Compile(cfg, OperandType.I64); + OperandType[] argTypes = new OperandType[] { OperandType.I64 }; + + GuestFunction func = Compiler.Compile(cfg, argTypes, OperandType.I64); return new TranslatedFunction(func); }