nitvm: Fixing a bug in superclasses ordering
[nit.git] / src / vm.nit
index 4d54f54..d68c394 100644 (file)
@@ -123,11 +123,12 @@ class VirtualMachine super NaiveInterpreter
                var super_id = sup.mclass.vtable.id
                var mask = sub.mclass.vtable.mask
 
-               return inter_is_subtype(super_id, mask, sub.mclass.vtable.internal_vtable)
+               # For now, we always use perfect hashing for subtyping test
+               return inter_is_subtype_ph(super_id, mask, sub.mclass.vtable.internal_vtable)
        end
 
        # Subtyping test with perfect hashing
-       private fun inter_is_subtype(id: Int, mask:Int, vtable: Pointer): Bool `{
+       private fun inter_is_subtype_ph(id: Int, mask:Int, vtable: Pointer): Bool `{
                // hv is the position in hashtable
                int hv = id & mask;
 
@@ -138,6 +139,14 @@ class VirtualMachine super NaiveInterpreter
                return *offset == id;
        `}
 
+       # Subtyping test with Cohen test (direct access)
+       private fun inter_is_subtype_sst(id: Int, position: Int, vtable: Pointer): Bool `{
+               // Direct access to the position given in parameter
+               int tableid = (long unsigned int)((long int *)vtable)[position];
+
+               return id == tableid;
+       `}
+
        # Redef init_instance to simulate the loading of a class
        redef fun init_instance(recv: Instance)
        do
@@ -195,17 +204,21 @@ class VirtualMachine super NaiveInterpreter
                var ret = send_commons(mproperty, args, mtype)
                if ret != null then return ret
 
-               var propdef = method_dispatch(mproperty, recv.vtable.as(not null))
+               var propdef = method_dispatch(mproperty, recv.vtable.as(not null), recv)
 
                return self.call(propdef, args)
        end
 
        # Method dispatch, for a given global method `mproperty`
        # returns the most specific local method in the class corresponding to `vtable`
-       private fun method_dispatch(mproperty: MMethod, vtable: VTable): MMethodDef
+       private fun method_dispatch(mproperty: MMethod, vtable: VTable, recv: Instance): MMethodDef
        do
-               return method_dispatch_ph(vtable.internal_vtable, vtable.mask,
+               if mproperty.intro_mclassdef.mclass.positions_methods[recv.mtype.as(MClassType).mclass] != -1 then
+                       return method_dispatch_sst(vtable.internal_vtable, mproperty.absolute_offset)
+               else
+                       return method_dispatch_ph(vtable.internal_vtable, vtable.mask,
                                mproperty.intro_mclassdef.mclass.vtable.id, mproperty.offset)
+               end
        end
 
        # Execute a method dispatch with perfect hashing
@@ -221,6 +234,17 @@ class VirtualMachine super NaiveInterpreter
                return propdef;
        `}
 
+       # Execute a method dispatch with direct access and return the appropriate `MMethodDef`
+       # `vtable` : Pointer to the internal pointer of the class
+       # `absolute_offset` : Absolute offset from the beginning of the virtual table
+       private fun method_dispatch_sst(vtable: Pointer, absolute_offset: Int): MMethodDef `{
+               // pointer+2 is the position where methods are
+               // Add the offset of property and get the method implementation
+               MMethodDef propdef = (MMethodDef)((long int *)vtable)[absolute_offset];
+
+               return propdef;
+       `}
+
        # Return the value of the attribute `mproperty` for the object `recv`
        redef fun read_attribute(mproperty: MAttribute, recv: Instance): Instance
        do
@@ -349,6 +373,10 @@ redef class MClass
        # True when the class is effectively loaded by the vm, false otherwise
        var loaded: Bool = false
 
+       # Color for Cohen subtyping test : the absolute position of the id
+       # of this class in virtual tables
+       var color: Int
+
        # For each loaded subclass, keep the position of the group of attributes
        # introduced by self class in the object
        var positions_attributes: HashMap[MClass, Int] = new HashMap[MClass, Int]
@@ -373,8 +401,11 @@ redef class MClass
 
                # Absolute offset of attribute from the beginning of the attributes table
                var offset_attributes = 0
-               # Absolute offset of method from the beginning of the methods table
-               var offset_methods = 0
+
+               # Absolute offset of method from the beginning of the methods table,
+               # is initialize to 3 because the first position is empty in the virtual table
+               # and the second and third are respectively class id and delta
+               var offset_methods = 3
 
                # The previous element in `superclasses`
                var previous_parent: nullable MClass = null
@@ -408,12 +439,16 @@ redef class MClass
 
                        offset_attributes += attributes
                        offset_methods += methods
+                       offset_methods += 2 # Because each block starts with an id and the delta
                end
 
                # When all super-classes have their identifiers and vtables, allocate current one
                allocate_vtable(v, ids, nb_methods, nb_attributes, offset_attributes, offset_methods)
                loaded = true
 
+               # Set the absolute position of the identifier of this class in the virtual table
+               color = offset_methods - 2
+
                # The virtual table now needs to be filled with pointer to methods
                superclasses.add(self)
                for cl in superclasses do
@@ -520,7 +555,9 @@ redef class MClass
        private fun superclasses_ordering(v: VirtualMachine): Array[MClass]
        do
                var superclasses = new Array[MClass]
-               superclasses.add_all(ancestors)
+
+               # Add all superclasses of `self`
+               superclasses.add_all(self.in_hierarchy(v.mainmodule).greaters)
 
                var res = new Array[MClass]
                if superclasses.length > 1 then