nitvm: Optimize attribute access and subtyping test by orienting between implementati...
authorJulien Pagès <julien.projet@gmail.com>
Fri, 23 Jan 2015 09:52:13 +0000 (10:52 +0100)
committerJulien Pagès <julien.projet@gmail.com>
Wed, 28 Jan 2015 11:08:04 +0000 (12:08 +0100)
Signed-off-by: Julien Pagès <julien.projet@gmail.com>

src/nit.nit
src/nitvm.nit
src/vm_optimizations.nit [new file with mode: 0644]

index 5a74d48..8be9ae2 100644 (file)
@@ -21,6 +21,7 @@ import interpreter
 import frontend
 import parser_util
 import vm
 import frontend
 import parser_util
 import vm
+import vm_optimizations
 
 # Create a tool context to handle options and paths
 var toolcontext = new ToolContext
 
 # Create a tool context to handle options and paths
 var toolcontext = new ToolContext
index 088cd92..5e5dde3 100644 (file)
@@ -18,6 +18,7 @@
 module nitvm
 
 import vm
 module nitvm
 
 import vm
+import vm_optimizations
 import frontend
 
 # Create a tool context to handle options and paths
 import frontend
 
 # Create a tool context to handle options and paths
diff --git a/src/vm_optimizations.nit b/src/vm_optimizations.nit
new file mode 100644 (file)
index 0000000..a906a6f
--- /dev/null
@@ -0,0 +1,289 @@
+# 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