Implementing reabstraction of default interface methods. (mono/mono#14790)
authorThays Grazia <thaystg@gmail.com>
Fri, 14 Jun 2019 19:15:38 +0000 (16:15 -0300)
committerGitHub <noreply@github.com>
Fri, 14 Jun 2019 19:15:38 +0000 (16:15 -0300)
Implementing reabstraction of default interface methods.
Fix mono/mono#14495

Commit migrated from https://github.com/mono/mono/commit/a81cc6732716f4f53b110777d4aa700708d27663

src/mono/mono/metadata/class-init.c
src/mono/mono/metadata/class-internals.h
src/mono/mono/metadata/loader.c
src/mono/mono/tests/Makefile.am
src/mono/mono/tests/dim-reabstraction-generics.il [new file with mode: 0644]
src/mono/mono/tests/dim-reabstraction.il [new file with mode: 0644]

index 38f8dc0..5932f08 100644 (file)
@@ -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++;
+                       }
                }
        }
 
index a76a919..586940e 100644 (file)
@@ -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;
 
        /*
index dac5ee2..f721cf8 100644 (file)
@@ -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;
        }
 
index 0241b62..9f96bb1 100755 (executable)
@@ -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 (file)
index 0000000..3342fce
--- /dev/null
@@ -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<T>
+  {
+
+    // 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<T>
+       implements class I1`1<!0>  {
+
+    // method line 3
+    .method private final virtual hidebysig abstract 
+           instance default int32 'I1<T>.M1' ()  cil managed 
+    {
+        // Method begins at RVA 0x0
+    } // end of method I2`1::I1<T>.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<int32>, class I1`1<int32>  {
+
+    // 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<int32>       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<int32>::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<int32>::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<System.Int32>.M1' ()  cil managed 
+    {
+        // Method begins at RVA 0x20c0
+       .override method instance int32 class I1`1<int32>::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<System.Int32>.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 (file)
index 0000000..d104945
--- /dev/null
@@ -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
+