assert sup isa MClassType
- # `sub` and `sup` can be discovered inside a Generic type during the subtyping test
- if not sup.mclass.loaded then load_class(sup.mclass)
+ # and `sup` can be discovered inside a Generic type during the subtyping test
if not sub.mclass.loaded then load_class(sub.mclass)
+ # If the target of the test is not-loaded yet, the subtyping-test will be false
+ if not sup.mclass.abstract_loaded then return false
+
# For now, always use perfect hashing for subtyping test
var super_id = sup.mclass.vtable.id
var mask = sub.mclass.vtable.mask
var res = inter_is_subtype_ph(super_id, mask, sub.mclass.vtable.internal_vtable)
- if res == false then return false
+ if not res then return false
# sub and sup can be generic types, each argument of generics has to be tested
if not sup isa MGenericType then return true
var sub_arg = sub2.arguments[i]
var sup_arg = sup.arguments[i]
var res2 = is_subtype(sub_arg, sup_arg)
- if res2 == false then return false
+ if not res2 then return false
end
return true
end
return attributes;
`}
- # Load the class and create its runtime structures
+ # Load the class and create its runtime structures, this loading is explicit
fun load_class(mclass: MClass)
do
if mclass.loaded then return
- # Recursively load superclasses
- for parent in mclass.in_hierarchy(mainmodule).direct_greaters do load_class(parent)
+ load_supers(mclass)
+
+ if mclass.abstract_loaded then
+ mclass.allocate_vtable(self)
+ else
+ mclass.make_vt(self, true)
+ end
+ end
+
+ # Recursively load superclasses.
+ private fun load_supers(mclass: MClass)
+ do
+ for parent in mclass.in_hierarchy(mainmodule).direct_greaters do
+ load_class_indirect(parent)
+ end
+ end
+
+ # This method is called to handle an implicitly loaded class,
+ # i.e. a superclass of an explicitly loaded class
+ # A class loaded implicitly will not be fully allocated
+ fun load_class_indirect(mclass: MClass)
+ do
+ # It the class was already implicitly loaded
+ if mclass.abstract_loaded then return
+
+ load_supers(mclass)
- mclass.make_vt(self)
+ mclass.make_vt(self, false)
end
# Execute `mproperty` for a `args` (where `args[0]` is the receiver).
# True when the class is effectively loaded by the vm, false otherwise
var loaded: Bool = false
+ # Indicate this class was partially loaded (it only has its identifier allocated)
+ var abstract_loaded: Bool = false
+
# Color for Cohen subtyping test : the absolute position of the id
# of this class in virtual tables
var color: Int
var mmethods = new Array[MMethod]
# Allocates a VTable for this class and gives it an id
- private fun make_vt(vm: VirtualMachine)
+ # * `vm` The currently executed VirtualMachine
+ # * `explicit` Indicate if this class was directly instantiated (i.e. not indirectly loaded)
+ private fun make_vt(vm: VirtualMachine, explicit: Bool)
do
# `ordering` contains the order of superclasses for virtual tables
ordering = superclasses_ordering(vm)
ordering.remove(self)
- # Make_vt for super-classes
var ids = new Array[Int]
var nb_methods = new Array[Int]
var nb_attributes = new Array[Int]
offset_methods += 2 # Because each block starts with an id and the delta
end
- # Recopy the position tables of the prefix in `self`
- for key, value in prefix.positions_methods do
- positions_methods[key] = value
- end
+ # Update the positions of the class
+ update_positions(offset_attributes, offset_methods)
- for key, value in prefix.positions_attributes do
- positions_attributes[key] = value
- end
+ ordering.add(self)
- # When all super-classes have their identifiers and vtables, allocate current one
- allocate_vtable(vm, ids, nb_methods, nb_attributes, offset_attributes, offset_methods)
- loaded = true
+ # Compute the identifier with Perfect Hashing
+ compute_identifier(vm, ids, offset_methods)
- # The virtual table now needs to be filled with pointer to methods
- ordering.add(self)
- for cl in ordering do
- fill_vtable(vm, vtable.as(not null), cl)
+ # Update caches and offsets of methods and attributes for this class
+ # If the loading was explicit, the virtual table will be allocated and filled
+ set_offsets(vm, explicit)
+
+ if not explicit then
+ # Just init the C-pointer to NULL to avoid errors
+ vtable.internal_vtable = vm.memory_manager.null_ptr
end
end
- # Allocate a single vtable
- # * `ids : Array of superclasses identifiers
- # * `nb_methods : Array which contain the number of introduced methods for each class in ids
- # * `nb_attributes : Array which contain the number of introduced attributes for each class in ids
- # * `offset_attributes : Offset from the beginning of the table of the group of attributes
+ # Allocate a unique identifier to the class with perfect hashing
+ # * `vm` The currently executed VirtualMachine
+ # * `ids` Array of superclasses identifiers
# * `offset_methods : Offset from the beginning of the table of the group of methods
- private fun allocate_vtable(v: VirtualMachine, ids: Array[Int], nb_methods: Array[Int], nb_attributes: Array[Int],
- offset_attributes: Int, offset_methods: Int)
+ private fun compute_identifier(vm: VirtualMachine, ids: Array[Int], offset_methods: Int)
do
vtable = new VTable
var idc = new Array[Int]
- vtable.mask = v.ph.pnand(ids, 1, idc) - 1
+ # Give an identifier to the class and put it inside the virtual table
+ vtable.mask = vm.ph.pnand(ids, 1, idc) - 1
vtable.id = idc[0]
vtable.classname = name
- # Add current id to Array of super-ids
- var ids_total = new Array[Int]
- ids_total.add_all(ids)
- ids_total.push(vtable.id)
+ # Set the color for subtyping tests in SST of this class
+ color = offset_methods - 2
- var nb_methods_total = new Array[Int]
- var nb_attributes_total = new Array[Int]
+ # Indicate the class has its identifier computed
+ abstract_loaded = true
+ end
- var self_methods = 0
- var nb_introduced_attributes = 0
+ # Update the positions of this class
+ # * `offset_attributes` The offset of the block of attributes of this class
+ # * `offset_methods` The offset of the block of methods of this class
+ private fun update_positions(offset_attributes: Int, offset_methods: Int)
+ do
+ # Recopy the position tables of the prefix in `self`
+ for key, value in prefix.positions_methods do
+ positions_methods[key] = value
+ end
+ for key, value in prefix.positions_attributes do
+ positions_attributes[key] = value
+ end
+
+ # Save the offsets of self class
+ position_attributes = offset_attributes
+ position_methods = offset_methods
+ end
+
+ # Set the offsets for the properties introduced by `self` class
+ # * `vm` The currently executed VirtualMachine
+ # * `explicit` Indicate if this class was explicitly loaded
+ private fun set_offsets(vm: VirtualMachine, explicit: Bool)
+ do
# Fixing offsets for self attributes and methods
var relative_offset_attr = 0
var relative_offset_meth = 0
for p in classdef.intro_mproperties do
# Collect properties and fixing offsets
if p isa MMethod then
- self_methods += 1
p.offset = relative_offset_meth
relative_offset_meth += 1
intro_mmethods.add(p)
end
if p isa MAttribute then
- nb_introduced_attributes += 1
p.offset = relative_offset_attr
relative_offset_attr += 1
mattributes.add_all(intro_mattributes)
mmethods.add_all(intro_mmethods)
- nb_methods_total.add_all(nb_methods)
- nb_methods_total.push(self_methods)
-
- nb_attributes_total.add_all(nb_attributes)
- nb_attributes_total.push(nb_introduced_attributes)
+ if explicit then allocate_vtable(vm)
+ end
- # Set the color for subtyping test of this class
- color = offset_methods - 2
+ # Allocate a single vtable
+ # * `vm` The currently executed VirtualMachine
+ private fun allocate_vtable(vm: VirtualMachine)
+ do
+ var ids = new Array[Int]
+ var nb_methods_total = new Array[Int]
+ var nb_attributes_total = new Array[Int]
- # Save the offsets of self class
- position_attributes = offset_attributes
- position_methods = offset_methods
+ for cl in ordering do
+ ids.add(cl.vtable.id)
+ nb_methods_total.add(cl.intro_mmethods.length)
+ nb_attributes_total.add(cl.intro_mattributes.length)
+ end
- # Since we have the number of attributes for each class, calculate the delta
+ # Calculate the delta to prepare object structure
var deltas = calculate_delta(nb_attributes_total)
- vtable.internal_vtable = v.memory_manager.init_vtable(ids_total, nb_methods_total, deltas, vtable.mask)
+ vtable.internal_vtable = vm.memory_manager.init_vtable(ids, nb_methods_total, deltas, vtable.mask)
+
+ # The virtual table now needs to be filled with pointer to methods
+ for cl in ordering do
+ fill_vtable(vm, vtable.as(not null), cl)
+ end
+
+ loaded = true
end
# Fill the vtable with local methods for `self` class
var super_id = current_class.vtable.id
var mask = sub.vtable.mask
+ vm.load_class(sub)
if vm.inter_is_subtype_ph(super_id, mask, sub.vtable.internal_vtable) then
if not sub.positions_methods.has_key(current_class) then
var super_id = current_class.vtable.id
var mask = sub.vtable.mask
+ vm.load_class(sub)
if vm.inter_is_subtype_ph(super_id, mask, sub.vtable.internal_vtable) then
if not sub.positions_methods.has_key(current_class) then
MMethodDef_incr_ref(method);
}
`}
+
+ # Return a NULL pointer, used to initialize virtual tables
+ private fun null_ptr: Pointer `{
+ return NULL;
+ `}
end