I lead Dart native runtime compilation pipeline development. Kevin's answer is pretty good but I want to add a bit more colour here.
The common perception in Flutter community is that debug Flutter mode is slow because of the JIT and release, this is not entirely true. In reality Flutter framework is filled with large number of very slow consistency checks/assertions which are only enabled in debug mode. That's where the large chunk of slowness is coming from. Disabling these assertions will make this comparison more apples-to-apples.
JIT and AOT have different strengths and weaknesses.
- AOT is characterised with very fast startup and requires no warmup to reach peak performance. AOT applications use less memory. On the other hand, AOT compiler does not have access to runtime profiling data and thus has to make conservative assumptions.
- In JIT mode application takes longer to start and requires warmup to reach peak performance. JIT applications use more memory (JIT's own overhead). However JIT also has access to runtime profiling data, which allows it to be more aggressive and more specific in its optimisations - which can allow it to reach higher peak performance.
AOT is great for UIs, because UIs can't tolerate unpredictability and warmup time of the JIT.
JIT is good for batch mode code.
That's basic comparison between AOT and the JIT. The reality is more complicated and nuanced. On paper JIT should better peak performance almost always, but that's not entirely true today. It's highly dependent on the particular code - whether it is going to run faster in AOT or JIT.
In fact we have been somewhat neglecting JIT performance for quite a while now, spending time on AOT performance and code size. There are things (like calls), which are much faster in AOT than JIT.
Hopefully this explains the landscape. I will take a look at your example and provide more in depth response for the specific test case - but this will take some time.