public Relocation(RelocType relocType, int offset, ISymbolNode target, int delta) { RelocType = relocType; Offset = offset; Target = target; Delta = delta; }
public HeaderItem(ReadyToRunSectionType id, ObjectNode node, ISymbolNode startSymbol, ISymbolNode endSymbol) { Id = id; Node = node; StartSymbol = startSymbol; EndSymbol = endSymbol; }
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 NonGCStaticsNode(MetadataType type) { _type = type; if (HasClassConstructorContext) { _classConstructorContext = new ObjectAndOffsetSymbolNode(this, 0, "__CCtorContext_" + NodeFactory.NameMangler.GetMangledTypeName(_type)); } }
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); }
/// <summary> /// Adds a new entry to the table. Thread safety: not thread safe. Expected to be called at the final /// object data emission phase from a single thread. /// </summary> public uint GetIndex(ISymbolNode symbol) { uint index; if (!_insertedSymbolsDictionary.TryGetValue(symbol, out index)) { index = (uint)_insertedSymbols.Count; _insertedSymbolsDictionary[symbol] = index; _insertedSymbols.Add(symbol); } return index; }
public NonGCStaticsNode(MetadataType type, NodeFactory factory) { _type = type; if (factory.TypeInitializationManager.HasLazyStaticConstructor(type)) { // Class constructor context is a small struct prepended to type's non-GC static data region // that keeps track of whether the .cctor executed and holds the pointer to the .cctor method. _classConstructorContext = new ObjectAndOffsetSymbolNode(this, 0, "__CCtorContext_" + NodeFactory.NameMangler.GetMangledTypeName(_type)); } }
public void Visit(ISymbolNode node) { VisitLog.Add(node.ToString()); }
public NodeInfo(ISymbolNode node, int nodeIndex, int symbolIndex) { Node = node; NodeIndex = nodeIndex; SymbolIndex = symbolIndex; }
public IndirectionNode Indirection(ISymbolNode symbol) { return(_indirectionNodes.GetOrAdd(symbol)); }
public SingleArgumentJumpThunk(ExternSymbolNode target, ISymbolNode argument) { _target = target; _argument = argument; }
public JumpStubNode(ISymbolNode target) { this._target = target; }
public static void EmitObject(string objectFilePath, IEnumerable <DependencyNode> nodes, NodeFactory factory, WebAssemblyCodegenCompilation compilation, IObjectDumper dumper) { WebAssemblyObjectWriter objectWriter = new WebAssemblyObjectWriter(objectFilePath, factory, compilation); bool succeeded = false; try { objectWriter.EmitReadyToRunHeaderCallback(compilation.Module.Context); //ObjectNodeSection managedCodeSection = null; var listOfOffsets = new List <int>(); foreach (DependencyNode depNode in nodes) { ObjectNode node = depNode as ObjectNode; if (node == null) { continue; } if (node.ShouldSkipEmittingObjectNode(factory)) { continue; } if (node is ReadyToRunGenericHelperNode readyToRunGenericHelperNode) { objectWriter.GetCodeForReadyToRunGenericHelper(compilation, readyToRunGenericHelperNode, factory); continue; } objectWriter.StartObjectNode(node); ObjectData nodeContents = node.GetData(factory); if (dumper != null) { dumper.DumpObjectNode(factory.NameMangler, node, nodeContents); } #if DEBUG foreach (ISymbolNode definedSymbol in nodeContents.DefinedSymbols) { try { _previouslyWrittenNodeNames.Add(definedSymbol.GetMangledName(factory.NameMangler), definedSymbol); } catch (ArgumentException) { ISymbolNode alreadyWrittenSymbol = _previouslyWrittenNodeNames[definedSymbol.GetMangledName(factory.NameMangler)]; Debug.Fail("Duplicate node name emitted to file", $"Symbol {definedSymbol.GetMangledName(factory.NameMangler)} has already been written to the output object file {objectFilePath} with symbol {alreadyWrittenSymbol}"); } } #endif ObjectNodeSection section = node.Section; if (objectWriter.ShouldShareSymbol(node)) { section = objectWriter.GetSharedSection(section, ((ISymbolNode)node).GetMangledName(factory.NameMangler)); } // Ensure section and alignment for the node. objectWriter.SetSection(section); objectWriter.EmitAlignment(nodeContents.Alignment); objectWriter.ResetByteRunInterruptionOffsets(nodeContents.Relocs); // Build symbol definition map. objectWriter.BuildSymbolDefinitionMap(node, nodeContents.DefinedSymbols); Relocation[] relocs = nodeContents.Relocs; int nextRelocOffset = -1; int nextRelocIndex = -1; if (relocs.Length > 0) { nextRelocOffset = relocs[0].Offset; nextRelocIndex = 0; } int i = 0; listOfOffsets.Clear(); listOfOffsets.AddRange(objectWriter._byteInterruptionOffsets); int offsetIndex = 0; while (i < nodeContents.Data.Length) { // Emit symbol definitions if necessary objectWriter.EmitSymbolDefinition(i); if (i == nextRelocOffset) { Relocation reloc = relocs[nextRelocIndex]; long delta; unsafe { fixed(void *location = &nodeContents.Data[i]) { delta = Relocation.ReadValue(reloc.RelocType, location); } } ISymbolNode symbolToWrite = reloc.Target; var eeTypeNode = reloc.Target as EETypeNode; if (eeTypeNode != null) { if (eeTypeNode.ShouldSkipEmittingObjectNode(factory)) { symbolToWrite = factory.ConstructedTypeSymbol(eeTypeNode.Type); } } int size = objectWriter.EmitSymbolReference(symbolToWrite, (int)delta, reloc.RelocType); /* * WebAssembly has no thumb * // Emit a copy of original Thumb2 instruction that came from RyuJIT * if (reloc.RelocType == RelocType.IMAGE_REL_BASED_THUMB_MOV32 || * reloc.RelocType == RelocType.IMAGE_REL_BASED_THUMB_BRANCH24) * { * unsafe * { * fixed (void* location = &nodeContents.Data[i]) * { * objectWriter.EmitBytes((IntPtr)location, size); * } * } * }*/ // Update nextRelocIndex/Offset if (++nextRelocIndex < relocs.Length) { nextRelocOffset = relocs[nextRelocIndex].Offset; } else { // This is the last reloc. Set the next reloc offset to -1 in case the last reloc has a zero size, // which means the reloc does not have vacant bytes corresponding to in the data buffer. E.g, // IMAGE_REL_THUMB_BRANCH24 is a kind of 24-bit reloc whose bits scatte over the instruction that // references it. We do not vacate extra bytes in the data buffer for this kind of reloc. nextRelocOffset = -1; } i += size; } else { while (offsetIndex < listOfOffsets.Count && listOfOffsets[offsetIndex] <= i) { offsetIndex++; } int nextOffset = offsetIndex == listOfOffsets.Count ? nodeContents.Data.Length : listOfOffsets[offsetIndex]; unsafe { // Todo: Use Span<T> instead once it's available to us in this repo fixed(byte *pContents = &nodeContents.Data[i]) { objectWriter.EmitBytes((IntPtr)(pContents), nextOffset - i); i += nextOffset - i; } } } } Debug.Assert(i == nodeContents.Data.Length); // It is possible to have a symbol just after all of the data. objectWriter.EmitSymbolDefinition(nodeContents.Data.Length); objectWriter.DoneObjectNode(); } succeeded = true; } finally { objectWriter.Dispose(); if (!succeeded) { // If there was an exception while generating the OBJ file, make sure we don't leave the unfinished // object file around. try { File.Delete(objectFilePath); } catch { } } } }
// Returns size of the emitted symbol reference public int EmitSymbolReference(ISymbolNode target, int delta, RelocType relocType) { _sb.Clear(); AppendExternCPrefix(_sb); target.AppendMangledName(NodeFactory.NameMangler, _sb); return EmitSymbolRef(_sb, relocType, delta); }
public void EmitPointerReloc(ISymbolNode symbol, int delta = 0) { EmitReloc(symbol, (_target.PointerSize == 8) ? RelocType.IMAGE_REL_BASED_DIR64 : RelocType.IMAGE_REL_BASED_HIGHLOW, delta); }
private DelegateCreationInfo(IMethodNode constructor, ISymbolNode target, IMethodNode thunk = null) { Constructor = constructor; Target = target; Thunk = thunk; }
private void ImportCall(ILOpcode opcode, int token) { // Strip runtime determined characteristics off of the method (because that's how RyuJIT operates) var runtimeDeterminedMethod = (MethodDesc)_methodIL.GetObject(token); MethodDesc method = runtimeDeterminedMethod; if (runtimeDeterminedMethod.IsRuntimeDeterminedExactMethod) { method = runtimeDeterminedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); } if (method.IsRawPInvoke()) { // Raw P/invokes don't have any dependencies. return; } string reason = null; switch (opcode) { case ILOpcode.newobj: reason = "newobj"; break; case ILOpcode.call: reason = "call"; break; case ILOpcode.callvirt: reason = "callvirt"; break; case ILOpcode.ldftn: reason = "ldftn"; break; case ILOpcode.ldvirtftn: reason = "ldvirtftn"; break; default: Debug.Assert(false); break; } // If we're scanning the fallback body because scanning the real body failed, don't trigger cctor. // Accessing the cctor could have been a reason why we failed. if (!_isFallbackBodyCompilation) { // Do we need to run the cctor? TypeDesc owningType = runtimeDeterminedMethod.OwningType; if (_factory.TypeSystemContext.HasLazyStaticConstructor(owningType)) { // For beforefieldinit, we can wait for field access. if (!((MetadataType)owningType).IsBeforeFieldInit) { // Accessing the static base will trigger the cctor. if (owningType.IsRuntimeDeterminedSubtype) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.GetNonGCStaticBase, owningType), reason); } else { _dependencies.Add(_factory.ReadyToRunHelper(ReadyToRunHelperId.GetNonGCStaticBase, owningType), reason); } } } } if (opcode == ILOpcode.newobj) { TypeDesc owningType = runtimeDeterminedMethod.OwningType; if (owningType.IsString) { // String .ctor handled specially below } else { // Nullable needs to be unwrapped. if (owningType.IsNullable) { owningType = owningType.Instantiation[0]; } if (owningType.IsRuntimeDeterminedSubtype) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, owningType), reason); } else { _dependencies.Add(_factory.ConstructedTypeSymbol(owningType), reason); } if (owningType.IsMdArray) { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.NewMultiDimArr_NonVarArg), reason); return; } else { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.NewObject), reason); } } if (owningType.IsDelegate) { // If this is a verifiable delegate construction sequence, the previous instruction is a ldftn/ldvirtftn if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.prefix1) { // TODO: for ldvirtftn we need to also check for the `dup` instruction, otherwise this is a normal newobj. ILOpcode previousOpcode = (ILOpcode)(0x100 + _ilBytes[_previousInstructionOffset + 1]); if (previousOpcode == ILOpcode.ldvirtftn || previousOpcode == ILOpcode.ldftn) { int delTargetToken = ReadILTokenAt(_previousInstructionOffset + 2); var delTargetMethod = (MethodDesc)_methodIL.GetObject(delTargetToken); TypeDesc canonDelegateType = method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific); DelegateCreationInfo info = _compilation.GetDelegateCtor(canonDelegateType, delTargetMethod, previousOpcode == ILOpcode.ldvirtftn); if (info.NeedsRuntimeLookup) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.DelegateCtor, info), reason); } else { _dependencies.Add(_factory.ReadyToRunHelper(ReadyToRunHelperId.DelegateCtor, info), reason); } return; } } } } if (method.OwningType.IsDelegate && method.Name == "Invoke") { // TODO: might not want to do this if scanning for reflection. // This is expanded as an intrinsic, not a function call. return; } if (method.IsIntrinsic) { if (IsRuntimeHelpersInitializeArray(method)) { if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.ldtoken) { return; } } if (IsRuntimeTypeHandleGetValueInternal(method)) { if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.ldtoken) { return; } } } TypeDesc exactType = method.OwningType; bool resolvedConstraint = false; bool forceUseRuntimeLookup = false; MethodDesc methodAfterConstraintResolution = method; if (_constrained != null) { // We have a "constrained." call. Try a partial resolve of the constraint call. Note that this // will not necessarily resolve the call exactly, since we might be compiling // shared generic code - it may just resolve it to a candidate suitable for // JIT compilation, and require a runtime lookup for the actual code pointer // to call. MethodDesc directMethod = _constrained.GetClosestDefType().TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup); if (directMethod == null && _constrained.IsEnum) { // Constrained calls to methods on enum methods resolve to System.Enum's methods. System.Enum is a reference // type though, so we would fail to resolve and box. We have a special path for those to avoid boxing. directMethod = _compilation.TypeSystemContext.TryResolveConstrainedEnumMethod(_constrained, method); } if (directMethod != null) { // Either // 1. no constraint resolution at compile time (!directMethod) // OR 2. no code sharing lookup in call // OR 3. we have have resolved to an instantiating stub methodAfterConstraintResolution = directMethod; Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface); resolvedConstraint = true; exactType = _constrained; } else if (_constrained.IsValueType) { // We'll need to box `this`. AddBoxingDependencies(_constrained, reason); } _constrained = null; } MethodDesc targetMethod = methodAfterConstraintResolution; bool exactContextNeedsRuntimeLookup; if (targetMethod.HasInstantiation) { exactContextNeedsRuntimeLookup = targetMethod.IsSharedByGenericInstantiations; } else { exactContextNeedsRuntimeLookup = exactType.IsCanonicalSubtype(CanonicalFormKind.Any); } // // Determine whether to perform direct call // bool directCall = false; if (targetMethod.Signature.IsStatic) { // Static methods are always direct calls directCall = true; } else if (targetMethod.OwningType.IsInterface) { // Force all interface calls to be interpreted as if they are virtual. directCall = false; } else if ((opcode != ILOpcode.callvirt && opcode != ILOpcode.ldvirtftn) || resolvedConstraint) { directCall = true; } else { if (!targetMethod.IsVirtual || targetMethod.IsFinal || targetMethod.OwningType.IsSealed()) { directCall = true; } } bool allowInstParam = opcode != ILOpcode.ldvirtftn && opcode != ILOpcode.ldftn; if (directCall && !allowInstParam && targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { // Needs a single address to call this method but the method needs a hidden argument. // We need a fat function pointer for this that captures both things. if (exactContextNeedsRuntimeLookup) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodEntry, runtimeDeterminedMethod), reason); } else { _dependencies.Add(_factory.FatFunctionPointer(runtimeDeterminedMethod), reason); } } else if (directCall) { bool referencingArrayAddressMethod = false; if (targetMethod.IsIntrinsic) { // If this is an intrinsic method with a callsite-specific expansion, this will replace // the method with a method the intrinsic expands into. If it's not the special intrinsic, // method stays unchanged. targetMethod = _compilation.ExpandIntrinsicForCallsite(targetMethod, _canonMethod); // Array address method requires special dependency tracking. referencingArrayAddressMethod = targetMethod.IsArrayAddressMethod(); } MethodDesc concreteMethod = targetMethod; targetMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); if (targetMethod.IsConstructor && targetMethod.OwningType.IsString) { _dependencies.Add(_factory.StringAllocator(targetMethod), reason); } else if (exactContextNeedsRuntimeLookup) { if (targetMethod.IsSharedByGenericInstantiations && !resolvedConstraint && !referencingArrayAddressMethod) { _dependencies.Add(_factory.RuntimeDeterminedMethod(runtimeDeterminedMethod), reason); } else { Debug.Assert(!forceUseRuntimeLookup); _dependencies.Add(_factory.MethodEntrypoint(targetMethod), reason); } } else { ISymbolNode instParam = null; if (targetMethod.RequiresInstMethodDescArg()) { instParam = _compilation.NodeFactory.MethodGenericDictionary(concreteMethod); } else if (targetMethod.RequiresInstMethodTableArg() || referencingArrayAddressMethod) { // Ask for a constructed type symbol because we need the vtable to get to the dictionary instParam = _compilation.NodeFactory.ConstructedTypeSymbol(concreteMethod.OwningType); } if (instParam != null) { _dependencies.Add(instParam, reason); if (!referencingArrayAddressMethod) { _dependencies.Add(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod), reason); } else { // We don't want array Address method to be modeled in the generic dependency analysis. // The method doesn't actually have runtime determined dependencies (won't do // any generic lookups). _dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason); } } else if (targetMethod.AcquiresInstMethodTableFromThis()) { _dependencies.Add(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod), reason); } else { _dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason); } } } else if (method.HasInstantiation) { // Generic virtual method call if (exactContextNeedsRuntimeLookup) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodHandle, runtimeDeterminedMethod), reason); } else { _dependencies.Add(_factory.RuntimeMethodHandle(runtimeDeterminedMethod), reason); } _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.GVMLookupForSlot), reason); } else { ReadyToRunHelperId helper; if (opcode == ILOpcode.ldvirtftn) { helper = ReadyToRunHelperId.ResolveVirtualFunction; } else { Debug.Assert(opcode == ILOpcode.callvirt); helper = ReadyToRunHelperId.VirtualCall; } if (exactContextNeedsRuntimeLookup && targetMethod.OwningType.IsInterface) { _dependencies.Add(GetGenericLookupHelper(helper, runtimeDeterminedMethod), reason); } else { // Get the slot defining method to make sure our virtual method use tracking gets this right. // For normal C# code the targetMethod will always be newslot. MethodDesc slotDefiningMethod = targetMethod.IsNewSlot ? targetMethod : MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(targetMethod); _dependencies.Add(_factory.ReadyToRunHelper(helper, slotDefiningMethod), reason); } } }
private void CreateNodeCaches() { _typeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) => { Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type)); if (_compilationModuleGroup.ContainsType(type)) { if (type.IsGenericDefinition) { return(new GenericDefinitionEETypeNode(this, type)); } else if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) { return(new CanonicalDefinitionEETypeNode(this, type)); } else if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { if (Target.Abi == TargetAbi.CoreRT) { return(new CanonicalEETypeNode(this, type)); } else { // Remove this once we stop using the STS dependency analysis. return(new NecessaryCanonicalEETypeNode(this, type)); } } else { return(new EETypeNode(this, type)); } } else { return(new ExternEETypeSymbolNode(this, type)); } }); _constructedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) => { // Canonical definition types are *not* constructed types (call NecessaryTypeSymbol to get them) Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any)); Debug.Assert(!_compilationModuleGroup.ShouldReferenceThroughImportTable(type)); if (_compilationModuleGroup.ContainsType(type)) { if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(new CanonicalEETypeNode(this, type)); } else { return(new ConstructedEETypeNode(this, type)); } } else { return(new ExternEETypeSymbolNode(this, type)); } }); _clonedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) => { // Only types that reside in other binaries should be cloned Debug.Assert(_compilationModuleGroup.ShouldReferenceThroughImportTable(type)); return(new ClonedConstructedEETypeNode(this, type)); }); _importedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) => { Debug.Assert(_compilationModuleGroup.ShouldReferenceThroughImportTable(type)); return(new ImportedEETypeSymbolNode(this, type)); }); _nonGCStatics = new NodeCache <MetadataType, ISymbolNode>((MetadataType type) => { if (_compilationModuleGroup.ContainsType(type)) { return(new NonGCStaticsNode(type, this)); } else if (_compilationModuleGroup.ShouldReferenceThroughImportTable(type)) { return(new ImportedNonGCStaticsNode(this, type)); } else { return(new ExternSymbolNode(NonGCStaticsNode.GetMangledName(type, NameMangler))); } }); _GCStatics = new NodeCache <MetadataType, ISymbolNode>((MetadataType type) => { if (_compilationModuleGroup.ContainsType(type)) { return(new GCStaticsNode(type)); } else if (_compilationModuleGroup.ShouldReferenceThroughImportTable(type)) { return(new ImportedGCStaticsNode(this, type)); } else { return(new ExternSymbolNode(GCStaticsNode.GetMangledName(type, NameMangler))); } }); _GCStaticIndirectionNodes = new NodeCache <MetadataType, EmbeddedObjectNode>((MetadataType type) => { ISymbolNode gcStaticsNode = TypeGCStaticsSymbol(type); Debug.Assert(gcStaticsNode is GCStaticsNode); return(GCStaticsRegion.NewNode((GCStaticsNode)gcStaticsNode)); }); _threadStatics = new NodeCache <MetadataType, ThreadStaticsNode>((MetadataType type) => { return(new ThreadStaticsNode(type, this)); }); _typeThreadStaticIndices = new NodeCache <MetadataType, TypeThreadStaticIndexNode>(type => { return(new TypeThreadStaticIndexNode(type)); }); _GCStaticEETypes = new NodeCache <GCPointerMap, GCStaticEETypeNode>((GCPointerMap gcMap) => { return(new GCStaticEETypeNode(Target, gcMap)); }); _readOnlyDataBlobs = new NodeCache <ReadOnlyDataBlobKey, BlobNode>(key => { return(new BlobNode(key.Name, ObjectNodeSection.ReadOnlyDataSection, key.Data, key.Alignment)); }); _externSymbols = new NodeCache <string, ExternSymbolNode>((string name) => { return(new ExternSymbolNode(name)); }); _pInvokeModuleFixups = new NodeCache <string, PInvokeModuleFixupNode>((string name) => { return(new PInvokeModuleFixupNode(name)); }); _pInvokeMethodFixups = new NodeCache <Tuple <string, string>, PInvokeMethodFixupNode>((Tuple <string, string> key) => { return(new PInvokeMethodFixupNode(key.Item1, key.Item2)); }); _methodEntrypoints = new NodeCache <MethodDesc, IMethodNode>(CreateMethodEntrypointNode); _unboxingStubs = new NodeCache <MethodDesc, IMethodNode>(CreateUnboxingStubNode); _fatFunctionPointers = new NodeCache <MethodKey, FatFunctionPointerNode>(method => { return(new FatFunctionPointerNode(method.Method, method.IsUnboxingStub)); }); _gvmDependenciesNode = new NodeCache <MethodDesc, GVMDependenciesNode>(method => { return(new GVMDependenciesNode(method)); }); _gvmTableEntries = new NodeCache <TypeDesc, TypeGVMEntriesNode>(type => { return(new TypeGVMEntriesNode(type)); }); _shadowConcreteMethods = new NodeCache <MethodKey, IMethodNode>(methodKey => { MethodDesc canonMethod = methodKey.Method.GetCanonMethodTarget(CanonicalFormKind.Specific); if (methodKey.IsUnboxingStub) { return(new ShadowConcreteUnboxingThunkNode(methodKey.Method, MethodEntrypoint(canonMethod, true))); } else { return(new ShadowConcreteMethodNode(methodKey.Method, MethodEntrypoint(canonMethod))); } }); _runtimeDeterminedMethods = new NodeCache <MethodDesc, IMethodNode>(method => { return(new RuntimeDeterminedMethodNode(method, MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)))); }); _virtMethods = new NodeCache <MethodDesc, VirtualMethodUseNode>((MethodDesc method) => { // We don't need to track virtual method uses for types that are producing full vtables. // It's a waste of CPU time and memory. Debug.Assert(!CompilationModuleGroup.ShouldProduceFullVTable(method.OwningType)); return(new VirtualMethodUseNode(method)); }); _readyToRunHelpers = new NodeCache <ReadyToRunHelperKey, ISymbolNode>(CreateReadyToRunHelperNode); _genericReadyToRunHelpersFromDict = new NodeCache <ReadyToRunGenericHelperKey, ISymbolNode>(data => { return(new ReadyToRunGenericLookupFromDictionaryNode(this, data.HelperId, data.Target, data.DictionaryOwner)); }); _genericReadyToRunHelpersFromType = new NodeCache <ReadyToRunGenericHelperKey, ISymbolNode>(data => { return(new ReadyToRunGenericLookupFromTypeNode(this, data.HelperId, data.Target, data.DictionaryOwner)); }); _indirectionNodes = new NodeCache <ISymbolNode, ISymbolNode>(indirectedNode => { return(new IndirectionNode(Target, indirectedNode, 0)); }); _frozenStringNodes = new NodeCache <string, FrozenStringNode>((string data) => { return(new FrozenStringNode(data, Target)); }); _interfaceDispatchCells = new NodeCache <DispatchCellKey, InterfaceDispatchCellNode>(callSiteCell => { return(new InterfaceDispatchCellNode(callSiteCell.Target, callSiteCell.CallsiteId)); }); _interfaceDispatchMaps = new NodeCache <TypeDesc, InterfaceDispatchMapNode>((TypeDesc type) => { return(new InterfaceDispatchMapNode(type)); }); _runtimeMethodHandles = new NodeCache <MethodDesc, RuntimeMethodHandleNode>((MethodDesc method) => { return(new RuntimeMethodHandleNode(method)); }); _runtimeFieldHandles = new NodeCache <FieldDesc, RuntimeFieldHandleNode>((FieldDesc field) => { return(new RuntimeFieldHandleNode(field)); }); _interfaceDispatchMapIndirectionNodes = new NodeCache <TypeDesc, EmbeddedObjectNode>((TypeDesc type) => { var dispatchMap = InterfaceDispatchMap(type); return(DispatchMapTable.NewNodeWithSymbol(dispatchMap, (indirectionNode) => { dispatchMap.SetDispatchMapIndex(this, DispatchMapTable.IndexOfEmbeddedObject(indirectionNode)); })); }); _genericCompositions = new NodeCache <GenericCompositionDetails, GenericCompositionNode>((GenericCompositionDetails details) => { return(new GenericCompositionNode(details)); }); _eagerCctorIndirectionNodes = new NodeCache <MethodDesc, EmbeddedObjectNode>((MethodDesc method) => { Debug.Assert(method.IsStaticConstructor); Debug.Assert(TypeSystemContext.HasEagerStaticConstructor((MetadataType)method.OwningType)); return(EagerCctorTable.NewNode(MethodEntrypoint(method))); }); _vTableNodes = new NodeCache <TypeDesc, VTableSliceNode>((TypeDesc type ) => { if (CompilationModuleGroup.ShouldProduceFullVTable(type)) { return(new EagerlyBuiltVTableSliceNode(type)); } else { return(new LazilyBuiltVTableSliceNode(type)); } }); _methodGenericDictionaries = new NodeCache <MethodDesc, ISymbolNode>(method => { if (CompilationModuleGroup.ContainsMethod(method)) { return(new MethodGenericDictionaryNode(method)); } else { return(new ImportedMethodGenericDictionaryNode(this, method)); } }); _typeGenericDictionaries = new NodeCache <TypeDesc, ISymbolNode>(type => { if (CompilationModuleGroup.ContainsType(type)) { return(new TypeGenericDictionaryNode(type)); } else { return(new ImportedTypeGenericDictionaryNode(this, type)); } }); _genericDictionaryLayouts = new NodeCache <TypeSystemEntity, DictionaryLayoutNode>(methodOrType => { return(new DictionaryLayoutNode(methodOrType)); }); _stringAllocators = new NodeCache <MethodDesc, IMethodNode>(constructor => { return(new StringAllocatorMethodNode(constructor)); }); NativeLayout = new NativeLayoutHelper(this); }
protected override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly) { switch (Id) { case ReadyToRunHelperId.VirtualCall: { MethodDesc targetMethod = (MethodDesc)Target; Debug.Assert(!targetMethod.OwningType.IsInterface); Debug.Assert(!targetMethod.CanMethodBeInSealedVTable()); int pointerSize = factory.Target.PointerSize; int slot = 0; if (!relocsOnly) { slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType); Debug.Assert(slot != -1); } encoder.EmitLDR(encoder.TargetRegister.InterproceduralScratch, encoder.TargetRegister.Arg0, 0); encoder.EmitLDR(encoder.TargetRegister.InterproceduralScratch, encoder.TargetRegister.InterproceduralScratch, EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize)); encoder.EmitJMP(encoder.TargetRegister.InterproceduralScratch); } break; case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)Target; bool hasLazyStaticConstructor = factory.PreinitializationManager.HasLazyStaticConstructor(target); encoder.EmitMOV(encoder.TargetRegister.Result, factory.TypeNonGCStaticsSymbol(target)); 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.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target)); encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)(factory.Target.PointerSize - NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)))); encoder.EmitCMP(encoder.TargetRegister.Arg3, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitMOV(encoder.TargetRegister.Arg0 /*Result*/, encoder.TargetRegister.Arg2); encoder.EmitSUB(encoder.TargetRegister.Arg0, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: { MetadataType target = (MetadataType)Target; encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeThreadStaticIndex(target)); // 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.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2); // Second arg: index of the type in the ThreadStatic section of the modules encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg2, factory.Target.PointerSize); if (!factory.PreinitializationManager.HasLazyStaticConstructor(target)) { encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType)); } else { encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target)); encoder.EmitSUB(encoder.TargetRegister.Arg2, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, 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.EmitMOV(encoder.TargetRegister.Result, factory.TypeGCStaticsSymbol(target)); encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result); encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result); if (!factory.PreinitializationManager.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.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target)); encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)(factory.Target.PointerSize - NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)))); encoder.EmitCMP(encoder.TargetRegister.Arg3, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitMOV(encoder.TargetRegister.Arg0 /*Result*/, encoder.TargetRegister.Arg2); encoder.EmitSUB(encoder.TargetRegister.Arg0, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.DelegateCtor: { DelegateCreationInfo target = (DelegateCreationInfo)Target; if (target.TargetNeedsVTableLookup) { Debug.Assert(!target.TargetMethod.CanMethodBeInSealedVTable()); encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg1); int slot = 0; if (!relocsOnly) { slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, target.TargetMethod, target.TargetMethod.OwningType); } Debug.Assert(slot != -1); encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize)); } else { ISymbolNode targetMethodNode = target.GetTargetNode(factory); encoder.EmitMOV(encoder.TargetRegister.Arg2, target.GetTargetNode(factory)); } if (target.Thunk != null) { Debug.Assert(target.Constructor.Method.Signature.Length == 3); encoder.EmitMOV(encoder.TargetRegister.Arg3, target.Thunk); } else { Debug.Assert(target.Constructor.Method.Signature.Length == 2); } encoder.EmitJMP(target.Constructor); } break; case ReadyToRunHelperId.ResolveVirtualFunction: { ARMDebug.EmitHelperNYIAssert(factory, ref encoder, ReadyToRunHelperId.ResolveVirtualFunction); /* *** ***NOT TESTED!!! *** ***MethodDesc targetMethod = (MethodDesc)Target; ***if (targetMethod.OwningType.IsInterface) ***{ ***encoder.EmitMOV(encoder.TargetRegister.Arg1, factory.InterfaceDispatchCell(targetMethod)); ***encoder.EmitJMP(factory.ExternSymbol("RhpResolveInterfaceMethod")); ***} ***else ***{ ***if (relocsOnly) *** break; *** ***encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Arg0); *** ***Debug.Assert(!targetMethod.CanMethodBeInSealedVTable()); *** ***int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, targetMethod.OwningType); ***Debug.Assert(slot != -1); ***encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result, *** ((short)(EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize)))); ***encoder.EmitRET(); ***} */ } break; default: throw new NotImplementedException(); } }
public override void AttachToDependencyGraph(DependencyAnalyzerBase <NodeFactory> graph) { Header = new HeaderNode(Target); var compilerIdentifierNode = new CompilerIdentifierNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.CompilerIdentifier, compilerIdentifierNode, compilerIdentifierNode); RuntimeFunctionsTable = new RuntimeFunctionsTableNode(this); Header.Add(Internal.Runtime.ReadyToRunSectionType.RuntimeFunctions, RuntimeFunctionsTable, RuntimeFunctionsTable); RuntimeFunctionsGCInfo = new RuntimeFunctionsGCInfoNode(); graph.AddRoot(RuntimeFunctionsGCInfo, "GC info is always generated"); ExceptionInfoLookupTableNode exceptionInfoLookupTableNode = new ExceptionInfoLookupTableNode(this); Header.Add(Internal.Runtime.ReadyToRunSectionType.ExceptionInfo, exceptionInfoLookupTableNode, exceptionInfoLookupTableNode); graph.AddRoot(exceptionInfoLookupTableNode, "ExceptionInfoLookupTable is always generated"); MethodEntryPointTable = new MethodEntryPointTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.MethodDefEntryPoints, MethodEntryPointTable, MethodEntryPointTable); InstanceEntryPointTable = new InstanceEntryPointTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.InstanceMethodEntryPoints, InstanceEntryPointTable, InstanceEntryPointTable); TypesTable = new TypesTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.AvailableTypes, TypesTable, TypesTable); ImportSectionsTable = new ImportSectionsTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.ImportSections, ImportSectionsTable, ImportSectionsTable.StartSymbol); DebugInfoTable = new DebugInfoTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.DebugInfo, DebugInfoTable, DebugInfoTable); EagerImports = new ImportSectionNode( "EagerImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_EAGER, (byte)Target.PointerSize, emitPrecode: false, emitGCRefMap: false); ImportSectionsTable.AddEmbeddedObject(EagerImports); // All ready-to-run images have a module import helper which gets patched by the runtime on image load ModuleImport = new Import(EagerImports, new ReadyToRunHelperSignature( ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_Module)); graph.AddRoot(ModuleImport, "Module import is required by the R2R format spec"); if (Target.Architecture != TargetArchitecture.X86) { Import personalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature( ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutine)); PersonalityRoutine = new ImportThunk( ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutine, this, personalityRoutineImport); graph.AddRoot(PersonalityRoutine, "Personality routine is faster to root early rather than referencing it from each unwind info"); Import filterFuncletPersonalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature( ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutineFilterFunclet)); FilterFuncletPersonalityRoutine = new ImportThunk( ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_PersonalityRoutineFilterFunclet, this, filterFuncletPersonalityRoutineImport); graph.AddRoot(FilterFuncletPersonalityRoutine, "Filter funclet personality routine is faster to root early rather than referencing it from each unwind info"); } MethodImports = new ImportSectionNode( "MethodImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE, (byte)Target.PointerSize, emitPrecode: false, emitGCRefMap: true); ImportSectionsTable.AddEmbeddedObject(MethodImports); DispatchImports = new ImportSectionNode( "DispatchImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE, (byte)Target.PointerSize, emitPrecode: false, emitGCRefMap: true); ImportSectionsTable.AddEmbeddedObject(DispatchImports); HelperImports = new ImportSectionNode( "HelperImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE, (byte)Target.PointerSize, emitPrecode: false, emitGCRefMap: false); ImportSectionsTable.AddEmbeddedObject(HelperImports); PrecodeImports = new ImportSectionNode( "PrecodeImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE, (byte)Target.PointerSize, emitPrecode: true, emitGCRefMap: false); ImportSectionsTable.AddEmbeddedObject(PrecodeImports); StringImports = new ImportSectionNode( "StringImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STRING_HANDLE, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_UNKNOWN, (byte)Target.PointerSize, emitPrecode: true, emitGCRefMap: false); ImportSectionsTable.AddEmbeddedObject(StringImports); graph.AddRoot(ImportSectionsTable, "Import sections table is always generated"); graph.AddRoot(ModuleImport, "Module import is always generated"); graph.AddRoot(EagerImports, "Eager imports are always generated"); graph.AddRoot(MethodImports, "Method imports are always generated"); graph.AddRoot(DispatchImports, "Dispatch imports are always generated"); graph.AddRoot(HelperImports, "Helper imports are always generated"); graph.AddRoot(PrecodeImports, "Precode imports are always generated"); graph.AddRoot(StringImports, "String imports are always generated"); graph.AddRoot(Header, "ReadyToRunHeader is always generated"); MetadataManager.AttachToDependencyGraph(graph); }
public static void EmitObject(string objectFilePath, IEnumerable <DependencyNode> nodes, NodeFactory factory, IObjectDumper dumper) { ObjectWriter objectWriter = new ObjectWriter(objectFilePath, factory); bool succeeded = false; try { ObjectNodeSection managedCodeSection; if (factory.Target.OperatingSystem == TargetOS.Windows) { managedCodeSection = MethodCodeNode.WindowsContentSection; // Emit sentinels for managed code section. ObjectNodeSection codeStartSection = factory.CompilationModuleGroup.IsSingleFileCompilation ? MethodCodeNode.StartSection : objectWriter.GetSharedSection(MethodCodeNode.StartSection, "__managedcode_a"); objectWriter.SetSection(codeStartSection); objectWriter.EmitSymbolDef(new Utf8StringBuilder().Append("__managedcode_a")); objectWriter.EmitIntValue(0, 1); ObjectNodeSection codeEndSection = factory.CompilationModuleGroup.IsSingleFileCompilation ? MethodCodeNode.EndSection : objectWriter.GetSharedSection(MethodCodeNode.EndSection, "__managedcode_z"); objectWriter.SetSection(codeEndSection); objectWriter.EmitSymbolDef(new Utf8StringBuilder().Append("__managedcode_z")); objectWriter.EmitIntValue(1, 1); } else { managedCodeSection = MethodCodeNode.UnixContentSection; // TODO 2916: managed code section has to be created here, switch is not necessary. objectWriter.SetSection(MethodCodeNode.UnixContentSection); objectWriter.SetSection(LsdaSection); } objectWriter.SetCodeSectionAttribute(managedCodeSection); // Build file info map. objectWriter.BuildFileInfoMap(nodes); var listOfOffsets = new List <int>(); foreach (DependencyNode depNode in nodes) { ObjectNode node = depNode as ObjectNode; if (node == null) { continue; } if (node.ShouldSkipEmittingObjectNode(factory)) { continue; } ObjectData nodeContents = node.GetData(factory); if (dumper != null) { dumper.DumpObjectNode(factory.NameMangler, node, nodeContents); } #if DEBUG foreach (ISymbolNode definedSymbol in nodeContents.DefinedSymbols) { try { _previouslyWrittenNodeNames.Add(definedSymbol.GetMangledName(factory.NameMangler), definedSymbol); } catch (ArgumentException) { ISymbolNode alreadyWrittenSymbol = _previouslyWrittenNodeNames[definedSymbol.GetMangledName(factory.NameMangler)]; Debug.Assert(false, "Duplicate node name emitted to file", $"Symbol {definedSymbol.GetMangledName(factory.NameMangler)} has already been written to the output object file {objectFilePath} with symbol {alreadyWrittenSymbol}"); } } #endif ObjectNodeSection section = node.Section; if (objectWriter.ShouldShareSymbol(node)) { section = objectWriter.GetSharedSection(section, ((ISymbolNode)node).GetMangledName(factory.NameMangler)); } // Ensure section and alignment for the node. objectWriter.SetSection(section); objectWriter.EmitAlignment(nodeContents.Alignment); objectWriter.ResetByteRunInterruptionOffsets(nodeContents.Relocs); // Build symbol definition map. objectWriter.BuildSymbolDefinitionMap(node, nodeContents.DefinedSymbols); if (!factory.Target.IsWindows) { objectWriter.BuildCFIMap(factory, node); } // Build debug location map objectWriter.BuildDebugLocInfoMap(node); Relocation[] relocs = nodeContents.Relocs; int nextRelocOffset = -1; int nextRelocIndex = -1; if (relocs.Length > 0) { nextRelocOffset = relocs[0].Offset; nextRelocIndex = 0; } int i = 0; listOfOffsets.Clear(); listOfOffsets.AddRange(objectWriter._byteInterruptionOffsets); int offsetIndex = 0; while (i < nodeContents.Data.Length) { // Emit symbol definitions if necessary objectWriter.EmitSymbolDefinition(i); // Emit CFI codes for the given offset. objectWriter.EmitCFICodes(i); // Emit debug loc info if needed. objectWriter.EmitDebugLocInfo(i); if (i == nextRelocOffset) { Relocation reloc = relocs[nextRelocIndex]; long delta; unsafe { fixed(void *location = &nodeContents.Data[i]) { delta = Relocation.ReadValue(reloc.RelocType, location); } } int size = objectWriter.EmitSymbolReference(reloc.Target, (int)delta, reloc.RelocType); // Update nextRelocIndex/Offset if (++nextRelocIndex < relocs.Length) { nextRelocOffset = relocs[nextRelocIndex].Offset; } else { // This is the last reloc. Set the next reloc offset to -1 in case the last reloc has a zero size, // which means the reloc does not have vacant bytes corresponding to in the data buffer. E.g, // IMAGE_REL_THUMB_BRANCH24 is a kind of 24-bit reloc whose bits scatte over the instruction that // references it. We do not vacate extra bytes in the data buffer for this kind of reloc. nextRelocOffset = -1; } i += size; } else { while (offsetIndex < listOfOffsets.Count && listOfOffsets[offsetIndex] <= i) { offsetIndex++; } int nextOffset = offsetIndex == listOfOffsets.Count ? nodeContents.Data.Length : listOfOffsets[offsetIndex]; unsafe { // Todo: Use Span<T> instead once it's available to us in this repo fixed(byte *pContents = &nodeContents.Data[i]) { objectWriter.EmitBytes((IntPtr)(pContents), nextOffset - i); i += nextOffset - i; } } } } Debug.Assert(i == nodeContents.Data.Length); // It is possible to have a symbol just after all of the data. objectWriter.EmitSymbolDefinition(nodeContents.Data.Length); // Publish Windows unwind info. if (factory.Target.IsWindows) { objectWriter.PublishUnwindInfo(node); } // Emit the last CFI to close the frame. objectWriter.EmitCFICodes(nodeContents.Data.Length); if (objectWriter.HasFunctionDebugInfo()) { if (factory.Target.OperatingSystem == TargetOS.Windows) { // Build debug local var info. // It currently supports only Windows CodeView format. objectWriter.EmitDebugVarInfo(node); } objectWriter.EmitDebugFunctionInfo(nodeContents.Data.Length); } } objectWriter.EmitDebugModuleInfo(); succeeded = true; } finally { objectWriter.Dispose(); if (!succeeded) { // If there was an exception while generating the OBJ file, make sure we don't leave the unfinished // object file around. try { File.Delete(objectFilePath); } catch { } } } }
public void BuildSymbolDefinitionMap(ISymbolNode[] definedSymbols) { _offsetToDefSymbol.Clear(); foreach (ISymbolNode n in definedSymbols) { if (!_offsetToDefSymbol.ContainsKey(n.Offset)) { _offsetToDefSymbol[n.Offset] = new List<ISymbolNode>(); } _offsetToDefSymbol[n.Offset].Add(n); } }
public static void EmitObject(string OutputPath, IEnumerable<DependencyNode> nodes, ISymbolNode mainMethodNode, NodeFactory factory) { using (ObjectWriter objectWriter = new ObjectWriter(OutputPath)) { string currentSection = ""; // Build file info map. string[] debugFileInfos = objectWriter.BuildFileInfoMap(nodes); if (debugFileInfos != null) { objectWriter.EmitDebugFileInfo(debugFileInfos.Length, debugFileInfos); } foreach (DependencyNode depNode in nodes) { ObjectNode node = depNode as ObjectNode; if (node == null) continue; if (node.ShouldSkipEmittingObjectNode(factory)) continue; ObjectNode.ObjectData nodeContents = node.GetData(factory); if (currentSection != node.Section) { currentSection = node.Section; objectWriter.SwitchSection(currentSection); } objectWriter.EmitAlignment(nodeContents.Alignment); Relocation[] relocs = nodeContents.Relocs; int nextRelocOffset = -1; int nextRelocIndex = -1; if (relocs != null && relocs.Length > 0) { nextRelocOffset = relocs[0].Offset; nextRelocIndex = 0; } if (mainMethodNode == node) { objectWriter.EmitSymbolDef(MainEntryNodeName); } // Build symbol definition map. objectWriter.BuildSymbolDefinitionMap(nodeContents.DefinedSymbols); // Build debug location map objectWriter.BuildDebugLocInfoMap(node); for (int i = 0; i < nodeContents.Data.Length; i++) { // Emit symbol definitions if necessary objectWriter.EmitSymbolDefinition(i); // Emit debug loc info if needed. objectWriter.EmitDebugLocInfo(i); if (i == nextRelocOffset) { Relocation reloc = relocs[nextRelocIndex]; ISymbolNode target = reloc.Target; string targetName = target.MangledName; int size = 0; bool isPCRelative = false; switch (reloc.RelocType) { // REVIEW: I believe the JIT is emitting 0x3 instead of 0xA // for x64, because emitter from x86 is ported for RyuJIT. // I will consult with Bruce and if he agrees, I will delete // this "case" duplicated by IMAGE_REL_BASED_DIR64. case (RelocType)0x03: // IMAGE_REL_BASED_HIGHLOW case RelocType.IMAGE_REL_BASED_DIR64: size = 8; break; case RelocType.IMAGE_REL_BASED_REL32: size = 4; isPCRelative = true; break; default: throw new NotImplementedException(); } // Emit symbol reference objectWriter.EmitSymbolRef(targetName, size, isPCRelative, reloc.Delta); // Update nextRelocIndex/Offset if (++nextRelocIndex < relocs.Length) { nextRelocOffset = relocs[nextRelocIndex].Offset; } i += size - 1; continue; } objectWriter.EmitIntValue(nodeContents.Data[i], 1); } // It is possible to have a symbol just after all of the data. objectWriter.EmitSymbolDefinition(nodeContents.Data.Length); // The first definition is the main node name string nodeName = objectWriter._offsetToDefSymbol[0][0].MangledName; // Emit frame info for object code. if (node is INodeWithFrameInfo) { FrameInfo[] frameInfos = ((INodeWithFrameInfo) node).FrameInfos; if (frameInfos != null) { foreach (var frameInfo in frameInfos) { objectWriter.EmitFrameInfo(nodeName, frameInfo.StartOffset, frameInfo.EndOffset, frameInfo.BlobData.Length, frameInfo.BlobData); } } } objectWriter.FlushDebugLocs(nodeName, nodeContents.Data.Length); objectWriter.SwitchSection(currentSection); } } }
public void Add(ReadyToRunSectionType id, ObjectNode node, ISymbolNode startSymbol, ISymbolNode endSymbol = null) { _items.Add(new HeaderItem(id, node, startSymbol, endSymbol)); }
public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0) { _relocs.Add(new Relocation(relocType, _data.Count, symbol)); // And add space for the reloc switch (relocType) { case RelocType.IMAGE_REL_BASED_REL32: case RelocType.IMAGE_REL_BASED_ABSOLUTE: EmitInt(delta); break; case RelocType.IMAGE_REL_BASED_DIR64: EmitLong(delta); break; default: throw new NotImplementedException(); } }
public SymbolAndDelta(ISymbolNode symbol, int delta) { Symbol = symbol; Delta = delta; }
public void BuildSymbolDefinitionMap(ObjectNode node, ISymbolNode[] definedSymbols) { _offsetToDefName.Clear(); foreach (ISymbolNode n in definedSymbols) { if (!_offsetToDefName.ContainsKey(n.Offset)) { _offsetToDefName[n.Offset] = new List<string>(); } string symbolToEmit = GetSymbolToEmitForTargetPlatform(n.MangledName); _offsetToDefName[n.Offset].Add(symbolToEmit); string alternateName = _nodeFactory.GetSymbolAlternateName(n); if (alternateName != null) { symbolToEmit = GetSymbolToEmitForTargetPlatform(alternateName); _offsetToDefName[n.Offset].Add(symbolToEmit); } } var symbolNode = node as ISymbolNode; if (symbolNode != null) { _currentNodeName = GetSymbolToEmitForTargetPlatform(symbolNode.MangledName); Debug.Assert(_offsetToDefName[symbolNode.Offset].Contains(_currentNodeName)); } else { _currentNodeName = null; } }
/// <summary> /// Construct the export symbol instance filling in its arguments /// </summary> /// <param name="name">Export symbol identifier</param> /// <param name="ordinal">Ordinal ID of the export symbol</param> /// <param name="symbol">Symbol to export</param> public ExportSymbol(string name, int ordinal, ISymbolNode symbol) { Name = name; Ordinal = ordinal; Symbol = symbol; }
/// <summary> /// Override entry point for the app. /// </summary> /// <param name="symbol">Symbol representing the new entry point</param> public void SetEntryPoint(ISymbolNode symbol) { _entryPointSymbol = symbol; }
private void CreateNodeCaches() { _typeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) => { if (_compilationModuleGroup.ContainsType(type)) { if (type.IsGenericDefinition) { return(new GenericDefinitionEETypeNode(this, type)); } else if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) { return(new CanonicalDefinitionEETypeNode(this, type)); } else if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(new CanonicalEETypeNode(this, type)); } else { return(new EETypeNode(this, type)); } } else { return(new ExternEETypeSymbolNode(this, type)); } }); _constructedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) => { if (_compilationModuleGroup.ContainsType(type)) { if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(new CanonicalEETypeNode(this, type)); } else { return(new ConstructedEETypeNode(this, type)); } } else { return(new ExternEETypeSymbolNode(this, type)); } }); _clonedTypeSymbols = new NodeCache <TypeDesc, IEETypeNode>((TypeDesc type) => { // Only types that reside in other binaries should be cloned Debug.Assert(_compilationModuleGroup.ShouldReferenceThroughImportTable(type)); return(new ClonedConstructedEETypeNode(this, type)); }); _nonGCStatics = new NodeCache <MetadataType, NonGCStaticsNode>((MetadataType type) => { return(new NonGCStaticsNode(type, this)); }); _GCStatics = new NodeCache <MetadataType, GCStaticsNode>((MetadataType type) => { return(new GCStaticsNode(type)); }); _GCStaticIndirectionNodes = new NodeCache <MetadataType, EmbeddedObjectNode>((MetadataType type) => { ISymbolNode gcStaticsNode = TypeGCStaticsSymbol(type); Debug.Assert(gcStaticsNode is GCStaticsNode); return(GCStaticsRegion.NewNode((GCStaticsNode)gcStaticsNode)); }); _threadStatics = new NodeCache <MetadataType, ThreadStaticsNode>((MetadataType type) => { return(new ThreadStaticsNode(type, this)); }); _typeThreadStaticIndices = new NodeCache <MetadataType, TypeThreadStaticIndexNode>(type => { return(new TypeThreadStaticIndexNode(type)); }); _GCStaticEETypes = new NodeCache <GCPointerMap, GCStaticEETypeNode>((GCPointerMap gcMap) => { return(new GCStaticEETypeNode(Target, gcMap)); }); _readOnlyDataBlobs = new NodeCache <Tuple <Utf8String, byte[], int>, BlobNode>((Tuple <Utf8String, byte[], int> key) => { return(new BlobNode(key.Item1, ObjectNodeSection.ReadOnlyDataSection, key.Item2, key.Item3)); }, new BlobTupleEqualityComparer()); _externSymbols = new NodeCache <string, ExternSymbolNode>((string name) => { return(new ExternSymbolNode(name)); }); _pInvokeModuleFixups = new NodeCache <string, PInvokeModuleFixupNode>((string name) => { return(new PInvokeModuleFixupNode(name)); }); _pInvokeMethodFixups = new NodeCache <Tuple <string, string>, PInvokeMethodFixupNode>((Tuple <string, string> key) => { return(new PInvokeMethodFixupNode(key.Item1, key.Item2)); }); _methodEntrypoints = new NodeCache <MethodDesc, IMethodNode>(CreateMethodEntrypointNode); _unboxingStubs = new NodeCache <MethodDesc, IMethodNode>(CreateUnboxingStubNode); _fatFunctionPointers = new NodeCache <MethodDesc, FatFunctionPointerNode>(method => { return(new FatFunctionPointerNode(method)); }); _gvmDependenciesNode = new NodeCache <MethodDesc, GVMDependenciesNode>(method => { return(new GVMDependenciesNode(method)); }); _gvmTableEntries = new NodeCache <TypeDesc, TypeGVMEntriesNode>(type => { return(new TypeGVMEntriesNode(type)); }); _shadowConcreteMethods = new NodeCache <MethodDesc, IMethodNode>(method => { return(new ShadowConcreteMethodNode <MethodCodeNode>(method, (MethodCodeNode)MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)))); }); _runtimeDeterminedMethods = new NodeCache <MethodDesc, IMethodNode>(method => { return(new RuntimeDeterminedMethodNode(method, MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)))); }); _virtMethods = new NodeCache <MethodDesc, VirtualMethodUseNode>((MethodDesc method) => { return(new VirtualMethodUseNode(method)); }); _readyToRunHelpers = new NodeCache <Tuple <ReadyToRunHelperId, Object>, ISymbolNode>(CreateReadyToRunHelperNode); _genericReadyToRunHelpersFromDict = new NodeCache <Tuple <ReadyToRunHelperId, object, TypeSystemEntity>, ISymbolNode>(data => { return(new ReadyToRunGenericLookupFromDictionaryNode(this, data.Item1, data.Item2, data.Item3)); }); _genericReadyToRunHelpersFromType = new NodeCache <Tuple <ReadyToRunHelperId, object, TypeSystemEntity>, ISymbolNode>(data => { return(new ReadyToRunGenericLookupFromTypeNode(this, data.Item1, data.Item2, data.Item3)); }); _indirectionNodes = new NodeCache <ISymbolNode, IndirectionNode>(symbol => { return(new IndirectionNode(symbol)); }); _frozenStringNodes = new NodeCache <string, FrozenStringNode>((string data) => { return(new FrozenStringNode(data, Target)); }); _interfaceDispatchCells = new NodeCache <Tuple <MethodDesc, string>, InterfaceDispatchCellNode>((Tuple <MethodDesc, string> callSiteCell) => { return(new InterfaceDispatchCellNode(callSiteCell.Item1, callSiteCell.Item2)); }); _interfaceDispatchMaps = new NodeCache <TypeDesc, InterfaceDispatchMapNode>((TypeDesc type) => { return(new InterfaceDispatchMapNode(type)); }); _runtimeMethodHandles = new NodeCache <MethodDesc, RuntimeMethodHandleNode>((MethodDesc method) => { return(new RuntimeMethodHandleNode(this, method)); }); _interfaceDispatchMapIndirectionNodes = new NodeCache <TypeDesc, EmbeddedObjectNode>((TypeDesc type) => { var dispatchMap = InterfaceDispatchMap(type); return(DispatchMapTable.NewNodeWithSymbol(dispatchMap, (indirectionNode) => { dispatchMap.SetDispatchMapIndex(this, DispatchMapTable.IndexOfEmbeddedObject(indirectionNode)); })); }); _genericCompositions = new NodeCache <GenericCompositionDetails, GenericCompositionNode>((GenericCompositionDetails details) => { return(new GenericCompositionNode(details)); }); _eagerCctorIndirectionNodes = new NodeCache <MethodDesc, EmbeddedObjectNode>((MethodDesc method) => { Debug.Assert(method.IsStaticConstructor); Debug.Assert(TypeSystemContext.HasEagerStaticConstructor((MetadataType)method.OwningType)); return(EagerCctorTable.NewNode(MethodEntrypoint(method))); }); _vTableNodes = new NodeCache <TypeDesc, VTableSliceNode>((TypeDesc type ) => { if (CompilationModuleGroup.ShouldProduceFullType(type)) { return(new EagerlyBuiltVTableSliceNode(type)); } else { return(new LazilyBuiltVTableSliceNode(type)); } }); _methodGenericDictionaries = new NodeCache <MethodDesc, GenericDictionaryNode>(method => { return(new MethodGenericDictionaryNode(method)); }); _typeGenericDictionaries = new NodeCache <TypeDesc, GenericDictionaryNode>(type => { return(new TypeGenericDictionaryNode(type)); }); _genericDictionaryLayouts = new NodeCache <TypeSystemEntity, DictionaryLayoutNode>(methodOrType => { return(new DictionaryLayoutNode(methodOrType)); }); _stringAllocators = new NodeCache <MethodDesc, IMethodNode>(constructor => { return(new StringAllocatorMethodNode(constructor)); }); NativeLayout = new NativeLayoutHelper(this); }
public void SetCorHeader(ISymbolNode symbol, int headerSize) { _corHeaderSymbol = symbol; _corHeaderSize = headerSize; }
public void AddRelocAtOffset(ISymbolNode symbol, RelocType relocType, int offset, int delta = 0) { Relocation symbolReloc = new Relocation(relocType, offset, symbol, delta); _relocs.Add(symbolReloc); }
public void SetDebugDirectory(ISymbolNode symbol, int size) { _debugDirectorySymbol = symbol; _debugDirectorySize = size; }
private static bool IsSameSymbolNode(ISymbolNode symbolParameterNode, ISymbolNode symbolCompareNode) { return symbolParameterNode.Symbol.Equals(symbolCompareNode.Symbol); }
internal void Add(ReadyToRunSectionType id, ObjectNode node, ISymbolNode startSymbol, ISymbolNode endSymbol = null) { _items.Add(new HeaderItem(id, node, startSymbol, endSymbol)); }
public int GetSymbolFilePosition(ISymbolNode symbol) { return(_sectionBuilder.GetSymbolFilePosition(symbol)); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } var writer = new NativeWriter(); var fieldMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(fieldMapHashTable); foreach (var fieldMapping in factory.MetadataManager.GetFieldMapping(factory)) { FieldDesc field = fieldMapping.Entity; if (field.IsLiteral || field.HasRva) { continue; } FieldTableFlags flags; if (field.IsThreadStatic) { flags = FieldTableFlags.ThreadStatic | FieldTableFlags.FieldOffsetEncodedDirectly; } else if (field.IsStatic) { flags = FieldTableFlags.Static; if (field.HasGCStaticBase) { flags |= FieldTableFlags.IsGcSection; } if (field.OwningType.HasInstantiation) { flags |= FieldTableFlags.FieldOffsetEncodedDirectly; } } else { flags = FieldTableFlags.Instance | FieldTableFlags.FieldOffsetEncodedDirectly; } if (fieldMapping.MetadataHandle != 0) { flags |= FieldTableFlags.HasMetadataHandle; } if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) { flags |= FieldTableFlags.IsAnyCanonicalEntry; } if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { flags |= FieldTableFlags.IsUniversalCanonicalEntry; } // Grammar of a hash table entry: // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset Vertex vertex = writer.GetUnsignedConstant((uint)flags); uint declaringTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(field.OwningType)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(declaringTypeId)); if ((flags & FieldTableFlags.HasMetadataHandle) != 0) { // Only store the offset portion of the metadata handle to get better integer compression vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(fieldMapping.MetadataHandle & MetadataManager.MetadataOffsetMask))); } else { // No metadata handle means we need to store name vertex = writer.GetTuple(vertex, writer.GetStringConstant(field.Name)); } if ((flags & FieldTableFlags.IsUniversalCanonicalEntry) != 0) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(checked ((uint)field.GetFieldOrdinal()))); } else { switch (flags & FieldTableFlags.StorageClass) { case FieldTableFlags.ThreadStatic: // TODO: CoreRT continue; case FieldTableFlags.Static: { if (field.OwningType.HasInstantiation) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt))); } else { MetadataType metadataType = (MetadataType)field.OwningType; ISymbolNode staticsNode = field.HasGCStaticBase ? factory.TypeGCStaticsSymbol(metadataType) : factory.TypeNonGCStaticsSymbol(metadataType); if (!field.HasGCStaticBase) { uint index = _externalReferences.GetIndex(staticsNode, field.Offset.AsInt); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index)); } else if (factory.Target.Abi == TargetAbi.CoreRT || factory.Target.Abi == TargetAbi.CppCodegen) { Debug.Assert(field.HasGCStaticBase); uint index = _externalReferences.GetIndex(staticsNode); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt))); } } } break; case FieldTableFlags.Instance: vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)field.Offset.AsInt)); break; } } int hashCode = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific).GetHashCode(); fieldMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
public void BuildSymbolDefinitionMap(ObjectNode node, ISymbolNode[] definedSymbols) { _offsetToDefName.Clear(); foreach (ISymbolNode n in definedSymbols) { if (!_offsetToDefName.ContainsKey(n.Offset)) { _offsetToDefName[n.Offset] = new List<ISymbolNode>(); } _offsetToDefName[n.Offset].Add(n); } var symbolNode = node as ISymbolNode; if (symbolNode != null) { _sb.Clear(); AppendExternCPrefix(_sb); symbolNode.AppendMangledName(NodeFactory.NameMangler, _sb); _currentNodeZeroTerminatedName = _sb.Append('\0').ToUtf8String(); } else { _currentNodeZeroTerminatedName = default(Utf8String); } }
public Relocation(RelocType relocType, int offset, ISymbolNode target) { RelocType = relocType; Offset = offset; Target = target; }
/// <summary> /// Add a symbol to the symbol map which defines the area of the binary between the two emitted symbols. /// This allows relocations (both position and size) to regions of the image. Both nodes must be in the /// same section and firstNode must be emitted before secondNode. /// </summary> public void AddSymbolForRange(ISymbolNode symbol, ISymbolNode firstNode, ISymbolNode secondNode) { _sectionBuilder.AddSymbolForRange(symbol, firstNode, secondNode); }
public void EmitPointerReloc(ISymbolNode symbol) { if (_target.PointerSize == 8) { EmitReloc(symbol, RelocType.IMAGE_REL_BASED_DIR64); } else { throw new NotImplementedException(); } }
public void SetWin32Resources(ISymbolNode symbol, int resourcesSize) { _win32ResourcesSymbol = symbol; _win32ResourcesSize = resourcesSize; }
//------------------------------------------------------------ // コンストラクタ。 public EvaluatedSymbolNode(ISymbolNode aSymbolNode, IEvaluateNode aEvaluateNode) { SymbolNode = aSymbolNode; EvaluateNode = aEvaluateNode; }
public void BuildSymbolDefinitionMap(ISymbolNode[] definedSymbols) { _offsetToDefName.Clear(); foreach (ISymbolNode n in definedSymbols) { if (!_offsetToDefName.ContainsKey(n.Offset)) { _offsetToDefName[n.Offset] = new List<string>(); } string symbolToEmit = GetSymbolToEmitForTargetPlatform(n.MangledName); _offsetToDefName[n.Offset].Add(symbolToEmit); string alternateName = _nodeFactory.GetSymbolAlternateName(n); if (alternateName != null) { symbolToEmit = GetSymbolToEmitForTargetPlatform(alternateName); _offsetToDefName[n.Offset].Add(symbolToEmit); } } // First entry is the node (entry point) name. _currentNodeName = _offsetToDefName[0][0]; // Publish it first. EmitSymbolDef(_currentNodeName); }
public readonly ushort Index; // インデックス値。 //------------------------------------------------------------ // コンストラクタ。 public BCSymbolLink(ISymbolNode aSymbol, ushort aIndex) { TargetNode = aSymbol; Index = aIndex; }
public void EmitJMP(ISymbolNode symbol) { Builder.EmitByte(0xE9); Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } // Ensure the native layout blob has been saved factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); Dictionary <int, HashSet <TypeDesc> > methodsEmitted = new Dictionary <int, HashSet <TypeDesc> >(); // Get a list of all methods that have a method body and metadata from the metadata manager. foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping(factory)) { MethodDesc method = mappingEntry.Entity; // The current format requires us to have an EEType for the owning type. We might want to lift this. if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType)) { continue; } // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail. if (!factory.MetadataManager.IsReflectionInvokable(method)) { continue; } // Only virtual methods are interesting if (!NeedsVirtualInvokeInfo(method)) { continue; } // // The vtable entries for each instantiated type might not necessarily exist. // Example 1: // If there's a call to Foo<string>.Method1 and a call to Foo<int>.Method2, Foo<string> will // not have Method2 in its vtable and Foo<int> will not have Method1. // Example 2: // If there's a call to Foo<string>.Method1 and a call to Foo<object>.Method2, given that both // of these instantiations share the same canonical form, Foo<__Canon> will have both method // entries, and therefore Foo<string> and Foo<object> will have both entries too. // For this reason, the entries that we write to the map in CoreRT will be based on the canonical form // of the method's containing type instead of the open type definition. // TypeDesc containingTypeKey = method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific); HashSet <TypeDesc> cache; if (!methodsEmitted.TryGetValue(mappingEntry.MetadataHandle, out cache)) { methodsEmitted[mappingEntry.MetadataHandle] = cache = new HashSet <TypeDesc>(); } // Only one record is needed for any instantiation. if (!cache.Add(containingTypeKey)) { continue; } // Grammar of an entry in the hash table: // Virtual Method uses a normal slot // TypeKey + NameAndSig metadata offset into the native layout metadata + (NumberOfStepsUpParentHierarchyToType << 1) + slot // OR // Generic Virtual Method // TypeKey + NameAndSig metadata offset into the native layout metadata + (NumberOfStepsUpParentHierarchyToType << 1 + 1) int parentHierarchyDistance; MethodDesc declaringMethodForSlot = GetDeclaringVirtualMethodAndHierarchyDistance(method, out parentHierarchyDistance); Vertex vertex = null; ISymbolNode containingTypeKeyNode = factory.NecessaryTypeSymbol(containingTypeKey); NativeLayoutMethodNameAndSignatureVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutPlacedSignatureVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); if (method.HasInstantiation) { vertex = writer.GetTuple( writer.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeKeyNode)), writer.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset), writer.GetUnsignedConstant(((uint)parentHierarchyDistance << 1) + VirtualInvokeTableEntry.GenericVirtualMethod)); } else { // Get the declaring method for slot on the instantiated declaring type int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, declaringMethodForSlot, declaringMethodForSlot.OwningType, true); Debug.Assert(slot != -1); vertex = writer.GetTuple( writer.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeKeyNode)), writer.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)parentHierarchyDistance << 1), writer.GetUnsignedConstant((uint)slot)); } int hashCode = containingTypeKey.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
public void EmitReloc(ISymbolNode symbol, RelocType relocType) { AddRelocAtOffset(symbol, relocType, _data.Count); // And add space for the reloc switch (relocType) { case RelocType.IMAGE_REL_BASED_REL32: EmitInt(0); break; case RelocType.IMAGE_REL_BASED_DIR64: EmitLong(0); 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: { 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)); 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), -NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, 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; encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.TypeThreadStaticIndex(target)); // 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). AddrMode loadFromArg2 = new AddrMode(encoder.TargetRegister.Arg2, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadFromArg2); // Second arg: index of the type in the ThreadStatic section of the modules AddrMode loadFromArg2AndDelta = new AddrMode(encoder.TargetRegister.Arg2, null, factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromArg2AndDelta); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType)); } else { encoder.EmitLEAQ(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target), -NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, 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), -NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, 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; if (target.TargetNeedsVTableLookup) { AddrMode loadFromThisPtr = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg2, ref loadFromThisPtr); int slot = 0; if (!relocsOnly) { slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, target.TargetMethod); } Debug.Assert(slot != -1); AddrMode loadFromSlot = new AddrMode(encoder.TargetRegister.Arg2, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize), 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg2, ref loadFromSlot); } else { ISymbolNode targetMethodNode = target.GetTargetNode(factory); encoder.EmitLEAQ(encoder.TargetRegister.Arg2, target.GetTargetNode(factory)); } 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; default: throw new NotImplementedException(); } }
public void AddRelocAtOffset(ISymbolNode symbol, RelocType relocType, int offset, int delta = 0) { Relocation symbolReloc = new Relocation(); symbolReloc.Target = symbol; symbolReloc.RelocType = relocType; symbolReloc.Offset = offset; symbolReloc.Delta = delta; _relocs.Add(symbolReloc); }
public override void AttachToDependencyGraph(DependencyAnalyzerBase <NodeFactory> graph) { Header = new HeaderNode(Target); var compilerIdentifierNode = new CompilerIdentifierNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.CompilerIdentifier, compilerIdentifierNode, compilerIdentifierNode); RuntimeFunctionsTable = new RuntimeFunctionsTableNode(this); Header.Add(Internal.Runtime.ReadyToRunSectionType.RuntimeFunctions, RuntimeFunctionsTable, RuntimeFunctionsTable); RuntimeFunctionsGCInfo = new RuntimeFunctionsGCInfoNode(); graph.AddRoot(RuntimeFunctionsGCInfo, "GC info is always generated"); ProfileDataSection = new ProfileDataSectionNode(); Header.Add(Internal.Runtime.ReadyToRunSectionType.ProfileDataInfo, ProfileDataSection, ProfileDataSection.StartSymbol); ExceptionInfoLookupTableNode exceptionInfoLookupTableNode = new ExceptionInfoLookupTableNode(this); Header.Add(Internal.Runtime.ReadyToRunSectionType.ExceptionInfo, exceptionInfoLookupTableNode, exceptionInfoLookupTableNode); graph.AddRoot(exceptionInfoLookupTableNode, "ExceptionInfoLookupTable is always generated"); MethodEntryPointTable = new MethodEntryPointTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.MethodDefEntryPoints, MethodEntryPointTable, MethodEntryPointTable); ManifestMetadataTable = new ManifestMetadataTableNode(InputModuleContext.GlobalContext); Header.Add(Internal.Runtime.ReadyToRunSectionType.ManifestMetadata, ManifestMetadataTable, ManifestMetadataTable); Resolver.SetModuleIndexLookup(ManifestMetadataTable.ModuleToIndex); InstanceEntryPointTable = new InstanceEntryPointTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.InstanceMethodEntryPoints, InstanceEntryPointTable, InstanceEntryPointTable); TypesTable = new TypesTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.AvailableTypes, TypesTable, TypesTable); ImportSectionsTable = new ImportSectionsTableNode(this); Header.Add(Internal.Runtime.ReadyToRunSectionType.ImportSections, ImportSectionsTable, ImportSectionsTable.StartSymbol); DebugInfoTable = new DebugInfoTableNode(Target); Header.Add(Internal.Runtime.ReadyToRunSectionType.DebugInfo, DebugInfoTable, DebugInfoTable); // Core library attributes are checked FAR more often than other dlls // attributes, so produce a highly efficient table for determining if they are // present. Other assemblies *MAY* benefit from this feature, but it doesn't show // as useful at this time. if (this.AttributePresenceFilter != null) { Header.Add(Internal.Runtime.ReadyToRunSectionType.AttributePresence, AttributePresenceFilter, AttributePresenceFilter); } EagerImports = new ImportSectionNode( "EagerImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_EAGER, (byte)Target.PointerSize, emitPrecode: false, emitGCRefMap: false); ImportSectionsTable.AddEmbeddedObject(EagerImports); // All ready-to-run images have a module import helper which gets patched by the runtime on image load ModuleImport = new Import(EagerImports, new ReadyToRunHelperSignature( ILCompiler.ReadyToRunHelper.Module)); graph.AddRoot(ModuleImport, "Module import is required by the R2R format spec"); if (Target.Architecture != TargetArchitecture.X86) { Import personalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature( ILCompiler.ReadyToRunHelper.PersonalityRoutine)); PersonalityRoutine = new ImportThunk( ILCompiler.ReadyToRunHelper.PersonalityRoutine, this, personalityRoutineImport, useVirtualCall: false); graph.AddRoot(PersonalityRoutine, "Personality routine is faster to root early rather than referencing it from each unwind info"); Import filterFuncletPersonalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature( ILCompiler.ReadyToRunHelper.PersonalityRoutineFilterFunclet)); FilterFuncletPersonalityRoutine = new ImportThunk( ILCompiler.ReadyToRunHelper.PersonalityRoutineFilterFunclet, this, filterFuncletPersonalityRoutineImport, useVirtualCall: false); graph.AddRoot(FilterFuncletPersonalityRoutine, "Filter funclet personality routine is faster to root early rather than referencing it from each unwind info"); } MethodImports = new ImportSectionNode( "MethodImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE, (byte)Target.PointerSize, emitPrecode: false, emitGCRefMap: true); ImportSectionsTable.AddEmbeddedObject(MethodImports); DispatchImports = new ImportSectionNode( "DispatchImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STUB_DISPATCH, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE, (byte)Target.PointerSize, emitPrecode: false, emitGCRefMap: true); ImportSectionsTable.AddEmbeddedObject(DispatchImports); HelperImports = new ImportSectionNode( "HelperImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE, (byte)Target.PointerSize, emitPrecode: false, emitGCRefMap: false); ImportSectionsTable.AddEmbeddedObject(HelperImports); PrecodeImports = new ImportSectionNode( "PrecodeImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_PCODE, (byte)Target.PointerSize, emitPrecode: true, emitGCRefMap: false); ImportSectionsTable.AddEmbeddedObject(PrecodeImports); StringImports = new ImportSectionNode( "StringImports", CorCompileImportType.CORCOMPILE_IMPORT_TYPE_STRING_HANDLE, CorCompileImportFlags.CORCOMPILE_IMPORT_FLAGS_UNKNOWN, (byte)Target.PointerSize, emitPrecode: true, emitGCRefMap: false); ImportSectionsTable.AddEmbeddedObject(StringImports); graph.AddRoot(ImportSectionsTable, "Import sections table is always generated"); graph.AddRoot(ModuleImport, "Module import is always generated"); graph.AddRoot(EagerImports, "Eager imports are always generated"); graph.AddRoot(MethodImports, "Method imports are always generated"); graph.AddRoot(DispatchImports, "Dispatch imports are always generated"); graph.AddRoot(HelperImports, "Helper imports are always generated"); graph.AddRoot(PrecodeImports, "Precode helper imports are always generated"); graph.AddRoot(StringImports, "String imports are always generated"); graph.AddRoot(Header, "ReadyToRunHeader is always generated"); graph.AddRoot(CopiedCorHeaderNode, "MSIL COR header is always generated"); if (Win32ResourcesNode != null) { graph.AddRoot(Win32ResourcesNode, "Win32 Resources are placed if not empty"); } MetadataManager.AttachToDependencyGraph(graph); }
private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_LOOKUP_KIND pGenericLookupKind, CorInfoHelpFunc id, ref CORINFO_CONST_LOOKUP pLookup) { switch (id) { case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEW: { var type = HandleToObject(pResolvedToken.hClass); Debug.Assert(type.IsDefType); if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(false); } pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.NewHelper, type, _signatureContext)); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NEWARR_1: { var type = HandleToObject(pResolvedToken.hClass); Debug.Assert(type.IsSzArray); if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(false); } pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.NewArr1, type, _signatureContext)); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_ISINSTANCEOF: { var type = HandleToObject(pResolvedToken.hClass); if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(false); } // ECMA-335 III.4.3: If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T if (type.IsNullable) { type = type.Instantiation[0]; } pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.IsInstanceOf, type, _signatureContext)); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_CHKCAST: { var type = HandleToObject(pResolvedToken.hClass); if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(false); } // ECMA-335 III.4.3: If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T if (type.IsNullable) { type = type.Instantiation[0]; } pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.CastClass, type, _signatureContext)); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE: { var type = HandleToObject(pResolvedToken.hClass); if (type.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(false); } pLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.ReadyToRunHelper(ReadyToRunHelperId.GetNonGCStaticBase, type, _signatureContext)); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE: { // Token == 0 means "initialize this class". We only expect RyuJIT to call it for this case. Debug.Assert(pResolvedToken.token == 0 && pResolvedToken.tokenScope == null); Debug.Assert(pGenericLookupKind.needsRuntimeLookup); DefType typeToInitialize = (DefType)MethodBeingCompiled.OwningType; Debug.Assert(typeToInitialize.IsCanonicalSubtype(CanonicalFormKind.Any)); DefType helperArg = typeToInitialize.ConvertToSharedRuntimeDeterminedForm(); TypeDesc contextType; if (pGenericLookupKind.runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ) { contextType = methodFromContext(pResolvedToken.tokenContext).OwningType; } else { contextType = null; } ISymbolNode helper = _compilation.SymbolNodeFactory.GenericLookupHelper( pGenericLookupKind.runtimeLookupKind, ReadyToRunHelperId.GetNonGCStaticBase, helperArg, contextType, _signatureContext); pLookup = CreateConstLookupToSymbol(helper); } break; case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_HANDLE: { Debug.Assert(pGenericLookupKind.needsRuntimeLookup); ReadyToRunHelperId helperId = (ReadyToRunHelperId)pGenericLookupKind.runtimeLookupFlags; object helperArg = HandleToObject((IntPtr)pGenericLookupKind.runtimeLookupArgs); if (helperArg is MethodDesc methodArg) { helperArg = new MethodWithToken(methodArg, new ModuleToken(_tokenContext, pResolvedToken.token)); } TypeDesc contextType; if (pGenericLookupKind.runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ) { contextType = methodFromContext(pResolvedToken.tokenContext).OwningType; } else { contextType = null; } ISymbolNode helper = _compilation.SymbolNodeFactory.GenericLookupHelper( pGenericLookupKind.runtimeLookupKind, helperId, helperArg, contextType, _signatureContext); pLookup = CreateConstLookupToSymbol(helper); } break; default: throw new NotImplementedException("ReadyToRun: " + id.ToString()); } return(true); }
public IndirectionNode(ISymbolNode indirectedNode) { _indirectedNode = indirectedNode; }
private void ComputeLookup(ref CORINFO_RESOLVED_TOKEN pResolvedToken, object entity, ReadyToRunHelperId helperId, ref CORINFO_LOOKUP lookup) { if (_compilation.NeedsRuntimeLookup(helperId, entity)) { lookup.lookupKind.needsRuntimeLookup = true; lookup.runtimeLookup.signature = null; MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); // Do not bother computing the runtime lookup if we are inlining. The JIT is going // to abort the inlining attempt anyway. if (contextMethod != MethodBeingCompiled) { return; } // Necessary type handle is not something that can be in a dictionary (only a constructed type). // We only use necessary type handles if we can do a constant lookup. if (helperId == ReadyToRunHelperId.NecessaryTypeHandle) { helperId = ReadyToRunHelperId.TypeHandle; } GenericDictionaryLookup genericLookup = _compilation.ComputeGenericLookup(contextMethod, helperId, entity); if (genericLookup.UseHelper) { lookup.runtimeLookup.indirections = CORINFO.USEHELPER; lookup.lookupKind.runtimeLookupFlags = (ushort)helperId; lookup.lookupKind.runtimeLookupArgs = (void *)ObjectToHandle(entity); } else { if (genericLookup.ContextSource == GenericContextSource.MethodParameter) { lookup.runtimeLookup.helper = CorInfoHelpFunc.CORINFO_HELP_RUNTIMEHANDLE_METHOD; } else { lookup.runtimeLookup.helper = CorInfoHelpFunc.CORINFO_HELP_RUNTIMEHANDLE_CLASS; } lookup.runtimeLookup.indirections = (ushort)genericLookup.NumberOfIndirections; lookup.runtimeLookup.offset0 = (IntPtr)genericLookup[0]; if (genericLookup.NumberOfIndirections > 1) { lookup.runtimeLookup.offset1 = (IntPtr)genericLookup[1]; } lookup.runtimeLookup.testForFixup = false; // TODO: this will be needed in true multifile lookup.runtimeLookup.testForNull = false; lookup.runtimeLookup.indirectFirstOffset = false; lookup.runtimeLookup.indirectSecondOffset = false; lookup.lookupKind.runtimeLookupFlags = 0; lookup.lookupKind.runtimeLookupArgs = null; } lookup.lookupKind.runtimeLookupKind = GetLookupKindFromContextSource(genericLookup.ContextSource); } else { lookup.lookupKind.needsRuntimeLookup = false; ISymbolNode constLookup = _compilation.SymbolNodeFactory.ComputeConstantLookup(helperId, entity, _signatureContext); lookup.constLookup = CreateConstLookupToSymbol(constLookup); } }
// Returns size of the emitted symbol reference public int EmitSymbolReference(ISymbolNode target, int delta, RelocType relocType) { string targetName = GetSymbolToEmitForTargetPlatform(target.MangledName); return EmitSymbolRef(targetName, relocType, delta); }