diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index db713f12bd930..49f97d62dee7d 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -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")) { diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs index 24e052f96d3fb..e2719713b02ab 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs @@ -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&,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&,int) to table", output); + Assert.Contains(" System.Random:Next () to table", output); } _testOutput.WriteLine("/// Done"); diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs index 6d093133b3771..07705d9f34f21 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs @@ -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; } } diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js index 3c8e36199d25e..21cc18cc3e715 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js @@ -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;