Skip to content

Commit

Permalink
[wasm] Intrinsics for blazor (#102670)
Browse files Browse the repository at this point in the history
Attempt to improve interp startup by adding intrinsics:
* Add IsNullRef/NullRef intrinsics
* Add Unsafe.Add intrinsic
Co-authored-by: Vlad Brezae <brezaevlad@gmail.com>
  • Loading branch information
kg authored Jun 19, 2024

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
1 parent c6779ba commit a2068b9
Showing 4 changed files with 66 additions and 13 deletions.
50 changes: 50 additions & 0 deletions src/mono/mono/mini/interp/transform.c
Original file line number Diff line number Diff line change
@@ -2252,6 +2252,56 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
#endif
} else if (!strcmp (tm, "InitBlockUnaligned") || !strcmp (tm, "InitBlock")) {
*op = MINT_INITBLK;
} else if (!strcmp (tm, "IsNullRef")) {
#if SIZEOF_VOID_P == 4
*op = MINT_CEQ0_I4;
#else
// FIXME: No CEQ0_I8
#endif
} else if (!strcmp (tm, "NullRef")) {
#if SIZEOF_VOID_P == 4
*op = MINT_LDC_I4_0;
#else
*op = MINT_LDC_I8_0;
#endif
} else if (!strcmp (tm, "Add")) {
MonoGenericContext *ctx = mono_method_get_context (target_method);
g_assert (ctx);
g_assert (ctx->method_inst);
g_assert (ctx->method_inst->type_argc == 1);
MonoType *t = ctx->method_inst->type_argv [0];

int base_var = td->sp [-2].var,
offset_var = td->sp [-1].var,
align, esize;

#if SIZEOF_VOID_P == 8
if (td->sp [-1].type == STACK_TYPE_I4) {
interp_add_ins (td, MINT_CONV_I8_I4);
interp_ins_set_sreg (td->last_ins, offset_var);
interp_ins_set_dreg (td->last_ins, offset_var);
}
#endif

td->sp -= 2;

esize = mono_type_size (t, &align);
if (esize != 1) {
g_assert (esize <= 32767);
interp_add_ins (td, MINT_MUL_P_IMM);
td->last_ins->data [0] = (gint16)esize;
interp_ins_set_sreg (td->last_ins, offset_var);
interp_ins_set_dreg (td->last_ins, offset_var);
}

interp_add_ins (td, MINT_ADD_P);
interp_ins_set_sregs2 (td->last_ins, base_var, offset_var);
push_simple_type (td, STACK_TYPE_MP);
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);

td->ip += 5;

return TRUE;
}
} else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.CompilerServices") && !strcmp (klass_name, "RuntimeHelpers")) {
if (!strcmp (tm, "get_OffsetToStringData")) {
Original file line number Diff line number Diff line change
@@ -28,9 +28,9 @@ public InterpPgoTests(ITestOutputHelper output, SharedBuildPerTestClassFixture b
[InlineData("Release")]
public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config)
{
// We need to invoke Greeting enough times to cause BCL code to tier so we can exercise interpreter PGO
// We need to invoke Random enough times to cause BCL code to tier so we can exercise interpreter PGO
// Invoking it too many times makes the test meaningfully slower.
const int iterationCount = 70;
const int iterationCount = 50;

_testOutput.WriteLine("/// Creating project");
CopyTestAsset("WasmBasicTestApp", "InterpPgoTest", "App");
@@ -61,13 +61,13 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config)
lock (runner.OutputLines)
output = string.Join(Environment.NewLine, runner.OutputLines);

Assert.Contains("Hello, World!", output);
Assert.Contains("I filled a buffer with random items", output);
// Verify that no PGO table was located in cache
Assert.Contains("Failed to load interp_pgo table", output);
// Verify that the table was saved after the app ran
Assert.Contains("Saved interp_pgo table", output);
// Verify that a specific method was tiered by the Greeting calls and recorded by PGO
Assert.Contains("added System.Runtime.CompilerServices.Unsafe:Add<byte> (byte&,int) to table", output);
Assert.Contains(" System.Random:Next () to table", output);
}

{
@@ -81,7 +81,7 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config)
lock (runner.OutputLines)
output = string.Join(Environment.NewLine, runner.OutputLines);

Assert.Contains("Hello, World!", output);
Assert.Contains("I filled a buffer with random items", output);
// Verify that table data was loaded from cache
// if this breaks, it could be caused by change in config which affects the config hash and the cache storage hash key
Assert.Contains(" bytes of interp_pgo data (table size == ", output);
@@ -90,7 +90,7 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config)
// Verify that method(s) were found in the table and eagerly tiered
Assert.Contains("because it was in the interp_pgo table", output);
// Verify that a specific method was tiered by the Greeting calls and recorded by PGO
Assert.Contains("added System.Runtime.CompilerServices.Unsafe:Add<byte> (byte&,int) to table", output);
Assert.Contains(" System.Random:Next () to table", output);
}

_testOutput.WriteLine("/// Done");
11 changes: 8 additions & 3 deletions src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs
Original file line number Diff line number Diff line change
@@ -12,10 +12,15 @@ public partial class InterpPgoTest
internal static partial string GetHRef();

[JSExport]
internal static string Greeting()
internal static void TryToTier(int iterationCount)
{
var text = $"Hello, World! Greetings from {GetHRef()}";
var buffer = new int[4096];
var random = new Random();
for (int i = 0; i < iterationCount; i++) {
for (int j = 0; j < buffer.Length; j++)
buffer[j] = random.Next();
}
var text = $"Greetings from {GetHRef()}. I filled a buffer with random items {iterationCount} times.";
Console.WriteLine(text);
return text;
}
}
6 changes: 2 additions & 4 deletions src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js
Original file line number Diff line number Diff line change
@@ -139,10 +139,8 @@ try {
}
}
});
const iterationCount = params.get("iterationCount") ?? 70;
for (let i = 0; i < iterationCount; i++) {
exports.InterpPgoTest.Greeting();
};
const iterationCount = params.get("iterationCount") ?? "70";
exports.InterpPgoTest.TryToTier(parseInt(iterationCount));
await INTERNAL.interp_pgo_save_data();
exit(0);
break;

0 comments on commit a2068b9

Please sign in to comment.