Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NativeAOT-LLVM] Add a native WASM object writer #2643

Merged
merged 4 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ The .NET Foundation licenses this file to you under the MIT license.
<LibFileExt Condition="'$(_targetOS)' != 'win'">.a</LibFileExt>

<IlcOutputFileExt Condition="$(IlcOutputFileExt) == ''">$(NativeObjectExt)</IlcOutputFileExt>
<IlcOutputFileExt Condition="'$(NativeCodeGen)' == 'llvm'">$(LlvmObjectExt)</IlcOutputFileExt>

<IsNativeExecutable Condition="'$(OutputType)' == 'Exe' or '$(OutputType)' == 'WinExe'">true</IsNativeExecutable>

Expand Down Expand Up @@ -375,13 +374,14 @@ The .NET Foundation licenses this file to you under the MIT license.
AfterTargets="IlcCompile"
BeforeTargets="CompileWasmObjects;LinkNativeLlvm">
<ReadLinesFromFile File="$(NativeIntermediateOutputPath)$(TargetName).results.txt">
<Output TaskParameter="Lines" ItemName="LlvmObjects" />
<Output TaskParameter="Lines" ItemName="_IlcProducedFiles" />
</ReadLinesFromFile>

<ItemGroup>
<LlvmObjects>
<LlvmObjects Include="@(_IlcProducedFiles)" Condition="'%(Extension)' == '$(LlvmObjectExt)'">
<NativeObject>%(RelativeDir)%(Filename)$(NativeObjectExt)</NativeObject>
</LlvmObjects>
<NativeObjects Include="@(_IlcProducedFiles)" Condition="'%(Extension)' == '$(NativeObjectExt)'" />
<NativeObjects Include="@(LlvmObjects->'%(NativeObject)')" />
</ItemGroup>
</Target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0)
// And add space for the reloc
switch (relocType)
{
case RelocType.R_WASM_FUNCTION_OFFSET_I32:
case RelocType.IMAGE_REL_BASED_REL32:
case RelocType.IMAGE_REL_BASED_RELPTR32:
case RelocType.IMAGE_REL_BASED_ABSOLUTE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ public enum RelocType
//
IMAGE_REL_SYMBOL_SIZE = 0x1000, // The size of data in the image represented by the target symbol node
IMAGE_REL_FILE_ABSOLUTE = 0x1001, // 32 bit offset from beginning of image

//
// WASM relocations.
//
R_WASM_FUNCTION_OFFSET_I32, // Offset of a function relative to the Code section.
}

