Skip to content
1 change: 1 addition & 0 deletions eng/native.wasm.targets
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
<EmccExportedFunction Include="stackRestore" />
<EmccExportedFunction Include="stackSave" />
<EmccExportedFunction Include="___stack_pointer" />
<EmccExportedFunction Include="___coreclr_wasm_rtlrestorecontext_tag" />
</ItemGroup>
<PropertyGroup>
<_EmccExportedRuntimeMethods>@(EmccExportedRuntimeMethod -> '%(Identity)',',')</_EmccExportedRuntimeMethods>
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/hosts/corerun/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ else()
-sENVIRONMENT=node,shell,web
-lexports.js
-Wl,--export=__stack_pointer
-Wl,--export=__coreclr_wasm_rtlrestorecontext_tag
-Wl,--error-limit=0)

if (CORERUN_IN_BROWSER)
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/hosts/corerun/wasm/libCorerun.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,15 @@ function libCoreRunFactory() {
if (typeof (wasmExports.__stack_pointer) === "undefined") {
throw new Error("__stack_pointer was not preserved by the linker or optimizer");
}
if (typeof (wasmExports.__coreclr_wasm_rtlrestorecontext_tag) === "undefined") {
throw new Error("__coreclr_wasm_rtlrestorecontext_tag was not preserved by the linker or optimizer");
}
payloadPtr = HEAPU32[ptrPtr >>> 2 >>> 0];
wasmInstance = new WebAssembly.Instance(wasmModule, {
webcil: {
memory: wasmMemory,
stackPointer: wasmExports.__stack_pointer,
rtlRestoreContextTag: wasmExports.__coreclr_wasm_rtlrestorecontext_tag,
table: wasmTable,
tableBase: new WebAssembly.Global({ value: "i32", mutable: false }, tableStartIndex),
imageBase: new WebAssembly.Global({ value: "i32", mutable: false }, payloadPtr)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,7 @@ enum class CorInfoReloc
WASM_GLOBAL_INDEX_LEB, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global.
WASM_MEMORY_ADDR_REL_LEB, // Wasm: a relative linear memory index encoded as a 5-byte varuint32. Used as the immediate argument of a load or store instruction,
// e.g. in R2R scenarios as an offset from __image_base
WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB, // Wasm: an exception tag index encoded as a 5-byte varuint32. Used to refer to the CoreCLR restore context exception tag.
};

enum CorInfoGCType
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,19 @@

#include <minipal/guid.h>

<<<<<<< wasm_eh_infra
constexpr GUID JITEEVersionIdentifier = { /* 61e50dd4-fda2-4184-a348-f64e501d6c60 */
0x61e50dd4,
0xfda2,
0x4184,
{0xa3, 0x48, 0xf6, 0x4e, 0x50, 0x1d, 0x6c, 0x60}
=======
constexpr GUID JITEEVersionIdentifier = { /* 59df85b8-c0fd-4e40-aea1-68cb2cd916cc */
0x59df85b8,
0xc0fd,
0x4e40,
{0xae, 0xa1, 0x68, 0xcb, 0x2c, 0xd9, 0x16, 0xcc}
>>>>>>> main
};
Comment thread
davidwrighton marked this conversation as resolved.
Outdated

#endif // JIT_EE_VERSIONING_GUID_H
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public enum RelocType
WASM_MEMORY_ADDR_REL_LEB = 0x209, // Wasm: a relative linear memory index encoded as a 5-byte varuint32. Used as the immediate argument of a load or store instruction,
// e.g. in R2R scenarios as an offset from $imageBase
WASM_TABLE_INDEX_REL_I32 = 0x20A, // Wasm: a table index encoded as a 4-byte uint32 relative to the tableBase of the R2R image
WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB = 0x20B, // Wasm: an exception tag index encoded as a 5-byte varuint32. Used to refer to the CoreCLR restore context exception tag.

//
// Relocation operators related to TLS access
Expand Down Expand Up @@ -672,6 +673,7 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v
case RelocType.WASM_FUNCTION_INDEX_LEB:
case RelocType.WASM_MEMORY_ADDR_LEB:
case RelocType.WASM_MEMORY_ADDR_REL_LEB:
case RelocType.WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB:
DwarfHelper.WritePaddedULEB128(new Span<byte>((byte*)location, WASM_PADDED_RELOC_SIZE_32), checked((ulong)value));
return;

Expand Down Expand Up @@ -731,6 +733,7 @@ public static int GetSize(RelocType relocType)
RelocType.WASM_MEMORY_ADDR_SLEB => WASM_PADDED_RELOC_SIZE_32,
RelocType.WASM_MEMORY_ADDR_REL_LEB => WASM_PADDED_RELOC_SIZE_32,
RelocType.WASM_MEMORY_ADDR_REL_SLEB => WASM_PADDED_RELOC_SIZE_32,
RelocType.WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB => WASM_PADDED_RELOC_SIZE_32,
RelocType.WASM_TABLE_INDEX_I32 => 4,
RelocType.WASM_TABLE_INDEX_REL_I32 => 4,
RelocType.WASM_TABLE_INDEX_I64 => 8,
Expand Down Expand Up @@ -802,6 +805,7 @@ public static unsafe long ReadValue(RelocType relocType, void* location)
case RelocType.WASM_FUNCTION_INDEX_LEB:
case RelocType.WASM_MEMORY_ADDR_LEB:
case RelocType.WASM_MEMORY_ADDR_REL_LEB:
case RelocType.WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB:
return checked((long)DwarfHelper.ReadULEB128(new ReadOnlySpan<byte>(location, WASM_PADDED_RELOC_SIZE_32)));
case RelocType.WASM_TABLE_INDEX_SLEB:
case RelocType.WASM_MEMORY_ADDR_SLEB:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ public int Encode(Span<byte> buffer)
case RelocType.WASM_MEMORY_ADDR_REL_LEB:
case RelocType.WASM_TYPE_INDEX_LEB:
case RelocType.WASM_GLOBAL_INDEX_LEB:
case RelocType.WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB:
DwarfHelper.WritePaddedULEB128(buffer.Slice(0, relocSize), 0);
break;

Expand Down
24 changes: 24 additions & 0 deletions src/coreclr/tools/Common/Compiler/ObjectWriter/WasmNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,30 @@ public override int EncodeSize()
public override int EncodeRelocations(Span<Relocation> buffer) => 0;
}

public class WasmTagImportType : WasmImportType
{
// Exception tag attribute: 0 means an exception tag.
private const byte ExceptionAttribute = 0x00;

private readonly int _typeIndex;

public WasmTagImportType(int typeIndex) : base(WasmExternalKind.Tag)
{
_typeIndex = typeIndex;
}

public override int Encode(Span<byte> buffer)
{
buffer[0] = ExceptionAttribute;

return 1 + DwarfHelper.WriteULEB128(buffer.Slice(1), (ulong)_typeIndex);
}

public override int EncodeSize() => 1 + (int)DwarfHelper.SizeOfULEB128((ulong)_typeIndex);
public override int EncodeRelocationCount() => 0;
public override int EncodeRelocations(Span<Relocation> buffer) => 0;
}

public class WasmImport : IWasmEncodable
{
public readonly string Module;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,17 +368,7 @@ public int GetFlatMappedSize()
// TODO-Wasm: for maintability, we should try and push some of this into the dependency graph when we do more stub generation.
private void RegisterStubIndexAndSignature(WasmFuncType signature)
{
Utf8String signatureKey = signature.GetMangledName(_nodeFactory.NameMangler);
if (!_uniqueSignatures.TryGetValue(signatureKey, out int signatureIndex))
{
signatureIndex = _uniqueSignatures.Count;
_uniqueSignatures.Add(signatureKey, signatureIndex);

SectionWriter typeSectionWriter = GetOrCreateSection(ObjectNodeSection.WasmTypeSection);
byte[] encodedSignature = new byte[signature.EncodeSize()];
signature.Encode(encodedSignature);
typeSectionWriter.EmitData(encodedSignature);
}
int signatureIndex = RegisterSignature(signature);

SectionWriter functionSectionWriter = GetOrCreateSection(WasmObjectNodeSection.FunctionSection);
functionSectionWriter.WriteULEB128((ulong)signatureIndex);
Expand Down Expand Up @@ -1011,6 +1001,11 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr
Relocation.WriteValue(reloc.Type, pData, index + addend);
break;
}
case RelocType.WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB:
{
Relocation.WriteValue(reloc.Type, pData, RtlRestoreContextTagIndex + addend);
break;
}
default:
// TODO-WASM: add other cases as needed;
// ignoring other reloc types for now
Expand Down Expand Up @@ -1040,19 +1035,49 @@ void WriteRelocFromDataSpan(SymbolicRelocation reloc, byte* pData, long sectionS
public const int StackPointerGlobalIndex = 0;
public const int ImageBaseGlobalIndex = 1;
public const int TableBaseGlobalIndex = 2;
public const int RtlRestoreContextTagIndex = 0;

private static readonly WasmFuncType RtlRestoreContextTagSignature = new(
Comment thread
davidwrighton marked this conversation as resolved.
new([WasmValueType.I32, WasmValueType.I32]),
new([]));

private WasmImport[] _defaultGlobalImports = new[]
private WasmImport[] CreateDefaultGlobalImports()
{
new WasmImport("webcil", "stackPointer", import: new WasmGlobalImportType(WasmValueType.I32, WasmMutabilityType.Mut), index: StackPointerGlobalIndex),
new WasmImport("webcil", "imageBase", import: new WasmGlobalImportType(WasmValueType.I32, WasmMutabilityType.Const), index: ImageBaseGlobalIndex),
new WasmImport("webcil", "tableBase", import: new WasmGlobalImportType(WasmValueType.I32, WasmMutabilityType.Const), index: TableBaseGlobalIndex),
new WasmImport("webcil", "table", import: new WasmTableImportType(), index: 0),
};
int rtlRestoreContextTagTypeIndex = RegisterSignature(RtlRestoreContextTagSignature);

return
[
new WasmImport("webcil", "stackPointer", import: new WasmGlobalImportType(WasmValueType.I32, WasmMutabilityType.Mut), index: StackPointerGlobalIndex),
new WasmImport("webcil", "imageBase", import: new WasmGlobalImportType(WasmValueType.I32, WasmMutabilityType.Const), index: ImageBaseGlobalIndex),
new WasmImport("webcil", "tableBase", import: new WasmGlobalImportType(WasmValueType.I32, WasmMutabilityType.Const), index: TableBaseGlobalIndex),
new WasmImport("webcil", "table", import: new WasmTableImportType(), index: 0),
new WasmImport("webcil", "rtlRestoreContextTag", import: new WasmTagImportType(rtlRestoreContextTagTypeIndex), index: RtlRestoreContextTagIndex),
];
}

private int RegisterSignature(WasmFuncType signature)
{
Utf8String signatureKey = signature.GetMangledName(_nodeFactory.NameMangler);
if (_uniqueSignatures.TryGetValue(signatureKey, out int signatureIndex))
{
return signatureIndex;
}

signatureIndex = _uniqueSignatures.Count;
_uniqueSignatures.Add(signatureKey, signatureIndex);

SectionWriter typeSectionWriter = GetOrCreateSection(ObjectNodeSection.WasmTypeSection);
byte[] encodedSignature = new byte[signature.EncodeSize()];
signature.Encode(encodedSignature);
typeSectionWriter.EmitData(encodedSignature);

return signatureIndex;
}

private void WriteImports()
{
int[] assignedImportIndices = new int[(int)WasmExternalKind.Count];
foreach (WasmImport import in _defaultGlobalImports)
foreach (WasmImport import in CreateDefaultGlobalImports())
{
if (import.Index.HasValue)
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4269,6 +4269,7 @@ private RelocType GetRelocType(CorInfoReloc reloc)
CorInfoReloc.WASM_MEMORY_ADDR_REL_LEB => RelocType.WASM_MEMORY_ADDR_REL_LEB,
CorInfoReloc.WASM_TYPE_INDEX_LEB => RelocType.WASM_TYPE_INDEX_LEB,
CorInfoReloc.WASM_GLOBAL_INDEX_LEB => RelocType.WASM_GLOBAL_INDEX_LEB,
CorInfoReloc.WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB => RelocType.WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB,
_ => throw new ArgumentException("Unsupported relocation type: " + reloc),
};

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ public enum CorInfoReloc
WASM_GLOBAL_INDEX_LEB, // Wasm: a global index encoded as a 5-byte varuint32, e.g. the index immediate in a get_global.
WASM_MEMORY_ADDR_REL_LEB, // Wasm: a relative linear memory index encoded as a 5-byte varuint32. Used as the immediate argument of a load or store instruction,
// e.g. in R2R scenarios, encoding an offset from $imageBase
WASM_CLR_RESTORE_CONTEXT_EXCEPTION_TAG_LEB, // Wasm: an exception tag index encoded as a 5-byte varuint32. Used to refer to the CoreCLR restore context exception tag.
}

public enum CorInfoGCType
Expand Down
73 changes: 73 additions & 0 deletions src/coreclr/vm/codeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6044,6 +6044,69 @@ TADDR ExecutionManager::GetWasmVirtualIPFromFunctionTableIndex(DWORD functionInd
return pR2RInfo->GetMinVirtualIP() + RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction);
} while (true);
}

TADDR ExecutionManager::GetWasmFunctionTableIndexFromVirtualIP(TADDR virtualIP)
{
LIMITED_METHOD_CONTRACT;

if (!ExecutionManager::IsVirtualIP((PCODE)virtualIP))
{
return 0;
}

Comment thread
davidwrighton marked this conversation as resolved.
VirtualIPRangeSection* pSection = FindVirtualIPRangeSection(virtualIP);
if (pSection == nullptr)
{
return 0;
}
Comment thread
davidwrighton marked this conversation as resolved.

Module* pModule = pSection->rangeSection._pR2RModule;
ReadyToRunInfo* pR2RInfo = pModule->GetReadyToRunInfo();
DWORD runtimeFunctionCount = pR2RInfo->GetRuntimeFunctionCount();
if (runtimeFunctionCount == 0)
{
return 0;
}

TADDR minVirtualIP = pR2RInfo->GetMinVirtualIP();
if (virtualIP < minVirtualIP)
{
return 0;
}

TADDR localVirtualIP = virtualIP - minVirtualIP;
if (localVirtualIP > UINT32_MAX)
{
return 0;
}

DWORD localVirtualIP32 = (DWORD)localVirtualIP;
PTR_RUNTIME_FUNCTION pRuntimeFunctions = pR2RInfo->GetRuntimeFunctions();

// Find the function entry with the greatest BeginAddress <= localVirtualIP.
DWORD low = 0;
DWORD high = runtimeFunctionCount;
while (low + 1 < high)
{
DWORD mid = low + ((high - low) / 2);
DWORD beginAddress = RUNTIME_FUNCTION__BeginAddress(pRuntimeFunctions + mid);
if (beginAddress <= localVirtualIP32)
{
low = mid;
}
else
{
high = mid;
}
}

if (RUNTIME_FUNCTION__BeginAddress(pRuntimeFunctions + low) > localVirtualIP32)
{
return 0;
}

return pR2RInfo->GetMinFunctionTableIndex() + low;
}
#endif // TARGET_WASM

// Deletes a single range starting at pStartRange
Expand Down Expand Up @@ -6903,6 +6966,16 @@ PTR_EXCEPTION_CLAUSE_TOKEN ReadyToRunJitManager::GetNextEHClause(EH_CLAUSE_ENUME
pEHClauseOut->Flags = pClause->Flags;
pEHClauseOut->FilterOffset = pClause->FilterOffset;

#ifdef TARGET_WASM
// Wasm Virtual IPs are encoded with half their virtual IP value
pEHClauseOut->TryStartPC *= 2;
pEHClauseOut->TryEndPC *= 2;
pEHClauseOut->HandlerStartPC *= 2;
pEHClauseOut->HandlerEndPC *= 2;
if (pEHClauseOut->Flags & COR_ILEXCEPTION_CLAUSE_FILTER)
pEHClauseOut->FilterOffset *= 2;
#endif

return dac_cast<PTR_EXCEPTION_CLAUSE_TOKEN>(pClause);
}

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/codeman.h
Original file line number Diff line number Diff line change
Expand Up @@ -2542,6 +2542,7 @@ class ExecutionManager
// then compute and return the virtual IP for that the entrypoint for that function
// (which may require a walk back to find the main function if functionIndex represents a funclet)
static TADDR GetWasmVirtualIPFromFunctionTableIndex(DWORD functionIndex);
static TADDR GetWasmFunctionTableIndexFromVirtualIP(TADDR virtualIP);
#endif // TARGET_WASM

static void DeleteRange(TADDR StartRange);
Expand Down
25 changes: 21 additions & 4 deletions src/coreclr/vm/eetwain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1716,17 +1716,25 @@ EXTERN_C DWORD_PTR STDCALL CallEHFunclet(Object *pThrowable, UINT_PTR pFuncletTo
EXTERN_C DWORD_PTR STDCALL CallEHFilterFunclet(Object *pThrowable, TADDR FP, UINT_PTR pFuncletToInvoke, UINT_PTR *pFuncletCallerSP);

typedef DWORD_PTR (HandlerFn)(UINT_PTR uStackFrame, Object* pExceptionObj);
#else
typedef TADDR HandlerFn;
TADDR GetWasmFramePointerFromStackPointer(TADDR sp);

DWORD_PTR CallFuncletWithThrowable(UINT_PTR pFuncletToInvoke, TADDR fp, Object *pThrowable, UINT_PTR *pFuncletCallerSP);
DWORD_PTR CallFuncletWithoutThrowable(UINT_PTR pFuncletToInvoke, TADDR fp, UINT_PTR *pFuncletCallerSP);
#endif // TARGET_WASM

static inline UINT_PTR CastHandlerFn(HandlerFn *pfnHandler)
{
#ifdef TARGET_ARM
return DataPointerToThumbCode<UINT_PTR, HandlerFn *>(pfnHandler);
#elif defined(TARGET_WASM)
return (TADDR)ExecutionManager::GetWasmFunctionTableIndexFromVirtualIP((TADDR)pfnHandler);
#else
Comment thread
davidwrighton marked this conversation as resolved.
return (UINT_PTR)pfnHandler;
#endif
}

#endif // TARGET_WASM

// Call catch, finally or filter funclet.
// Return value:
Expand All @@ -1736,15 +1744,24 @@ static inline UINT_PTR CastHandlerFn(HandlerFn *pfnHandler)
DWORD_PTR EECodeManager::CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilterFunclet)
{
DWORD_PTR dwResult = 0;
#ifdef TARGET_WASM
_ASSERTE(!"CallFunclet for WASM not implemented yet");
#else
HandlerFn* pfnHandler = (HandlerFn*)pHandler;

// Since the actual caller of the funclet is the assembly helper, pass the reference
// to the CallerStackFrame instance so that it can be updated.
UINT_PTR *pFuncletCallerSP = &(pExInfo->m_csfEHClause.SP);

#ifdef TARGET_WASM
TADDR wasmFramePointer = GetWasmFramePointerFromStackPointer(GetSP(pRD->pCurrentContext));
TADDR handlerFnIndex = CastHandlerFn(pfnHandler);
if (throwable != NULL)
{
dwResult = CallFuncletWithThrowable(handlerFnIndex, wasmFramePointer, OBJECTREFToObject(throwable), pFuncletCallerSP);
}
else
{
dwResult = CallFuncletWithoutThrowable(handlerFnIndex, wasmFramePointer, pFuncletCallerSP);
}
#else
if (isFilterFunclet)
{
// For invoking IL filter funclet, we pass the CallerSP to the funclet using which
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/vm/eventtrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2856,7 +2856,12 @@ VOID ETW::ExceptionLog::ExceptionThrown(CrawlFrame *pCf, BOOL bIsReThrownExcept
// This check has been copied from StackTraceInfo::AppendElement
if (!(pCf->HasFaulted() || pCf->IsIPadjusted()) && exceptionEIP != 0)
{
exceptionEIP = (PVOID)((UINT_PTR)exceptionEIP - 1);
#ifdef TARGET_WASM
if (!ExecutionManager::IsVirtualIP((PCODE)exceptionEIP))
#endif
{
exceptionEIP = (PVOID)((UINT_PTR)exceptionEIP - 1);
Comment thread
davidwrighton marked this conversation as resolved.
}
Comment thread
davidwrighton marked this conversation as resolved.
Comment thread
davidwrighton marked this conversation as resolved.
}

gc.exceptionMessageRef = ((EXCEPTIONREF)gc.exceptionObj)->GetMessage();
Expand Down
Loading