public void EmitMOV(Register regDst, Register regSrc) { AddrMode rexAddrMode = new AddrMode(regSrc, null, 0, 0, AddrModeSize.Int64); EmitRexPrefix(regDst, ref rexAddrMode); Builder.EmitByte(0x89); Builder.EmitByte((byte)(0xC0 | (((int)regSrc & 0x07) << 3) | (((int)regDst & 0x07)))); }
public void EmitMOV(Register regDst, int imm32) { AddrMode rexAddrMode = new AddrMode(regDst, null, 0, 0, AddrModeSize.Int32); EmitRexPrefix(regDst, ref rexAddrMode); Builder.EmitByte((byte)(0xB8 | ((int)regDst & 0x07))); Builder.EmitInt(imm32); }
public void EmitADD(ref AddrMode addrMode, sbyte immediate) { if (addrMode.Size == AddrModeSize.Int16) Builder.EmitByte(0x66); EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), (byte)0, ref addrMode); Builder.EmitByte((byte)immediate); }
protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { AddrMode thisPtr = new AddrMode( Register.RegDirect | encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitADD(ref thisPtr, (sbyte)factory.Target.PointerSize); encoder.EmitJMP(factory.MethodEntrypoint(_target)); }
public void EmitLEAQ(Register reg, ISymbolNode symbol, int delta = 0) { AddrMode rexAddrMode = new AddrMode(Register.RAX, null, 0, 0, AddrModeSize.Int64); EmitRexPrefix(reg, ref rexAddrMode); Builder.EmitByte(0x8D); Builder.EmitByte((byte)(0x05 | (((int)reg) & 0x07) << 3)); Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32, delta); }
public void EmitLEAQ(Register reg, ISymbolNode symbol) { AddrMode rexAddrMode = new AddrMode(Register.RAX, null, 0, 0, AddrModeSize.Int64); EmitRexPrefix(reg, ref rexAddrMode); Builder.EmitByte(0x8D); int regNumLowBits = ((int)reg) & 0x07; int regNumLowBitsShifted = regNumLowBits << 3; byte modRM = (byte)(regNumLowBitsShifted | 0x05); Builder.EmitByte(modRM); Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); }
private void EmitIndirInstructionSize(int opcode, Register dstReg, ref AddrMode addrMode) { //# ifndef _TARGET_AMD64_ // assert that ESP, EBP, ESI, EDI are not accessed as bytes in 32-bit mode // Debug.Assert(!(addrMode.Size == AddrModeSize.Int8 && dstReg > Register.RBX)); //#endif Debug.Assert(addrMode.Size != 0); if (addrMode.Size == AddrModeSize.Int16) { Builder.EmitByte(0x66); } EmitIndirInstruction(opcode + ((addrMode.Size != AddrModeSize.Int8) ? 1 : 0), dstReg, ref addrMode); }
private void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { foreach (MethodCodeNode methodCodeNodeNeedingCode in obj) { MethodDesc method = methodCodeNodeNeedingCode.Method; string methodName = method.ToString(); Log.WriteLine("Compiling " + methodName); var methodIL = _ilProvider.GetMethodIL(method); if (methodIL == null) { return; } try { if (Path.DirectorySeparatorChar != '\\' && _skipJitList.Contains(new TypeAndMethod(method.OwningType.Name, method.Name))) { throw new NotImplementedException("SkipJIT"); } _corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (Exception e) { Log.WriteLine("*** " + e.Message + " (" + method + ")"); // Call the __not_yet_implemented method DependencyAnalysis.X64.X64Emitter emit = new DependencyAnalysis.X64.X64Emitter(_nodeFactory); emit.Builder.RequireAlignment(_nodeFactory.Target.MinimumFunctionAlignment); emit.Builder.DefinedSymbols.Add(methodCodeNodeNeedingCode); emit.EmitLEAQ(emit.TargetRegister.Arg0, _nodeFactory.StringIndirection(method.ToString())); DependencyAnalysis.X64.AddrMode loadFromArg0 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg0, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitLEAQ(emit.TargetRegister.Arg1, _nodeFactory.StringIndirection(e.Message)); DependencyAnalysis.X64.AddrMode loadFromArg1 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg1, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitJMP(_nodeFactory.ExternSymbol("__not_yet_implemented")); methodCodeNodeNeedingCode.SetCode(emit.Builder.ToObjectData()); continue; } } }
private void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { foreach (MethodCodeNode methodCodeNodeNeedingCode in obj) { MethodDesc method = methodCodeNodeNeedingCode.Method; if (_options.Verbose) { string methodName = method.ToString(); Log.WriteLine("Compiling " + methodName); } var methodIL = GetMethodIL(method); if (methodIL == null) { return; } try { _corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (Exception e) { Log.WriteLine("*** " + method + ": " + e.Message); // Call the __not_yet_implemented method DependencyAnalysis.X64.X64Emitter emit = new DependencyAnalysis.X64.X64Emitter(_nodeFactory); emit.Builder.RequireAlignment(_nodeFactory.Target.MinimumFunctionAlignment); emit.Builder.DefinedSymbols.Add(methodCodeNodeNeedingCode); emit.EmitLEAQ(emit.TargetRegister.Arg0, _nodeFactory.StringIndirection(method.ToString())); DependencyAnalysis.X64.AddrMode loadFromArg0 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg0, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitLEAQ(emit.TargetRegister.Arg1, _nodeFactory.StringIndirection(e.Message)); DependencyAnalysis.X64.AddrMode loadFromArg1 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg1, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitJMP(_nodeFactory.ExternSymbol("__not_yet_implemented")); methodCodeNodeNeedingCode.SetCode(emit.Builder.ToObjectData()); continue; } } }
protected void EmitDictionaryLookup(NodeFactory factory, ref X64Emitter encoder, Register context, Register result, GenericLookupResult lookup, bool relocsOnly) { // INVARIANT: must not trash context register // Find the generic dictionary slot int dictionarySlot = 0; if (!relocsOnly) { // The concrete slot won't be known until we're emitting data - don't ask for it in relocsOnly. dictionarySlot = factory.GenericDictionaryLayout(_dictionaryOwner).GetSlotForEntry(lookup); } // Load the generic dictionary cell AddrMode loadEntry = new AddrMode( context, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitMOV(result, ref loadEntry); }
private void EmitRexPrefix(Register reg, ref AddrMode addrMode) { byte rexPrefix = 0; // Check the situations where a REX prefix is needed // Are we accessing a byte register that wasn't byte accessible in x86? if (addrMode.Size == AddrModeSize.Int8 && reg >= Register.RSP) { rexPrefix |= 0x40; // REX - access to new 8-bit registers } // Is this a 64 bit instruction? if (addrMode.Size == AddrModeSize.Int64) { rexPrefix |= 0x48; // REX.W - 64-bit data operand } // Is the destination register one of the new ones? if (reg >= Register.R8) { rexPrefix |= 0x44; // REX.R - extension of the register field } // Is the index register one of the new ones? if (addrMode.IndexReg.HasValue && addrMode.IndexReg.Value >= Register.R8 && addrMode.IndexReg.Value <= Register.R15) { rexPrefix |= 0x42; // REX.X - extension of the SIB index field } // Is the base register one of the new ones? if (addrMode.BaseReg >= Register.R8 && addrMode.BaseReg <= Register.R15 || addrMode.BaseReg >= (int)Register.R8 + Register.RegDirect && addrMode.BaseReg <= (int)Register.R15 + Register.RegDirect) { rexPrefix |= 0x41; // REX.WB (Wide, extended Base) } // If we have anything so far, emit it. if (rexPrefix != 0) { Builder.EmitByte(rexPrefix); } }
public void EmitJmpToAddrMode(ref AddrMode addrMode) { EmitIndirInstruction(0xFF, 0x4, ref addrMode); }
protected override void EmitLoadGenericContext(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { // We start with Arg0 pointing to the EEType // Locate the VTable slot that points to the dictionary int vtableSlot = 0; if (!relocsOnly) { // The concrete slot won't be known until we're emitting data - don't ask for it in relocsOnly. vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)_dictionaryOwner); } int pointerSize = factory.Target.PointerSize; int slotOffset = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize); // Load the dictionary pointer from the VTable AddrMode loadDictionary = new AddrMode(encoder.TargetRegister.Arg0, null, slotOffset, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadDictionary); }
private void EmitIndirInstructionSize(int opcode, Register dstReg, ref AddrMode addrMode) { //# ifndef _TARGET_AMD64_ // assert that ESP, EBP, ESI, EDI are not accessed as bytes in 32-bit mode // Debug.Assert(!(addrMode.Size == AddrModeSize.Int8 && dstReg > Register.RBX)); //#endif Debug.Assert(addrMode.Size != 0); if (addrMode.Size == AddrModeSize.Int16) Builder.EmitByte(0x66); EmitIndirInstruction(opcode + ((addrMode.Size != AddrModeSize.Int8) ? 1 : 0), dstReg, ref addrMode); }
private void EmitIndirInstruction(int opcode, Register dstReg, ref AddrMode addrMode) { EmitRexPrefix(dstReg, ref addrMode); if ((opcode >> 8) != 0) { EmitExtendedOpcode(opcode); } Builder.EmitByte((byte)opcode); EmitModRM((byte)((int)dstReg & 0x07), ref addrMode); }
protected sealed override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { // First load the generic context into Arg0. EmitLoadGenericContext(factory, ref encoder, relocsOnly); switch (_id) { case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)_target; if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); } else { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, _lookupSignature, relocsOnly); // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); AddrMode loadBase = new AddrMode(encoder.TargetRegister.Arg0, null, cctorContextSize, 0, AddrModeSize.Int64); encoder.EmitLEA(encoder.TargetRegister.Result, ref loadBase); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)_target; EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); AddrMode loadFromResult = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromResult); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromResult); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, nonGcRegionLookup, relocsOnly); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; // These are all simple: just get the thing from the dictionary and we're done case ReadyToRunHelperId.TypeHandle: case ReadyToRunHelperId.MethodDictionary: case ReadyToRunHelperId.VirtualCall: case ReadyToRunHelperId.ResolveVirtualFunction: case ReadyToRunHelperId.MethodEntry: { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); } break; default: throw new NotImplementedException(); } }
protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { switch (Id) { case ReadyToRunHelperId.NewHelper: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewObjectHelperForType(target))); } break; case ReadyToRunHelperId.VirtualCall: { if (relocsOnly) break; AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, (MethodDesc)Target); Debug.Assert(slot != -1); AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } break; case ReadyToRunHelperId.IsInstanceOf: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, false))); } break; case ReadyToRunHelperId.CastClass: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, true))); } break; case ReadyToRunHelperId.NewArr1: { TypeDesc target = (TypeDesc)Target; // TODO: Swap argument order instead encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0); encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewArrayHelperForType(target))); } break; case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)Target; bool hasLazyStaticConstructor = factory.TypeInitializationManager.HasLazyStaticConstructor(target); encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target), hasLazyStaticConstructor ? NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target) : 0); if (!hasLazyStaticConstructor) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target)); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: encoder.EmitINT3(); break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)Target; encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol(target)); AddrMode loadFromRax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); if (!factory.TypeInitializationManager.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target)); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.DelegateCtor: { DelegateCreationInfo target = (DelegateCreationInfo)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg2, target.Target); if (target.Thunk != null) { Debug.Assert(target.Constructor.Method.Signature.Length == 3); encoder.EmitLEAQ(encoder.TargetRegister.Arg3, target.Thunk); } else { Debug.Assert(target.Constructor.Method.Signature.Length == 2); } encoder.EmitJMP(target.Constructor); } break; case ReadyToRunHelperId.InterfaceDispatch: { encoder.EmitLEAQ(Register.R10, factory.InterfaceDispatchCell((MethodDesc)Target)); AddrMode jmpAddrMode = new AddrMode(Register.R10, null, 0, 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } break; case ReadyToRunHelperId.ResolveVirtualFunction: { MethodDesc targetMethod = (MethodDesc)Target; if (targetMethod.OwningType.IsInterface) { encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.InterfaceDispatchCell(targetMethod)); encoder.EmitJMP(factory.ExternSymbol("RhpResolveInterfaceMethod")); } else { if (relocsOnly) break; AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod); Debug.Assert(slot != -1); AddrMode loadFromSlot = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromSlot); encoder.EmitRET(); } } break; default: throw new NotImplementedException(); } }
private void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { foreach (MethodCodeNode methodCodeNodeNeedingCode in obj) { MethodDesc method = methodCodeNodeNeedingCode.Method; string methodName = method.ToString(); Log.WriteLine("Compiling " + methodName); var methodIL = _ilProvider.GetMethodIL(method); if (methodIL == null) { return; } MethodCode methodCode; try { if (_skipJitList.Contains(new TypeAndMethod(method.OwningType.Name, method.Name))) { throw new NotImplementedException("SkipJIT"); } methodCode = _corInfo.CompileMethod(method); if (methodCode.Relocs != null) { if (methodCode.Relocs.Any(r => r.Target is FieldDesc)) { // We only support FieldDesc for InitializeArray intrinsic right now. throw new NotImplementedException("RuntimeFieldHandle is not implemented"); } } } catch (Exception e) { Log.WriteLine("*** " + e.Message + " (" + method + ")"); // Call the __not_yet_implemented method DependencyAnalysis.X64.X64Emitter emit = new DependencyAnalysis.X64.X64Emitter(_nodeFactory); emit.Builder.RequireAlignment(_nodeFactory.Target.MinimumFunctionAlignment); emit.Builder.DefinedSymbols.Add(methodCodeNodeNeedingCode); emit.EmitLEAQ(emit.TargetRegister.Arg0, _nodeFactory.StringIndirection(method.ToString())); DependencyAnalysis.X64.AddrMode loadFromArg0 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg0, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitLEAQ(emit.TargetRegister.Arg1, _nodeFactory.StringIndirection(e.Message)); DependencyAnalysis.X64.AddrMode loadFromArg1 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg1, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitJMP(_nodeFactory.ExternSymbol("__not_yet_implemented")); methodCodeNodeNeedingCode.SetCode(emit.Builder.ToObjectData()); continue; } ObjectDataBuilder objData = new ObjectDataBuilder(); objData.Alignment = _nodeFactory.Target.MinimumFunctionAlignment; objData.EmitBytes(methodCode.Code); objData.DefinedSymbols.Add(methodCodeNodeNeedingCode); BlobNode readOnlyDataBlob = null; if (methodCode.ROData != null) { readOnlyDataBlob = _nodeFactory.ReadOnlyDataBlob( "__readonlydata_" + _nameMangler.GetMangledMethodName(method), methodCode.ROData, methodCode.RODataAlignment); } if (methodCode.Relocs != null) { for (int i = 0; i < methodCode.Relocs.Length; i++) { // TODO: Arbitrary relocs if (methodCode.Relocs[i].Block != BlockType.Code) { throw new NotImplementedException(); } int offset = methodCode.Relocs[i].Offset; int delta = methodCode.Relocs[i].Delta; RelocType relocType = (RelocType)methodCode.Relocs[i].RelocType; ISymbolNode targetNode; object target = methodCode.Relocs[i].Target; if (target is MethodDesc) { targetNode = _nodeFactory.MethodEntrypoint((MethodDesc)target); } else if (target is ReadyToRunHelper) { targetNode = _nodeFactory.ReadyToRunHelper((ReadyToRunHelper)target); } else if (target is JitHelper) { targetNode = _nodeFactory.ExternSymbol(((JitHelper)target).MangledName); } else if (target is string) { targetNode = _nodeFactory.StringIndirection((string)target); } else if (target is TypeDesc) { targetNode = _nodeFactory.NecessaryTypeSymbol((TypeDesc)target); } else if (target is RvaFieldData) { var rvaFieldData = (RvaFieldData)target; targetNode = _nodeFactory.ReadOnlyDataBlob(rvaFieldData.MangledName, rvaFieldData.Data, _typeSystemContext.Target.PointerSize); } else if (target is BlockRelativeTarget) { var blockRelativeTarget = (BlockRelativeTarget)target; // TODO: Arbitrary block relative relocs if (blockRelativeTarget.Block != BlockType.ROData) { throw new NotImplementedException(); } targetNode = readOnlyDataBlob; } else { // TODO: throw new NotImplementedException(); } objData.AddRelocAtOffset(targetNode, relocType, offset, delta); } } // TODO: ColdCode if (methodCode.ColdCode != null) { throw new NotImplementedException(); } methodCodeNodeNeedingCode.SetCode(objData.ToObjectData()); methodCodeNodeNeedingCode.InitializeFrameInfos(methodCode.FrameInfos); methodCodeNodeNeedingCode.InitializeDebugLocInfos(methodCode.DebugLocInfos); } }
private void ComputeDependencyNodeDependencies(List<DependencyNodeCore<NodeFactory>> obj) { foreach (MethodCodeNode methodCodeNodeNeedingCode in obj) { MethodDesc method = methodCodeNodeNeedingCode.Method; string methodName = method.ToString(); Log.WriteLine("Compiling " + methodName); var methodIL = GetMethodIL(method); if (methodIL == null) return; try { _corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (Exception e) { Log.WriteLine("*** " + method + ": " + e.Message); // Call the __not_yet_implemented method DependencyAnalysis.X64.X64Emitter emit = new DependencyAnalysis.X64.X64Emitter(_nodeFactory); emit.Builder.RequireAlignment(_nodeFactory.Target.MinimumFunctionAlignment); emit.Builder.DefinedSymbols.Add(methodCodeNodeNeedingCode); emit.EmitLEAQ(emit.TargetRegister.Arg0, _nodeFactory.StringIndirection(method.ToString())); DependencyAnalysis.X64.AddrMode loadFromArg0 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg0, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitMOV(emit.TargetRegister.Arg0, ref loadFromArg0); emit.EmitLEAQ(emit.TargetRegister.Arg1, _nodeFactory.StringIndirection(e.Message)); DependencyAnalysis.X64.AddrMode loadFromArg1 = new DependencyAnalysis.X64.AddrMode(emit.TargetRegister.Arg1, null, 0, 0, DependencyAnalysis.X64.AddrModeSize.Int64); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitMOV(emit.TargetRegister.Arg1, ref loadFromArg1); emit.EmitJMP(_nodeFactory.ExternSymbol("__not_yet_implemented")); methodCodeNodeNeedingCode.SetCode(emit.Builder.ToObjectData()); continue; } } }
// Assembly stub creation api. TBD, actually make this general purpose public void EmitMOV(Register regDst, ref AddrMode memory) { EmitIndirInstructionSize(0x8a, regDst, ref memory); }
protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { switch (Id) { case ReadyToRunHelperId.NewHelper: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewObjectHelperForType(target))); } break; case ReadyToRunHelperId.VirtualCall: if (relocsOnly) break; AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); { int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, (MethodDesc)Target); Debug.Assert(slot != -1); AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } break; case ReadyToRunHelperId.IsInstanceOf: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, false))); } break; case ReadyToRunHelperId.CastClass: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, true))); } break; case ReadyToRunHelperId.NewArr1: { TypeDesc target = (TypeDesc)Target; // TODO: Swap argument order instead // mov arg1, arg0 encoder.Builder.EmitByte(0x48); encoder.Builder.EmitShort((short)((encoder.TargetRegister.Arg0 == Register.RCX) ? 0xD18B : 0xF78B)); encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewArrayHelperForType(target))); } break; case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)Target; if (!target.HasStaticConstructor) { Debug.Assert(Id == ReadyToRunHelperId.GetNonGCStaticBase); encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target)); encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol(target)); encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeNonGCStaticsSymbol(target)); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: encoder.EmitINT3(); break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)Target; if (!target.HasStaticConstructor) { encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol(target)); AddrMode loadFromRax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol(target)); encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeGCStaticsSymbol(target)); AddrMode loadFromRdx = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.DelegateCtor: { DelegateInfo target = (DelegateInfo)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.MethodEntrypoint(target.Target)); if (target.ShuffleThunk != null) encoder.EmitLEAQ(encoder.TargetRegister.Arg3, factory.MethodEntrypoint(target.ShuffleThunk)); encoder.EmitJMP(factory.MethodEntrypoint(target.Ctor)); } break; case ReadyToRunHelperId.InterfaceDispatch: { encoder.EmitLEAQ(Register.R10, factory.InterfaceDispatchCell((MethodDesc)Target)); AddrMode jmpAddrMode = new AddrMode(Register.R10, null, 0, 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } break; default: throw new NotImplementedException(); } }
public void EmitLEA(Register reg, ref AddrMode addrMode) { Debug.Assert(addrMode.Size != AddrModeSize.Int8 && addrMode.Size != AddrModeSize.Int16); EmitIndirInstruction(0x8D, reg, ref addrMode); }
protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { switch (Id) { case ReadyToRunHelperId.NewHelper: encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol((TypeDesc)Target)); encoder.EmitJMP(factory.ExternSymbol("__allocate_object")); break; case ReadyToRunHelperId.VirtualCall: if (relocsOnly) break; AddrMode loadFromRcx = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRcx); // TODO: More efficient lookup of the slot { MethodDesc method = (MethodDesc)Target; TypeDesc owningType = method.OwningType; int baseSlots = 0; var baseType = owningType.BaseType; while (baseType != null) { List<MethodDesc> baseVirtualSlots; factory.VirtualSlots.TryGetValue(baseType, out baseVirtualSlots); if (baseVirtualSlots != null) baseSlots += baseVirtualSlots.Count; baseType = baseType.BaseType; } List<MethodDesc> virtualSlots = factory.VirtualSlots[owningType]; int methodSlot = -1; for (int slot = 0; slot < virtualSlots.Count; slot++) { if (virtualSlots[slot] == method) { methodSlot = slot; break; } } Debug.Assert(methodSlot != -1); AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, 16 + (baseSlots + methodSlot) * factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } break; case ReadyToRunHelperId.IsInstanceOf: encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target)); encoder.EmitJMP(factory.ExternSymbol("__isinst_class")); break; case ReadyToRunHelperId.CastClass: encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target)); encoder.EmitJMP(factory.ExternSymbol("__castclass_class")); break; case ReadyToRunHelperId.NewArr1: encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target)); encoder.EmitJMP(factory.ExternSymbol("__allocate_array")); break; case ReadyToRunHelperId.GetNonGCStaticBase: if (!((MetadataType)Target).HasStaticConstructor) { Debug.Assert(Id == ReadyToRunHelperId.GetNonGCStaticBase); encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol((MetadataType)Target)); encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol((MetadataType)Target)); encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeNonGCStaticsSymbol((MetadataType)Target)); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } break; case ReadyToRunHelperId.GetThreadStaticBase: encoder.EmitINT3(); break; case ReadyToRunHelperId.GetGCStaticBase: if (!((MetadataType)Target).HasStaticConstructor) { encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol((MetadataType)Target)); AddrMode loadFromRax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol((MetadataType)Target)); encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeGCStaticsSymbol((MetadataType)Target)); AddrMode loadFromRdx = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } break; case ReadyToRunHelperId.DelegateCtor: { DelegateInfo target = (DelegateInfo)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.MethodEntrypoint(target.Target)); if (target.ShuffleThunk != null) encoder.EmitLEAQ(encoder.TargetRegister.Arg3, factory.MethodEntrypoint(target.ShuffleThunk)); encoder.EmitJMP(factory.MethodEntrypoint(target.Ctor)); } break; default: throw new NotImplementedException(); } }
private void EmitIndirInstruction(int opcode, byte subOpcode, ref AddrMode addrMode) { EmitRexPrefix(Register.RAX, ref addrMode); if ((opcode >> 8) != 0) { EmitExtendedOpcode(opcode); } Builder.EmitByte((byte)opcode); EmitModRM(subOpcode, ref addrMode); }
protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { switch (Id) { case ReadyToRunHelperId.NewHelper: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewObjectHelperForType(target))); } break; case ReadyToRunHelperId.VirtualCall: { MethodDesc targetMethod = (MethodDesc)Target; if (targetMethod.OwningType.IsInterface) { encoder.EmitLEAQ(Register.R10, factory.InterfaceDispatchCell((MethodDesc)Target)); AddrMode jmpAddrMode = new AddrMode(Register.R10, null, 0, 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } else { if (relocsOnly) break; AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); int pointerSize = factory.Target.PointerSize; int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod); Debug.Assert(slot != -1); AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize), 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } } break; case ReadyToRunHelperId.IsInstanceOf: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, false))); } break; case ReadyToRunHelperId.CastClass: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, true))); } break; case ReadyToRunHelperId.NewArr1: { TypeDesc target = (TypeDesc)Target; // TODO: Swap argument order instead encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0); encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewArrayHelperForType(target))); } break; case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)Target; bool hasLazyStaticConstructor = factory.TypeSystemContext.HasLazyStaticConstructor(target); encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target), hasLazyStaticConstructor ? NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target) : 0); if (!hasLazyStaticConstructor) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target)); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: { MetadataType target = (MetadataType)Target; ThreadStaticsNode targetNode = factory.TypeThreadStaticsSymbol(target) as ThreadStaticsNode; int typeTlsIndex = 0; // The GetThreadStaticBase helper should be generated only in the compilation module group // that contains the thread static field because the helper needs the index of the type // in Thread Static section of the containing module. // TODO: This needs to be fixed this for the multi-module compilation Debug.Assert(targetNode != null); if (!relocsOnly) { // Get index of the targetNode in the Thread Static region typeTlsIndex = factory.ThreadStaticsRegion.IndexOfEmbeddedObject(targetNode); } // First arg: address of the TypeManager slot that provides the helper with // information about module index and the type manager instance (which is used // for initialization on first access). encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeManagerIndirection); // Second arg: index of the type in the ThreadStatic section of the modules encoder.EmitMOV(encoder.TargetRegister.Arg1, typeTlsIndex); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType)); } else { encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target)); // TODO: performance optimization - inline the check verifying whether we need to trigger the cctor encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase)); } } break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)Target; encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol(target)); AddrMode loadFromRax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target)); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.DelegateCtor: { DelegateCreationInfo target = (DelegateCreationInfo)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg2, target.Target); if (target.Thunk != null) { Debug.Assert(target.Constructor.Method.Signature.Length == 3); encoder.EmitLEAQ(encoder.TargetRegister.Arg3, target.Thunk); } else { Debug.Assert(target.Constructor.Method.Signature.Length == 2); } encoder.EmitJMP(target.Constructor); } break; case ReadyToRunHelperId.ResolveVirtualFunction: { MethodDesc targetMethod = (MethodDesc)Target; if (targetMethod.OwningType.IsInterface) { encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.InterfaceDispatchCell(targetMethod)); encoder.EmitJMP(factory.ExternSymbol("RhpResolveInterfaceMethod")); } else { if (relocsOnly) break; AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod); Debug.Assert(slot != -1); AddrMode loadFromSlot = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromSlot); encoder.EmitRET(); } } break; case ReadyToRunHelperId.ResolveGenericVirtualMethod: encoder.EmitINT3(); break; default: throw new NotImplementedException(); } }
protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { switch (Id) { case ReadyToRunHelperId.NewHelper: encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol((TypeDesc)Target)); encoder.EmitJMP(factory.ExternSymbol("__allocate_object")); break; case ReadyToRunHelperId.VirtualCall: if (relocsOnly) break; AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); { int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, (MethodDesc)Target); Debug.Assert(slot != -1); AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } break; case ReadyToRunHelperId.IsInstanceOf: encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target)); encoder.EmitJMP(factory.ExternSymbol("__isinst_class")); break; case ReadyToRunHelperId.CastClass: encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target)); encoder.EmitJMP(factory.ExternSymbol("__castclass_class")); break; case ReadyToRunHelperId.NewArr1: encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol((TypeDesc)Target)); encoder.EmitJMP(factory.ExternSymbol("__allocate_array")); break; case ReadyToRunHelperId.GetNonGCStaticBase: if (!((MetadataType)Target).HasStaticConstructor) { Debug.Assert(Id == ReadyToRunHelperId.GetNonGCStaticBase); encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol((MetadataType)Target)); encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol((MetadataType)Target)); encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeNonGCStaticsSymbol((MetadataType)Target)); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } break; case ReadyToRunHelperId.GetThreadStaticBase: encoder.EmitINT3(); break; case ReadyToRunHelperId.GetGCStaticBase: if (!((MetadataType)Target).HasStaticConstructor) { encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol((MetadataType)Target)); AddrMode loadFromRax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol((MetadataType)Target)); encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeGCStaticsSymbol((MetadataType)Target)); AddrMode loadFromRdx = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromRdx); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } break; case ReadyToRunHelperId.DelegateCtor: { DelegateInfo target = (DelegateInfo)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.MethodEntrypoint(target.Target)); if (target.ShuffleThunk != null) encoder.EmitLEAQ(encoder.TargetRegister.Arg3, factory.MethodEntrypoint(target.ShuffleThunk)); encoder.EmitJMP(factory.MethodEntrypoint(target.Ctor)); } break; default: throw new NotImplementedException(); } }
private void EmitModRM(byte subOpcode, ref AddrMode addrMode) { byte modRM = (byte)((subOpcode & 0x07) << 3); if (addrMode.BaseReg > Register.None) { Debug.Assert(addrMode.BaseReg >= Register.RegDirect); Register reg = (Register)(addrMode.BaseReg - Register.RegDirect); Builder.EmitByte((byte)(0xC0 | modRM | ((int)reg & 0x07))); } else { byte lowOrderBitsOfBaseReg = (byte)((int)addrMode.BaseReg & 0x07); modRM |= lowOrderBitsOfBaseReg; int offsetSize = 0; if (addrMode.Offset == 0 && (lowOrderBitsOfBaseReg != (byte)Register.RBP)) { offsetSize = 0; } else if (InSignedByteRange(addrMode.Offset)) { offsetSize = 1; modRM |= 0x40; } else { offsetSize = 4; modRM |= 0x80; } bool emitSibByte = false; Register sibByteBaseRegister = addrMode.BaseReg; if (addrMode.BaseReg == Register.None) { //# ifdef _TARGET_AMD64_ // x64 requires SIB to avoid RIP relative address emitSibByte = true; //#else // emitSibByte = (addrMode.m_indexReg != MDIL_REG_NO_INDEX); //#endif modRM &= 0x38; // set Mod bits to 00 and clear out base reg offsetSize = 4; // this forces 32-bit displacement if (emitSibByte) { // EBP in SIB byte means no base // ModRM base register forced to ESP in SIB code below sibByteBaseRegister = Register.RBP; } else { // EBP in ModRM means no base modRM |= (byte)(Register.RBP); } } else if (lowOrderBitsOfBaseReg == (byte)Register.RSP || addrMode.IndexReg.HasValue) { emitSibByte = true; } if (!emitSibByte) { Builder.EmitByte(modRM); } else { // MDIL_REG_ESP as the base is the marker that there is a SIB byte modRM = (byte)((modRM & 0xF8) | (int)Register.RSP); Builder.EmitByte(modRM); int indexRegAsInt = (int)(addrMode.IndexReg.HasValue ? addrMode.IndexReg.Value : Register.RSP); Builder.EmitByte((byte)((addrMode.Scale << 6) + ((indexRegAsInt & 0x07) << 3) + ((int)sibByteBaseRegister & 0x07))); } EmitImmediate(addrMode.Offset, offsetSize); } }
private void EmitRexPrefix(Register reg, ref AddrMode addrMode) { byte rexPrefix = 0; // Check the situations where a REX prefix is needed // Are we accessing a byte register that wasn't byte accessible in x86? if (addrMode.Size == AddrModeSize.Int8 && reg >= Register.RSP) { rexPrefix |= 0x40; } // Is this a 64 bit instruction? if (addrMode.Size == AddrModeSize.Int64) { rexPrefix |= 0x48; } // Is the destination register one of the new ones? if (reg >= Register.R8) { rexPrefix |= 0x44; } // Is the index register one of the new ones? if (addrMode.IndexReg.HasValue && addrMode.IndexReg.Value >= Register.R8 && addrMode.IndexReg.Value <= Register.R15) { rexPrefix |= 0x42; } // Is the base register one of the new ones? if (addrMode.BaseReg >= Register.R8 && addrMode.BaseReg <= Register.R15 || addrMode.BaseReg >= (int)Register.R8 + Register.RegDirect && addrMode.BaseReg <= (int)Register.R15 + Register.RegDirect) { rexPrefix |= 0x41; } // If we have anything so far, emit it. if (rexPrefix != 0) { Builder.EmitByte(rexPrefix); } }
protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { switch (Id) { case ReadyToRunHelperId.NewHelper: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewObjectHelperForType(target))); } break; case ReadyToRunHelperId.VirtualCall: { MethodDesc targetMethod = (MethodDesc)Target; if (targetMethod.OwningType.IsInterface) { encoder.EmitLEAQ(Register.R10, factory.InterfaceDispatchCell((MethodDesc)Target)); AddrMode jmpAddrMode = new AddrMode(Register.R10, null, 0, 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } else { if (relocsOnly) break; AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); int pointerSize = factory.Target.PointerSize; int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod); Debug.Assert(slot != -1); AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize), 0, AddrModeSize.Int64); encoder.EmitJmpToAddrMode(ref jmpAddrMode); } } break; case ReadyToRunHelperId.IsInstanceOf: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, false))); } break; case ReadyToRunHelperId.CastClass: { TypeDesc target = (TypeDesc)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.NecessaryTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetCastingHelperNameForType(target, true))); } break; case ReadyToRunHelperId.NewArr1: { TypeDesc target = (TypeDesc)Target; // TODO: Swap argument order instead encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0); encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.ConstructedTypeSymbol(target)); encoder.EmitJMP(factory.ExternSymbol(JitHelper.GetNewArrayHelperForType(target))); } break; case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)Target; bool hasLazyStaticConstructor = factory.TypeSystemContext.HasLazyStaticConstructor(target); encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target), hasLazyStaticConstructor ? NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target) : 0); if (!hasLazyStaticConstructor) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target)); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: encoder.EmitINT3(); break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)Target; encoder.EmitLEAQ(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol(target)); AddrMode loadFromRax = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromRax); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeNonGCStaticsSymbol(target)); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.DelegateCtor: { DelegateCreationInfo target = (DelegateCreationInfo)Target; encoder.EmitLEAQ(encoder.TargetRegister.Arg2, target.Target); if (target.Thunk != null) { Debug.Assert(target.Constructor.Method.Signature.Length == 3); encoder.EmitLEAQ(encoder.TargetRegister.Arg3, target.Thunk); } else { Debug.Assert(target.Constructor.Method.Signature.Length == 2); } encoder.EmitJMP(target.Constructor); } break; case ReadyToRunHelperId.ResolveVirtualFunction: { MethodDesc targetMethod = (MethodDesc)Target; if (targetMethod.OwningType.IsInterface) { encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.InterfaceDispatchCell(targetMethod)); encoder.EmitJMP(factory.ExternSymbol("RhpResolveInterfaceMethod")); } else { if (relocsOnly) break; AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromThisPtr); int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod); Debug.Assert(slot != -1); AddrMode loadFromSlot = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromSlot); encoder.EmitRET(); } } break; case ReadyToRunHelperId.GenericLookupFromThis: { int pointerSize = factory.Target.PointerSize; var lookupInfo = (GenericLookupDescriptor)Target; // Arg0 points to the EEType // Locate the VTable slot that points to the dictionary int vtableSlot = 0; if (!relocsOnly) vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)lookupInfo.CanonicalOwner); int slotOffset = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize); // Load the dictionary pointer from the VTable AddrMode loadDictionary = new AddrMode(encoder.TargetRegister.Arg0, null, slotOffset, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadDictionary); // What's left now is the actual dictionary lookup goto case ReadyToRunHelperId.GenericLookupFromDictionary; } case ReadyToRunHelperId.GenericLookupFromDictionary: { var lookupInfo = (GenericLookupDescriptor)Target; // Find the generic dictionary slot int dictionarySlot = 0; if (!relocsOnly) { // The concrete slot won't be known until we're emitting data. dictionarySlot = factory.GenericDictionaryLayout(lookupInfo.CanonicalOwner).GetSlotForEntry(lookupInfo.Signature); } // Load the generic dictionary cell AddrMode loadEntry = new AddrMode( encoder.TargetRegister.Arg0, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadEntry); encoder.EmitRET(); } break; default: throw new NotImplementedException(); } }
public void EmitCompareToZero(Register reg) { AddrMode rexAddrMode = new AddrMode(Register.RegDirect | reg, null, 0, 0, AddrModeSize.Int64); EmitIndirInstructionSize(0x84, reg, ref rexAddrMode); }