model: add MMethod::is_new to distinguish new and init constructors
[nit.git] / src / runtime_type.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
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
18 # Rapid type analysis on the AST with heterogenous generics and customization
19 #
20 # Rapid type analysis is an analyse that aproximates the set of live classes
21 # and the set of live methods starting from the entry point of the program.
22 # These two sets are interdependant and computed together.
23 # It is quite efficient but the type set is global and pollutes each call site.
24 #
25 # Heterogenous generics means that each intancied generic class is associated
26 # to a distinct runtime type.
27 # Heterogenous generics has the advantage to resolve the formal generic
28 # parameters types but increase the number of types.
29 # More important, heterogenous generics cannot deal with infinite number of runtime
30 # types since the analyse tries to list them all (so some programs will be badly refused)
31 #
32 # Customization means that each method definition is analyzed one per runtime
33 # type of receiver.
34 # Customization have the following advantages:
35 # * `self' is monomorphic
36 # * virtual types are all resolved
37 # * live attributes can be determined on each class
38 # But has the disadvantage to explode the number of runtime method: each method
39 # definition for each runtime type that need it
40 module runtime_type
41
42 import model
43 import modelbuilder
44 import typing
45 import auto_super_init
46
47 redef class MModule
48 var main_type: nullable MClassType
49 var main_init: nullable MMethod
50 var main_method: nullable MMethod
51 end
52
53 redef class ModelBuilder
54 fun do_runtime_type(mainmodule: MModule): RuntimeTypeAnalysis
55 do
56 var model = self.model
57 var analysis = new RuntimeTypeAnalysis(self, mainmodule)
58 var nmodule = self.nmodules.first
59 var mainclass = self.try_get_mclass_by_name(nmodule, mainmodule, "Sys")
60 if mainclass == null then return analysis # No entry point
61 var maintype = mainclass.mclass_type
62 analysis.add_type(maintype)
63 mainmodule.main_type = maintype
64 var initprop = self.try_get_mproperty_by_name2(nmodule, mainmodule, maintype, "init")
65 if initprop != null then
66 assert initprop isa MMethod
67 analysis.add_monomorphic_send(maintype, initprop)
68 end
69 mainmodule.main_init = initprop
70 var mainprop = self.try_get_mproperty_by_name2(nmodule, mainmodule, maintype, "main")
71 if mainprop != null then
72 assert mainprop isa MMethod
73 analysis.add_monomorphic_send(maintype, mainprop)
74 end
75 mainmodule.main_method = mainprop
76 analysis.run_analysis
77 return analysis
78 end
79 end
80
81 # RuntimeTypeAnalysis looks for alive runtime types in application.
82 # The entry point of the analysis is the mainmodule of the application.
83 class RuntimeTypeAnalysis
84 var modelbuilder: ModelBuilder
85 var mainmodule: MModule
86 var live_types: HashSet[MClassType] = new HashSet[MClassType]
87 var live_cast_types: HashSet[MClassType] = new HashSet[MClassType]
88 var polymorphic_methods: HashSet[MMethod] = new HashSet[MMethod]
89 var live_methoddefs: HashSet[MMethodDef] = new HashSet[MMethodDef]
90 var runtime_methods: HashSet[RuntimeMethod] = new HashSet[RuntimeMethod]
91 var live_send_site: HashSet[RuntimeSendSite] = new HashSet[RuntimeSendSite]
92
93 private var todo: List[RuntimeMethod] = new List[RuntimeMethod]
94
95 fun add_type(mtype: MClassType)
96 do
97 if self.live_types.has(mtype) then return
98
99 assert not mtype.need_anchor
100 self.live_types.add(mtype)
101
102 # Collect default attributes
103 for cd in mtype.collect_mclassdefs(self.mainmodule)
104 do
105 var nclassdef = self.modelbuilder.mclassdef2nclassdef[cd]
106 for npropdef in nclassdef.n_propdefs do
107 if not npropdef isa AAttrPropdef then continue
108 var nexpr = npropdef.n_expr
109 if nexpr == null then continue
110 var v = new RuntimeTypeVisitor(self, nclassdef, npropdef.mpropdef.as(not null), mtype)
111 v.enter_visit(nexpr)
112 end
113 end
114
115
116 for rss in self.live_send_site do
117 if not mtype.is_subtype(self.mainmodule, null, rss.receiver) then continue
118 if mtype.has_mproperty(self.mainmodule, rss.mmethod) then
119 self.add_monomorphic_send(mtype, rss.mmethod)
120 end
121 end
122 end
123
124 fun add_send(mtype: MClassType, mmethod: MMethod)
125 do
126 var rss = new RuntimeSendSite(mmethod, mtype)
127 if self.live_send_site.has(rss) then return
128
129 self.live_send_site.add(rss)
130 self.polymorphic_methods.add(mmethod)
131
132 for mtype2 in self.live_types do
133 if not mtype2.is_subtype(self.mainmodule, null, mtype) then continue
134 if mtype2.has_mproperty(self.mainmodule, mmethod) then
135 self.add_monomorphic_send(mtype2, mmethod)
136 end
137 end
138 end
139
140 fun add_monomorphic_send(mtype: MClassType, mmethod: MMethod)
141 do
142 assert self.live_types.has(mtype)
143 var defs = mmethod.lookup_definitions(self.mainmodule, mtype)
144 if defs.is_empty then return
145 assert defs.length == 1 else print "conflict on {mtype} for {mmethod}: {defs.join(" ")}"
146 self.add_static_call(mtype, defs.first)
147 end
148
149 fun add_static_call(mtype: MClassType, mmethoddef: MMethodDef)
150 do
151 assert self.live_types.has(mtype)
152 var rm = new RuntimeMethod(mmethoddef, mtype)
153 if self.runtime_methods.has(rm) then return
154 self.runtime_methods.add(rm)
155 self.todo.add(rm)
156 self.live_methoddefs.add(mmethoddef)
157 end
158
159 fun add_cast_type(mtype: MClassType)
160 do
161 if self.live_cast_types.has(mtype) then return
162
163 assert not mtype.need_anchor
164 self.live_cast_types.add(mtype)
165 end
166
167 # Start the analysis.
168 fun run_analysis
169 do
170 # Force Bool
171 var classes = self.modelbuilder.model.get_mclasses_by_name("Bool")
172 if classes != null then for c in classes do self.add_type(c.mclass_type)
173
174 while not todo.is_empty do
175 var mr = todo.shift
176 if not self.modelbuilder.mpropdef2npropdef.has_key(mr.mmethoddef) then
177 # It is an init for a class?
178 if mr.mmethoddef.mproperty.name == "init" then
179 var nclassdef = self.modelbuilder.mclassdef2nclassdef[mr.mmethoddef.mclassdef]
180 var super_inits = nclassdef.super_inits
181 if super_inits != null then
182 #assert args.length == 1
183 for su in super_inits do
184 self.add_monomorphic_send(mr.receiver, su)
185 end
186 end
187
188 else
189 abort
190 end
191 continue
192 end
193 var npropdef = self.modelbuilder.mpropdef2npropdef[mr.mmethoddef]
194 if npropdef isa AConcreteMethPropdef then
195 #npropdef.debug("Visit {mr.mmethoddef} for {mr.receiver}")
196 var nclassdef = npropdef.parent.as(AClassdef)
197 var mmethoddef = npropdef.mpropdef.as(not null)
198 var auto_super_inits = npropdef.auto_super_inits
199 if auto_super_inits != null then
200 for auto_super_init in auto_super_inits do
201 self.add_monomorphic_send(mr.receiver, auto_super_init)
202 end
203 end
204 var v = new RuntimeTypeVisitor(self, nclassdef, mmethoddef, mr.receiver)
205 v.enter_visit(npropdef.n_block)
206 else if npropdef isa ADeferredMethPropdef then
207 # nothing to do (maybe add a waring?)
208 else if npropdef isa AAttrPropdef then
209 # nothing to do
210 else if npropdef isa AInternMethPropdef or npropdef isa AExternMethPropdef then
211 # UGLY: We force the "instantation" of the concrete return type if any
212 var ret = mr.mmethoddef.msignature.return_mtype
213 if ret != null and ret isa MClassType and ret.mclass.kind != abstract_kind and ret.mclass.kind != interface_kind then
214 ret = ret.anchor_to(self.mainmodule, mr.receiver)
215 self.add_type(ret)
216 end
217 else if npropdef isa AExternInitPropdef then
218 self.add_type(mr.receiver)
219 else
220 npropdef.debug("Not yet implemented")
221 abort
222 end
223 end
224 end
225 end
226
227 class RuntimeMethod
228 var mmethoddef: MMethodDef
229 var receiver: MClassType
230
231 redef fun to_s
232 do
233 return "{self.mmethoddef}({receiver})"
234 end
235
236 redef fun ==(o)
237 do
238 return o isa RuntimeMethod and o.mmethoddef == self.mmethoddef and o.receiver == self.receiver
239 end
240
241 redef fun hash
242 do
243 return self.mmethoddef.hash + self.receiver.hash
244 end
245 end
246
247 class RuntimeSendSite
248 var mmethod: MMethod
249 var receiver: MClassType
250
251 redef fun ==(o)
252 do
253 return o isa RuntimeSendSite and o.mmethod == self.mmethod and o.receiver == self.receiver
254 end
255
256 redef fun hash
257 do
258 return self.mmethod.hash + self.receiver.hash
259 end
260 end
261
262 private class RuntimeTypeVisitor
263 super Visitor
264
265 var analysis: RuntimeTypeAnalysis
266
267 var nclassdef: AClassdef
268
269 var mpropdef: MPropDef
270
271 var receiver: MClassType
272
273 init(analysis: RuntimeTypeAnalysis, nclassdef: AClassdef, mpropdef: MPropDef, receiver: MClassType)
274 do
275 self.analysis = analysis
276 self.nclassdef = nclassdef
277 self.mpropdef = mpropdef
278 self.receiver = receiver
279 end
280
281 # Adapt and remove nullable
282 # return null if we got the null type
283 fun cleanup_type(mtype: MType): nullable MClassType
284 do
285 mtype = mtype.anchor_to(self.analysis.mainmodule, self.receiver)
286 if mtype isa MNullType then return null
287 if mtype isa MNullableType then mtype = mtype.mtype
288 assert mtype isa MClassType
289 assert not mtype.need_anchor
290 return mtype
291 end
292
293 fun add_type(mtype: MType)
294 do
295 var runtimetype = cleanup_type(mtype)
296 if runtimetype == null then return # we do not care about null
297
298 self.analysis.add_type(runtimetype)
299 #self.current_node.debug("add_type {runtimetype}")
300 end
301
302 fun add_send(mtype: MType, mproperty: MMethod)
303 do
304 var runtimetype = cleanup_type(mtype)
305 if runtimetype == null then return # we do not care about null
306
307 analysis.add_send(runtimetype, mproperty)
308 #self.current_node.debug("add_send {mproperty}")
309 end
310
311 fun add_monomorphic_send(mtype: MType, mproperty: MMethod)
312 do
313 var runtimetype = cleanup_type(mtype)
314 if runtimetype == null then return # we do not care about null
315
316 self.analysis.add_monomorphic_send(runtimetype, mproperty)
317 #self.current_node.debug("add_static call {runtimetype} {mproperty}")
318 end
319
320 fun add_cast_type(mtype: MType)
321 do
322 var runtimetype = cleanup_type(mtype)
323 if runtimetype == null then return # we do not care about null
324
325 self.analysis.add_cast_type(runtimetype)
326 #self.current_node.debug("add_cast_type {runtimetype}")
327 end
328
329 redef fun visit(node)
330 do
331 if node == null then return
332 node.accept_runtime_type_vistor(self)
333 node.visit_all(self)
334 end
335
336 # Force to get the primitive class named `name' or abort
337 fun get_class(name: String): MClass
338 do
339 var cla = analysis.mainmodule.model.get_mclasses_by_name(name)
340 if cla == null then
341 if name == "Bool" then
342 var c = new MClass(analysis.mainmodule, name, 0, enum_kind, public_visibility)
343 var cladef = new MClassDef(analysis.mainmodule, c.mclass_type, new Location(null, 0,0,0,0), new Array[String])
344 self.add_type(c.mclass_type)
345 return c
346 end
347 self.current_node.debug("Fatal Error: no primitive class {name}")
348 abort
349 end
350 assert cla.length == 1 else print cla.join(", ")
351 return cla.first
352 end
353
354 # Force to get the primitive property named `name' in the instance `recv' or abort
355 fun get_method(recv: MType, name: String): MMethod
356 do
357 var runtimetype = cleanup_type(recv)
358 if runtimetype == null then abort
359
360 var props = self.analysis.mainmodule.model.get_mproperties_by_name(name)
361 if props == null then
362 self.current_node.debug("Fatal Error: no primitive property {name} on {runtimetype}")
363 abort
364 end
365 var res: nullable MMethod = null
366 for mprop in props do
367 assert mprop isa MMethod
368 if not runtimetype.has_mproperty(self.analysis.mainmodule, mprop) then continue
369 if mprop.is_init and mprop.intro_mclassdef.mclass != runtimetype.mclass then continue
370 if res == null then
371 res = mprop
372 else
373 self.current_node.debug("Fatal Error: ambigous property name '{name}'; conflict between {mprop.full_name} and {res.full_name}")
374 abort
375 end
376 end
377 if res == null then
378 self.current_node.debug("Fatal Error: no primitive property {name} on {runtimetype}")
379 abort
380 end
381 return res
382 end
383 end
384
385 ###
386
387 redef class ANode
388 private fun accept_runtime_type_vistor(v: RuntimeTypeVisitor)
389 do
390 end
391 end
392
393 redef class AIntExpr
394 redef fun accept_runtime_type_vistor(v)
395 do
396 v.add_type(self.mtype.as(not null))
397 end
398 end
399
400 redef class AFloatExpr
401 redef fun accept_runtime_type_vistor(v)
402 do
403 v.add_type(self.mtype.as(not null))
404 end
405 end
406
407 redef class ACharExpr
408 redef fun accept_runtime_type_vistor(v)
409 do
410 v.add_type(self.mtype.as(not null))
411 end
412 end
413
414 redef class AArrayExpr
415 redef fun accept_runtime_type_vistor(v)
416 do
417 var mtype = self.mtype.as(not null)
418 v.add_type(mtype)
419 var native = v.get_class("NativeArray").get_mtype([mtype.as(MGenericType).arguments.first])
420 v.add_type(native)
421 var prop = v.get_method(mtype, "with_native")
422 v.add_monomorphic_send(mtype, prop)
423 end
424 end
425
426 redef class AStringFormExpr
427 redef fun accept_runtime_type_vistor(v)
428 do
429 var mtype = self.mtype.as(not null)
430 v.add_type(mtype)
431 var native = v.get_class("NativeString").mclass_type
432 v.add_type(native)
433 var prop = v.get_method(mtype, "from_cstring")
434 v.add_monomorphic_send(mtype, prop)
435 end
436 end
437
438 redef class ASuperstringExpr
439 redef fun accept_runtime_type_vistor(v)
440 do
441 var arraytype = v.get_class("Array").get_mtype([v.get_class("Object").mclass_type])
442 v.add_type(arraytype)
443 var prop = v.get_method(arraytype, "join")
444 v.add_monomorphic_send(arraytype, prop)
445 end
446 end
447
448 redef class ACrangeExpr
449 redef fun accept_runtime_type_vistor(v)
450 do
451 var mtype = self.mtype.as(not null)
452 v.add_type(mtype)
453 var prop = v.get_method(mtype, "init")
454 v.add_monomorphic_send(mtype, prop)
455 end
456 end
457
458 redef class AOrangeExpr
459 redef fun accept_runtime_type_vistor(v)
460 do
461 var mtype = self.mtype.as(not null)
462 v.add_type(mtype)
463 var prop = v.get_method(mtype, "without_last")
464 v.add_monomorphic_send(mtype, prop)
465 end
466 end
467
468 redef class ATrueExpr
469 redef fun accept_runtime_type_vistor(v)
470 do
471 v.add_type(self.mtype.as(not null))
472 end
473 end
474
475 redef class AFalseExpr
476 redef fun accept_runtime_type_vistor(v)
477 do
478 v.add_type(self.mtype.as(not null))
479 end
480 end
481
482 redef class AIsaExpr
483 redef fun accept_runtime_type_vistor(v)
484 do
485 v.add_cast_type(self.cast_type.as(not null))
486 end
487 end
488
489 redef class AAsCastExpr
490 redef fun accept_runtime_type_vistor(v)
491 do
492 v.add_cast_type(self.mtype.as(not null))
493 end
494 end
495
496 #
497
498 redef class ASendExpr
499 redef fun accept_runtime_type_vistor(v)
500 do
501 var mproperty = self.mproperty.as(not null)
502 if n_expr isa ASelfExpr then
503 v.add_monomorphic_send(v.receiver, mproperty)
504 else
505 var recvtype = self.n_expr.mtype.as(not null)
506 v.add_send(recvtype, mproperty)
507 end
508 end
509 end
510
511 redef class ASendReassignFormExpr
512 redef fun accept_runtime_type_vistor(v)
513 do
514 v.add_send(self.read_type.as(not null), self.reassign_property.mproperty)
515 var mproperty = self.mproperty.as(not null)
516 var write_mproperty = self.write_mproperty.as(not null)
517 if n_expr isa ASelfExpr then
518 v.add_monomorphic_send(v.receiver, mproperty)
519 v.add_monomorphic_send(v.receiver, write_mproperty)
520 else
521 var recvtype = self.n_expr.mtype.as(not null)
522 v.add_send(recvtype, mproperty)
523 v.add_send(recvtype, write_mproperty)
524 end
525 end
526 end
527
528 redef class AVarReassignExpr
529 redef fun accept_runtime_type_vistor(v)
530 do
531 v.add_send(self.read_type.as(not null), self.reassign_property.mproperty)
532 end
533 end
534
535 redef class AAttrReassignExpr
536 redef fun accept_runtime_type_vistor(v)
537 do
538 v.add_send(self.read_type.as(not null), self.reassign_property.mproperty)
539 end
540 end
541
542 redef class ASuperExpr
543 redef fun accept_runtime_type_vistor(v)
544 do
545 var mproperty = self.mproperty
546 if mproperty != null then
547 v.add_monomorphic_send(v.receiver, mproperty)
548 return
549 end
550
551 #FIXME: we do not want an ugly static call!
552 var mpropdef = v.mpropdef
553 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
554 if mpropdefs.length != 1 then
555 debug("MPRODFEFS for super {mpropdef} for {v.receiver}: {mpropdefs.join(", ")}")
556 end
557 var msuperpropdef = mpropdefs.first
558 assert msuperpropdef isa MMethodDef
559 v.analysis.add_static_call(v.receiver, msuperpropdef)
560 end
561 end
562
563 redef class AForExpr
564 redef fun accept_runtime_type_vistor(v)
565 do
566 var recvtype = self.n_expr.mtype.as(not null)
567 var colltype = v.get_class("Collection").mclassdefs.first.bound_mtype
568 v.add_send(recvtype, v.get_method(colltype, "iterator"))
569 var iteratortype = v.get_class("Iterator").mclassdefs.first.bound_mtype
570 var objtype = v.get_class("Object").mclass_type
571 v.add_send(objtype, v.get_method(iteratortype, "is_ok"))
572 v.add_send(objtype, v.get_method(iteratortype, "item"))
573 v.add_send(objtype, v.get_method(iteratortype, "next"))
574 end
575 end
576
577 redef class ANewExpr
578 redef fun accept_runtime_type_vistor(v)
579 do
580 var recvtype = self.mtype.as(not null)
581 v.add_type(recvtype)
582 v.add_monomorphic_send(recvtype, mproperty.as(not null))
583 end
584 end