public struct Relocation
Expand Down Expand Up @@ -499,6 +504,7 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v
{
switch (relocType)
{
case RelocType.R_WASM_FUNCTION_OFFSET_I32:
case RelocType.IMAGE_REL_BASED_ABSOLUTE:
case RelocType.IMAGE_REL_BASED_ADDR32NB:
case RelocType.IMAGE_REL_BASED_HIGHLOW:
Expand Down Expand Up @@ -569,6 +575,7 @@ public static unsafe long ReadValue(RelocType relocType, void* location)
{
switch (relocType)
{
case RelocType.R_WASM_FUNCTION_OFFSET_I32:
case RelocType.IMAGE_REL_BASED_ABSOLUTE:
case RelocType.IMAGE_REL_BASED_ADDR32NB:
case RelocType.IMAGE_REL_BASED_HIGHLOW:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ public void Add(T item)
}

#if NET
public readonly Span<T> AsSpan(int start) => _items.AsSpan(start);
public readonly Span<T> AsSpan() => _items.AsSpan(0, _count);

public readonly Span<T> AsSpan(int start) => _items.AsSpan(start, _count - start);

public Span<T> AppendSpan(int length)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
command |= StackTraceDataCommand.IsStackTraceHidden;
}

RelocType reloc = factory.Target.IsWasm ? RelocType.R_WASM_FUNCTION_OFFSET_I32 : RelocType.IMAGE_REL_BASED_RELPTR32;
objData.EmitByte(commandReservation, command);
objData.EmitReloc(factory.MethodEntrypoint(entry.Method), RelocType.IMAGE_REL_BASED_RELPTR32);
objData.EmitReloc(factory.MethodEntrypoint(entry.Method), reloc);
}

_size = objData.CountBytes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Numerics;

using ILCompiler.DependencyAnalysis;
using ILCompiler.ObjectWriter;

using Internal.JitInterface;
using Internal.JitInterface.LLVMInterop;
Expand Down Expand Up @@ -47,6 +48,116 @@ public override ISymbolNode GetExternalMethodAccessor(MethodDesc method, ReadOnl

public override CorInfoLlvmEHModel GetLlvmExceptionHandlingModel() => Options.ExceptionHandlingModel;

internal WasmFunctionType GetWasmFunctionTypeForMethod(MethodSignature signature, bool hasHiddenParam)
{
WasmValueType wasmPointerType = _nodeFactory.Target.PointerSize == 4 ? WasmValueType.I32 : WasmValueType.I64;

WasmValueType GetWasmTypeForTypeDesc(TypeDesc type)
kg marked this conversation as resolved.
Show resolved Hide resolved
{
switch (type.Category)
{
case TypeFlags.Boolean:
case TypeFlags.SByte:
case TypeFlags.Byte:
case TypeFlags.Int16:
case TypeFlags.UInt16:
case TypeFlags.Char:
case TypeFlags.Int32:
case TypeFlags.UInt32:
return WasmValueType.I32;

case TypeFlags.IntPtr:
case TypeFlags.UIntPtr:
case TypeFlags.Array:
case TypeFlags.SzArray:
case TypeFlags.ByRef:
case TypeFlags.Class:
case TypeFlags.Interface:
case TypeFlags.Pointer:
case TypeFlags.FunctionPointer:
return wasmPointerType;

case TypeFlags.Int64:
case TypeFlags.UInt64:
return WasmValueType.I64;

case TypeFlags.Single:
return WasmValueType.F32;

case TypeFlags.Double:
return WasmValueType.F64;

case TypeFlags.Enum:
return GetWasmTypeForTypeDesc(type.UnderlyingType);

case TypeFlags.Void:
return WasmValueType.Invalid;

default:
throw new UnreachableException(type.Category.ToString());
}
}

WasmValueType GetWasmReturnType(TypeDesc sigReturnType, out bool isPassedByRef)
{
TypeDesc returnType = sigReturnType;
if (IsStruct(sigReturnType))
{
returnType = GetPrimitiveTypeForTrivialWasmStruct(sigReturnType);
}

isPassedByRef = returnType == null;
return isPassedByRef ? WasmValueType.Invalid : GetWasmTypeForTypeDesc(returnType);
}

WasmValueType GetWasmArgTypeForArg(TypeDesc argSigType)
{
bool isPassedByRef = false;
TypeDesc argType = argSigType;
if (IsStruct(argSigType))
{
argType = GetPrimitiveTypeForTrivialWasmStruct(argSigType);
if (argType == null)
{
isPassedByRef = true;
}
}

return isPassedByRef ? wasmPointerType : GetWasmTypeForTypeDesc(argType);
}

WasmValueType wasmReturnType = GetWasmReturnType(signature.ReturnType, out bool isReturnByRef);

int maxWasmSigLength = signature.Length + 4;
Span<WasmValueType> signatureTypes =
maxWasmSigLength > 100 ? new WasmValueType[maxWasmSigLength] : stackalloc WasmValueType[maxWasmSigLength];

int index = 0;
signatureTypes[index++] = wasmPointerType;

if (!signature.IsStatic) // TODO-LLVM-Bug: doesn't handle explicit 'this'.
{
signatureTypes[index++] = wasmPointerType;
}

if (isReturnByRef)
{
signatureTypes[index++] = wasmPointerType;
}

if (hasHiddenParam)
{
signatureTypes[index++] = wasmPointerType;
}

foreach (TypeDesc type in signature)
{
signatureTypes[index++] = GetWasmArgTypeForArg(type);
}

return new WasmFunctionType(wasmReturnType, signatureTypes.Slice(0, index).ToArray());
}

internal LLVMTypeRef GetLLVMSignatureForMethod(MethodSignature signature, bool hasHiddenParam)
{
LLVMTypeRef llvmReturnType = GetLlvmReturnType(signature.ReturnType, out bool isReturnByRef);
Expand All @@ -58,7 +169,7 @@ internal LLVMTypeRef GetLLVMSignatureForMethod(MethodSignature signature, bool h
int index = 0;
signatureTypes[index++] = LLVMPtrType;

if (!signature.IsStatic) // Bug: doesn't handle explicit 'this'.
if (!signature.IsStatic) // TODO-LLVM-Bug: doesn't handle explicit 'this'.
{
signatureTypes[index++] = LLVMPtrType;
}
Expand Down
Loading