[t][TT #1119] Convert t/op/bitwise.t to PIR
[parrot.git] / src / frame_builder.c
blobe123c36b709f27c982b87d84268d5d46e004e87c
1 /*
2 Copyright (C) 2008-2009, Parrot Foundation.
3 $Id$
4 */
6 /* HEADERIZER HFILE: none */
7 /* HEADERIZER STOP */
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"
17 =over 4
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.
24 =cut
28 void
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);
33 free(priv);
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.
43 =back
45 =cut
49 PMC *
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);
71 if (freepriv) {
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 */
81 if (clonepriv) {
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);
93 if (!newptr)
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;
100 return rv;
105 emit_is8bit(long disp)
107 return disp >= -128 && disp <= 127;
110 char *
111 emit_disp8_32(char *pc, int disp)
113 if (emit_is8bit(disp)) {
114 *(pc++) = (char)disp;
115 return pc;
117 else {
118 *(long *)pc = disp;
119 return pc + 4;
123 void
124 emit_sib(PARROT_INTERP, char *pc, int scale, int i, int base)
126 int scale_byte;
128 switch (scale) {
129 case 1:
130 scale_byte = emit_Scale_1;
131 break;
132 case 2:
133 scale_byte = emit_Scale_2;
134 break;
135 case 4:
136 scale_byte = emit_Scale_4;
137 break;
138 case 8:
139 scale_byte = emit_Scale_8;
140 break;
141 default:
142 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR,
143 "Invalid scale factor %d\n", scale);
144 return;
147 *pc = (char)(scale_byte | (i == emit_None ? emit_Index_None : emit_reg_Index(i)) |
148 emit_reg_Base(base));
151 char *
152 emit_r_X(PARROT_INTERP, char *pc, int reg_opcode, int base, int i, int scale, long disp)
154 if (i && !scale)
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) {
159 /* modrm disp */
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);
165 /* modrm sib disp */
166 else {
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);
174 /* modrm sib 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);
182 /* modrm disp32 */
183 if (!base && !(i && scale)) {
184 *(pc++) = (char)(emit_Mod_b00 | reg_opcode | emit_rm_b101);
185 *(long *)pc = disp;
186 return pc + 4;
189 /* Ok, everything should be more regular here */
190 *(pc++) = (char)((disp == 0 ? emit_Mod_b00 :
191 (emit_is8bit(disp) ?
192 emit_Mod_b01 : emit_Mod_b10)) |
193 reg_opcode |
194 (!base || (scale && i) ? emit_rm_b100 : emit_reg_rm(base)));
196 if (!base || (scale && i)) {
197 emit_sib(interp, pc++, scale, i, base);
199 if (disp)
200 pc = emit_disp8_32(pc, disp);
202 return pc;
205 char *
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 */
210 imm = -imm;
213 if (imm == 0) {
214 /* noop */
216 else if (imm == 1) {
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);
223 *(pc++) = (char)imm;
225 else {
226 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR,
227 "emit_shift_i_r passed invalid shift\n");
230 return pc;
233 char *
234 emit_popl_r(char *pc, int reg)
236 *(pc++) = (char)(0x58 | (reg - 1));
237 return pc;
240 unsigned char *lastpc;
242 size_t
243 calc_signature_needs(const char *sig, int *strings)
245 size_t stack_size = 0;
246 while (*sig) {
247 switch (*sig) {
248 case 't':
249 (*strings)++;
250 stack_size +=4;
251 break;
252 case 'd':
253 stack_size +=8;
254 break;
255 default:
256 stack_size +=4;
257 break;
259 sig++;
261 return stack_size;
266 * The function generated here is called as func(interp, nci_info)
267 * interp ... 8(%ebp)
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.
278 void *
279 Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, STRING *signature, int *sizeptr)
281 char *pc;
282 char *execmem;
283 int i = 0;
284 int arg_count = 0;
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);
295 int base_offset = 0;
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;
303 * ESP
304 * 0-15, 16 bytes for utility calls
305 * stack_space_needed for actual NCI call
306 * st
307 * STRINGS -> char * holding space
308 * EBP
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);
315 if (! pc)
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);
333 /*&st*/
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);
337 /*interpreter*/
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); */
345 while (*sig) {
346 emitm_movl_i_m(pc, arg_count, emit_EBP, 0, 1, temp_calls_offset + 8);
348 switch (*sig) {
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);
352 break;
353 case 'f':
354 /* FIXME emitm_call_cfunc(pc, get_nci_N); */
355 emitm_fstps(interp, pc, emit_EBP, 0, 1, args_offset);
356 break;
357 case 'N':
358 case 'd':
359 /* FIXME emitm_call_cfunc(pc, get_nci_N); */
360 emitm_fstpl(interp, pc, emit_EBP, 0, 1, args_offset);
361 args_offset += 4;
362 break;
363 case 'I': /* INTVAL */
364 case 'l': /* long */
365 case 'i': /* int */
366 /* FIXME emitm_call_cfunc(pc, get_nci_I); */
367 emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset);
368 break;
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);
377 strings_offset += 4;
379 /* reset ESP(4) */
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);
382 break;
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);
387 break;
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);
392 break;
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);
396 arg_count--;
397 break;
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);
401 break;
402 case 'O': /* push PMC * object in P2 */
403 case 'P': /* push PMC * */
404 case '@':
405 /* FIXME emitm_call_cfunc(pc, get_nci_P); */
406 emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset);
407 break;
408 case 'v':
409 break;
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);
415 break;
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);
421 break;
422 case 'S':
423 /* FIXME emitm_call_cfunc(pc, get_nci_S); */
424 emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset);
425 break;
428 /* I have no idea how to handle these */
429 case '2':
430 case '3':
431 case '4':
432 case 'V':
433 mem_free_executable(execmem, JIT_ALLOC_SIZE);
434 Parrot_str_free_cstring(signature_str);
435 return NULL;
436 break;
437 default:
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);
446 return NULL;
448 args_offset +=4;
449 arg_count++;
450 sig++;
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);
474 /* SAVE OFF EAX */
475 emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8);
477 /*&st*/
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);
481 /*interpreter*/
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 */
491 switch (*sig) {
492 /* I have no idea how to handle these */
493 case '2':
494 case '3':
495 case '4':
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);*/
501 break;
502 case 'f':
503 case 'd':
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 */
507 break;
508 case 's':
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); */
513 break;
514 case 'c':
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); */
519 break;
520 case 'I': /* INTVAL */
521 case 'l':
522 case 'i':
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); */
525 break;
526 case 'v': /* void - do nothing */
527 break;
528 case 'P':
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); */
531 break;
532 case 'p': /* make a new unmanaged struct */
533 /* save return value on stack */
535 /* save pointer p */
536 emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 12);
538 /* make new pmc */
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));
555 /* reset EBP(4) */
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); */
560 break;
561 case 'S':
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); */
564 break;
565 case 't': /* string */
566 /* EAX is char* */
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);
576 /* reset EBP(4) */
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); */
581 break;
582 default:
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);
591 return NULL;
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);
600 strings_offset += 4;
603 jit_emit_stack_frame_leave(pc);
604 emitm_ret(pc);
605 PARROT_ASSERT(pc - execmem <= JIT_ALLOC_SIZE);
607 if (sizeptr)
608 *sizeptr = JIT_ALLOC_SIZE;
609 Parrot_str_free_cstring(signature_str);
610 return (void *)D2FPTR(execmem);
614 * Local variables:
615 * c-file-style: "parrot"
616 * End:
617 * vim: expandtab shiftwidth=4: