a906a6f1e5898c675e8c75a98536f90bf62bcbcc
[nit.git] / src / vm_optimizations.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Optimization of the nitvm
18 module vm_optimizations
19
20 import vm
21
22 redef class AAttrFormExpr
23 # Position of the attribute in attribute table
24 #
25 # The relative position of this attribute if perfect hashing is used,
26 # The absolute position of this attribute if SST is used
27 var offset: Int
28
29 # Indicate the status of the optimization for this node
30 #
31 # 0: default value
32 # 1: SST (direct access) can be used
33 # 2: PH (multiple inheritance implementation) must be used
34 var status: Int = 0
35
36 # Identifier of the class which introduced the attribute
37 var id: Int
38
39 # Optimize this attribute access
40 # * `mproperty` The attribute which is accessed
41 # * `recv` The receiver (The object) of the access
42 protected fun optimize(mproperty: MAttribute, recv: MutableInstance)
43 do
44 if mproperty.intro_mclassdef.mclass.positions_attributes[recv.mtype.as(MClassType).mclass] != -1 then
45 # if this attribute class has an unique position for this receiver, then use direct access
46 offset = mproperty.absolute_offset
47 status = 1
48 else
49 # Otherwise, perfect hashing must be used
50 id = mproperty.intro_mclassdef.mclass.vtable.id
51 offset = mproperty.offset
52 status = 2
53 end
54 end
55 end
56
57 redef class AAttrExpr
58 redef fun expr(v)
59 do
60 # TODO : a workaround for now
61 if not v isa VirtualMachine then return super
62
63 var recv = v.expr(self.n_expr)
64 if recv == null then return null
65 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
66 var mproperty = self.mproperty.as(not null)
67
68 assert recv isa MutableInstance
69 if status == 0 then optimize(mproperty, recv)
70
71 var i: Instance
72 if status == 1 then
73 # SST
74 i = v.read_attribute_sst(recv.internal_attributes, offset)
75 else
76 # PH
77 i = v.read_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable, recv.vtable.mask, id, offset)
78 end
79
80 # If we get a `MInit` value, throw an error
81 if i == v.initialization_value then
82 v.fatal("Uninitialized attribute {mproperty.name}")
83 abort
84 end
85
86 return i
87 end
88 end
89
90 redef class AAttrAssignExpr
91 redef fun stmt(v)
92 do
93 # TODO : a workaround for now
94 if not v isa VirtualMachine then
95 super
96 return
97 end
98
99 var recv = v.expr(self.n_expr)
100 if recv == null then return
101 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
102 var i = v.expr(self.n_value)
103 if i == null then return
104 var mproperty = self.mproperty.as(not null)
105
106 assert recv isa MutableInstance
107 if status == 0 then optimize(mproperty, recv)
108
109 if status == 1 then
110 v.write_attribute_sst(recv.internal_attributes, offset, i)
111 else
112 v.write_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
113 recv.vtable.mask, id, offset, i)
114 end
115 end
116 end
117
118 # Add informations to optimize some method calls
119 redef class CallSite
120 # Position of the method in virtual table
121 #
122 # The relative position of this MMethod if perfect hashing is used,
123 # The absolute position of this MMethod if SST is used
124 var offset: Int
125
126 # Indicate the status of the optimization for this node
127 #
128 # 0: default value
129 # 1: SST (direct access) can be used
130 # 2: PH (multiple inheritance implementation) must be used
131 var status: Int = 0
132
133 # Identifier of the class which introduced the MMethod
134 var id: Int
135
136 # Optimize a method dispatch
137 fun optimize(recv: Instance)
138 do
139 if mproperty.intro_mclassdef.mclass.positions_methods[recv.mtype.as(MClassType).mclass] != -1 then
140 offset = mproperty.absolute_offset
141 status = 1
142 else
143 offset = mproperty.offset
144 status = 2
145 end
146 id = mproperty.intro_mclassdef.mclass.vtable.id
147 end
148 end
149
150 redef class AIsaExpr
151 # Identifier of the target class type
152 var id: Int
153
154 # If the Cohen test is used, the position of the target id in vtable
155 var position: Int
156
157 # Indicate the status of the optimization for this node
158 #
159 # 0 : the default value
160 # 1 : this test can be implemented with direct access
161 # 2 : this test must be implemented with perfect hashing
162 var status: Int = 0
163
164 redef fun expr(v)
165 do
166 # TODO : a workaround for now
167 if not v isa VirtualMachine then return super
168
169 var recv = v.expr(self.n_expr)
170 if recv == null then return null
171
172 if status == 0 then optimize(v, recv.mtype, self.cast_type.as(not null))
173 var mtype = v.unanchor_type(self.cast_type.as(not null))
174
175 # If this test can be optimized, directly call appropriate subtyping methods
176 if status == 1 and recv.mtype isa MClassType then
177 # Direct access
178 return v.bool_instance(v.inter_is_subtype_sst(id, position, recv.mtype.as(MClassType).mclass.vtable.internal_vtable))
179 else if status == 2 and recv.mtype isa MClassType then
180 # Perfect hashing
181 return v.bool_instance(v.inter_is_subtype_ph(id, recv.vtable.mask, recv.mtype.as(MClassType).mclass.vtable.internal_vtable))
182 else
183 # Use the slow path (default)
184 return v.bool_instance(v.is_subtype(recv.mtype, mtype))
185 end
186 end
187
188 # Optimize a `AIsaExpr`
189 # `source` the source type of the expression
190 # `target` the target type of the subtyping test
191 private fun optimize(v: VirtualMachine, source: MType, target: MType)
192 do
193 # If the source class and target class are not classic classes (non-generics) then return
194 if not source isa MClassType or not target isa MClassType or target isa MGenericType then
195 return
196 end
197
198 if not target.mclass.loaded then return
199
200 # Try to get the position of the target type in source's structures
201 var value = source.mclass.positions_methods.get_or_null(target.mclass)
202
203 if value != null then
204 if value != -1 then
205 # Store informations for Cohen test
206 position = target.mclass.color
207 status = 1
208 else
209 # We use perfect hashing
210 status = 2
211 end
212 end
213 id = target.mclass.vtable.id
214 end
215 end
216
217 redef class AAsCastExpr
218 # Identifier of the target class type
219 var id: Int
220
221 # If the Cohen test is used, the position of the target id in vtable
222 var position: Int
223
224 # Indicate the status of the optimization for this node
225 #
226 # 0 : the default value
227 # 1 : this test can be implemented with direct access
228 # 2 : this test must be implemented with perfect hashing
229 var status: Int = 0
230
231 redef fun expr(v)
232 do
233 # TODO : a workaround for now
234 if not v isa VirtualMachine then return super
235
236 var recv = v.expr(self.n_expr)
237 if recv == null then return null
238
239 if status == 0 then optimize(v, recv.mtype, self.mtype.as(not null))
240
241 var mtype = self.mtype.as(not null)
242 var amtype = v.unanchor_type(mtype)
243
244 var res: Bool
245 if status == 1 and recv.mtype isa MClassType then
246 # Direct access
247 res = v.inter_is_subtype_sst(id, position, recv.mtype.as(MClassType).mclass.vtable.internal_vtable)
248 else if status == 2 and recv.mtype isa MClassType then
249 # Perfect hashing
250 res = v.inter_is_subtype_ph(id, recv.vtable.mask, recv.mtype.as(MClassType).mclass.vtable.internal_vtable)
251 else
252 # Use the slow path (default)
253 res = v.is_subtype(recv.mtype, amtype)
254 end
255
256 if not res then
257 fatal(v, "Cast failed. Expected `{amtype}`, got `{recv.mtype}`")
258 end
259 return recv
260 end
261
262 # Optimize a `AAsCastExpr`
263 # * `source` the source type of the expression
264 # * `target` the target type of the subtyping test
265 private fun optimize(v: VirtualMachine, source: MType, target: MType)
266 do
267 # If the source class and target class are not classic classes (non-generics) then return
268 if not source isa MClassType or not target isa MClassType or target isa MGenericType then
269 return
270 end
271
272 if not target.mclass.loaded then return
273
274 # Try to get the position of the target type in source's structures
275 var value = source.mclass.positions_methods.get_or_null(target.mclass)
276
277 if value != null then
278 if value != -1 then
279 # Store informations for Cohen test
280 position = target.mclass.color
281 status = 1
282 else
283 # We use perfect hashing
284 status = 2
285 end
286 end
287 id = target.mclass.vtable.id
288 end
289 end