self.mainmodule = mainmodule
self.arguments = arguments
self.true_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, true)
+ init_instance_primitive(self.true_instance)
self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
+ init_instance_primitive(self.false_instance)
self.null_instance = new MutableInstance(mainmodule.model.null_type)
end
# Return the integer instance associated with `val`.
fun int_instance(val: Int): Instance
do
- var ic = self.mainmodule.get_primitive_class("Int")
- return new PrimitiveInstance[Int](ic.mclass_type, val)
+ var ic = get_primitive_class("Int")
+ var instance = new PrimitiveInstance[Int](ic.mclass_type, val)
+ init_instance_primitive(instance)
+ return instance
end
# Return the char instance associated with `val`.
fun char_instance(val: Char): Instance
do
- var ic = self.mainmodule.get_primitive_class("Char")
- return new PrimitiveInstance[Char](ic.mclass_type, val)
+ var ic = get_primitive_class("Char")
+ var instance = new PrimitiveInstance[Char](ic.mclass_type, val)
+ init_instance_primitive(instance)
+ return instance
end
# Return the float instance associated with `val`.
fun float_instance(val: Float): Instance
do
- var ic = self.mainmodule.get_primitive_class("Float")
- return new PrimitiveInstance[Float](ic.mclass_type, val)
+ var ic = get_primitive_class("Float")
+ var instance = new PrimitiveInstance[Float](ic.mclass_type, val)
+ init_instance_primitive(instance)
+ return instance
end
# The unique intance of the `true` value.
fun array_instance(values: Array[Instance], elttype: MType): Instance
do
assert not elttype.need_anchor
- var nat = new PrimitiveInstance[Array[Instance]](self.mainmodule.get_primitive_class("NativeArray").get_mtype([elttype]), values)
- var mtype = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
+ var nat = new PrimitiveInstance[Array[Instance]](get_primitive_class("NativeArray").get_mtype([elttype]), values)
+ init_instance_primitive(nat)
+ var mtype = get_primitive_class("Array").get_mtype([elttype])
var res = new MutableInstance(mtype)
self.init_instance(res)
self.send(self.force_get_primitive_method("with_native", mtype), [res, nat, self.int_instance(values.length)])
do
var val = new FlatBuffer.from(txt)
val.add('\0')
- var ic = self.mainmodule.get_primitive_class("NativeString")
- return new PrimitiveInstance[Buffer](ic.mclass_type, val)
+ var ic = get_primitive_class("NativeString")
+ var instance = new PrimitiveInstance[Buffer](ic.mclass_type, val)
+ init_instance_primitive(instance)
+ return instance
end
# The current frame used to store local variables of the current method executed
end
end
+ # A hook to initialize a `PrimitiveInstance`
+ fun init_instance_primitive(recv: Instance) do end
+
+ # Return the primitive `MClass` corresponding to the `name` given in parameter
+ # `name` : name of the primitive class
+ fun get_primitive_class(name: String): MClass
+ do
+ return mainmodule.get_primitive_class(name)
+ end
+
# This function determine the correct type according the reciever of the current definition (self).
fun unanchor_type(mtype: MType): MType
do
else if cname == "NativeArray" then
if pname == "init" then
var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
- return new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
+ var instance = new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
+ v.init_instance_primitive(instance)
+ return instance
end
var recvval = args.first.val.as(Array[Instance])
if pname == "[]" then
end
else if cname == "NativeFile" then
if pname == "native_stdout" then
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+ var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "native_stdin" then
- return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+ var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "native_stderr" then
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+ var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "io_open_read" then
var a1 = args[1].val.as(Buffer)
- return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+ var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "io_open_write" then
var a1 = args[1].val.as(Buffer)
- return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+ var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+ v.init_instance_primitive(instance)
+ return instance
end
var recvval = args.first.val
if pname == "io_write" then
else if pname == "calloc_array" then
var recvtype = args.first.mtype.as(MClassType)
var mtype: MType
- mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.mainmodule.get_primitive_class("ArrayCapable"))
+ mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.get_primitive_class("ArrayCapable"))
mtype = mtype.arguments.first
var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
- return new PrimitiveInstance[Array[Instance]](v.mainmodule.get_primitive_class("NativeArray").get_mtype([mtype]), val)
+ var instance = new PrimitiveInstance[Array[Instance]](v.get_primitive_class("NativeArray").get_mtype([mtype]), val)
+ v.init_instance_primitive(instance)
+ return instance
else if pname == "native_argc" then
return v.int_instance(v.arguments.length)
else if pname == "native_argv" then
if i == null then return null
array.add(i)
end
- var i = v.array_instance(array, v.mainmodule.get_primitive_class("Object").mclass_type)
+ var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
assert res != null
return res
init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String])
do
- super
var init_type = new MInitType(mainmodule.model)
initialization_value = new MutableInstance(init_type)
+ super
end
# Subtyping test for the virtual machine
recv.vtable = recv.mtype.as(MClassType).mclass.vtable
- assert(recv isa MutableInstance)
+ assert recv isa MutableInstance
recv.internal_attributes = init_internal_attributes(initialization_value, recv.mtype.as(MClassType).mclass.all_mattributes(mainmodule, none_visibility).length)
super
end
+ # Associate a `PrimitiveInstance` to its `VTable`
+ redef fun init_instance_primitive(recv: Instance)
+ do
+ if not recv.mtype.as(MClassType).mclass.loaded then create_class(recv.mtype.as(MClassType).mclass)
+
+ recv.vtable = recv.mtype.as(MClassType).mclass.vtable
+ end
+
+ # Create a virtual table for this `MClass` if not already done
+ redef fun get_primitive_class(name: String): MClass
+ do
+ var mclass = super
+
+ if not mclass.loaded then create_class(mclass)
+
+ return mclass
+ end
+
# Initialize the internal representation of an object (its attribute values)
# `init_instance` is the initial value of attributes
private fun init_internal_attributes(init_instance: Instance, size: Int): Pointer
# Creates the runtime structures for this class
fun create_class(mclass: MClass) do mclass.make_vt(self)
+ # Execute `mproperty` for a `args` (where `args[0]` is the receiver).
+ redef fun send(mproperty: MMethod, args: Array[Instance]): nullable Instance
+ do
+ var recv = args.first
+ var mtype = recv.mtype
+ var ret = send_commons(mproperty, args, mtype)
+ if ret != null then return ret
+
+ var propdef = method_dispatch(mproperty, recv.vtable.as(not null))
+
+ 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
+ do
+ return method_dispatch_ph(vtable.internal_vtable, vtable.mask,
+ mproperty.intro_mclassdef.mclass.vtable.id, mproperty.offset)
+ end
+
+ # Execute a method dispatch with perfect hashing
+ private fun method_dispatch_ph(vtable: Pointer, mask: Int, id: Int, offset: Int): MMethodDef `{
+ // Perfect hashing position
+ int hv = mask & id;
+ long unsigned int *pointer = (long unsigned int*)(((long int *)vtable)[-hv]);
+
+ // pointer+2 is the position where methods are
+ // Add the offset of property and get the method implementation
+ MMethodDef propdef = (MMethodDef)*(pointer + 2 + offset);
+
+ return propdef;
+ `}
+
# Return the value of the attribute `mproperty` for the object `recv`
redef fun read_attribute(mproperty: MAttribute, recv: Instance): Instance
do
# 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
+
# The virtual table now needs to be filled with pointer to methods
+ superclasses.add(self)
+ for cl in superclasses do
+ fill_vtable(v, vtable.as(not null), cl)
+ end
end
# Allocate a single vtable
var self_methods = 0
var nb_introduced_attributes = 0
- # For self attributes, fixing offsets
- var relative_offset = 0
+ # Fixing offsets for self attributes and methods
+ var relative_offset_attr = 0
+ var relative_offset_meth = 0
for p in intro_mproperties(none_visibility) do
- if p isa MMethod then self_methods += 1
+ if p isa MMethod then
+ self_methods += 1
+ p.offset = relative_offset_meth
+ relative_offset_meth += 1
+ end
if p isa MAttribute then
nb_introduced_attributes += 1
- p.offset = relative_offset
- relative_offset += 1
+ p.offset = relative_offset_attr
+ relative_offset_attr += 1
end
end
vtable.internal_vtable = v.memory_manager.init_vtable(ids_total, nb_methods_total, d, vtable.mask)
end
+ # Fill the vtable with methods of `self` class
+ # `v` : Current instance of the VirtualMachine
+ # `table` : the table of self class, will be filled with its methods
+ private fun fill_vtable(v:VirtualMachine, table: VTable, cl: MClass)
+ do
+ var methods = new Array[MMethodDef]
+ for m in cl.intro_mproperties(none_visibility) do
+ if m isa MMethod then
+ # `propdef` is the most specific implementation for this MMethod
+ var propdef = m.lookup_first_definition(v.mainmodule, self.intro.bound_mtype)
+ methods.push(propdef)
+ end
+ end
+
+ # Call a method in C to put propdefs of self methods in the vtables
+ v.memory_manager.put_methods(vtable.internal_vtable, vtable.mask, cl.vtable.id, methods)
+ end
+
# Computes delta for each class
# A delta represents the offset for this group of attributes in the object
# `nb_attributes` : number of attributes for each class (classes are linearized from Object to current)
var offset: Int
end
+redef class MMethod
+ # Represents the relative offset of this attribute in the runtime instance
+ var offset: Int
+end
+
# Redef MutableInstance to improve implementation of attributes in objects
redef class MutableInstance
var internal_attributes: Pointer
end
+# Redef to associate an `Instance` to its `VTable`
+redef class Instance
+ var vtable: nullable VTable
+end
+
# Is the type of the initial value inside attributes
class MInitType
super MType
var classname: String is noinit
end
-redef class Instance
- var vtable: nullable VTable
-end
-
# Handle memory, used for allocate virtual table and associated structures
class MemoryManager
return vtable;
`}
+
+ # Put implementation of methods of a class in `vtable`
+ # `vtable` : Pointer to the C-virtual table
+ # `mask` : perfect-hashing mask of the class corresponding to the vtable
+ # `id` : id of the target class
+ # `methods` : array of MMethodDef of the target class
+ fun put_methods(vtable: Pointer, mask: Int, id: Int, methods: Array[MMethodDef])
+ import Array[MMethodDef].length, Array[MMethodDef].[] `{
+
+ // Get the area to fill with methods by a sequence of perfect hashing
+ int hv = mask & id;
+ long unsigned int *pointer = (long unsigned int*)(((long unsigned int *)vtable)[-hv]);
+
+ // pointer+2 is the beginning of the area for methods implementation
+ int length = Array_of_MMethodDef_length(methods);
+ long unsigned int *area = (pointer + 2);
+ int i;
+
+ for(i=0; i<length; i++)
+ {
+ MMethodDef method = Array_of_MMethodDef__index(methods, i);
+ area[i] = (long unsigned int)method;
+ MMethodDef_incr_ref(method);
+ }
+ `}
end