Skip to content

[wasm coreclr] workflow and near future work #119002

@radekdoulik

Description

@radekdoulik

Workflow

Build the runtime like

./build.sh -bl -os browser -c Debug -subset clr.runtime+libs

That should install the emsdk, build the runtime and the libs.

To test the runtime startup I usually use these steps

  • remove artifacts/obj/coreclr/browser.wasm.Debug/hosts/corewasmrun (this is because libs were not available at the time when corewasmrun was linked. this is temporary issue and will not happen once we have proper assembly loading)

  • build simple-server like this

    ./dotnet.sh build -c Release src/mono/sample/wasm/simple-server

  • build corewasmrun and run it in the browser. For quicker roundtrip, I run this command in src/coreclr

    (source "../mono/browser/emsdk/emsdk_env.sh" && cd ../../artifacts/obj/coreclr/browser.wasm.Debug/; make corewasmrun -j12) && (cp hosts/corewasmrun/index.html ../../artifacts/obj/coreclr/browser.wasm.Debug/hosts/corewasmrun/;cd ../../artifacts/obj/coreclr/browser.wasm.Debug/hosts/corewasmrun/; ~/git/runtime-main/src/mono/sample/wasm/simple-server/bin/Release/net8.0/HttpServer)

It builds the corewasmrun, opens index.html in the default browser and runs the runtime initialization. It should also forward the browser console output to the terminal. (if chrome is not your default browser, you can just copy the URL in chrome)

On windows it should work in similar way, you might need to run ninja instead of make though.

Debugging

For debugging I use chrome browser with "C/C++ DevTools Support (DWARF)" extension. It is not perfect, but works most of the time. It can step through C code, set breakpoints, inspect wasm linear memory.

Next steps

These are the areas to work on to progress with the runtime initialization and improve code in the main branch.

Current state

