1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2009 Jean Privat <jean@pryen.org>
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 # Help generation of icode
22 # Helps to generate icodes in a iroutine
24 # Add a new statment in the current icode sequence
25 # Can be used with expression if the result is ignored of if the result is already set
28 s
.location
= _current_location
32 # Add a new expression in the current icode sequence and return a new associated result register
33 fun expr
(e
: ICode, s
: MMType): IRegister
36 assert e
.result
== null
37 var reg
= new_register
(s
)
42 # Add an assignement (IMove) in the current icode sequence
43 fun add_assignment
(reg
: IRegister, v
: IRegister)
45 stmt
(new IMove(reg
, v
))
48 # Check that the reciever e is not null (IIs + IAbort)
49 fun add_null_reciever_check
(e
: IRegister)
51 var nul
= lit_null_reg
52 var c
= expr
(new IIs(e
, nul
), mmmodule
.type_bool
)
57 add_abort
("Reciever is null")
61 # Add a type cast (ITypeCheck + IAbort) in the current icode sequence
62 fun add_type_cast
(e
: IRegister, stype
: MMType)
64 var c
= expr
(new ITypeCheck(iroutine
.params
.first
, e
, stype
), mmmodule
.type_bool
)
69 add_abort
("Cast failed")
73 # Add an attr check (IAttrIsset + IAbort) in the current icode sequence
74 fun add_attr_check
(prop
: MMAttribute, e
: IRegister)
76 if not prop
.signature
.return_type
.is_nullable
then
77 var cond
= expr
(new IAttrIsset(prop
, e
), mmmodule
.type_bool
)
78 var iif
= new IIf(cond
)
82 add_abort
("Uninitialized attribute %s", prop
.name
.to_s
)
87 # Add an IAttrRead guarded by an add_attr_check in the current icode sequence
88 fun add_attr_read
(prop
: MMAttribute, e
: IRegister): IRegister
90 add_attr_check
(prop
, e
)
91 return expr
(new IAttrRead(prop
, e
), prop
.signature
.return_type
.as(not null))
94 # Add a localized IAbort
95 fun add_abort
(s
: String...)
97 stmt
(new IAbort(s
, mmmodule
))
100 # Add an assigment to the iroutine return value
101 # Beware, no jump is generated
102 fun add_return_value
(reg
: IRegister)
104 add_assignment
(iroutine
.result
.as(not null), reg
)
107 # Add an ICall with possible simple inlining in the current icode sequence
108 fun add_call
(prop
: MMMethod, args
: Array[IRegister], closcns
: nullable Array[nullable IClosureDef]): nullable IRegister
110 var ee
= once
"==".to_symbol
112 # Inline "x!=y" as "not x==y"
113 var ne
= once
"!=".to_symbol
114 if prop
.name
== ne
then
115 var eqp
= prop
.signature
.recv
.local_class
.select_method
(ee
)
116 var eqcall
= add_call
(eqp
, args
, closcns
).as(not null)
117 return expr
(new INot(eqcall
), mmmodule
.type_bool
)
120 # TODO: Inline x==y as "x is y or (x != null and (== is not the Object one) and x.==(y))"
121 # inline "x==y" as "x is y or x != null and x.==(y)"
122 var icall
= new ICall(prop
, args
)
123 icall
.closure_defs
= closcns
124 if prop
.name
== ee
then
126 var reg
= new_register
(mmmodule
.type_bool
)
128 var cond
= expr
(new IIs(args
[0], args
[1]), mmmodule
.type_bool
)
129 var iif
= new IIf(cond
)
133 add_assignment
(reg
, cond
)
136 # Do the "x != null" part iff x is nullable
137 if args
[0].stype
.is_nullable
then
138 var nul
= lit_null_reg
139 cond
= expr
(new IIs(args
[0], nul
), mmmodule
.type_bool
)
143 add_assignment
(reg
, lit_false_reg
)
147 add_assignment
(reg
, expr
(icall
, mmmodule
.type_bool
))
152 if args
.first
.stype
.is_nullable
then add_null_reciever_check
(args
.first
)
153 var rtype
= prop
.signature
.return_type
154 if rtype
!= null then
155 return expr
(icall
, rtype
)
162 # Add an escape to a given sequence
163 # Create a new IEscapeMark if required
164 fun add_escape
(seq
: ISeq)
166 var mark
= seq
.iescape_mark
168 mark
= new IEscapeMark
169 iroutine
.escape_marks
.add
(mark
)
170 seq
.iescape_mark
= mark
172 stmt
(new IEscape(mark
))
175 # Return a literal "null" value
176 fun lit_null_reg
: IRegister
178 return new_register
(mmmodule
.type_none
)
181 # Return a literal "true" value
182 fun lit_true_reg
: IRegister
184 var e
= new IBoolValue(true)
185 return expr
(e
, mmmodule
.type_bool
)
188 # Return a literal "false" value
189 fun lit_false_reg
: IRegister
191 var e
= new IBoolValue(false)
192 return expr
(e
, mmmodule
.type_bool
)
196 fun new_register
(s
: MMType): IRegister
198 var r
= new IRegister(s
)
199 iroutine
.registers
.add
(r
)
203 # The module where classes and types are extracted
204 readable var _mmmodule
: MMModule
206 # The current iroutine build
207 readable var _iroutine
: IRoutine
209 # The current sequence of icodes
210 readable writable var _seq
: ISeq
212 init(mod
: MMModule, r
: IRoutine)
215 _current_location
= r
.location
220 # New ICodes are set to this location
221 readable writable var _current_location
: nullable Location = null
224 redef class MMSignature
225 # Create an empty IRoutine that match the signature
226 fun generate_empty_iroutine
: IRoutine
228 var args
= new Array[IRegister]
229 args
.add
(new IRegister(recv
)) # Self
230 for i
in [0..arity
[ do
231 args
.add
(new IRegister(self[i
]))
233 var res
: nullable IRegister = null
234 var rtype
= return_type
235 if rtype
!= null then
236 res
= new IRegister(rtype
)
238 var iroutine
= new IRoutine(args
, res
)
239 var clos
: nullable Array[IClosureDecl] = null
240 if not closures
.is_empty
then
241 clos
= new Array[IClosureDecl]
243 clos
.add
(new IClosureDecl(c
))
245 iroutine
.closure_decls
= clos
247 # Add automatic test for virtual types
248 var icb
= new ICodeBuilder(recv
.mmmodule
, iroutine
)
249 for i
in [0..arity
[ do
251 if t
isa MMVirtualType then
252 icb
.add_type_cast
(args
[i
+1], t
)
258 # Create an empty IClosureDef that match the signature
259 fun generate_empty_iclosuredef
(icb
: ICodeBuilder): IClosureDef
261 var args
= new Array[IRegister]
262 for i
in [0..arity
[ do
263 args
.add
(icb
.new_register
(self[i
]))
265 var res
: nullable IRegister = null
266 var rtype
= return_type
267 if rtype
!= null then
268 res
= icb
.new_register
(rtype
)
270 var iroutine
= new IClosureDef(args
, res
)
271 var clos
: nullable Array[IClosureDecl] = null
272 if not closures
.is_empty
then
273 clos
= new Array[IClosureDecl]
275 clos
.add
(new IClosureDecl(c
))
277 iroutine
.closure_decls
= clos
279 # TODO: add automatic test for virtual types?