private void GetCodeForReadyToRunGenericHelper(WebAssemblyCodegenCompilation compilation, ReadyToRunGenericHelperNode node, NodeFactory factory) { LLVMBuilderRef builder = compilation.Module.Context.CreateBuilder(); var args = new List <LLVMTypeRef>(); MethodDesc delegateCtor = null; if (node.Id == ReadyToRunHelperId.DelegateCtor) { DelegateCreationInfo target = (DelegateCreationInfo)node.Target; delegateCtor = target.Constructor.Method; bool isStatic = delegateCtor.Signature.IsStatic; int argCount = delegateCtor.Signature.Length; if (!isStatic) { argCount++; } for (int i = 0; i < argCount; i++) { TypeDesc argType; if (i == 0 && !isStatic) { argType = delegateCtor.OwningType; } else { argType = delegateCtor.Signature[i - (isStatic ? 0 : 1)]; } args.Add(ILImporter.GetLLVMTypeForTypeDesc(argType)); } } LLVMValueRef helperFunc = Module.GetNamedFunction(node.GetMangledName(factory.NameMangler)); if (helperFunc.Handle == IntPtr.Zero) { throw new Exception("if the function is requested here, it should have been created earlier"); } var helperBlock = helperFunc.AppendBasicBlock("genericHelper"); builder.PositionAtEnd(helperBlock); var importer = new ILImporter(builder, compilation, Module, helperFunc, delegateCtor); LLVMValueRef ctx; string gepName; if (node is ReadyToRunGenericLookupFromTypeNode) { // Locate the VTable slot that points to the dictionary int vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)node.DictionaryOwner); int pointerSize = factory.Target.PointerSize; // Load the dictionary pointer from the VTable int slotOffset = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize); var slotGep = builder.BuildGEP(helperFunc.GetParam(1), new[] { LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, (ulong)slotOffset, false) }, "slotGep"); var slotGepPtrPtr = builder.BuildPointerCast(slotGep, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), "slotGepPtrPtr"); ctx = builder.BuildLoad(slotGepPtrPtr, "dictGep"); gepName = "typeNodeGep"; } else { ctx = helperFunc.GetParam(1); gepName = "paramGep"; } LLVMValueRef resVar = OutputCodeForDictionaryLookup(builder, factory, node, node.LookupSignature, ctx, gepName); switch (node.Id) { case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)node.Target; if (compilation.TypeSystemContext.HasLazyStaticConstructor(target)) { importer.OutputCodeForTriggerCctor(target, resVar); } } break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)node.Target; var ptrPtrPtr = builder.BuildBitCast(resVar, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), 0), "ptrPtrPtr"); resVar = builder.BuildLoad(builder.BuildLoad(ptrPtrPtr, "ind1"), "ind2"); if (compilation.TypeSystemContext.HasLazyStaticConstructor(target)) { GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); var nonGcStaticsBase = OutputCodeForDictionaryLookup(builder, factory, node, nonGcRegionLookup, ctx, "lazyGep"); importer.OutputCodeForTriggerCctor(target, nonGcStaticsBase); } } break; case ReadyToRunHelperId.GetThreadStaticBase: { MetadataType target = (MetadataType)node.Target; if (compilation.TypeSystemContext.HasLazyStaticConstructor(target)) { GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); var threadStaticBase = OutputCodeForDictionaryLookup(builder, factory, node, nonGcRegionLookup, ctx, "tsGep"); importer.OutputCodeForTriggerCctor(target, threadStaticBase); } resVar = importer.OutputCodeForGetThreadStaticBaseForType(resVar).ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), builder); } break; case ReadyToRunHelperId.DelegateCtor: { DelegateCreationInfo target = (DelegateCreationInfo)node.Target; MethodDesc constructor = target.Constructor.Method; var fatPtr = ILImporter.MakeFatPointer(builder, resVar, compilation); importer.OutputCodeForDelegateCtorInit(builder, helperFunc, constructor, fatPtr); } break; // These are all simple: just get the thing from the dictionary and we're done case ReadyToRunHelperId.TypeHandle: case ReadyToRunHelperId.MethodHandle: case ReadyToRunHelperId.FieldHandle: case ReadyToRunHelperId.MethodDictionary: case ReadyToRunHelperId.MethodEntry: case ReadyToRunHelperId.VirtualDispatchCell: case ReadyToRunHelperId.DefaultConstructor: break; default: throw new NotImplementedException(); } if (node.Id != ReadyToRunHelperId.DelegateCtor) { builder.BuildRet(resVar); } else { builder.BuildRetVoid(); } }
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 { } } } }
public static void CompileMethod(WebAssemblyCodegenCompilation compilation, WebAssemblyMethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; if (compilation.Logger.IsVerbose) { string methodName = method.ToString(); compilation.Logger.Writer.WriteLine("Compiling " + methodName); } if (method.HasCustomAttribute("System.Runtime", "RuntimeImportAttribute")) { methodCodeNodeNeedingCode.CompilationCompleted = true; //throw new NotImplementedException(); //CompileExternMethod(methodCodeNodeNeedingCode, ((EcmaMethod)method).GetRuntimeImportName()); //return; } if (method.IsRawPInvoke()) { //CompileExternMethod(methodCodeNodeNeedingCode, method.GetPInvokeMethodMetadata().Name ?? method.Name); //return; } var methodIL = compilation.GetMethodIL(method); if (methodIL == null) { return; } ILImporter ilImporter = null; try { string mangledName; // TODO: Better detection of the StartupCodeMain method if (methodCodeNodeNeedingCode.Method.Signature.IsStatic && methodCodeNodeNeedingCode.Method.Name == "StartupCodeMain") { mangledName = "StartupCodeMain"; } else { mangledName = compilation.NameMangler.GetMangledMethodName(methodCodeNodeNeedingCode.Method).ToString(); } ilImporter = new ILImporter(compilation, method, methodIL, mangledName); CompilerTypeSystemContext typeSystemContext = compilation.TypeSystemContext; //MethodDebugInformation debugInfo = compilation.GetDebugInfo(methodIL); /* if (!compilation.Options.HasOption(CppCodegenConfigProvider.NoLineNumbersString))*/ { //IEnumerable<ILSequencePoint> sequencePoints = debugInfo.GetSequencePoints(); /*if (sequencePoints != null) * ilImporter.SetSequencePoints(sequencePoints);*/ } //IEnumerable<ILLocalVariable> localVariables = debugInfo.GetLocalVariables(); /*if (localVariables != null) * ilImporter.SetLocalVariables(localVariables);*/ IEnumerable <string> parameters = GetParameterNamesForMethod(method); /*if (parameters != null) * ilImporter.SetParameterNames(parameters);*/ ilImporter.Import(); methodCodeNodeNeedingCode.CompilationCompleted = true; } catch (Exception e) { compilation.Logger.Writer.WriteLine(e.Message + " (" + method + ")"); methodCodeNodeNeedingCode.CompilationCompleted = true; // methodCodeNodeNeedingCode.SetDependencies(ilImporter.GetDependencies()); //throw new NotImplementedException(); //methodCodeNodeNeedingCode.SetCode(sb.ToString(), Array.Empty<Object>()); } // Uncomment the block below to get specific method failures when LLVM fails for cryptic reasons #if false LLVMBool result = LLVM.VerifyFunction(ilImporter._llvmFunction, LLVMVerifierFailureAction.LLVMPrintMessageAction); if (result.Value != 0) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Error compliling {method.OwningType}.{method}"); Console.ResetColor(); } #endif // false // Ensure dependencies show up regardless of exceptions to avoid breaking LLVM methodCodeNodeNeedingCode.SetDependencies(ilImporter.GetDependencies()); }
internal static LLVMValueRef MakeFatPointer(LLVMBuilderRef builder, LLVMValueRef targetLlvmFunction, WebAssemblyCodegenCompilation compilation) { var asInt = LLVM.BuildPtrToInt(builder, targetLlvmFunction, LLVMTypeRef.Int32Type(), "toInt"); return(LLVM.BuildBinOp(builder, LLVMOpcode.LLVMOr, asInt, LLVM.ConstInt(LLVM.Int32Type(), (ulong)compilation.TypeSystemContext.Target.FatFunctionPointerOffset, LLVMMisc.False), "makeFat")); }
public WebAssemblyObjectWriter(string objectFilePath, NodeFactory factory, WebAssemblyCodegenCompilation compilation) { _nodeFactory = factory; _objectFilePath = objectFilePath; Module = compilation.Module; }
public static void CompileMethod(WebAssemblyCodegenCompilation compilation, WebAssemblyMethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; compilation.Logger.Writer.WriteLine("Compiling " + method.ToString()); if (method.HasCustomAttribute("System.Runtime", "RuntimeImportAttribute")) { throw new NotImplementedException(); //CompileExternMethod(methodCodeNodeNeedingCode, ((EcmaMethod)method).GetRuntimeImportName()); //return; } if (method.IsRawPInvoke()) { //CompileExternMethod(methodCodeNodeNeedingCode, method.GetPInvokeMethodMetadata().Name ?? method.Name); //return; } var methodIL = compilation.GetMethodIL(method); if (methodIL == null) { return; } ILImporter ilImporter = null; try { ilImporter = new ILImporter(compilation, method, methodIL, methodCodeNodeNeedingCode.GetMangledName(compilation.NameMangler)); CompilerTypeSystemContext typeSystemContext = compilation.TypeSystemContext; //MethodDebugInformation debugInfo = compilation.GetDebugInfo(methodIL); /* if (!compilation.Options.HasOption(CppCodegenConfigProvider.NoLineNumbersString))*/ { //IEnumerable<ILSequencePoint> sequencePoints = debugInfo.GetSequencePoints(); /*if (sequencePoints != null) * ilImporter.SetSequencePoints(sequencePoints);*/ } //IEnumerable<ILLocalVariable> localVariables = debugInfo.GetLocalVariables(); /*if (localVariables != null) * ilImporter.SetLocalVariables(localVariables);*/ IEnumerable <string> parameters = GetParameterNamesForMethod(method); /*if (parameters != null) * ilImporter.SetParameterNames(parameters);*/ ilImporter.Import(); methodCodeNodeNeedingCode.CompilationCompleted = true; } catch (Exception e) { compilation.Logger.Writer.WriteLine(e.Message + " (" + method + ")"); methodCodeNodeNeedingCode.CompilationCompleted = true; // methodCodeNodeNeedingCode.SetDependencies(ilImporter.GetDependencies()); //throw new NotImplementedException(); //methodCodeNodeNeedingCode.SetCode(sb.ToString(), Array.Empty<Object>()); } // Ensure dependencies show up regardless of exceptions to avoid breaking LLVM methodCodeNodeNeedingCode.SetDependencies(ilImporter.GetDependencies()); }