From: Vlad Brezae Date: Fri, 26 Apr 2019 21:28:12 +0000 (+0300) Subject: [interp] Optimize special static field access (mono/mono#14202) X-Git-Tag: submit/tizen/20210909.063632~10331^2~5^2~1360 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=26cd59d84d9a6b57ee346abd85f0074ff4e81e17;p=platform%2Fupstream%2Fdotnet%2Fruntime.git [interp] Optimize special static field access (mono/mono#14202) * [interp] Optimize special static field access 3x faster. For value types 10x. * [interp] Remove duplicated code * [interp] Further optimize thread static field access Provides an additional 50% perf gain. Commit migrated from https://github.com/mono/mono/commit/a68022ae7e26952e7a5dfe6cbe99b3021b3c98cc --- diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 9b6b7cb..82b9142 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -4842,23 +4842,46 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClause MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDSSFLD_SLOW) - MINT_IN_CASE(MINT_LDSSFLD_VT_SLOW) { - gboolean is_vt = *ip == MINT_LDSSFLD_VT_SLOW; +#define LDTSFLD(datamem, fieldtype) { \ + guint32 offset = READ32(ip + 1); \ + MonoInternalThread *thread = mono_thread_internal_current (); \ + gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \ + sp[0].data.datamem = *(fieldtype*)addr; \ + ip += 3; \ + ++sp; \ + } + MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_LDSSFLD) { MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)]; - gpointer addr = mono_class_static_field_address (imethod->domain, field); - EXCEPTION_CHECKPOINT; - if (is_vt) { - int size = READ32 (ip + 2); - sp->data.p = vt_sp; - vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT); - } + guint32 offset = READ32(ip + 2); + gpointer addr = mono_get_special_static_data (offset); stackval_from_data (field->type, sp, addr, FALSE); - ip += (is_vt ? 4 : 2); + ip += 4; ++sp; MINT_IN_BREAK; } + MINT_IN_CASE(MINT_LDSSFLD_VT) { + guint32 offset = READ32(ip + 1); + gpointer addr = mono_get_special_static_data (offset); + int size = READ32 (ip + 3); + memcpy (vt_sp, addr, size); + sp->data.p = vt_sp; + vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT); + ip += 5; + ++sp; + MINT_IN_BREAK; + } #define STSFLD(datamem, fieldtype) { \ MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \ INIT_VTABLE (vtable); \ @@ -4891,23 +4914,46 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClause MINT_IN_BREAK; } - MINT_IN_CASE(MINT_STSSFLD_SLOW) - MINT_IN_CASE(MINT_STSSFLD_VT_SLOW) { - gboolean is_vt = *ip == MINT_STSSFLD_VT_SLOW; +#define STTSFLD(datamem, fieldtype) { \ + guint32 offset = READ32(ip + 1); \ + MonoInternalThread *thread = mono_thread_internal_current (); \ + gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \ + sp--; \ + *(fieldtype*)addr = sp[0].data.datamem; \ + ip += 3; \ + } + + MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_STSSFLD) { MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)]; - gpointer addr = mono_class_static_field_address (imethod->domain, field); - EXCEPTION_CHECKPOINT; + guint32 offset = READ32(ip + 2); + gpointer addr = mono_get_special_static_data (offset); --sp; stackval_to_data (field->type, sp, addr, FALSE); - if (is_vt) { - int size = READ32 (ip + 2); - vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT); - ip += 4; - } else { - ip += 2; - } + ip += 4; MINT_IN_BREAK; } + MINT_IN_CASE(MINT_STSSFLD_VT) { + guint32 offset = READ32(ip + 1); + gpointer addr = mono_get_special_static_data (offset); + --sp; + int size = READ32 (ip + 3); + memcpy (addr, sp->data.vt, size); + vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT); + ip += 5; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_STOBJ_VT) { int size; c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)]; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 1dc503e..5342285 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -107,8 +107,19 @@ OPDEF(MINT_STFLD_R8_UNALIGNED, "stfld.r8.unaligned", 2, MintOpUShortInt) OPDEF(MINT_STRMFLD, "strmfld", 2, MintOpFieldToken) OPDEF(MINT_STRMFLD_VT, "strmfld.vt", 2, MintOpUShortInt) -OPDEF(MINT_LDSSFLD_SLOW, "ldssfld.slow", 2, MintOpFieldToken) -OPDEF(MINT_LDSSFLD_VT_SLOW, "ldssfld.vt.slow", 4, MintOpFieldToken) +OPDEF(MINT_LDTSFLD_I1, "ldtsfld.i1", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_U1, "ldtsfld.u1", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_I2, "ldtsfld.i2", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_U2, "ldtsfld.u2", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_I4, "ldtsfld.i4", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_I8, "ldtsfld.i8", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_R4, "ldtsfld.r4", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_R8, "ldtsfld.r8", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_O, "ldtsfld.o", 3, MintOpInt) +OPDEF(MINT_LDTSFLD_P, "ldtsfld.p", 3, MintOpInt) +OPDEF(MINT_LDSSFLD, "ldssfld", 4, MintOpFieldToken) +OPDEF(MINT_LDSSFLD_VT, "ldssfld.vt", 5, MintOpInt) + OPDEF(MINT_LDSFLD_I1, "ldsfld.i1", 3, MintOpUShortInt) OPDEF(MINT_LDSFLD_U1, "ldsfld.u1", 3, MintOpUShortInt) OPDEF(MINT_LDSFLD_I2, "ldsfld.i2", 3, MintOpUShortInt) @@ -121,8 +132,18 @@ OPDEF(MINT_LDSFLD_O, "ldsfld.o", 3, MintOpUShortInt) OPDEF(MINT_LDSFLD_P, "ldsfld.p", 3, MintOpUShortInt) OPDEF(MINT_LDSFLD_VT, "ldsfld.vt", 5, MintOpTwoShorts) -OPDEF(MINT_STSSFLD_SLOW, "stssfld.slow", 2, MintOpFieldToken) -OPDEF(MINT_STSSFLD_VT_SLOW, "stssfld.vt.slow", 4, MintOpFieldToken) +OPDEF(MINT_STTSFLD_I1, "sttsfld.i1", 3, MintOpInt) +OPDEF(MINT_STTSFLD_U1, "sttsfld.u1", 3, MintOpInt) +OPDEF(MINT_STTSFLD_I2, "sttsfld.i2", 3, MintOpInt) +OPDEF(MINT_STTSFLD_U2, "sttsfld.u2", 3, MintOpInt) +OPDEF(MINT_STTSFLD_I4, "sttsfld.i4", 3, MintOpInt) +OPDEF(MINT_STTSFLD_I8, "sttsfld.i8", 3, MintOpInt) +OPDEF(MINT_STTSFLD_R4, "sttsfld.r4", 3, MintOpInt) +OPDEF(MINT_STTSFLD_R8, "sttsfld.r8", 3, MintOpInt) +OPDEF(MINT_STTSFLD_O, "sttsfld.o", 3, MintOpInt) +OPDEF(MINT_STTSFLD_P, "sttsfld.p", 3, MintOpInt) +OPDEF(MINT_STSSFLD, "stssfld", 4, MintOpFieldToken) +OPDEF(MINT_STSSFLD_VT, "stssfld.vt", 5, MintOpInt) OPDEF(MINT_STSFLD_I1, "stsfld.i1", 3, MintOpUShortInt) OPDEF(MINT_STSFLD_U1, "stsfld.u1", 3, MintOpUShortInt) OPDEF(MINT_STSFLD_I2, "stsfld.i2", 3, MintOpUShortInt) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 2390941..ba49c9e 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2560,45 +2560,46 @@ interp_emit_stobj (TransformData *td, MonoClass *klass) } static void -interp_emit_ldsfld (TransformData *td, MonoClassField *field, MonoClass *field_class, int mt, MonoError *error) +interp_emit_sfld_access (TransformData *td, MonoClassField *field, MonoClass *field_class, int mt, gboolean is_load, MonoError *error) { - if (mono_class_field_is_special_static (field)) { - interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_LDSSFLD_VT_SLOW : MINT_LDSSFLD_SLOW); - td->last_ins->data [0] = get_data_item_index (td, field); - if (mt == MINT_TYPE_VT) { - int size = mono_class_value_size (field_class, NULL); - WRITE32_INS(td->last_ins, 1, &size); - } - } else { - MonoVTable *vtable = mono_class_vtable_checked (td->rtm->domain, field->parent, error); - return_if_nok (error); - - interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_LDSFLD_VT : (MINT_LDSFLD_I1 + mt - MINT_TYPE_I1)); - td->last_ins->data [0] = get_data_item_index (td, vtable); - td->last_ins->data [1] = get_data_item_index (td, (char*)mono_vtable_get_static_field_data (vtable) + field->offset); - - if (mt == MINT_TYPE_VT) { - int size = mono_class_value_size (field_class, NULL); - WRITE32_INS(td->last_ins, 2, &size); - } - } -} + MonoDomain *domain = td->rtm->domain; + // Initialize the offset for the field + MonoVTable *vtable = mono_class_vtable_checked (domain, field->parent, error); + return_if_nok (error); -static void -interp_emit_stsfld (TransformData *td, MonoClassField *field, MonoClass *field_class, int mt, MonoError *error) -{ if (mono_class_field_is_special_static (field)) { - interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_STSSFLD_VT_SLOW : MINT_STSSFLD_SLOW); - td->last_ins->data [0] = get_data_item_index (td, field); - if (mt == MINT_TYPE_VT) { - int size = mono_class_value_size (field_class, NULL); - WRITE32_INS(td->last_ins, 1, &size); + guint32 offset; + + mono_domain_lock (domain); + g_assert (domain->special_static_fields); + offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field)); + mono_domain_unlock (domain); + g_assert (offset); + + // Offset is SpecialStaticOffset + if ((offset & 0x80000000) == 0 && mt != MINT_TYPE_VT) { + // This field is thread static + interp_add_ins (td, (is_load ? MINT_LDTSFLD_I1 : MINT_STTSFLD_I1) + mt); + WRITE32_INS(td->last_ins, 0, &offset); + } else { + if (mt == MINT_TYPE_VT) { + interp_add_ins (td, is_load ? MINT_LDSSFLD_VT : MINT_STSSFLD_VT); + WRITE32_INS(td->last_ins, 0, &offset); + + int size = mono_class_value_size (field_class, NULL); + WRITE32_INS(td->last_ins, 2, &size); + } else { + interp_add_ins (td, is_load ? MINT_LDSSFLD : MINT_STSSFLD); + td->last_ins->data [0] = get_data_item_index (td, field); + WRITE32_INS(td->last_ins, 1, &offset); + } } } else { - MonoVTable *vtable = mono_class_vtable_checked (td->rtm->domain, field->parent, error); - return_if_nok (error); + if (is_load) + interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_LDSFLD_VT : (MINT_LDSFLD_I1 + mt - MINT_TYPE_I1)); + else + interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_STSFLD_VT : (MINT_STSFLD_I1 + mt - MINT_TYPE_I1)); - interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_STSFLD_VT : (MINT_STSFLD_I1 + mt - MINT_TYPE_I1)); td->last_ins->data [0] = get_data_item_index (td, vtable); td->last_ins->data [1] = get_data_item_index (td, (char*)mono_vtable_get_static_field_data (vtable) + field->offset); @@ -4057,7 +4058,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (is_static) { interp_add_ins (td, MINT_POP); td->last_ins->data [0] = 0; - interp_emit_ldsfld (td, field, field_klass, mt, error); + interp_emit_sfld_access (td, field, field_klass, mt, TRUE, error); goto_if_nok (error, exit); } else { int opcode = MINT_LDFLD_I1 + mt - MINT_TYPE_I1; @@ -4127,7 +4128,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (is_static) { interp_add_ins (td, MINT_POP); td->last_ins->data [0] = 1; - interp_emit_stsfld (td, field, field_klass, mt, error); + interp_emit_sfld_access (td, field, field_klass, mt, FALSE, error); goto_if_nok (error, exit); /* the vtable of the field might not be initialized at this point */ @@ -4177,7 +4178,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, mt = mint_type (ftype); klass = mono_class_from_mono_type_internal (ftype); - interp_emit_ldsfld (td, field, klass, mt, error); + interp_emit_sfld_access (td, field, klass, mt, TRUE, error); goto_if_nok (error, exit); if (mt == MINT_TYPE_VT) { @@ -4201,7 +4202,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, mono_class_vtable_checked (domain, fld_klass, error); goto_if_nok (error, exit); - interp_emit_stsfld (td, field, fld_klass, mt, error); + interp_emit_sfld_access (td, field, fld_klass, mt, FALSE, error); goto_if_nok (error, exit); if (mt == MINT_TYPE_VT) {