1 # This file contains code relating to method translation.
5 # This is the starting point for translating a method.
10 .param int real_method
12 .local pmc rettype, ptypes, ltypes, ex
13 .local string pir_output, name, pir_params, pir_multi, pir_locals, pir_body, ns
14 .local int flags, impl_flags, static_check, abstract_check, runtime_check
16 # Check if method is static, abstract and/or runtime provided.
17 flags = meth.get_flags()
18 impl_flags = meth.get_impl_flags()
19 static_check = band flags, 0x10
20 abstract_check = band flags, 0x0400
21 runtime_check = band impl_flags, 0x1002 # Internal or runtime
23 # Get details of parameter info and multi-method dispatch markup.
24 ns = class.get_fullname()
25 (rettype, ptypes, pir_params, pir_multi) = trans_method_params(assembly, meth, ns)
28 pir_output = ".sub \""
30 pir_output = concat name
31 pir_output = concat "\""
32 if real_method == 0 goto ISMETHOD
33 if static_check == 0 goto ISMETHOD
36 pir_output = concat " :method"
38 pir_output = concat " :multi("
39 pir_output = concat pir_multi
40 pir_output = concat ")\n"
43 unless trace goto NOTRACE
49 # If it is runtime provided, try to get body and add it, then go to end.
50 if runtime_check == 0 goto NOT_RUNTIME
51 pir_body = internal_method_body(class, meth)
52 pir_output = concat pir_body
57 pir_output = concat pir_params
59 # If it's an abstract method, need to throw an exception if it's called
60 # then not bother with locals, the instruction translator etc.
61 if abstract_check == 0 goto NOT_ABSTRACT
62 pir_output = concat <<"PIR"
64 $P0["_message"] = "Ooh, naughty! A non-abstract class didn't implement an abstract method!"
71 (ltypes, pir_locals) = trans_method_locals(assembly, meth)
72 pir_output = concat pir_locals
74 # Need to set arg0 = self if it's an instance method.
75 if static_check != 0 goto NOSELF
76 pir_output = concat ".local pmc arg0\narg0 = self\n"
80 pir_body = trans_instructions(assembly, class, meth, ptypes, ltypes, rettype, trace)
81 pir_output = concat pir_body
85 pir_output = concat ".end\n\n"
87 # Return generated string.
92 # This translates the method parameters signature.
93 .sub trans_method_params
97 .param int no_pir :optional
98 .local int sig_pos, sig_type
99 .local string sig_data
100 .local pmc signature, classes, class, ex
101 .local int flags, param_count, i, static_check, this_offset, type, token
102 .local int class_type, class_id, explicit_check, vararg_check
103 .local string pir_output, pir_multi, pir_mmdunbox, param_reg_type, tmp
104 .local pmc rettype, ptypes, ptype
107 sig_pos = meth.get_signature()
108 sig_data = assembly.get_blob(sig_pos)
109 signature = new "DotNetSignature"
113 flags = signature.read_uint8()
115 # Check if it's a static method, has this specified explicitly or is
117 static_check = band flags, 0x20
118 explicit_check = band flags, 0x40
119 vararg_check = band flags, 0x7
121 # Get number of parameters.
122 param_count = signature.read_compressed()
125 rettype = get_signature_RetType_or_Param(signature)
126 annotate_reg_type(rettype)
128 # Create parameter types array.
129 ptypes = new .ResizablePMCArray
131 # If it's an instance method and explicit not set, add "this" to the list.
134 if static_check == 0 goto NOSELF
135 if explicit_check != 0 goto NOSELF
139 annotate_reg_type(ptype)
143 # Also generate MMD entry.
144 self_ns = namespace_to_key(self_ns)
145 pir_multi = concat self_ns
148 # Loop over parameters and produce list.
153 if i >= param_count goto ENDPARAM
155 # Emit first bit of PIR.
156 pir_output = concat " .param "
159 ptype = get_signature_RetType_or_Param(signature)
160 annotate_reg_type(ptype)
162 param_reg_type = ptype["reg_type_long"]
163 pir_output = concat param_reg_type
165 # Emit argument name.
166 pir_output = concat " arg"
167 $I0 = i + this_offset
169 pir_output = concat $S0
170 pir_output = concat "\n"
173 if pir_multi == "" goto NOCOMMA
174 pir_multi = concat ", "
177 if type == 0x12 goto MMD_CLASS
178 if type == 0x4 goto MMD_I1
179 if type == 0x5 goto MMD_U1
180 if type == 0x6 goto MMD_I2
181 if type == 0x7 goto MMD_U2
182 if type == 0x9 goto MMD_U4
183 if type == 0xC goto MMD_R4
184 pir_multi = concat param_reg_type
187 token = ptype["token"]
188 class_type = band token, 0x3
189 class_id = token >> 2
191 if class_type == 0 goto MMD_CLASS_DEF
192 if class_type == 1 goto MMD_CLASS_REF
194 ex["_message"] = "Unknown class type to build MMD signature for."
197 classes = assembly.get_classes()
199 class = classes[class_id]
200 tmp = class.get_fullname()
201 tmp = namespace_to_key(tmp)
202 pir_multi = concat tmp
205 classes = assembly.get_typerefs()
206 class = classes[class_id]
208 tmp = namespace_to_key(tmp)
209 pir_multi = concat tmp
212 pir_multi = concat "\"@@DOTNET_MMDBOX_I1\""
215 pir_multi = concat "\"@@DOTNET_MMDBOX_U1\""
218 pir_multi = concat "\"@@DOTNET_MMDBOX_I2\""
221 pir_multi = concat "\"@@DOTNET_MMDBOX_U2\""
224 pir_multi = concat "\"@@DOTNET_MMDBOX_U4\""
227 pir_multi = concat "\"@@DOTNET_MMDBOX_R4\""
236 # If it's var arg, add slurply parameter too.
237 if vararg_check != 5 goto NOT_VARARG
238 pir_output = concat ".param pmc varargs :slurpy\n"
242 pir_output = concat pir_mmdunbox
243 .return(rettype, ptypes, pir_output, pir_multi)
247 # This translates the method's locals signature.
248 .sub trans_method_locals
251 .local int sig_pos, sig_type
252 .local string sig_data
253 .local pmc bc, signature, ex
254 .local int sig_type, count, i, type
255 .local string pir_output :unique_reg
256 .local string param_reg_type
257 .local pmc ltypes, ltype
260 ltypes = new .ResizablePMCArray
263 bc = meth.get_bytecode()
264 sig_pos = bc.get_locals_sig()
265 if sig_pos == 0 goto EXIT
266 sig_data = assembly.get_blob(sig_pos)
267 signature = new "DotNetSignature"
270 # Ensure it's a local sig. XXX Right thing to do when it's not?
271 sig_type = signature.read_uint8()
272 if sig_type == 0x7 goto SIG_OK
274 ex["_message"] = "Locals signature is not a locals signature."
279 count = signature.read_compressed()
281 # Loop over local variabless.
284 if i == count goto EXIT
286 # Emit first bit of PIR.
287 pir_output = concat " .local "
290 ltype = get_signature_Local(signature)
291 annotate_reg_type(ltype)
293 param_reg_type = ltype["reg_type_long"]
294 pir_output = concat param_reg_type
296 # Emit argument name.
297 pir_output = concat " local"
299 pir_output = concat $S0
300 pir_output = concat "\n"
302 # If it's a value type, need to instantiate it.
304 if type != 0x11 goto NOT_VT
305 type = ltype["token"]
306 pir_output = concat "local"
307 pir_output = concat $S0
308 pir_output = concat " = new "
309 ($P0, $S0) = class_info_from_sig(assembly, type)
310 $S0 = namespace_to_key($S0)
311 pir_output = concat $S0
312 pir_output = concat "\n"
321 .return (ltypes, pir_output)
325 # This gets method info from a method token.
326 .sub method_info_from_token
329 .local pmc class, meth, memberrefs, memberref, rettype, ptypes
330 .local pmc typerefs, ex
331 .local int test, meth_id, class_type, class_id
332 .local string ns, tmp
334 # Check whether it's internal or external.
335 test = band token, 0x8000000
336 if test goto EXTERNAL
338 # If we're here, it's an internal method. Get method PMC, namespace, parse
340 meth_id = band token, 0x1FFFFFF
341 meth = assembly.get_method(meth_id)
342 class = meth.get_class()
343 ns = class.get_fullname()
344 (rettype, ptypes, tmp) = trans_method_params(assembly, meth, ns)
347 # If we get here, it's an external method. Get member semantics PMC.
349 meth_id = band token, 0x1FFFFFF
351 memberrefs = assembly.get_memberrefs()
352 memberref = memberrefs[meth_id]
353 class_type = memberref.get_class_type()
354 class_id = memberref.get_class_id()
356 if class_type == 1 goto TYPEREF
357 if class_type == 3 goto METHODDEF
359 ex["message"] = "Unsupported member reference type for method"
362 # If we have a typeref, get it.
364 typerefs = assembly.get_typerefs()
365 class = typerefs[class_id]
366 tmp = class.get_namespace()
368 if ns == "" goto NO_DOT
373 (rettype, ptypes, tmp) = trans_method_params(assembly, memberref, ns)
377 # If we have a methoddef, grab it.
379 meth = assembly.get_method(class_id)
380 class = meth.get_class()
381 ns = class.get_fullname()
382 (rettype, ptypes, tmp) = trans_method_params(assembly, meth, ns)
387 .return(meth, ns, rettype, ptypes, class)
391 # This generates code to box up primitive types for MMD dispatch.
392 .sub method_call_mmd_box
397 .local string pir_output, box_name, tmp, reg_name
398 .local int i, num_params, type
400 # Loop over parameters.
403 num_params = elements params
405 if i == num_params goto PLOOP_END
407 # Get parameter type and see if it's one that needs boxing, and if so
408 # what the box is called.
411 if type == 0x4 goto MMD_I1
412 if type == 0x5 goto MMD_U1
413 if type == 0x6 goto MMD_I2
414 if type == 0x7 goto MMD_U2
415 if type == 0x9 goto MMD_U4
416 if type == 0xC goto MMD_R4
419 box_name = "@@DOTNET_MMDBOX_I1"
422 box_name = "@@DOTNET_MMDBOX_U1"
425 box_name = "@@DOTNET_MMDBOX_I2"
428 box_name = "@@DOTNET_MMDBOX_U2"
431 box_name = "@@DOTNET_MMDBOX_U4"
434 box_name = "@@DOTNET_MMDBOX_R4"
437 # Now generate box instruction and rename parameter.
439 reg_name = "$P200000"
441 reg_name = concat tmp
442 pir_output = concat reg_name
443 pir_output = concat " = new \""
444 pir_output = concat box_name
445 pir_output = concat "\"\n"
446 pir_output = concat reg_name
447 pir_output = concat " = "
449 pir_output = concat tmp
450 pir_output = concat "\n"
453 # Go to next parameter.
459 # Return generated PIR.
464 # This gets info from a type def or ref in a signature.
465 .sub class_info_from_sig
468 .local pmc ex, classes, pclass
469 .local string pclass_ns, tmp
470 .local int class_type, class_id
472 # Get class type and class id.
473 class_id = token >> 2
474 class_type = band token, 3
476 # Find out what type of class we have.
478 if class_type == 0 goto DEF
479 if class_type == 1 goto REF
481 ex["_message"] = "Unknown class type."
484 # A type in this file.
486 dec class_id # Because row 2 = element 0 here, thanks to the global class
487 classes = assembly.get_classes()
488 pclass = classes[class_id]
489 pclass_ns = pclass.get_fullname()
492 # A type in another file.
494 classes = assembly.get_typerefs()
495 pclass = classes[class_id]
496 pclass_ns = pclass.get_namespace()
497 pclass_ns = clone pclass_ns
498 if pclass_ns == "" goto NO_NS
499 pclass_ns = concat "."
502 pclass_ns = concat tmp
504 # Return class and its namespace.
506 .return (pclass, pclass_ns)
513 # vim: expandtab shiftwidth=4 ft=pir: