+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Optimization of the nitvm
+module vm_optimizations
+
+import vm
+
+redef class AAttrFormExpr
+ # Position of the attribute in attribute table
+ #
+ # The relative position of this attribute if perfect hashing is used,
+ # The absolute position of this attribute if SST is used
+ var offset: Int
+
+ # Indicate the status of the optimization for this node
+ #
+ # 0: default value
+ # 1: SST (direct access) can be used
+ # 2: PH (multiple inheritance implementation) must be used
+ var status: Int = 0
+
+ # Identifier of the class which introduced the attribute
+ var id: Int
+
+ # Optimize this attribute access
+ # * `mproperty` The attribute which is accessed
+ # * `recv` The receiver (The object) of the access
+ protected fun optimize(mproperty: MAttribute, recv: MutableInstance)
+ do
+ if mproperty.intro_mclassdef.mclass.positions_attributes[recv.mtype.as(MClassType).mclass] != -1 then
+ # if this attribute class has an unique position for this receiver, then use direct access
+ offset = mproperty.absolute_offset
+ status = 1
+ else
+ # Otherwise, perfect hashing must be used
+ id = mproperty.intro_mclassdef.mclass.vtable.id
+ offset = mproperty.offset
+ status = 2
+ end
+ end
+end
+
+redef class AAttrExpr
+ redef fun expr(v)
+ do
+ # TODO : a workaround for now
+ if not v isa VirtualMachine then return super
+
+ var recv = v.expr(self.n_expr)
+ if recv == null then return null
+ if recv.mtype isa MNullType then fatal(v, "Receiver is null")
+ var mproperty = self.mproperty.as(not null)
+
+ assert recv isa MutableInstance
+ if status == 0 then optimize(mproperty, recv)
+
+ var i: Instance
+ if status == 1 then
+ # SST
+ i = v.read_attribute_sst(recv.internal_attributes, offset)
+ else
+ # PH
+ i = v.read_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable, recv.vtable.mask, id, offset)
+ end
+
+ # If we get a `MInit` value, throw an error
+ if i == v.initialization_value then
+ v.fatal("Uninitialized attribute {mproperty.name}")
+ abort
+ end
+
+ return i
+ end
+end
+
+redef class AAttrAssignExpr
+ redef fun stmt(v)
+ do
+ # TODO : a workaround for now
+ if not v isa VirtualMachine then
+ super
+ return
+ end
+
+ var recv = v.expr(self.n_expr)
+ if recv == null then return
+ if recv.mtype isa MNullType then fatal(v, "Receiver is null")
+ var i = v.expr(self.n_value)
+ if i == null then return
+ var mproperty = self.mproperty.as(not null)
+
+ assert recv isa MutableInstance
+ if status == 0 then optimize(mproperty, recv)
+
+ if status == 1 then
+ v.write_attribute_sst(recv.internal_attributes, offset, i)
+ else
+ v.write_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
+ recv.vtable.mask, id, offset, i)
+ end
+ end
+end
+
+# Add informations to optimize some method calls
+redef class CallSite
+ # Position of the method in virtual table
+ #
+ # The relative position of this MMethod if perfect hashing is used,
+ # The absolute position of this MMethod if SST is used
+ var offset: Int
+
+ # Indicate the status of the optimization for this node
+ #
+ # 0: default value
+ # 1: SST (direct access) can be used
+ # 2: PH (multiple inheritance implementation) must be used
+ var status: Int = 0
+
+ # Identifier of the class which introduced the MMethod
+ var id: Int
+
+ # Optimize a method dispatch
+ fun optimize(recv: Instance)
+ do
+ if mproperty.intro_mclassdef.mclass.positions_methods[recv.mtype.as(MClassType).mclass] != -1 then
+ offset = mproperty.absolute_offset
+ status = 1
+ else
+ offset = mproperty.offset
+ status = 2
+ end
+ id = mproperty.intro_mclassdef.mclass.vtable.id
+ end
+end
+
+redef class AIsaExpr
+ # Identifier of the target class type
+ var id: Int
+
+ # If the Cohen test is used, the position of the target id in vtable
+ var position: Int
+
+ # Indicate the status of the optimization for this node
+ #
+ # 0 : the default value
+ # 1 : this test can be implemented with direct access
+ # 2 : this test must be implemented with perfect hashing
+ var status: Int = 0
+
+ redef fun expr(v)
+ do
+ # TODO : a workaround for now
+ if not v isa VirtualMachine then return super
+
+ var recv = v.expr(self.n_expr)
+ if recv == null then return null
+
+ if status == 0 then optimize(v, recv.mtype, self.cast_type.as(not null))
+ var mtype = v.unanchor_type(self.cast_type.as(not null))
+
+ # If this test can be optimized, directly call appropriate subtyping methods
+ if status == 1 and recv.mtype isa MClassType then
+ # Direct access
+ return v.bool_instance(v.inter_is_subtype_sst(id, position, recv.mtype.as(MClassType).mclass.vtable.internal_vtable))
+ else if status == 2 and recv.mtype isa MClassType then
+ # Perfect hashing
+ return v.bool_instance(v.inter_is_subtype_ph(id, recv.vtable.mask, recv.mtype.as(MClassType).mclass.vtable.internal_vtable))
+ else
+ # Use the slow path (default)
+ return v.bool_instance(v.is_subtype(recv.mtype, mtype))
+ end
+ end
+
+ # Optimize a `AIsaExpr`
+ # `source` the source type of the expression
+ # `target` the target type of the subtyping test
+ private fun optimize(v: VirtualMachine, source: MType, target: MType)
+ do
+ # If the source class and target class are not classic classes (non-generics) then return
+ if not source isa MClassType or not target isa MClassType or target isa MGenericType then
+ return
+ end
+
+ if not target.mclass.loaded then return
+
+ # Try to get the position of the target type in source's structures
+ var value = source.mclass.positions_methods.get_or_null(target.mclass)
+
+ if value != null then
+ if value != -1 then
+ # Store informations for Cohen test
+ position = target.mclass.color
+ status = 1
+ else
+ # We use perfect hashing
+ status = 2
+ end
+ end
+ id = target.mclass.vtable.id
+ end
+end
+
+redef class AAsCastExpr
+ # Identifier of the target class type
+ var id: Int
+
+ # If the Cohen test is used, the position of the target id in vtable
+ var position: Int
+
+ # Indicate the status of the optimization for this node
+ #
+ # 0 : the default value
+ # 1 : this test can be implemented with direct access
+ # 2 : this test must be implemented with perfect hashing
+ var status: Int = 0
+
+ redef fun expr(v)
+ do
+ # TODO : a workaround for now
+ if not v isa VirtualMachine then return super
+
+ var recv = v.expr(self.n_expr)
+ if recv == null then return null
+
+ if status == 0 then optimize(v, recv.mtype, self.mtype.as(not null))
+
+ var mtype = self.mtype.as(not null)
+ var amtype = v.unanchor_type(mtype)
+
+ var res: Bool
+ if status == 1 and recv.mtype isa MClassType then
+ # Direct access
+ res = v.inter_is_subtype_sst(id, position, recv.mtype.as(MClassType).mclass.vtable.internal_vtable)
+ else if status == 2 and recv.mtype isa MClassType then
+ # Perfect hashing
+ res = v.inter_is_subtype_ph(id, recv.vtable.mask, recv.mtype.as(MClassType).mclass.vtable.internal_vtable)
+ else
+ # Use the slow path (default)
+ res = v.is_subtype(recv.mtype, amtype)
+ end
+
+ if not res then
+ fatal(v, "Cast failed. Expected `{amtype}`, got `{recv.mtype}`")
+ end
+ return recv
+ end
+
+ # Optimize a `AAsCastExpr`
+ # * `source` the source type of the expression
+ # * `target` the target type of the subtyping test
+ private fun optimize(v: VirtualMachine, source: MType, target: MType)
+ do
+ # If the source class and target class are not classic classes (non-generics) then return
+ if not source isa MClassType or not target isa MClassType or target isa MGenericType then
+ return
+ end
+
+ if not target.mclass.loaded then return
+
+ # Try to get the position of the target type in source's structures
+ var value = source.mclass.positions_methods.get_or_null(target.mclass)
+
+ if value != null then
+ if value != -1 then
+ # Store informations for Cohen test
+ position = target.mclass.color
+ status = 1
+ else
+ # We use perfect hashing
+ status = 2
+ end
+ end
+ id = target.mclass.vtable.id
+ end
+end
\ No newline at end of file