enabled thread static fields in WebAssembly (#4999)
* enabled thread static fields, changed vtable dispatch to not be dependent on EETypeNode, added typed node factory
This commit is contained in:
Родитель
b68c08e3ce
Коммит
d80ed0826b
|
@ -847,12 +847,9 @@ namespace Internal.IL
|
|||
|
||||
private LLVMValueRef GetOrCreateMethodSlot(MethodDesc method)
|
||||
{
|
||||
var globalRefName = "__getslot__" + _compilation.NameMangler.GetMangledMethodName(method);
|
||||
LLVMValueRef slot = LLVM.GetNamedGlobal(Module, globalRefName);
|
||||
if(slot.Pointer == IntPtr.Zero)
|
||||
{
|
||||
slot = LLVM.AddGlobal(Module, LLVM.Int32Type(), globalRefName);
|
||||
}
|
||||
var vtableSlotSymbol = _compilation.NodeFactory.VTableSlot(method);
|
||||
_dependencies.Add(vtableSlotSymbol);
|
||||
LLVMValueRef slot = LoadAddressOfSymbolNode(vtableSlotSymbol);
|
||||
return LLVM.BuildLoad(_builder, slot, string.Empty);
|
||||
}
|
||||
|
||||
|
|
|
@ -203,11 +203,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
|
||||
public static LLVMValueRef EmitGlobal(LLVMModuleRef module, FieldDesc field, NameMangler nameMangler)
|
||||
{
|
||||
if (field.IsThreadStatic)
|
||||
{
|
||||
throw new NotImplementedException("thread static field");
|
||||
}
|
||||
else if (field.IsStatic)
|
||||
if (field.IsStatic)
|
||||
{
|
||||
if (s_staticFieldMapping.TryGetValue(field, out LLVMValueRef existingValue))
|
||||
return existingValue;
|
||||
|
@ -217,6 +213,10 @@ namespace ILCompiler.DependencyAnalysis
|
|||
var llvmValue = LLVM.AddGlobal(module, valueType, nameMangler.GetMangledFieldName(field).ToString());
|
||||
LLVM.SetLinkage(llvmValue, LLVMLinkage.LLVMInternalLinkage);
|
||||
LLVM.SetInitializer(llvmValue, GetConstZeroArray(field.FieldType.GetElementSize().AsInt));
|
||||
if (field.IsThreadStatic)
|
||||
{
|
||||
LLVM.SetThreadLocal(llvmValue, LLVMMisc.True);
|
||||
}
|
||||
s_staticFieldMapping.Add(field, llvmValue);
|
||||
return llvmValue;
|
||||
}
|
||||
|
@ -699,28 +699,6 @@ namespace ILCompiler.DependencyAnalysis
|
|||
if (node.ShouldSkipEmittingObjectNode(factory))
|
||||
continue;
|
||||
|
||||
if (node is EETypeNode)
|
||||
{
|
||||
DefType t = ((EETypeNode)node).Type.GetClosestDefType();
|
||||
int iSlot = GetVTableSlotsCount(factory, t.BaseType);
|
||||
var pointerSize = factory.Target.PointerSize;
|
||||
foreach (MethodDesc m in factory.VTable(t).Slots)
|
||||
{
|
||||
// set _getslot variable to sizeof(EEType) + iSlot * pointer size
|
||||
string realSymbolName = factory.NameMangler.GetMangledMethodName(m).ToString();
|
||||
var globalRefName = "__getslot__" + realSymbolName;
|
||||
LLVMValueRef slot = LLVM.GetNamedGlobal(compilation.Module, globalRefName);
|
||||
if (slot.Pointer == IntPtr.Zero)
|
||||
{
|
||||
slot = LLVM.AddGlobal(compilation.Module, LLVM.Int32Type(), globalRefName);
|
||||
}
|
||||
LLVM.SetInitializer(slot, LLVM.ConstInt(LLVM.Int32Type(), (ulong)((EETypeNode.GetVTableOffset(pointerSize) / pointerSize) + iSlot), LLVMMisc.False));
|
||||
LLVM.SetGlobalConstant(slot, LLVMMisc.True);
|
||||
iSlot++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
objectWriter.StartObjectNode(node);
|
||||
ObjectData nodeContents = node.GetData(factory);
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ namespace ILCompiler.DependencyAnalysis
|
|||
{
|
||||
public sealed class WebAssemblyCodegenNodeFactory : NodeFactory
|
||||
{
|
||||
private NodeCache<MethodDesc, WebAssemblyVTableSlotNode> _vTableSlotNodes;
|
||||
|
||||
public WebAssemblyCodegenNodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup, MetadataManager metadataManager,
|
||||
InteropStubManager interopStubManager, NameMangler nameMangler, VTableSliceProvider vtableSliceProvider, DictionaryLayoutProvider dictionaryLayoutProvider)
|
||||
: base(context,
|
||||
|
@ -22,6 +24,10 @@ namespace ILCompiler.DependencyAnalysis
|
|||
dictionaryLayoutProvider,
|
||||
new ImportedNodeProviderThrowing())
|
||||
{
|
||||
_vTableSlotNodes = new NodeCache<MethodDesc, WebAssemblyVTableSlotNode>(methodKey =>
|
||||
{
|
||||
return new WebAssemblyVTableSlotNode(methodKey);
|
||||
});
|
||||
}
|
||||
|
||||
public override bool IsCppCodegenTemporaryWorkaround => true;
|
||||
|
@ -38,6 +44,11 @@ namespace ILCompiler.DependencyAnalysis
|
|||
}
|
||||
}
|
||||
|
||||
public WebAssemblyVTableSlotNode VTableSlot(MethodDesc method)
|
||||
{
|
||||
return _vTableSlotNodes.GetOrAdd(method);
|
||||
}
|
||||
|
||||
protected override IMethodNode CreateUnboxingStubNode(MethodDesc method)
|
||||
{
|
||||
// TODO: this is wrong: this returns an unstubbed node
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
using Internal.Runtime;
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
public class WebAssemblyVTableSlotNode : ObjectNode, ISymbolDefinitionNode
|
||||
{
|
||||
private readonly MethodDesc _targetMethod;
|
||||
|
||||
public WebAssemblyVTableSlotNode(MethodDesc targetMethod)
|
||||
{
|
||||
Debug.Assert(targetMethod.IsVirtual);
|
||||
Debug.Assert(!targetMethod.IsSharedByGenericInstantiations);
|
||||
_targetMethod = targetMethod;
|
||||
}
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetMangledName(nameMangler, _targetMethod));
|
||||
}
|
||||
public int Offset => 0;
|
||||
|
||||
public override bool IsShareable => false;
|
||||
|
||||
public static string GetMangledName(NameMangler nameMangler, MethodDesc method)
|
||||
{
|
||||
return "__getslot__" + nameMangler.GetMangledMethodName(method);
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
|
||||
|
||||
public override ObjectNodeSection Section => ObjectNodeSection.DataSection;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
|
||||
{
|
||||
DependencyList result = new DependencyList();
|
||||
|
||||
if (!factory.VTable(_targetMethod.OwningType).HasFixedSlots)
|
||||
{
|
||||
result.Add(factory.VirtualMethodUse(_targetMethod), "VTable method use");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
Debug.Assert((EETypeNode.GetVTableOffset(factory.Target.PointerSize) % factory.Target.PointerSize) == 0, "vtable offset must be aligned");
|
||||
ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly);
|
||||
|
||||
objData.AddSymbol(this);
|
||||
|
||||
if (!relocsOnly)
|
||||
{
|
||||
var tableOffset = EETypeNode.GetVTableOffset(factory.Target.PointerSize) / factory.Target.PointerSize;
|
||||
objData.EmitInt(tableOffset + VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, _targetMethod));
|
||||
}
|
||||
return objData.ToObjectData();
|
||||
}
|
||||
|
||||
protected override int ClassCode => 0;
|
||||
|
||||
protected override int CompareToImpl(SortableDependencyNode other, CompilerComparer comparer)
|
||||
{
|
||||
return comparer.Compare(_targetMethod, ((WebAssemblyVTableSlotNode)other)._targetMethod);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,15 +16,16 @@ namespace ILCompiler
|
|||
{
|
||||
internal WebAssemblyCodegenConfigProvider Options { get; }
|
||||
internal LLVMModuleRef Module { get; }
|
||||
|
||||
public new WebAssemblyCodegenNodeFactory NodeFactory { get; }
|
||||
internal WebAssemblyCodegenCompilation(
|
||||
DependencyAnalyzerBase<NodeFactory> dependencyGraph,
|
||||
NodeFactory nodeFactory,
|
||||
WebAssemblyCodegenNodeFactory nodeFactory,
|
||||
IEnumerable<ICompilationRootProvider> roots,
|
||||
Logger logger,
|
||||
WebAssemblyCodegenConfigProvider options)
|
||||
: base(dependencyGraph, nodeFactory, GetCompilationRoots(roots, nodeFactory), null, logger)
|
||||
{
|
||||
NodeFactory = nodeFactory;
|
||||
LLVM.LoadLibrary_libLLVM("./libLLVM-x64.dll");
|
||||
Module = LLVM.ModuleCreateWithName("netscripten");
|
||||
LLVM.SetTarget(Module, "asmjs-unknown-emscripten");
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<Compile Include="Compiler\DependencyAnalysis\RawMainMethodRootProvider.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WebAssemblyCodegenNodeFactory.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WebAssemblyMethodCodeNode.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WebAssemblyVTableSlotNode.cs" />
|
||||
<Compile Include="Compiler\WebAssemblyNodeMangler.cs" />
|
||||
<Compile Include="Compiler\WebAssemblyCodegenCompilation.cs" />
|
||||
<Compile Include="Compiler\WebAssemblyCodegenCompilationBuilder.cs" />
|
||||
|
|
|
@ -8,6 +8,8 @@ using System.Runtime.InteropServices;
|
|||
internal static class Program
|
||||
{
|
||||
private static int staticInt;
|
||||
[ThreadStatic]
|
||||
private static int threadStaticInt;
|
||||
private static unsafe void Main(string[] args)
|
||||
{
|
||||
Add(1, 2);
|
||||
|
@ -39,6 +41,17 @@ internal static class Program
|
|||
PrintLine("static int field test: Ok.");
|
||||
}
|
||||
|
||||
if(threadStaticInt == 0)
|
||||
{
|
||||
PrintLine("thread static int initial value field test: Ok.");
|
||||
}
|
||||
|
||||
threadStaticInt = 9;
|
||||
if(threadStaticInt == 9)
|
||||
{
|
||||
PrintLine("thread static int field test: Ok.");
|
||||
}
|
||||
|
||||
var boxedInt = (object)tempInt;
|
||||
if(((int)boxedInt) == 9)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче