Skip to content

[Wasm] Very large methods cause interpreter tiering to fail and allocates a lot of unmanaged memory #93192

Closed
@jeromelaban

Description

@jeromelaban

Description

When a very large C# method is encountered the interpreter tries to optimize that method, seemingly fails to do so and leaks memory every time the method is invoked, eventually exhausing the wasm heap.

Reproduction Steps

Build an app with the following t4 template:

<#@template language="C#"#>
<#@output extension="g.cs" #>

public class LargeMethodTest
{
    public static Test(string value)
    {
        int value = 0;

        switch(value)
        {
            <# for(int i=0; i<20000; i++) { #>
            case "<#= i #>":
                value++;
                break;
            <# } #>
            default:
            break;
        }
    }
}

Then create a loop over the Test method:

  staticvoid TestLargeSwitchCase()
  {
      var sw = Stopwatch.StartNew();

      // Over 1000 iterations so that tiering kicks in
      for (int i = 0; i < 2000; i++)
      {
          LargeMethodTest.Test("42");
      }

      Console.WriteLine($"Elapsed: {sw.Elapsed}");
  }

Expected behavior

The code does not fail and runs to the end.

Actual behavior

The app fails as follows:

 Cannot enlarge memory, asked to go up to 4294918144 bytes, but the limit is 4294901760 bytes!

_emscripten_resize_heap	@	dotnet.native.js:4293
$sbrk	@	dotnet.native.wasm:0x2ce8fa
$dlmalloc	@	dotnet.native.wasm:0x2cc5b5
$monoeg_malloc	@	dotnet.native.wasm:0x9fbaf
$mono_mempool_alloc	@	dotnet.native.wasm:0x119464
$interp_link_bblocks	@	dotnet.native.wasm:0x8d21e
$handle_branch	@	dotnet.native.wasm:0x8f585
$generate_code	@	dotnet.native.wasm:0x85cbd
$generate	@	dotnet.native.wasm:0x9306d
$mono_interp_transform_method	@	dotnet.native.wasm:0x92b30
$tier_up_method	@	dotnet.native.wasm:0x9c627
$mono_interp_tier_up_frame_enter	@	dotnet.native.wasm:0x9c37b
$mono_interp_exec_method	@	dotnet.native.wasm:0x762dc
$interp_entry	@	dotnet.native.wasm:0x7bbad
$interp_entry_instance_1	@	dotnet.native.wasm:0x7bdb8
$aot_instances_aot_wrapper_gsharedvt_in_sig_void_this_obj

Each invocation of the method will show a trace like this one:

image

Regression?

Not sure, it may have worked before tiering.

Known Workarounds

Use smaller methods

Configuration

.NET 8 RC1

Other information

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions