From 446a6fafae85a4e7b0d6420fd1d3bf1b6590d381 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 23 Jan 2020 20:04:51 +0000 Subject: [PATCH] Optimize "constant_string".Length ```csharp static int Test() => "Hello".Length; // replace with just `5` ``` Before: ```asm movabs rax,0x7fd6c1758160 mov eax,DWORD PTR [rax] ret ``` Now: ```asm mov eax,0x5 ret ``` Also, handles cases after inlining, e.g.: ```csharp bool Validate(string str) { return str.Length > 0 && str.Length <= 100; } bool Test() { return Validate("Hello"); // Validate() will be inlined } ``` New codegen for `Test`: ```asm mov eax, 1 ; return true ret ``` I have a similar PR for CoreCLR: https://github.com/dotnet/runtime/pull/1378 jit-diff report found >30k bytes of improvements. --- src/mono/mono/mini/decompose.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/decompose.c b/src/mono/mono/mini/decompose.c index a448e218185b07..29796230f91603 100644 --- a/src/mono/mono/mini/decompose.c +++ b/src/mono/mono/mini/decompose.c @@ -1587,8 +1587,20 @@ mono_decompose_array_access_opts (MonoCompile *cfg) } break; case OP_STRLEN: - MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg, - ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD); + if (ins->prev && ins->prev->opcode == OP_I8CONST) { + // Optimize String.get_length for ldstr, e.g.: + // "hello".Length => 5 + mono_domain_lock(cfg->domain); + MonoGHashTable* table = cfg->domain->ldstr_table; + MonoString* str = (MonoString*)mono_g_hash_table_lookup(table, GUINT_TO_POINTER(ins->prev->data.i8const)); + mono_domain_unlock(cfg->domain); + if (str && str->length >= 0) { + MONO_EMIT_NEW_ICONST(cfg, ins->dreg, str->length); + break; + } + } + MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS(cfg, OP_LOADI4_MEMBASE, ins->dreg, + ins->sreg1, MONO_STRUCT_OFFSET(MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD); break; default: break;