Repository: godot
Issue: Unexpected C# performance loss on simple scripts
Labels: needs testing,topic:dotnet,performance

### Tested versions

- 3.5.3
- 4.2.1
- 4.3-dev4
- custom build branched from 4.2 branch

### System information

Godot v4.3.dev4.mono - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2070 SUPER (NVIDIA; 31.0.15.4633) - AMD Ryzen 9 3900X 12-Core Processor (24 Threads)

### Issue description

### Short Version 

C# performance seems to have suffer due to StringName equality checks in generated methods like `HasGodotClassMethod `and `InvokeGodotClassMethod`

### Long Version

I noticed that performance in my game drops sharply with a large number of nodes doing basically nothing. So I created a small repro project to try and explain what I have observed. 

In the repro project we have a very simple script that toggles a Label from `a` to `b` every second. This is done in a `_process` callback in both GDScript and C#. We instantiate 1000 instances of the label to simulate a large number of nodes. At a too large number (10000) the project is very slow, so differences between GDScript and C# are not noticable.

( all screenshots are in the repro project)
Here are the graphs for the 4.x version of Godot:
GDScript
![label_gd_4 3](https://github.com/godotengine/godot/assets/2500134/3d498d98-efc1-4ab2-9913-bf20f3c0aef6)
C#
![label_mono_4 3](https://github.com/godotengine/godot/assets/2500134/14a9e8d9-a09b-4205-9413-b9eac1a33fe0)

All 4.x versions tested exhibit the same behavior, which is GDScript being almost double the speed of C#.

For comparison here are the graphs for 3.5.3, where C# is faster than GDScript:
GDScript
![label_gd_3 5 3](https://github.com/godotengine/godot/assets/2500134/19441c3c-d916-4f06-add4-ea79cea9b13b)
C#
![label_mono_3 5 3](https://github.com/godotengine/godot/assets/2500134/b3be0155-6937-42a4-9626-73327a343220)

I ran a dotTrace using Rider to try and figure out what is going on, and here are the results for 4.2.1
![test_cache_4_2_1_trace](https://github.com/godotengine/godot/assets/2500134/acbcb2d8-e8db-43b7-9b5d-59f42ec5b8dc)

it's here I first noticed the equality checks on StringNames taking up a bit of time. Which led me to assume that the if-else chain in the `HasGodotClassMethod `and `InvokeGodotClassMethod` might be part of the problem.

I experimented in modifying the ScriptGenerators to use cached method calls instead of comparison checks https://github.com/TheOrioli/godot/commit/c291f64568899bb17d300655aa6a57179ae91cb0 and it seems to provide a bit of a speedup in my main project, but I do not know how to change those methods for built-in godot types. 

You can see a small pyramid in the flame graph disappear under `TestLabel.InvokeGodotClassMethod` 
![test_cache_custom_trace](https://github.com/godotengine/godot/assets/2500134/a6d22a8f-dd84-465a-a952-fcbe2b5520d0)

I there is definitely something here, and there is potential to eliminate all those comparison checks which should provide a speedup and bring C# closer to GDScript in performance. I am hoping someone more familiar with the codebase can help out in figuring this out and testing more properly.

This behavior unfortunately means that making lots of small scripts in C# will lead to unintended performance degradation in games.

### Steps to reproduce

- Open repro project
- Run `main.tscn` with the Node property "Use CSharp" set to false
- Observe FPS monitors
- Run `main.tscn` with the Node property "Use CSharp" set to true
- Observe FPS monitors

### Minimal reproduction project (MRP)

4.3-dev4, contains screenshots from above in folder [test_mono_method_cache.zip](https://github.com/godotengine/godot/files/14511773/test_mono_method_cache.zip)
3.5.3 [test_mono_method_gd3.zip](https://github.com/godotengine/godot/files/14511792/test_mono_method_gd3.zip)