2 Copyright (C) 2008-2009, Parrot Foundation.
11 Functions for the ManagedStruct PMC and others.
19 /* HEADERIZER HFILE: none */
22 #include "parrot/parrot.h"
23 #include "pmc/pmc_fixedintegerarray.h"
24 #include "pmc/pmc_unmanagedstruct.h"
25 #include "pmc/pmc_managedstruct.h"
26 #include "frame_builder.h"
32 =item C<void Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv)>
34 This is a callback to implement the proper freeing semantics. It is called by
35 the ManagedStruct PMC as it is garbage collected.
42 Parrot_jit_free_buffer(SHIM_INTERP
, void *ptr
, void *priv
)
44 const struct jit_buffer_private_data
* const jit
= (struct jit_buffer_private_data
*)priv
;
45 mem_free_executable(ptr
, jit
->size
);
51 =item C<PMC *Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv)>
53 This is a callback to implement the proper cloning semantics for jit buffers.
54 It is called by the ManagedStruct PMC's clone() function.
63 Parrot_jit_clone_buffer(PARROT_INTERP
, PMC
*pmc
, void *priv
)
65 PMC
* const rv
= Parrot_pmc_new(interp
, pmc
->vtable
->base_type
);
67 VTABLE_init(interp
, rv
);
68 /* copy the attributes */
70 void (*tmpfreefunc
)(PARROT_INTERP
, void*, void*);
71 GETATTR_ManagedStruct_custom_free_func(interp
, pmc
, tmpfreefunc
);
72 SETATTR_ManagedStruct_custom_free_func(interp
, rv
, tmpfreefunc
);
75 PMC
* (*tmpclonefunc
)(PARROT_INTERP
, PMC
*, void*);
76 GETATTR_ManagedStruct_custom_clone_func(interp
, pmc
, tmpclonefunc
);
77 SETATTR_ManagedStruct_custom_clone_func(interp
, rv
, tmpclonefunc
);
81 void *freepriv
, *clonepriv
;
82 GETATTR_ManagedStruct_custom_free_priv(interp
, pmc
, freepriv
);
83 GETATTR_ManagedStruct_custom_clone_priv(interp
, pmc
, clonepriv
);
85 void *tmp
= mem_gc_allocate_zeroed_typed(interp
, struct jit_buffer_private_data
);
86 memcpy(tmp
, freepriv
, sizeof (struct jit_buffer_private_data
));
87 SETATTR_ManagedStruct_custom_free_priv(interp
, rv
, tmp
);
88 if (clonepriv
== freepriv
) {
89 /* clonepriv is a copy of freepriv, make it a copy in the clone too. */
90 SETATTR_ManagedStruct_custom_clone_priv(interp
, rv
, tmp
);
91 clonepriv
= NULL
; /* disable the clonepriv copying below */
95 void *tmp
= mem_gc_allocate_zeroed_typed(interp
, struct jit_buffer_private_data
);
96 memcpy(tmp
, clonepriv
, sizeof (struct jit_buffer_private_data
));
97 SETATTR_ManagedStruct_custom_clone_priv(interp
, rv
, tmp
);
101 /* copy the execmem buffer */
102 if (PARROT_MANAGEDSTRUCT(pmc
)->ptr
) {
103 struct jit_buffer_private_data
*jit
= (struct jit_buffer_private_data
*)priv
;
104 void *ptr
= PARROT_MANAGEDSTRUCT(pmc
)->ptr
;
105 void *newptr
= mem_alloc_executable(jit
->size
);
107 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
108 "Cannot allocate executable memory");
109 memcpy(newptr
, ptr
, jit
->size
);
110 PARROT_MANAGEDSTRUCT(rv
)->ptr
= newptr
;
118 emit_is8bit(long disp
)
120 return disp
>= -128 && disp
<= 127;
124 emit_disp8_32(char *pc
, int disp
)
126 if (emit_is8bit(disp
)) {
127 *(pc
++) = (char)disp
;
137 emit_sib(PARROT_INTERP
, char *pc
, int scale
, int i
, int base
)
143 scale_byte
= emit_Scale_1
;
146 scale_byte
= emit_Scale_2
;
149 scale_byte
= emit_Scale_4
;
152 scale_byte
= emit_Scale_8
;
155 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
156 "Invalid scale factor %d\n", scale
);
160 *pc
= (char)(scale_byte
| (i
== emit_None
? emit_Index_None
: emit_reg_Index(i
)) |
161 emit_reg_Base(base
));
165 emit_r_X(PARROT_INTERP
, char *pc
, int reg_opcode
, int base
, int i
, int scale
, long disp
)
168 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
169 "emit_r_X passed invalid scale+index combo\n");
171 if (base
== emit_EBP
) {
173 if (i
== emit_None
) {
174 *(pc
++) = (char)((emit_is8bit(disp
) ? emit_Mod_b01
: emit_Mod_b10
)
175 | reg_opcode
| emit_reg_rm(emit_EBP
));
176 return emit_disp8_32(pc
, disp
);
180 *(pc
++) = (char)((emit_is8bit(disp
) ? emit_Mod_b01
: emit_Mod_b10
)
181 | reg_opcode
| emit_b100
);
182 emit_sib(interp
, pc
++, scale
, i
, base
);
183 return emit_disp8_32(pc
, disp
);
188 if (base
== emit_ESP
) {
189 *(pc
++) = (char)((emit_is8bit(disp
) ? emit_Mod_b01
: emit_Mod_b10
)
190 | reg_opcode
| emit_rm_b100
);
191 emit_sib(interp
, pc
++, scale
, i
, emit_ESP
);
192 return emit_disp8_32(pc
, disp
);
196 if (!base
&& !(i
&& scale
)) {
197 *(pc
++) = (char)(emit_Mod_b00
| reg_opcode
| emit_rm_b101
);
202 /* Ok, everything should be more regular here */
203 *(pc
++) = (char)((disp
== 0 ? emit_Mod_b00
:
205 emit_Mod_b01
: emit_Mod_b10
)) |
207 (!base
|| (scale
&& i
) ? emit_rm_b100
: emit_reg_rm(base
)));
209 if (!base
|| (scale
&& i
)) {
210 emit_sib(interp
, pc
++, scale
, i
, base
);
213 pc
= emit_disp8_32(pc
, disp
);
219 emit_shift_i_r(PARROT_INTERP
, char *pc
, int opcode
, int imm
, int reg
)
221 if (opcode
== emit_b000
&& imm
< 0) {
222 opcode
= emit_b001
; /* -rol => 32 + ror */
230 *(pc
++) = (char) 0xd1;
231 *(pc
++) = (char) emit_alu_X_r(opcode
, reg
);
233 else if (imm
> 1 && imm
< 33) {
234 *(pc
++) = (char) 0xc1;
235 *(pc
++) = (char) emit_alu_X_r(opcode
, reg
);
239 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
240 "emit_shift_i_r passed invalid shift\n");
247 emit_popl_r(char *pc
, int reg
)
249 *(pc
++) = (char)(0x58 | (reg
- 1));
253 unsigned char *lastpc
;
256 calc_signature_needs(const char *sig
, int *strings
)
258 size_t stack_size
= 0;
279 * The function generated here is called as func(interp, nci_info)
281 * nci_info ... 12(%ebp)
283 * The generate function for a specific signature looks quite similar to
284 * an optimized compile of src/nci.c:pcf_x_yy(). In case of any troubles
285 * just compare the disassembly.
287 * If a non-NULL sizeptr is passed, the integer it points to will be written
288 * with the size of the allocated execmem buffer.
292 Parrot_jit_build_call_func(PARROT_INTERP
, PMC
*pmc_nci
, STRING
*signature
, int *sizeptr
)
298 int string_buffer_count
= 0;
299 const int ST_SIZE_OF
= 124;
300 const int JIT_ALLOC_SIZE
= 1024;
302 char *signature_str
= Parrot_str_to_cstring(interp
, signature
);
303 /* skip over the result */
304 char *sig
= signature_str
+ 1;
305 size_t stack_space_needed
= calc_signature_needs(sig
,
306 &string_buffer_count
);
309 int strings_offset
= base_offset
- (sizeof (char *) * string_buffer_count
);
310 int st_offset
= strings_offset
- ST_SIZE_OF
;
311 int args_offset
= st_offset
- stack_space_needed
;
312 int temp_calls_offset
= args_offset
- 16;
313 int total_stack_needed
= -temp_calls_offset
;
319 * 0-15, 16 bytes for utility calls
320 * stack_space_needed for actual NCI call
322 * STRINGS -> char * holding space
326 /* this ought to be enough - the caller of this function
327 * should free the function pointer returned here
329 pc
= execmem
= (char *)mem_alloc_executable(JIT_ALLOC_SIZE
);
331 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
332 "Cannot allocate executable memory");
335 /* this generated jit function will be called as (INTERP (EBP 8), func_ptr
336 * (ESP 12), args signature (ESP 16)) */
338 /* make stack frame, preserve %ebx */
339 jit_emit_stack_frame_enter(pc
);
341 emitm_subl_i_r(pc
, total_stack_needed
, emit_ESP
);
343 /* Parrot_init_arg_nci(interp, &st, "S"); */
344 /* args signature "S" */
345 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 16);
346 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
349 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
350 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
353 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 8);
354 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 0);
356 /* XXX FIXME (TT #1325) This whole function require major rework */
357 /* if (sig && *sig) */
358 /* emitm_call_cfunc(pc, Parrot_init_arg_nci); */
361 emitm_movl_i_m(pc
, arg_count
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
364 case '0': /* null ptr or such - doesn't consume a reg */
365 jit_emit_bxor_rr_i(interp
, pc
, emit_EAX
, emit_EAX
);
366 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
369 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_N); */
370 emitm_fstps(interp
, pc
, emit_EBP
, 0, 1, args_offset
);
374 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_N); */
375 emitm_fstpl(interp
, pc
, emit_EBP
, 0, 1, args_offset
);
378 case 'I': /* INTVAL */
381 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_I); */
382 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
384 case 't': /* string, pass a cstring */
385 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_S); */
386 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
387 emitm_call_cfunc(pc
, string_to_cstring_nullable
);
389 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
390 /* save off temporary allocation address */
391 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, strings_offset
);
395 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
396 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
398 case 's': /* short: movswl intreg_o(base), %eax */
399 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_I); */
400 emitm_movswl_r_r(pc
, emit_EAX
, emit_EAX
);
401 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
403 case 'c': /* char: movsbl intreg_o(base), %eax */
404 /* emitm_call_cfunc(pc, get_nci_I); */
405 emitm_movsbl_r_r(pc
, emit_EAX
, emit_EAX
);
406 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
408 case 'J': /* interpreter */
409 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 8);
410 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
413 case 'p': /* push pmc->data */
414 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_p); */
415 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
417 case 'O': /* push PMC * object in P2 */
418 case 'P': /* push PMC * */
420 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_P); */
421 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
425 case 'b': /* buffer (void*) pass Buffer_bufstart(SReg) */
426 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_S); */
427 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1,
428 (size_t) &Buffer_bufstart((STRING
*) NULL
));
429 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
431 case 'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */
432 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_S); */
433 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1,
434 (size_t) &Buffer_bufstart((STRING
*) NULL
));
435 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
438 /* FIXME (TT #1325) emitm_call_cfunc(pc, get_nci_S); */
439 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
443 /* I have no idea how to handle these */
448 mem_free_executable(execmem
, JIT_ALLOC_SIZE
);
449 Parrot_str_free_cstring(signature_str
);
453 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
454 "Unknown arg Signature %c\n", *sig
);
456 * oops unknown signature:
457 * cleanup and try nci.c
459 mem_free_executable(execmem
, JIT_ALLOC_SIZE
);
460 Parrot_str_free_cstring(signature_str
);
468 /* prepare to call VTABLE_get_pointer, set up args */
469 /* interpreter - movl 8(%ebp), %eax */
470 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 8);
471 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 0);
473 /* pmc - movl 12(%ebp), %eax */
474 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 12);
475 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
477 /* get the get_pointer() pointer from the pmc's vtable */
478 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1, offsetof(PMC
, vtable
));
479 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1, offsetof(VTABLE
, get_pointer
));
481 /* call get_pointer(), result goes into eax */
482 emitm_callr(pc
, emit_EAX
);
483 emitm_addl_i_r(pc
, 16, emit_ESP
);
485 /* call the resulting function pointer */
486 emitm_callr(pc
, emit_EAX
);
487 emitm_subl_i_r(pc
, 16, emit_ESP
);
490 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
493 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
494 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
497 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 8);
498 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 0);
500 /* RESTORE BACK EAX */
501 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
503 /* now place return value in registers */
504 /* first in signature is the return value */
505 sig
= signature_str
; /* the result */
507 /* I have no idea how to handle these */
511 /* get integer from pointer - untested */
512 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1, 0);
513 if (*sig
== 2) /* short */
514 emitm_movswl_r_r(pc
, emit_EAX
, emit_EAX
);
515 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_I);*/
519 jit_emit_fstore_mb_n(interp
, pc
, emit_EBP
, temp_calls_offset
+ 8);
520 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_N); */
521 /* pop num from st(0) and mov to reg */
524 /* movswl %ax, %eax */
525 emitm_movswl_r_r(pc
, emit_EAX
, emit_EAX
);
526 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
527 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_I); */
530 /* movsbl %al, %eax */
531 emitm_movsbl_r_r(pc
, emit_EAX
, emit_EAX
);
532 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
533 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_I); */
535 case 'I': /* INTVAL */
538 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
539 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_I); */
541 case 'v': /* void - do nothing */
544 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
545 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_P); */
547 case 'p': /* make a new unmanaged struct */
548 /* save return value on stack */
551 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 12);
554 emitm_movl_i_m(pc
, enum_class_UnManagedStruct
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
555 emitm_call_cfunc(pc
, Parrot_pmc_new
);
557 /* restore pointer p to EDX */
558 emitm_movl_m_r(interp
, pc
, emit_EDX
, emit_EBP
, 0, 1, temp_calls_offset
+ 12);
560 /* copy UnManagedStruct to stack for set_nci_P call */
561 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
563 /* eax = PMC, get return value into edx */
564 /* mov data(%eax), %eax
565 mov %edx, ptr(%eax) */
566 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1, offsetof(struct PMC
, data
));
567 emitm_movl_r_m(interp
, pc
, emit_EDX
, emit_EAX
, 0, 1,
568 offsetof(struct Parrot_UnManagedStruct_attributes
, ptr
));
571 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
572 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
574 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_P); */
577 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
578 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_S); */
580 case 't': /* string */
582 emitm_movl_i_m(pc
, 0, emit_EBP
, 0, 1, temp_calls_offset
+ 8); /* len */
584 /* overwrites address of st in EBP(4) */
585 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
587 emitm_call_cfunc(pc
, Parrot_str_new
);
589 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
592 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
593 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
595 /* XXX FIXME (TT #1325) emitm_call_cfunc(pc, set_nci_S); */
598 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
599 "Unknown return Signature %c\n", *sig
);
601 * oops unknown signature:
602 * cleanup and try nci.c
604 Parrot_str_free_cstring(signature_str
);
605 mem_free_executable(execmem
, JIT_ALLOC_SIZE
);
609 /* free temporary strings */
610 strings_offset
= st_offset
+ ST_SIZE_OF
;
611 for (i
=0; i
<string_buffer_count
; i
++) {
612 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, strings_offset
);
613 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 0);
614 emitm_call_cfunc(pc
, Parrot_str_free_cstring
);
618 jit_emit_stack_frame_leave(pc
);
620 PARROT_ASSERT(pc
- execmem
<= JIT_ALLOC_SIZE
);
623 *sizeptr
= JIT_ALLOC_SIZE
;
624 Parrot_str_free_cstring(signature_str
);
625 return (void *)D2FPTR(execmem
);
630 * c-file-style: "parrot"
632 * vim: expandtab shiftwidth=4: