Skip to content

[Wasm] Write barriers#128225

Draft
kg wants to merge 4 commits into
dotnet:mainfrom
kg:wasm-writebarriers-callconv
Draft

[Wasm] Write barriers#128225
kg wants to merge 4 commits into
dotnet:mainfrom
kg:wasm-writebarriers-callconv

Conversation

@kg
Copy link
Copy Markdown
Member

@kg kg commented May 14, 2026

Sufficient for the R2R'd version of this to run without crashing:

    static string? TestField;

    [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
    public static void ConcatTwoStrings (string a, string b) {
        TestField = a + b;
    }

    [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
    public static int Main () {
        Console.WriteLine("Hello world!");
        ConcatTwoStrings("A", "B");
        Console.WriteLine(TestField);
        return 42;
    }

Currently the write barrier in ConcatTwoStrings fails due to the calling convention being wrong and then once the calling convention is fixed, it fails because we didn't implement the write barriers yet.

This PR:

  • Updates the calling convention of the write barriers to match that expected by the JIT (bare calling convention without sp/pep args) by adding new FCDECL2_RAW / FCIMPL2_RAW macros
  • Fixes RhpByRefAssignRef's signature being incorrect (missing *)
  • Implements the checked and unchecked write barriers in inline wasm assembly in the new wasm/writebarriers.cpp file

Copilot AI review requested due to automatic review settings May 14, 2026 20:11
@kg kg added the arch-wasm WebAssembly architecture label May 14, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Initial scaffolding to make the WASM portable write barriers (RhpAssignRef, RhpCheckedAssignRef, RhpByRefAssignRef) use a "raw" calling convention that matches what RyuJIT expects for write barriers, rather than the trampolined WASM FCALL convention that threads callersStackPointer / portableEntryPointContext through. The actual barrier implementations still assert and will be filled in later.

Changes:

  • Add new FCDECL2_RAW / FCIMPL2_RAW macros that bypass the WASM stack-pointer/entrypoint-context plumbing and define the function with the plain (a1, a2) signature; provide non-WASM fallbacks that alias to FCDECL2 / FCIMPL2.
  • Switch the three Rhp*AssignRef declarations in jitinterface.h and definitions in WriteBarriers.cpp to the new _RAW variants.
  • Trivial whitespace cleanup in jitinterface.h.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/coreclr/vm/fcall.h Adds WASM-specific FCDECL2_RAW / FCIMPL2_RAW macros and non-WASM fallbacks aliasing to the standard FCDECL2 / FCIMPL2.
src/coreclr/vm/jitinterface.h Switches Rhp{Checked,ByRef,}AssignRef declarations to FCDECL2_RAW; trims trailing whitespace.
src/coreclr/runtime/portable/WriteBarriers.cpp Updates the three portable write-barrier stubs to use FCDECL2_RAW / FCIMPL2_RAW.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/vm/fcall.h Outdated
Comment thread src/coreclr/runtime/portable/WriteBarriers.cpp Outdated
Comment thread src/coreclr/runtime/portable/WriteBarriers.cpp Outdated
Comment thread src/coreclr/runtime/portable/WriteBarriers.cpp Outdated
Comment thread src/coreclr/vm/fcall.h
Comment thread src/coreclr/runtime/portable/WriteBarriers.cpp Outdated
Comment thread src/coreclr/runtime/portable/WriteBarriers.cpp Outdated
Comment thread src/coreclr/runtime/portable/WriteBarriers.cpp Outdated
@kg kg force-pushed the wasm-writebarriers-callconv branch from a35761f to 6604569 Compare May 18, 2026 21:46
Copilot AI review requested due to automatic review settings May 18, 2026 21:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/vm/wasm/writebarriers.cpp Outdated
Comment thread src/coreclr/vm/wasm/writebarriers.cpp Outdated
@kg kg requested a review from jkotas May 18, 2026 22:05
#include <fcall.h>
#include "../gchelpers.inl"
#include "gcheaputilities.h"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can use comment about why we have inline wasm implementation and not just regular C/C++ implementation.

@@ -0,0 +1,113 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this file to src/coreclr/runtime/wasm ? We will want to use this implementation for naot. src/coreclr/runtime/wasm is the directory where files shared between regular coreclr and naot live.

Comment on lines +100 to +107
EXTERN_C FCDECL2_RAW(VOID, RhpAssignRef, Object **dst, Object *ref);
ASM_HELPER_2(VOID, RhpAssignRef, Object **dst, Object *ref)
__attribute__((alias("JIT_WriteBarrier")));

EXTERN_C FCDECL2_RAW(VOID, RhpCheckedAssignRef, Object **dst, Object *ref);
ASM_HELPER_2(VOID, RhpCheckedAssignRef, Object **dst, Object *ref)
__attribute__((alias("JIT_CheckedWriteBarrier")));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
EXTERN_C FCDECL2_RAW(VOID, RhpAssignRef, Object **dst, Object *ref);
ASM_HELPER_2(VOID, RhpAssignRef, Object **dst, Object *ref)
__attribute__((alias("JIT_WriteBarrier")));
EXTERN_C FCDECL2_RAW(VOID, RhpCheckedAssignRef, Object **dst, Object *ref);
ASM_HELPER_2(VOID, RhpCheckedAssignRef, Object **dst, Object *ref)
__attribute__((alias("JIT_CheckedWriteBarrier")));

Do we need these aliases?

It seems that things should work fine if the functions implementing this are called RhpAssignRef and RhpCheckedAssignRef, and JIT_WriteBarrier does not need to exist. Or is JIT_WriteBarrier referenced from somewhere in wasm builds?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are comments that refer to JIT_WriteBarrier but the thing that the comment is attached to is actually RhpAssignRef, e.g.

;; JIT_CheckedWriteBarrier(Object** dst, Object* src)
;;
;; Write barrier for writes to objects that may reside
;; on the managed heap.
;;
;; On entry:
;; x14 : the destination address (LHS of the assignment).
;; May not be a heap location (hence the checked).
;; x15 : the object reference (RHS of the assignment)
;;
;; On exit:
;; x12, x17 : trashed
;; x14 : incremented by 8
LEAF_ENTRY RhpCheckedAssignRefArm64
. It would be nice to clean those us. JIT_WriteBarrier should only be used with the dynamically runtime generated write barriers.

Comment on lines +108 to +113
EXTERN_C FCDECL2_RAW(VOID, RhpByRefAssignRef, Object **dst, Object **ref);
ASM_HELPER_2(VOID, RhpByRefAssignRef, Object **dst, Object **ref)
{
GC_ASM("unreachable"
);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
EXTERN_C FCDECL2_RAW(VOID, RhpByRefAssignRef, Object **dst, Object **ref);
ASM_HELPER_2(VOID, RhpByRefAssignRef, Object **dst, Object **ref)
{
GC_ASM("unreachable"
);
}

We can define this helper as not implemented for wasm in src\coreclr\inc\jithelpers.h (notice that this file has similar arch-specific ifdefs for number of other helpers):

#ifdef TARGET_WASM
    JITHELPER(CORINFO_HELP_ASSIGN_BYREF, NULL,METHOD__NIL)
#else
    DYNAMICJITHELPER(CORINFO_HELP_ASSIGN_BYREF, RhpByRefAssignRef, METHOD__NIL)
#endif

#include "../gchelpers.inl"
#include "gcheaputilities.h"

#define ASM_HELPER_2(rettype, funcname, a1, a2) \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ASM_HELPER_2(rettype, funcname, a1, a2) \
#ifdef FEATURE_MULTITHREADING
#error The assembly implemementaiton of write barriers assumes single threaded wasm
#endif
#define ASM_HELPER_2(rettype, funcname, a1, a2) \

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-VM-coreclr

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants