1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Optimization of the nitvm
18 module vm_optimizations
20 import virtual_machine
22 redef class VirtualMachine
24 # Add optimization of the method dispatch
25 redef fun callsite
(callsite
: nullable CallSite, arguments
: Array[Instance]): nullable Instance
27 return send_optimize
(callsite
.as(not null), arguments
)
30 # Try to have the most efficient implementation of the method dispatch
31 fun send_optimize
(callsite
: CallSite, args
: Array[Instance]): nullable Instance
34 var mtype
= recv
.mtype
35 var ret
= send_commons
(callsite
.mproperty
, args
, mtype
)
36 if ret
!= null then return ret
38 if callsite
.status
== 0 then callsite
.optimize
(recv
)
41 if callsite
.status
== 1 then
42 propdef
= method_dispatch_sst
(recv
.vtable
.internal_vtable
, callsite
.offset
)
44 propdef
= method_dispatch_ph
(recv
.vtable
.internal_vtable
, recv
.vtable
.mask
,
45 callsite
.id
, callsite
.offset
)
48 #TODO : we need recompilations here
50 return self.call
(propdef
, args
)
54 redef class AAttrFormExpr
55 # Position of the attribute in attribute table
57 # The relative position of this attribute if perfect hashing is used,
58 # The absolute position of this attribute if SST is used
61 # Indicate the status of the optimization for this node
64 # 1: SST (direct access) can be used
65 # 2: PH (multiple inheritance implementation) must be used
68 # Identifier of the class which introduced the attribute
71 # Optimize this attribute access
72 # * `mproperty` The attribute which is accessed
73 # * `recv` The receiver (The object) of the access
74 protected fun optimize
(mproperty
: MAttribute, recv
: MutableInstance)
76 var position
= recv
.mtype
.as(MClassType).mclass
.get_position_attributes
(mproperty
.intro_mclassdef
.mclass
)
78 # if this attribute class has an unique position for this receiver, then use direct access
79 offset
= position
+ mproperty
.offset
82 # Otherwise, perfect hashing must be used
83 id
= mproperty
.intro_mclassdef
.mclass
.vtable
.id
84 offset
= mproperty
.offset
93 # TODO : a workaround for now
94 if not v
isa VirtualMachine then return super
96 var recv
= v
.expr
(self.n_expr
)
97 if recv
== null then return null
98 if recv
.mtype
isa MNullType then fatal
(v
, "Receiver is null")
99 var mproperty
= self.mproperty
.as(not null)
101 assert recv
isa MutableInstance
102 if status
== 0 then optimize
(mproperty
, recv
)
107 i
= v
.read_attribute_sst
(recv
.internal_attributes
, offset
)
110 i
= v
.read_attribute_ph
(recv
.internal_attributes
, recv
.vtable
.internal_vtable
, recv
.vtable
.mask
, id
, offset
)
113 # If we get a `MInit` value, throw an error
114 if i
== v
.initialization_value
then
115 v
.fatal
("Uninitialized attribute {mproperty.name}")
119 #TODO : we need recompilations here
126 redef class AAttrAssignExpr
129 # TODO : a workaround for now
130 if not v
isa VirtualMachine then
135 var recv
= v
.expr
(self.n_expr
)
136 if recv
== null then return
137 if recv
.mtype
isa MNullType then fatal
(v
, "Receiver is null")
138 var i
= v
.expr
(self.n_value
)
139 if i
== null then return
140 var mproperty
= self.mproperty
.as(not null)
142 assert recv
isa MutableInstance
143 if status
== 0 then optimize
(mproperty
, recv
)
146 v
.write_attribute_sst
(recv
.internal_attributes
, offset
, i
)
148 v
.write_attribute_ph
(recv
.internal_attributes
, recv
.vtable
.internal_vtable
,
149 recv
.vtable
.mask
, id
, offset
, i
)
152 #TODO : we need recompilations here
157 # Add informations to optimize some method calls
159 # Position of the method in virtual table
161 # The relative position of this MMethod if perfect hashing is used,
162 # The absolute position of this MMethod if SST is used
165 # Indicate the status of the optimization for this node
168 # 1: SST (direct access) can be used
169 # 2: PH (multiple inheritance implementation) must be used
172 # Identifier of the class which introduced the MMethod
175 # Optimize a method dispatch,
176 # If this method is always at the same position in virtual table, we can use direct access,
177 # Otherwise we must use perfect hashing
178 fun optimize
(recv
: Instance)
180 var position
= recv
.mtype
.as(MClassType).mclass
.get_position_methods
(mproperty
.intro_mclassdef
.mclass
)
182 offset
= position
+ mproperty
.offset
185 offset
= mproperty
.offset
188 id
= mproperty
.intro_mclassdef
.mclass
.vtable
.id
193 # Identifier of the target class type
196 # If the Cohen test is used, the position of the target id in vtable
199 # Indicate the status of the optimization for this node
201 # 0 : the default value
202 # 1 : this test can be implemented with direct access
203 # 2 : this test must be implemented with perfect hashing
208 # TODO : a workaround for now
209 if not v
isa VirtualMachine then return super
211 var recv
= v
.expr
(self.n_expr
)
212 if recv
== null then return null
214 optimize
(v
, recv
.mtype
, self.cast_type
.as(not null))
215 var mtype
= v
.unanchor_type
(self.cast_type
.as(not null))
217 # If this test can be optimized, directly call appropriate subtyping methods
218 if status
== 1 and recv
.mtype
isa MClassType then
220 return v
.bool_instance
(v
.inter_is_subtype_sst
(id
, position
, recv
.mtype
.as(MClassType).mclass
.vtable
.internal_vtable
))
221 else if status
== 2 and recv
.mtype
isa MClassType then
223 return v
.bool_instance
(v
.inter_is_subtype_ph
(id
, recv
.vtable
.mask
, recv
.mtype
.as(MClassType).mclass
.vtable
.internal_vtable
))
225 # Use the slow path (default)
226 return v
.bool_instance
(v
.is_subtype
(recv
.mtype
, mtype
))
230 # Optimize a `AIsaExpr`
231 # `source` the source type of the expression
232 # `target` the target type of the subtyping test
233 private fun optimize
(v
: VirtualMachine, source
: MType, target
: MType)
235 # If the source class and target class are not classic classes (non-generics) then return
236 if not source
isa MClassType or not target
isa MClassType or target
isa MGenericType then
240 if not target
.mclass
.abstract_loaded
then return
242 # If the value is positive, the target class has an invariant position in source's structures
243 var value
= source
.mclass
.get_position_methods
(target
.mclass
)
246 # `value - 2` is the position of the target identifier in source vtable
250 # We use perfect hashing
253 id
= target
.mclass
.vtable
.id
257 redef class AAsCastExpr
258 # Identifier of the target class type
261 # If the Cohen test is used, the position of the target id in vtable
264 # Indicate the status of the optimization for this node
266 # 0 : the default value
267 # 1 : this test can be implemented with direct access
268 # 2 : this test must be implemented with perfect hashing
273 # TODO : a workaround for now
274 if not v
isa VirtualMachine then return super
276 var recv
= v
.expr
(self.n_expr
)
277 if recv
== null then return null
279 optimize
(v
, recv
.mtype
, self.mtype
.as(not null))
281 var mtype
= self.mtype
.as(not null)
282 var amtype
= v
.unanchor_type
(mtype
)
285 if status
== 1 and recv
.mtype
isa MClassType then
287 res
= v
.inter_is_subtype_sst
(id
, position
, recv
.mtype
.as(MClassType).mclass
.vtable
.internal_vtable
)
288 else if status
== 2 and recv
.mtype
isa MClassType then
290 res
= v
.inter_is_subtype_ph
(id
, recv
.vtable
.mask
, recv
.mtype
.as(MClassType).mclass
.vtable
.internal_vtable
)
292 # Use the slow path (default)
293 res
= v
.is_subtype
(recv
.mtype
, amtype
)
297 fatal
(v
, "Cast failed. Expected `{amtype}`, got `{recv.mtype}`")
302 # Optimize a `AAsCastExpr`
303 # * `source` the source type of the expression
304 # * `target` the target type of the subtyping test
305 private fun optimize
(v
: VirtualMachine, source
: MType, target
: MType)
307 # If the source class and target class are not classic classes (non-generics) then return
308 if not source
isa MClassType or not target
isa MClassType or target
isa MGenericType then
312 if not target
.mclass
.loaded
then return
314 # If the value is positive, the target class has an invariant position in source's structures
315 var value
= source
.mclass
.get_position_methods
(target
.mclass
)
318 # `value - 2` is the position of the target identifier in source vtable
322 # We use perfect hashing
325 id
= target
.mclass
.vtable
.id