From: Thays Grazia Date: Fri, 14 Jun 2019 19:15:38 +0000 (-0300) Subject: Implementing reabstraction of default interface methods. (mono/mono#14790) X-Git-Tag: submit/tizen/20210909.063632~10331^2~5^2~1166 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=56c896167444bac5045243d041f33c2f921cacc8;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Implementing reabstraction of default interface methods. (mono/mono#14790) Implementing reabstraction of default interface methods. Fix mono/mono#14495 Commit migrated from https://github.com/mono/mono/commit/a81cc6732716f4f53b110777d4aa700708d27663 --- diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 38f8dc0..5932f08 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -1533,6 +1533,14 @@ print_implemented_interfaces (MonoClass *klass) } } +static gboolean +method_is_reabstracted (guint16 flags) +{ + if ((flags & METHOD_ATTRIBUTE_ABSTRACT && flags & METHOD_ATTRIBUTE_FINAL)) + return TRUE; + return FALSE; +} + /* * Return the number of virtual methods. * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods. @@ -1554,8 +1562,11 @@ count_virtual_methods (MonoClass *klass) mcount = mono_class_get_method_count (klass); for (i = 0; i < mcount; ++i) { flags = klass->methods [i]->flags; - if (flags & METHOD_ATTRIBUTE_VIRTUAL) + if ((flags & METHOD_ATTRIBUTE_VIRTUAL)) { + if (method_is_reabstracted (flags)) + continue; ++vcount; + } } } else { int first_idx = mono_class_get_first_method_idx (klass); @@ -1563,8 +1574,11 @@ count_virtual_methods (MonoClass *klass) for (i = 0; i < mcount; ++i) { flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS); - if (flags & METHOD_ATTRIBUTE_VIRTUAL) + if ((flags & METHOD_ATTRIBUTE_VIRTUAL)) { + if (method_is_reabstracted (flags)) + continue; ++vcount; + } } } return vcount; @@ -3161,6 +3175,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o // it can happen (for injected generic array interfaces) that the same slot is // processed multiple times (those interfaces have overlapping slots), and it // will not always be the first pass the one that fills the slot. + // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted if (!mono_class_is_abstract (klass)) { for (i = 0; i < klass->interface_offsets_count; i++) { int ic_offset; @@ -3176,6 +3191,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o if (im->flags & METHOD_ATTRIBUTE_STATIC) continue; + if (im->is_reabstracted == 1) + continue; TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n", im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL))); @@ -3313,9 +3330,12 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o g_assert (cur_slot <= max_vtsize); /* Ensure that all vtable slots are filled with concrete instance methods */ + // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted if (!mono_class_is_abstract (klass)) { for (i = 0; i < cur_slot; ++i) { if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) { + if (vtable [i]->is_reabstracted == 1) + continue; char *type_name = mono_type_get_full_name (klass); char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none"); mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name); @@ -4994,7 +5014,13 @@ mono_class_setup_methods (MonoClass *klass) /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/ for (i = 0; i < count; ++i) { if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL) + { + if (method_is_reabstracted (methods[i]->flags)) { + methods [i]->is_reabstracted = 1; + continue; + } methods [i]->slot = slot++; + } } } diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index a76a919..586940e 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -78,6 +78,7 @@ struct _MonoMethod { unsigned int is_inflated:1; /* whether we're a MonoMethodInflated */ unsigned int skip_visibility:1; /* whenever to skip JIT visibility checks */ unsigned int verification_success:1; /* whether this method has been verified successfully.*/ + unsigned int is_reabstracted:1; /* whenever this is a reabstraction of another interface */ signed int slot : 16; /* diff --git a/src/mono/mono/metadata/loader.c b/src/mono/mono/metadata/loader.c index dac5ee2..f721cf8 100644 --- a/src/mono/mono/metadata/loader.c +++ b/src/mono/mono/metadata/loader.c @@ -2906,7 +2906,10 @@ mono_method_get_header_internal (MonoMethod *method, MonoError *error) // FIXME: for internal callers maybe it makes sense to do this check at the call site, not // here? if (mono_method_has_no_body (method)) { - mono_error_set_bad_image (error, img, "Method has no body"); + if (method->is_reabstracted == 1) + mono_error_set_generic_error (error, "System", "EntryPointNotFoundException", "%s", method->name); + else + mono_error_set_bad_image (error, img, "Method has no body"); return NULL; } diff --git a/src/mono/mono/tests/Makefile.am b/src/mono/mono/tests/Makefile.am index 0241b62..9f96bb1 100755 --- a/src/mono/mono/tests/Makefile.am +++ b/src/mono/mono/tests/Makefile.am @@ -1009,6 +1009,8 @@ TESTS_IL_SRC= \ dim-sealed.il \ dim-protected-accessibility1.il \ dim-protected-accessibility2.il \ + dim-reabstraction.il \ + dim-reabstraction-generics.il \ twopassvariance.il \ tailcall-generic-cast-conservestack-il.il \ tailcall-generic-cast-nocrash-il.il \ diff --git a/src/mono/mono/tests/dim-reabstraction-generics.il b/src/mono/mono/tests/dim-reabstraction-generics.il new file mode 100644 index 0000000..3342fce --- /dev/null +++ b/src/mono/mono/tests/dim-reabstraction-generics.il @@ -0,0 +1,178 @@ + +// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0 +// Copyright (c) Microsoft Corporation. All rights reserved. + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .ver 4:0:0:0 + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. +} +.assembly 'dim-reabstraction-generics' +{ + .custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::'.ctor'(int32) = (01 00 08 00 00 00 00 00 ) // ........ + + .custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::'.ctor'() = ( + 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + + .custom instance void class [mscorlib]System.Diagnostics.DebuggableAttribute::'.ctor'(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (01 00 07 01 00 00 00 00 ) // ........ + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module 'dim-reabstraction-generics.exe' // GUID = {198880C7-E25B-497F-AE09-6C555BBBAB42} + + + .class interface public auto ansi abstract I1`1 + { + + // method line 1 + .method public virtual hidebysig newslot abstract + instance default int32 M1 () cil managed + { + // Method begins at RVA 0x0 + } // end of method I1`1::M1 + + // method line 2 + .method public virtual hidebysig newslot + instance default int32 M2 () cil managed + { + // Method begins at RVA 0x2050 + // Code size 7 (0x7) + .maxstack 1 + .locals init ( + int32 V_0) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0005 + + IL_0005: ldloc.0 + IL_0006: ret + } // end of method I1`1::M2 + + } // end of class I1`1 + + .class interface public auto ansi abstract I2`1 + implements class I1`1 { + + // method line 3 + .method private final virtual hidebysig abstract + instance default int32 'I1.M1' () cil managed + { + // Method begins at RVA 0x0 + } // end of method I2`1::I1.M1 + + // method line 4 + .method public virtual hidebysig newslot + instance default int32 M2 () cil managed + { + // Method begins at RVA 0x2064 + // Code size 11 (0xb) + .maxstack 1 + .locals init ( + int32 V_0) + IL_0000: nop + IL_0001: ldc.i4 200 + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method I2`1::M2 + + } // end of class I2`1 + + .class private auto ansi beforefieldinit Test1 + extends [mscorlib]System.Object + implements class I2`1, class I1`1 { + + // method line 5 + .method private static hidebysig + default int32 Main () cil managed + { + // Method begins at RVA 0x207c + .entrypoint + // Code size 54 (0x36) + .maxstack 2 + .locals init ( + class I1`1 V_0, + bool V_1, + int32 V_2, + bool V_3) + IL_0000: nop + IL_0001: newobj instance void class Test1::'.ctor'() + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: callvirt instance int32 class I1`1::M1() + IL_000d: ldc.i4.s 0x64 + IL_000f: ceq + IL_0011: ldc.i4.0 + IL_0012: ceq + IL_0014: stloc.1 + IL_0015: ldloc.1 + IL_0016: brfalse.s IL_001d + + IL_0018: nop + IL_0019: ldc.i4.m1 + IL_001a: stloc.2 + IL_001b: br.s IL_0034 + + IL_001d: ldloc.0 + IL_001e: callvirt instance int32 class I1`1::M2() + IL_0023: ldc.i4.0 + IL_0024: cgt.un + IL_0026: stloc.3 + IL_0027: ldloc.3 + IL_0028: brfalse.s IL_0030 + + IL_002a: nop + IL_002b: ldc.i4.s 0xfffffffe + IL_002d: stloc.2 + IL_002e: br.s IL_0034 + + IL_0030: ldc.i4.0 + IL_0031: stloc.2 + IL_0032: br.s IL_0034 + + IL_0034: ldloc.2 + IL_0035: ret + } // end of method Test1::Main + + // method line 6 + .method private final virtual hidebysig newslot + instance default int32 'I1.M1' () cil managed + { + // Method begins at RVA 0x20c0 + .override method instance int32 class I1`1::M1() + // Code size 8 (0x8) + .maxstack 1 + .locals init ( + int32 V_0) + IL_0000: nop + IL_0001: ldc.i4.s 0x64 + IL_0003: stloc.0 + IL_0004: br.s IL_0006 + + IL_0006: ldloc.0 + IL_0007: ret + } // end of method Test1::I1.M1 + + // method line 7 + .method public hidebysig specialname rtspecialname + instance default void '.ctor' () cil managed + { + // Method begins at RVA 0x20d4 + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void object::'.ctor'() + IL_0006: nop + IL_0007: ret + } // end of method Test1::.ctor + + } // end of class Test1 + diff --git a/src/mono/mono/tests/dim-reabstraction.il b/src/mono/mono/tests/dim-reabstraction.il new file mode 100644 index 0000000..d104945 --- /dev/null +++ b/src/mono/mono/tests/dim-reabstraction.il @@ -0,0 +1,178 @@ + +// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0 +// Copyright (c) Microsoft Corporation. All rights reserved. + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .ver 4:0:0:0 + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. +} +.assembly 'reabstraction' +{ + .custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::'.ctor'(int32) = (01 00 08 00 00 00 00 00 ) // ........ + + .custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::'.ctor'() = ( + 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + + .custom instance void class [mscorlib]System.Diagnostics.DebuggableAttribute::'.ctor'(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (01 00 07 01 00 00 00 00 ) // ........ + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module reabstraction.exe // GUID = {874DD85D-9771-40F1-A6BB-D80FDAA9CF69} + + + .class interface public auto ansi abstract I1 + { + + // method line 1 + .method public virtual hidebysig newslot abstract + instance default int32 M1 () cil managed + { + // Method begins at RVA 0x0 + } // end of method I1::M1 + + // method line 2 + .method public virtual hidebysig newslot + instance default int32 M2 () cil managed + { + // Method begins at RVA 0x2050 + // Code size 7 (0x7) + .maxstack 1 + .locals init ( + int32 V_0) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0005 + + IL_0005: ldloc.0 + IL_0006: ret + } // end of method I1::M2 + + } // end of class I1 + + .class interface public auto ansi abstract I2 + implements I1 { + + // method line 3 + .method private final virtual hidebysig abstract + instance default int32 I1.M1 () cil managed + { + // Method begins at RVA 0x0 + } // end of method I2::I1.M1 + + // method line 4 + .method public virtual hidebysig newslot + instance default int32 M2 () cil managed + { + // Method begins at RVA 0x2064 + // Code size 11 (0xb) + .maxstack 1 + .locals init ( + int32 V_0) + IL_0000: nop + IL_0001: ldc.i4 200 + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method I2::M2 + + } // end of class I2 + + .class private auto ansi beforefieldinit Test1 + extends [mscorlib]System.Object + implements I2, I1 { + + // method line 5 + .method private static hidebysig + default int32 Main () cil managed + { + // Method begins at RVA 0x207c + .entrypoint + // Code size 59 (0x3b) + .maxstack 2 + .locals init ( + class I1 V_0, + bool V_1, + int32 V_2, + bool V_3) + IL_0000: nop + IL_0001: newobj instance void class Test1::'.ctor'() + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: callvirt instance int32 class I1::M1() + IL_000d: ldc.i4.s 0x64 + IL_000f: ceq + IL_0011: ldc.i4.0 + IL_0012: ceq + IL_0014: stloc.1 + IL_0015: ldloc.1 + IL_0016: brfalse.s IL_001c + + IL_0018: ldc.i4.m1 + IL_0019: stloc.2 + IL_001a: br.s IL_0039 + + IL_001c: ldloc.0 + IL_001d: callvirt instance int32 class I1::M2() + IL_0022: ldc.i4 0 + IL_0027: ceq + IL_0029: ldc.i4.0 + IL_002a: ceq + IL_002c: stloc.3 + IL_002d: ldloc.3 + IL_002e: brfalse.s IL_0035 + + IL_0030: ldc.i4.s 0xfffffffe + IL_0032: stloc.2 + IL_0033: br.s IL_0039 + + IL_0035: ldc.i4.0 + IL_0036: stloc.2 + IL_0037: br.s IL_0039 + + IL_0039: ldloc.2 + IL_003a: ret + } // end of method Test1::Main + + // method line 6 + .method private final virtual hidebysig newslot + instance default int32 I1.M1 () cil managed + { + // Method begins at RVA 0x20c4 + .override class I1::M1 + // Code size 8 (0x8) + .maxstack 1 + .locals init ( + int32 V_0) + IL_0000: nop + IL_0001: ldc.i4.s 0x64 + IL_0003: stloc.0 + IL_0004: br.s IL_0006 + + IL_0006: ldloc.0 + IL_0007: ret + } // end of method Test1::I1.M1 + + // method line 7 + .method public hidebysig specialname rtspecialname + instance default void '.ctor' () cil managed + { + // Method begins at RVA 0x20d8 + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void object::'.ctor'() + IL_0006: nop + IL_0007: ret + } // end of method Test1::.ctor + + } // end of class Test1 +