2 Copyright (C) 2008-2009, Parrot Foundation.
6 /* HEADERIZER HFILE: none */
9 #include "parrot/parrot.h"
10 #include "pmc/pmc_fixedintegerarray.h"
11 #include "pmc/pmc_unmanagedstruct.h"
12 #include "pmc/pmc_managedstruct.h"
13 #include "frame_builder.h"
19 =item C<void Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv)>
21 This is a callback to implement the proper freeing semantics. It is called by
22 the ManagedStruct PMC as it is garbage collected.
29 Parrot_jit_free_buffer(PARROT_INTERP
, void *ptr
, void *priv
)
31 const struct jit_buffer_private_data
* const jit
= (struct jit_buffer_private_data
*)priv
;
32 mem_free_executable(ptr
, jit
->size
);
38 =item C<PMC *Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv)>
40 This is a callback to implement the proper cloning semantics for jit buffers.
41 It is called by the ManagedStruct PMC's clone() function.
50 Parrot_jit_clone_buffer(PARROT_INTERP
, PMC
*pmc
, void *priv
)
52 PMC
* const rv
= pmc_new(interp
, pmc
->vtable
->base_type
);
54 VTABLE_init(interp
, rv
);
55 /* copy the attributes */
57 void (*tmpfreefunc
)(PARROT_INTERP
, void*, void*);
58 GETATTR_ManagedStruct_custom_free_func(interp
, pmc
, tmpfreefunc
);
59 SETATTR_ManagedStruct_custom_free_func(interp
, rv
, tmpfreefunc
);
62 PMC
* (*tmpclonefunc
)(PARROT_INTERP
, PMC
*, void*);
63 GETATTR_ManagedStruct_custom_clone_func(interp
, pmc
, tmpclonefunc
);
64 SETATTR_ManagedStruct_custom_clone_func(interp
, rv
, tmpclonefunc
);
68 void *freepriv
, *clonepriv
;
69 GETATTR_ManagedStruct_custom_free_priv(interp
, pmc
, freepriv
);
70 GETATTR_ManagedStruct_custom_clone_priv(interp
, pmc
, clonepriv
);
72 void *tmp
= mem_sys_allocate(sizeof (struct jit_buffer_private_data
));
73 memcpy(tmp
, freepriv
, sizeof (struct jit_buffer_private_data
));
74 SETATTR_ManagedStruct_custom_free_priv(interp
, rv
, tmp
);
75 if (clonepriv
== freepriv
) {
76 /* clonepriv is a copy of freepriv, make it a copy in the clone too. */
77 SETATTR_ManagedStruct_custom_clone_priv(interp
, rv
, tmp
);
78 clonepriv
= NULL
; /* disable the clonepriv copying below */
82 void *tmp
= mem_sys_allocate(sizeof (struct jit_buffer_private_data
));
83 memcpy(tmp
, clonepriv
, sizeof (struct jit_buffer_private_data
));
84 SETATTR_ManagedStruct_custom_clone_priv(interp
, rv
, tmp
);
88 /* copy the execmem buffer */
89 if (PARROT_MANAGEDSTRUCT(pmc
)->ptr
) {
90 struct jit_buffer_private_data
*jit
= (struct jit_buffer_private_data
*)priv
;
91 void *ptr
= PARROT_MANAGEDSTRUCT(pmc
)->ptr
;
92 void *newptr
= mem_alloc_executable(jit
->size
);
94 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
95 "Cannot allocate executable memory");
96 memcpy(newptr
, ptr
, jit
->size
);
97 PARROT_MANAGEDSTRUCT(rv
)->ptr
= newptr
;
105 emit_is8bit(long disp
)
107 return disp
>= -128 && disp
<= 127;
111 emit_disp8_32(char *pc
, int disp
)
113 if (emit_is8bit(disp
)) {
114 *(pc
++) = (char)disp
;
124 emit_sib(PARROT_INTERP
, char *pc
, int scale
, int i
, int base
)
130 scale_byte
= emit_Scale_1
;
133 scale_byte
= emit_Scale_2
;
136 scale_byte
= emit_Scale_4
;
139 scale_byte
= emit_Scale_8
;
142 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
143 "Invalid scale factor %d\n", scale
);
147 *pc
= (char)(scale_byte
| (i
== emit_None
? emit_Index_None
: emit_reg_Index(i
)) |
148 emit_reg_Base(base
));
152 emit_r_X(PARROT_INTERP
, char *pc
, int reg_opcode
, int base
, int i
, int scale
, long disp
)
155 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
156 "emit_r_X passed invalid scale+index combo\n");
158 if (base
== emit_EBP
) {
160 if (i
== emit_None
) {
161 *(pc
++) = (char)((emit_is8bit(disp
) ? emit_Mod_b01
: emit_Mod_b10
)
162 | reg_opcode
| emit_reg_rm(emit_EBP
));
163 return emit_disp8_32(pc
, disp
);
167 *(pc
++) = (char)((emit_is8bit(disp
) ? emit_Mod_b01
: emit_Mod_b10
)
168 | reg_opcode
| emit_b100
);
169 emit_sib(interp
, pc
++, scale
, i
, base
);
170 return emit_disp8_32(pc
, disp
);
175 if (base
== emit_ESP
) {
176 *(pc
++) = (char)((emit_is8bit(disp
) ? emit_Mod_b01
: emit_Mod_b10
)
177 | reg_opcode
| emit_rm_b100
);
178 emit_sib(interp
, pc
++, scale
, i
, emit_ESP
);
179 return emit_disp8_32(pc
, disp
);
183 if (!base
&& !(i
&& scale
)) {
184 *(pc
++) = (char)(emit_Mod_b00
| reg_opcode
| emit_rm_b101
);
189 /* Ok, everything should be more regular here */
190 *(pc
++) = (char)((disp
== 0 ? emit_Mod_b00
:
192 emit_Mod_b01
: emit_Mod_b10
)) |
194 (!base
|| (scale
&& i
) ? emit_rm_b100
: emit_reg_rm(base
)));
196 if (!base
|| (scale
&& i
)) {
197 emit_sib(interp
, pc
++, scale
, i
, base
);
200 pc
= emit_disp8_32(pc
, disp
);
206 emit_shift_i_r(PARROT_INTERP
, char *pc
, int opcode
, int imm
, int reg
)
208 if (opcode
== emit_b000
&& imm
< 0) {
209 opcode
= emit_b001
; /* -rol => 32 + ror */
217 *(pc
++) = (char) 0xd1;
218 *(pc
++) = (char) emit_alu_X_r(opcode
, reg
);
220 else if (imm
> 1 && imm
< 33) {
221 *(pc
++) = (char) 0xc1;
222 *(pc
++) = (char) emit_alu_X_r(opcode
, reg
);
226 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
227 "emit_shift_i_r passed invalid shift\n");
234 emit_popl_r(char *pc
, int reg
)
236 *(pc
++) = (char)(0x58 | (reg
- 1));
240 unsigned char *lastpc
;
243 calc_signature_needs(const char *sig
, int *strings
)
245 size_t stack_size
= 0;
266 * The function generated here is called as func(interp, nci_info)
268 * nci_info ... 12(%ebp)
270 * The generate function for a specific signature looks quite similar to
271 * an optimized compile of src/nci.c:pcf_x_yy(). In case of any troubles
272 * just compare the disassembly.
274 * If a non-NULL sizeptr is passed, the integer it points to will be written
275 * with the size of the allocated execmem buffer.
279 Parrot_jit_build_call_func(PARROT_INTERP
, PMC
*pmc_nci
, STRING
*signature
, int *sizeptr
)
285 int string_buffer_count
= 0;
286 const int ST_SIZE_OF
= 124;
287 const int JIT_ALLOC_SIZE
= 1024;
289 char *signature_str
= Parrot_str_to_cstring(interp
, signature
);
290 /* skip over the result */
291 char *sig
= signature_str
+ 1;
292 size_t stack_space_needed
= calc_signature_needs(sig
,
293 &string_buffer_count
);
296 int strings_offset
= base_offset
- (sizeof (char *) * string_buffer_count
);
297 int st_offset
= strings_offset
- ST_SIZE_OF
;
298 int args_offset
= st_offset
- stack_space_needed
;
299 int temp_calls_offset
= args_offset
- 16;
300 int total_stack_needed
= -temp_calls_offset
;
304 * 0-15, 16 bytes for utility calls
305 * stack_space_needed for actual NCI call
307 * STRINGS -> char * holding space
311 /* this ought to be enough - the caller of this function
312 * should free the function pointer returned here
314 pc
= execmem
= (char *)mem_alloc_executable(JIT_ALLOC_SIZE
);
316 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
317 "Cannot allocate executable memory");
320 /* this generated jit function will be called as (INTERP (EBP 8), func_ptr
321 * (ESP 12), args signature (ESP 16)) */
323 /* make stack frame, preserve %ebx */
324 jit_emit_stack_frame_enter(pc
);
326 emitm_subl_i_r(pc
, total_stack_needed
, emit_ESP
);
328 /* Parrot_init_arg_nci(interp, &st, "S"); */
329 /* args signature "S" */
330 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 16);
331 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
334 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
335 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
338 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 8);
339 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 0);
341 /* XXX FIXME This whole function require major rework */
342 /* XXX FIXME if (sig && *sig) */
343 /* XXX FIXME emitm_call_cfunc(pc, Parrot_init_arg_nci); */
346 emitm_movl_i_m(pc
, arg_count
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
349 case '0': /* null ptr or such - doesn't consume a reg */
350 jit_emit_bxor_rr_i(interp
, pc
, emit_EAX
, emit_EAX
);
351 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
354 /* FIXME emitm_call_cfunc(pc, get_nci_N); */
355 emitm_fstps(interp
, pc
, emit_EBP
, 0, 1, args_offset
);
359 /* FIXME emitm_call_cfunc(pc, get_nci_N); */
360 emitm_fstpl(interp
, pc
, emit_EBP
, 0, 1, args_offset
);
363 case 'I': /* INTVAL */
366 /* FIXME emitm_call_cfunc(pc, get_nci_I); */
367 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
369 case 't': /* string, pass a cstring */
370 /* FIXME emitm_call_cfunc(pc, get_nci_S); */
371 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
372 emitm_call_cfunc(pc
, string_to_cstring_nullable
);
374 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
375 /* save off temporary allocation address */
376 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, strings_offset
);
380 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
381 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
383 case 's': /* short: movswl intreg_o(base), %eax */
384 /* FIXME emitm_call_cfunc(pc, get_nci_I); */
385 emitm_movswl_r_r(pc
, emit_EAX
, emit_EAX
);
386 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
388 case 'c': /* char: movsbl intreg_o(base), %eax */
389 /* emitm_call_cfunc(pc, get_nci_I); */
390 emitm_movsbl_r_r(pc
, emit_EAX
, emit_EAX
);
391 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
393 case 'J': /* interpreter */
394 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 8);
395 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
398 case 'p': /* push pmc->data */
399 /* FIXME emitm_call_cfunc(pc, get_nci_p); */
400 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
402 case 'O': /* push PMC * object in P2 */
403 case 'P': /* push PMC * */
405 /* FIXME emitm_call_cfunc(pc, get_nci_P); */
406 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
410 case 'b': /* buffer (void*) pass Buffer_bufstart(SReg) */
411 /* FIXME emitm_call_cfunc(pc, get_nci_S); */
412 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1,
413 (size_t) &Buffer_bufstart((STRING
*) NULL
));
414 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
416 case 'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */
417 /* FIXME emitm_call_cfunc(pc, get_nci_S); */
418 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1,
419 (size_t) &Buffer_bufstart((STRING
*) NULL
));
420 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
423 /* FIXME emitm_call_cfunc(pc, get_nci_S); */
424 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, args_offset
);
428 /* I have no idea how to handle these */
433 mem_free_executable(execmem
, JIT_ALLOC_SIZE
);
434 Parrot_str_free_cstring(signature_str
);
438 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
439 "Unknown arg Signature %c\n", *sig
);
441 * oops unknown signature:
442 * cleanup and try nci.c
444 mem_free_executable(execmem
, JIT_ALLOC_SIZE
);
445 Parrot_str_free_cstring(signature_str
);
453 /* prepare to call VTABLE_get_pointer, set up args */
454 /* interpreter - movl 8(%ebp), %eax */
455 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 8);
456 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 0);
458 /* pmc - movl 12(%ebp), %eax */
459 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 12);
460 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
462 /* get the get_pointer() pointer from the pmc's vtable */
463 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1, offsetof(PMC
, vtable
));
464 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1, offsetof(VTABLE
, get_pointer
));
466 /* call get_pointer(), result goes into eax */
467 emitm_callr(pc
, emit_EAX
);
468 emitm_addl_i_r(pc
, 16, emit_ESP
);
470 /* call the resulting function pointer */
471 emitm_callr(pc
, emit_EAX
);
472 emitm_subl_i_r(pc
, 16, emit_ESP
);
475 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
478 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
479 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
482 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, 8);
483 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 0);
485 /* RESTORE BACK EAX */
486 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
488 /* now place return value in registers */
489 /* first in signature is the return value */
490 sig
= signature_str
; /* the result */
492 /* I have no idea how to handle these */
496 /* get integer from pointer - untested */
497 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1, 0);
498 if (*sig
== 2) /* short */
499 emitm_movswl_r_r(pc
, emit_EAX
, emit_EAX
);
500 /* XXX FIXME emitm_call_cfunc(pc, set_nci_I);*/
504 jit_emit_fstore_mb_n(interp
, pc
, emit_EBP
, temp_calls_offset
+ 8);
505 /* XXX FIXME emitm_call_cfunc(pc, set_nci_N); */
506 /* pop num from st(0) and mov to reg */
509 /* movswl %ax, %eax */
510 emitm_movswl_r_r(pc
, emit_EAX
, emit_EAX
);
511 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
512 /* XXX FIXME emitm_call_cfunc(pc, set_nci_I); */
515 /* movsbl %al, %eax */
516 emitm_movsbl_r_r(pc
, emit_EAX
, emit_EAX
);
517 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
518 /* XXX FIXME emitm_call_cfunc(pc, set_nci_I); */
520 case 'I': /* INTVAL */
523 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
524 /* XXX FIXME emitm_call_cfunc(pc, set_nci_I); */
526 case 'v': /* void - do nothing */
529 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
530 /* XXX FIXME emitm_call_cfunc(pc, set_nci_P); */
532 case 'p': /* make a new unmanaged struct */
533 /* save return value on stack */
536 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 12);
539 emitm_movl_i_m(pc
, enum_class_UnManagedStruct
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
540 emitm_call_cfunc(pc
, pmc_new
);
542 /* restore pointer p to EDX */
543 emitm_movl_m_r(interp
, pc
, emit_EDX
, emit_EBP
, 0, 1, temp_calls_offset
+ 12);
545 /* copy UnManagedStruct to stack for set_nci_P call */
546 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
548 /* eax = PMC, get return value into edx */
549 /* mov data(%eax), %eax
550 mov %edx, ptr(%eax) */
551 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EAX
, 0, 1, offsetof(struct PMC
, data
));
552 emitm_movl_r_m(interp
, pc
, emit_EDX
, emit_EAX
, 0, 1,
553 offsetof(struct Parrot_UnManagedStruct_attributes
, ptr
));
556 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
557 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
559 /* XXX FIXME emitm_call_cfunc(pc, set_nci_P); */
562 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
563 /* XXX FIXME emitm_call_cfunc(pc, set_nci_S); */
565 case 't': /* string */
567 emitm_movl_i_m(pc
, 0, emit_EBP
, 0, 1, temp_calls_offset
+ 8); /* len */
569 /* overwrites address of st in EBP(4) */
570 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
572 emitm_call_cfunc(pc
, Parrot_str_new
);
574 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 8);
577 emitm_lea_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, st_offset
);
578 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 4);
580 /* XXX FIXME emitm_call_cfunc(pc, set_nci_S); */
583 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_JIT_ERROR
,
584 "Unknown return Signature %c\n", *sig
);
586 * oops unknown signature:
587 * cleanup and try nci.c
589 Parrot_str_free_cstring(signature_str
);
590 mem_free_executable(execmem
, JIT_ALLOC_SIZE
);
594 /* free temporary strings */
595 strings_offset
= st_offset
+ ST_SIZE_OF
;
596 for (i
=0; i
<string_buffer_count
; i
++) {
597 emitm_movl_m_r(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, strings_offset
);
598 emitm_movl_r_m(interp
, pc
, emit_EAX
, emit_EBP
, 0, 1, temp_calls_offset
+ 0);
599 emitm_call_cfunc(pc
, Parrot_str_free_cstring
);
603 jit_emit_stack_frame_leave(pc
);
605 PARROT_ASSERT(pc
- execmem
<= JIT_ALLOC_SIZE
);
608 *sizeptr
= JIT_ALLOC_SIZE
;
609 Parrot_str_free_cstring(signature_str
);
610 return (void *)D2FPTR(execmem
);
615 * c-file-style: "parrot"
617 * vim: expandtab shiftwidth=4: