Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/mcs/ilasm
diff options
context:
space:
mode:
authorThays Grazia <thaystg@gmail.com>2019-04-04 21:38:21 +0300
committerGitHub <noreply@github.com>2019-04-04 21:38:21 +0300
commitbeb81d3deb068f03efa72be986c96f9c3ab66275 (patch)
treeca1f1b780d40de6a4544e4e7cba2943885cf8ca9 /mcs/ilasm
parentaba1bac992971a1784fdf1db9a346bc7a305876c (diff)
[DIM] Do not order implemented interfaces (#13721)
This test https://github.com/dotnet/coreclr/blob/1649da12db73c8c07513c9168cb30ec70c310063/tests/src/Regressions/coreclr/20452/twopassvariance.il On mono we were ordering the list of implemented interfaces and shouldn't do this as it's described on ECMA-335 Section II.12.2.1 and II.12.2.2. The ordering was removed on ilasm and some changes were needed on metadata either because it's not ordered anymore. There were two bugs, one on ilasm and other on class initialization on mono. ### ILAsm ### If we get the .exe generated by .net Framework it doesn't execute on mono without modifications because we ordered the implemented interfaces list by id. And doing that the order defined on source code is ignored. If we get the .exe generated by Mono it doesn't execute on .net Framework because on IlAsm we order the list and loose the order defined on source code. The interfaces on metadata before these changes on IlAsm were like this: ``` 1: Fooer1 implements class IFoo<class Derived> 2: Fooer1 implements class IFoo<class Base> 3: Fooer2 implements class IFoo<class Base> 4: Fooer2 implements class IFoo<class Derived> 5: Fooer3 implements class IFoo<object> 6: Fooer3 implements class IBar<class Derived> 7: Fooer3 implements class IBaz<class Base> 8: IBar implements class IFoo<!0> 9: IBaz implements class IFoo<!0> 10: Fooer4 implements IQux 11: Fooer4 implements class IBar<class Derived> 12: IQux implements class IFoo<class Base> 13: IQux implements class IFoo<class Derived> 14: Fooer5 implements IQux 15: Fooer5 implements class IBar<class Derived> 16: Fooer6 implements class IBar<class Base> 17: Fooer6 implements class IFoo<class Base> 18: Fooer7 implements class IFoo<class Base> 19: Fooer7 implements class IBar<class Base> ``` And After the changes they follow the definition order which is the same order of IlAsm for .net framework and .net core. ``` 1: IBar implements class IFoo<!0> 2: IBaz implements class IFoo<!0> 3: IQux implements class IFoo<class Base> 4: IQux implements class IFoo<class Derived> 5: Fooer1 implements class IFoo<class Base> 6: Fooer1 implements class IFoo<class Derived> 7: Fooer2 implements class IFoo<class Derived> 8: Fooer2 implements class IFoo<class Base> 9: Fooer3 implements class IBaz<class Base> 10: Fooer3 implements class IBar<class Derived> 11: Fooer3 implements class IFoo<object> 12: Fooer4 implements IQux 13: Fooer4 implements class IBar<class Derived> 14: Fooer5 implements class IBar<class Derived> 15: Fooer5 implements IQux 16: Fooer6 implements class IFoo<class Base> 17: Fooer6 implements class IBar<class Base> 18: Fooer7 implements class IBar<class Base> 19: Fooer7 implements class IFoo<class Base> ``` ### Mono vtable layout ### Internally when Mono computes the interface table for each class, it would previously sort the interfaces by `MonoClass:interface_id` which is a unique id assigned (roughly) in load order. This was incorrect because the order of the interfaces determines the final vtable for the class. This PR changes the interface table computation so that the interfaces of a single class are ordered in declaration order, following ECMA. One consequence is that we can no longer use binary search with the interface id as the key to find out if a class implements an interface. We have to do a linear scan. On the other hand, we expect that the number of interfaces implemented by a single class is small in practice. This is how the Vtable for Fooer1 and Fooer2 looks like after the changes: ``` *** Vtable for class 'Fooer1' at "FINALLY" (size 6) [O][000][INDEX 000] object:ToString () [0x7fd78681db20] [O][001][INDEX 001] object:GetHashCode () [0x7fd78681daf8] [O][002][INDEX 002] object:Finalize () [0x7fd78681dad0] [O][003][INDEX 003] object:Equals (object) [0x7fd78681daa8] [I][004][INDEX 000] IFoo:Gimme () [0x7fd786503800] [I][005][INDEX 000] IFoo:Gimme () [0x7fd7865038c0] Packed interface table for class Fooer1 has size 2 [000][UUID 078][SLOT 004][SIZE 001] interface IFoo[Base] [001][UUID 079][SLOT 005][SIZE 001] interface IFoo[Derived] ``` and ``` *** Vtable for class 'Fooer2' at "FINALLY" (size 6) [O][000][INDEX 000] object:ToString () [0x7fd78681db20] [O][001][INDEX 001] object:GetHashCode () [0x7fd78681daf8] [O][002][INDEX 002] object:Finalize () [0x7fd78681dad0] [O][003][INDEX 003] object:Equals (object) [0x7fd78681daa8] [I][004][INDEX 000] IFoo:Gimme () [0x7fd7865038c0] [I][005][INDEX 000] IFoo:Gimme () [0x7fd786503800] Packed interface table for class Fooer2 has size 2 [000][UUID 079][SLOT 004][SIZE 001] interface IFoo[Derived] [001][UUID 078][SLOT 005][SIZE 001] interface IFoo[Base] ``` This is how the VTable for Fooer1 and Fooer2 looks like before the changes, as you can see Packed interface table are the same in Fooer1 and Fooer2, so the behavior of both classes was the same: ``` Vtable for class 'Fooer1' at "FINALLY" (size 6) [O][000][INDEX 000] object:ToString () [0x7fcf3801d920] [O][001][INDEX 001] object:GetHashCode () [0x7fcf3801d8f8] [O][002][INDEX 002] object:Finalize () [0x7fcf3801d8d0] [O][003][INDEX 003] object:Equals (object) [0x7fcf3801d8a8] [I][004][INDEX 000] IFoo:Gimme () [0x7fcf37c29880] [I][005][INDEX 000] IFoo:Gimme () [0x7fcf37c29940] Packed interface table for class Fooer1 has size 2 [000][UUID 076][SLOT 004][SIZE 001] interface IFoo[Base] [001][UUID 077][SLOT 005][SIZE 001] interface IFoo[Derived] ``` ``` Vtable for class 'Fooer2' at "FINALLY" (size 6) [O][000][INDEX 000] object:ToString () [0x7fcf3801d920] [O][001][INDEX 001] object:GetHashCode () [0x7fcf3801d8f8] [O][002][INDEX 002] object:Finalize () [0x7fcf3801d8d0] [O][003][INDEX 003] object:Equals (object) [0x7fcf3801d8a8] [I][004][INDEX 000] IFoo:Gimme () [0x7fcf37c29940] [I][005][INDEX 000] IFoo:Gimme () [0x7fcf37c29880] Packed interface table for class Fooer2 has size 2 [000][UUID 076][SLOT 005][SIZE 001] interface IFoo[Base] [001][UUID 077][SLOT 004][SIZE 001] interface IFoo[Derived] ```
Diffstat (limited to 'mcs/ilasm')
-rw-r--r--mcs/ilasm/codegen/TypeManager.cs6
-rw-r--r--mcs/ilasm/parser/ILParser.jay2
2 files changed, 4 insertions, 4 deletions
diff --git a/mcs/ilasm/codegen/TypeManager.cs b/mcs/ilasm/codegen/TypeManager.cs
index 029b3144632..54d4bdd9abc 100644
--- a/mcs/ilasm/codegen/TypeManager.cs
+++ b/mcs/ilasm/codegen/TypeManager.cs
@@ -13,7 +13,7 @@ using System.Collections;
namespace Mono.ILASM {
public class TypeManager {
-
+ private ArrayList type_list;
private Hashtable type_table;
private CodeGen code_gen;
@@ -21,6 +21,7 @@ namespace Mono.ILASM {
{
this.code_gen = code_gen;
type_table = new Hashtable ();
+ type_list = new ArrayList ();
}
public TypeDef this[string full_name] {
@@ -29,6 +30,7 @@ namespace Mono.ILASM {
}
set {
type_table[full_name] = value;
+ type_list.Add(value);
}
}
@@ -47,8 +49,6 @@ namespace Mono.ILASM {
public void DefineAll ()
{
- ArrayList type_list = new ArrayList (type_table.Values);
- type_list.Sort ();
foreach (TypeDef typedef in type_list) {
typedef.Define (code_gen);
}
diff --git a/mcs/ilasm/parser/ILParser.jay b/mcs/ilasm/parser/ILParser.jay
index bfaa1aa39a6..9f4c8819887 100644
--- a/mcs/ilasm/parser/ILParser.jay
+++ b/mcs/ilasm/parser/ILParser.jay
@@ -652,7 +652,7 @@ impl_class_refs : K_IMPLEMENTS generic_class_ref
{
ArrayList al = (ArrayList) $1;
- al.Insert (0, $3);
+ al.Add ($3);
$$ = al;
}
;