On main branch it gets to the point, where it compiles and runs 6 managed methods, before it breaks. The filtered (|grep Compiled) terminal output should look like this:

  log: stdout: Compiled method: .System.AppContext:Setup(ptr,ptr,int)
  log: stdout: Compiled method: .System.Diagnostics.Debug:Assert(bool,System.String)
  log: stdout: Compiled method: .System.Diagnostics.Debug:Assert(bool,System.String,System.String)
  log: stdout: Compiled method: .System.Collections.Generic.Dictionary`2[System.__Canon,System.__Canon]:.ctor(int)
  log: stdout: Compiled method: .System.Collections.Generic.Dictionary`2[System.__Canon,System.__Canon]:.ctor(int,System.Collections.Generic.IEqualityComparer`1[System.__Canon])
  log: stdout: Compiled method: .System.Object:.ctor()

With proof of concept code it compiles/runs 60 methods/native functions before it breaks. The code is in https://github.com/radekdoulik/runtime/tree/clr-interp-qcall-and-helper-call-poc branch. Filtered output looks like this:

  log: stdout: Compiled method: .System.AppContext:Setup(ptr,ptr,int)
  log: stdout: Compiled method: .System.Diagnostics.Debug:Assert(bool,System.String)
  log: stdout: Compiled method: .System.Diagnostics.Debug:Assert(bool,System.String,System.String)
  log: stdout: Compiled method: .System.Collections.Generic.Dictionary`2[System.__Canon,System.__Canon]:.ctor(int)
  log: stdout: Compiled method: .System.Collections.Generic.Dictionary`2[System.__Canon,System.__Canon]:.ctor(int,System.Collections.Generic.IEqualityComparer`1[System.__Canon])
  log: stdout: Compiled method: .System.Object:.ctor()
  log: stdout: Compiled method: .System.RuntimeTypeHandle:GetRuntimeTypeFromHandle(nint)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.TypeHandle:.ctor(ptr)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.TypeHandle:get_IsTypeDesc()
  log: stdout: Compiled method: .System.Runtime.CompilerServices.TypeHandle:AsMethodTable()
  log: stdout: Compiled method: .System.Runtime.CompilerServices.MethodTableAuxiliaryData:get_ExposedClassObject()
  log: stdout: Compiled method: .System.Runtime.CompilerServices.Unsafe:AsPointer[nint](byref)
  log: stdout: Compiled method: .System.RuntimeTypeHandle:GetRuntimeTypeFromHandleSlow(nint)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.ObjectHandleOnStack:Create[System.__Canon](byref)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.Unsafe:AsPointer[System.__Canon](byref)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.ObjectHandleOnStack:.ctor(ptr)
  log: stdout: InvokeCompiledMethod: System.RuntimeTypeHandle.GetRuntimeTypeFromHandleSlow --> RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow [entrypoint]
  log: stdout: Compiled method: .System.Type:GetTypeFromHandle(System.RuntimeTypeHandle)
  log: stdout: Compiled method: .System.Type:get_IsValueType()
  log: stdout: Compiled method: .System.RuntimeType:IsValueTypeImpl()
  log: stdout: Compiled method: .System.RuntimeType:GetNativeTypeHandle()
  log: stdout: Compiled method: .System.Runtime.CompilerServices.MethodTable:get_IsValueType()
  log: stdout: Compiled method: .System.GC:KeepAlive(System.Object)
  log: stdout: Compiled method: .System.Collections.Generic.EqualityComparer`1[System.__Canon]:get_Default()
  log: stdout: Compiled method: .System.Runtime.CompilerServices.StaticsHelpers:GetGCStaticBase(ptr)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.MethodTableAuxiliaryData:GetDynamicStaticsInfo()
  log: stdout: Compiled method: .System.Runtime.CompilerServices.Unsafe:As[System.Runtime.CompilerServices.MethodTableAuxiliaryData,System.Runtime.CompilerServices.DynamicStaticsInfo](byref)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.Unsafe:Subtract[System.Runtime.CompilerServices.DynamicStaticsInfo](byref,int)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.StaticsHelpers:VolatileReadAsByref(byref)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.Unsafe:AsPointer[byte](byref)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.StaticsHelpers:GetGCStaticBaseSlow(ptr)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.InitHelpers:InitClassSlow(ptr)
  log: stdout: InvokeCompiledMethod: System.Runtime.CompilerServices.InitHelpers.InitClassHelper --> InitClassHelper [entrypoint]
  log: stdout: Compiled method: .System.Collections.Generic.EqualityComparer`1[System.__Canon]:.cctor()
  log: stdout: Compiled method: .System.Collections.Generic.ComparerHelpers:CreateDefaultEqualityComparer(System.Type)
  log: stdout: Compiled method: .System.Type:op_Inequality(System.Type,System.Type)
  log: stdout: Compiled method: .System.Type:op_Equality(System.Type,System.Type)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.CastHelpers:IsInstanceOfClass(ptr,System.Object)
  log: stdout: Compiled method: .System.Diagnostics.Debug:Fail(System.String,System.String)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.InitHelpers:InitClass(ptr)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.MethodTableAuxiliaryData:get_IsClassInited()
  log: stdout: Compiled method: .System.Threading.Volatile:Read(byref)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.Unsafe:AsRef[uint](byref)
  log: stdout: Compiled method: .System.Runtime.CompilerServices.Unsafe:As[uint,System.Threading.Volatile+VolatileUInt32](byref)
  log: stdout: InvokeCompiledMethod: System.Runtime.CompilerServices.InitHelpers.InitClassHelper --> InitClassHelper [entrypoint]
  log: stdout: Compiled method: .System.Diagnostics.Debug:.cctor()
  log: stdout: Compiled method: .System.Diagnostics.DebugProvider:.ctor()
  log: stdout: InvokeCompiledMethod: System.Runtime.CompilerServices.InitHelpers.InitClassHelper --> InitClassHelper [entrypoint]
  log: stdout: InvokeCompiledMethod: System.Runtime.CompilerServices.InitHelpers.InitClassHelper --> InitClassHelper [entrypoint]
  log: stdout: Compiled method: .System.Diagnostics.DebugProvider:Fail(System.String,System.String)
  log: stdout: Compiled method: .System.Diagnostics.StackTrace:.ctor(int,bool)
  log: stdout: Compiled method: .System.ArgumentOutOfRangeException:ThrowIfNegative[int](int,System.String)
  log: stdout: Compiled method: .System.Int32:IsNegative(int)
  log: stdout: Compiled method: .System.Diagnostics.StackTrace:InitializeForCurrentThread(int,bool)
  log: stdout: Compiled method: .System.Diagnostics.StackTrace:CaptureStackTrace(int,bool,System.Exception)
  log: stdout: Compiled method: .System.Diagnostics.StackFrameHelper:.ctor()
  log: stdout: Compiled method: .System.Diagnostics.StackFrameHelper:InitializeSourceInfo(bool,System.Exception)
  log: stdout: Compiled method: .System.Diagnostics.StackTrace:GetStackFramesInternal(System.Diagnostics.StackFrameHelper,bool,System.Exception)
  log: stdout: Compiled method: .System.Diagnostics.StackTrace:GetStackFramesInternal(System.Runtime.CompilerServices.ObjectHandleOnStack,bool,System.Runtime.CompilerServices.ObjectHandleOnStack)
  log: stdout: InvokeCompiledMethod: System.Diagnostics.StackTrace.<GetStackFramesInternal>g____PInvoke|0_0 --> StackTrace_GetStackFramesInternal [entrypoint]

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions