1 /***********************************************************************/
5 /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
7 /* Copyright 1996 Institut National de Recherche en Informatique et */
8 /* en Automatique. All rights reserved. This file is distributed */
9 /* under the terms of the GNU Library General Public License, with */
10 /* the special exception on linking described in file ../LICENSE. */
12 /***********************************************************************/
14 /* $Id: interp.c 9513 2010-01-08 10:33:23Z xleroy $ */
16 /* The bytecode interpreter */
19 #include "backtrace.h"
24 #include "instrtrace.h"
35 /* Registers for the abstract machine:
37 sp the stack pointer (grows downward)
39 env heap-allocated environment
40 caml_trapsp pointer to the current trap frame
41 extra_args number of extra arguments provided by the caller
43 sp is a local copy of the global variable caml_extern_sp. */
45 /* Instruction decoding */
48 # define Instruct(name) lbl_##name
49 # if defined(ARCH_SIXTYFOUR) && !defined(ARCH_CODE32)
50 # define Jumptbl_base ((char *) &&lbl_ACC0)
52 # define Jumptbl_base ((char *) 0)
53 # define jumptbl_base ((char *) 0)
56 # define Next goto next_instr
58 # define Next goto *(void *)(jumptbl_base + *pc++)
61 # define Instruct(name) case name
67 #define Setup_for_gc \
68 { sp -= 2; sp[0] = accu; sp[1] = env; caml_extern_sp = sp; }
69 #define Restore_after_gc \
70 { accu = sp[0]; env = sp[1]; sp += 2; }
71 #define Setup_for_c_call \
72 { saved_pc = pc; *--sp = env; caml_extern_sp = sp; }
73 #define Restore_after_c_call \
74 { sp = caml_extern_sp; env = *sp++; saved_pc = NULL; }
76 /* An event frame must look like accu + a C_CALL frame + a RETURN 1 frame */
77 #define Setup_for_event \
79 sp[0] = accu; /* accu */ \
80 sp[1] = Val_unit; /* C_CALL frame: dummy environment */ \
81 sp[2] = Val_unit; /* RETURN frame: dummy local 0 */ \
82 sp[3] = (value) pc; /* RETURN frame: saved return address */ \
83 sp[4] = env; /* RETURN frame: saved environment */ \
84 sp[5] = Val_long(extra_args); /* RETURN frame: saved extra args */ \
85 caml_extern_sp = sp; }
86 #define Restore_after_event \
87 { sp = caml_extern_sp; accu = sp[0]; \
88 pc = (code_t) sp[3]; env = sp[4]; extra_args = Long_val(sp[5]); \
91 /* Debugger interface */
93 #define Setup_for_debugger \
95 sp[0] = accu; sp[1] = (value)(pc - 1); \
96 sp[2] = env; sp[3] = Val_long(extra_args); \
97 caml_extern_sp = sp; }
98 #define Restore_after_debugger { sp += 4; }
101 #define Restart_curr_instr \
102 goto *(jumptable[caml_saved_code[pc - 1 - caml_start_code]])
104 #define Restart_curr_instr \
105 curr_instr = caml_saved_code[pc - 1 - caml_start_code]; \
109 /* Register optimization.
110 Some compilers underestimate the use of the local variables representing
111 the abstract machine registers, and don't put them in hardware registers,
112 which slows down the interpreter considerably.
113 For GCC, I have hand-assigned hardware registers for several architectures.
116 #if defined(__GNUC__) && !defined(DEBUG) && !defined(__INTEL_COMPILER) && !defined(__llvm__)
118 #define PC_REG asm("$16")
119 #define SP_REG asm("$17")
120 #define ACCU_REG asm("$18")
123 #define PC_REG asm("%l0")
124 #define SP_REG asm("%l1")
125 #define ACCU_REG asm("%l2")
129 #define PC_REG asm("r9")
130 #define SP_REG asm("r10")
131 #define ACCU_REG asm("r11")
132 #define JUMPTBL_BASE_REG asm("r12")
134 #define PC_REG asm("$9")
135 #define SP_REG asm("$10")
136 #define ACCU_REG asm("$11")
137 #define JUMPTBL_BASE_REG asm("$12")
141 #define PC_REG asm("%esi")
142 #define SP_REG asm("%edi")
145 #if defined(__ppc__) || defined(__ppc64__)
146 #define PC_REG asm("26")
147 #define SP_REG asm("27")
148 #define ACCU_REG asm("28")
151 #define PC_REG asm("%r18")
152 #define SP_REG asm("%r17")
153 #define ACCU_REG asm("%r16")
156 #define PC_REG asm("a5")
157 #define SP_REG asm("a4")
158 #define ACCU_REG asm("d7")
160 /* PR#4953: these specific registers not available in Thumb mode */
161 #if defined (__arm__) && !defined(__thumb__)
162 #define PC_REG asm("r9")
163 #define SP_REG asm("r8")
164 #define ACCU_REG asm("r7")
167 #define PC_REG asm("36")
168 #define SP_REG asm("37")
169 #define ACCU_REG asm("38")
170 #define JUMPTBL_BASE_REG asm("39")
173 #define PC_REG asm("%r15")
174 #define SP_REG asm("%r14")
175 #define ACCU_REG asm("%r13")
179 /* Division and modulus madness */
181 #ifdef NONSTANDARD_DIV_MOD
182 extern intnat caml_safe_div(intnat p, intnat q);
183 extern intnat caml_safe_mod(intnat p, intnat q);
188 static intnat caml_bcodcount;
191 /* The interpreter itself */
193 value caml_interprete(code_t prog, asize_t prog_size)
196 register code_t pc PC_REG;
197 register value * sp SP_REG;
198 register value accu ACCU_REG;
204 #if defined(THREADED_CODE) && defined(ARCH_SIXTYFOUR) && !defined(ARCH_CODE32)
205 #ifdef JUMPTBL_BASE_REG
206 register char * jumptbl_base JUMPTBL_BASE_REG;
208 register char * jumptbl_base;
213 struct longjmp_buffer * initial_external_raise;
214 int initial_sp_offset;
215 /* volatile ensures that initial_local_roots and saved_pc
216 will keep correct value across longjmp */
217 struct caml__roots_block * volatile initial_local_roots;
218 volatile code_t saved_pc = NULL;
219 struct longjmp_buffer raise_buf;
220 value * modify_dest, modify_newval;
221 #ifndef THREADED_CODE
226 static void * jumptable[] = {
227 # include "jumptbl.h"
231 if (prog == NULL) { /* Interpreter is initializing */
233 caml_instr_table = (char **) jumptable;
234 caml_instr_base = Jumptbl_base;
239 #if defined(THREADED_CODE) && defined(ARCH_SIXTYFOUR) && !defined(ARCH_CODE32)
240 jumptbl_base = Jumptbl_base;
242 initial_local_roots = caml_local_roots;
243 initial_sp_offset = (char *) caml_stack_high - (char *) caml_extern_sp;
244 initial_external_raise = caml_external_raise;
245 caml_callback_depth++;
248 if (sigsetjmp(raise_buf.buf, 0)) {
249 caml_local_roots = initial_local_roots;
251 accu = caml_exn_bucket;
252 pc = saved_pc; saved_pc = NULL;
253 if (pc != NULL) pc += 2;
254 /* +2 adjustement for the sole purpose of backtraces */
255 goto raise_exception;
257 caml_external_raise = &raise_buf;
268 if (caml_icount-- == 0) caml_stop_here ();
269 Assert(sp >= caml_stack_low);
270 Assert(sp <= caml_stack_high);
272 goto *(void *)(jumptbl_base + *pc++); /* Jump to the first instruction */
277 if (caml_icount-- == 0) caml_stop_here ();
278 if (caml_trace_flag>1) printf("\n##%ld\n", caml_bcodcount);
279 if (caml_trace_flag) caml_disasm_instr(pc);
280 if (caml_trace_flag>1) {
282 caml_trace_value_file(env,prog,prog_size,stdout);
284 caml_trace_accu_sp_file(accu,sp,prog,prog_size,stdout);
287 Assert(sp >= caml_stack_low);
288 Assert(sp <= caml_stack_high);
296 /* Basic stack operations */
315 Instruct(PUSH): Instruct(PUSHACC0):
318 *--sp = accu; accu = sp[1]; Next;
320 *--sp = accu; accu = sp[2]; Next;
322 *--sp = accu; accu = sp[3]; Next;
324 *--sp = accu; accu = sp[4]; Next;
326 *--sp = accu; accu = sp[5]; Next;
328 *--sp = accu; accu = sp[6]; Next;
330 *--sp = accu; accu = sp[7]; Next;
347 /* Access in heap-allocated environment */
350 accu = Field(env, 1); Next;
352 accu = Field(env, 2); Next;
354 accu = Field(env, 3); Next;
356 accu = Field(env, 4); Next;
358 Instruct(PUSHENVACC1):
359 *--sp = accu; accu = Field(env, 1); Next;
360 Instruct(PUSHENVACC2):
361 *--sp = accu; accu = Field(env, 2); Next;
362 Instruct(PUSHENVACC3):
363 *--sp = accu; accu = Field(env, 3); Next;
364 Instruct(PUSHENVACC4):
365 *--sp = accu; accu = Field(env, 4); Next;
367 Instruct(PUSHENVACC):
371 accu = Field(env, *pc++);
374 /* Function application */
376 Instruct(PUSH_RETADDR): {
378 sp[0] = (value) (pc + *pc);
380 sp[2] = Val_long(extra_args);
385 extra_args = *pc - 1;
396 sp[3] = Val_long(extra_args);
410 sp[4] = Val_long(extra_args);
426 sp[5] = Val_long(extra_args);
438 /* Slide the nargs bottom words of the current frame to the top
439 of the frame, and discard the remainder of the frame */
440 newsp = sp + slotsize - nargs;
441 for (i = nargs - 1; i >= 0; i--) newsp[i] = sp[i];
445 extra_args += nargs - 1;
448 Instruct(APPTERM1): {
456 Instruct(APPTERM2): {
467 Instruct(APPTERM3): {
483 if (extra_args > 0) {
488 pc = (code_t)(sp[0]);
490 extra_args = Long_val(sp[2]);
497 int num_args = Wosize_val(env) - 2;
500 for (i = 0; i < num_args; i++) sp[i] = Field(env, i + 2);
502 extra_args += num_args;
507 int required = *pc++;
508 if (extra_args >= required) {
509 extra_args -= required;
511 mlsize_t num_args, i;
512 num_args = 1 + extra_args; /* arg1 + extra args */
513 Alloc_small(accu, num_args + 2, Closure_tag);
514 Field(accu, 1) = env;
515 for (i = 0; i < num_args; i++) Field(accu, i + 2) = sp[i];
516 Code_val(accu) = pc - 3; /* Point to the preceding RESTART instr. */
518 pc = (code_t)(sp[0]);
520 extra_args = Long_val(sp[2]);
529 if (nvars > 0) *--sp = accu;
530 Alloc_small(accu, 1 + nvars, Closure_tag);
531 Code_val(accu) = pc + *pc;
533 for (i = 0; i < nvars; i++) Field(accu, i + 1) = sp[i];
538 Instruct(CLOSUREREC): {
543 if (nvars > 0) *--sp = accu;
544 Alloc_small(accu, nfuncs * 2 - 1 + nvars, Closure_tag);
545 p = &Field(accu, nfuncs * 2 - 1);
546 for (i = 0; i < nvars; i++) {
551 *p = (value) (pc + pc[0]);
554 for (i = 1; i < nfuncs; i++) {
555 *p = Make_header(i * 2, Infix_tag, Caml_white); /* color irrelevant. */
557 *p = (value) (pc + pc[i]);
565 Instruct(PUSHOFFSETCLOSURE):
566 *--sp = accu; /* fallthrough */
567 Instruct(OFFSETCLOSURE):
568 accu = env + *pc++ * sizeof(value); Next;
570 Instruct(PUSHOFFSETCLOSUREM2):
571 *--sp = accu; /* fallthrough */
572 Instruct(OFFSETCLOSUREM2):
573 accu = env - 2 * sizeof(value); Next;
574 Instruct(PUSHOFFSETCLOSURE0):
575 *--sp = accu; /* fallthrough */
576 Instruct(OFFSETCLOSURE0):
578 Instruct(PUSHOFFSETCLOSURE2):
579 *--sp = accu; /* fallthrough */
580 Instruct(OFFSETCLOSURE2):
581 accu = env + 2 * sizeof(value); Next;
584 /* Access to global variables */
586 Instruct(PUSHGETGLOBAL):
590 accu = Field(caml_global_data, *pc);
594 Instruct(PUSHGETGLOBALFIELD):
597 Instruct(GETGLOBALFIELD): {
598 accu = Field(caml_global_data, *pc);
600 accu = Field(accu, *pc);
606 caml_modify(&Field(caml_global_data, *pc), accu);
611 /* Allocation of blocks */
617 accu = Atom(0); Next;
623 accu = Atom(*pc++); Next;
625 Instruct(MAKEBLOCK): {
626 mlsize_t wosize = *pc++;
630 if (wosize <= Max_young_wosize) {
631 Alloc_small(block, wosize, tag);
632 Field(block, 0) = accu;
633 for (i = 1; i < wosize; i++) Field(block, i) = *sp++;
635 block = caml_alloc_shr(wosize, tag);
636 caml_initialize(&Field(block, 0), accu);
637 for (i = 1; i < wosize; i++) caml_initialize(&Field(block, i), *sp++);
642 Instruct(MAKEBLOCK1): {
645 Alloc_small(block, 1, tag);
646 Field(block, 0) = accu;
650 Instruct(MAKEBLOCK2): {
653 Alloc_small(block, 2, tag);
654 Field(block, 0) = accu;
655 Field(block, 1) = sp[0];
660 Instruct(MAKEBLOCK3): {
663 Alloc_small(block, 3, tag);
664 Field(block, 0) = accu;
665 Field(block, 1) = sp[0];
666 Field(block, 2) = sp[1];
671 Instruct(MAKEFLOATBLOCK): {
672 mlsize_t size = *pc++;
675 if (size <= Max_young_wosize / Double_wosize) {
676 Alloc_small(block, size * Double_wosize, Double_array_tag);
678 block = caml_alloc_shr(size * Double_wosize, Double_array_tag);
680 Store_double_field(block, 0, Double_val(accu));
681 for (i = 1; i < size; i++){
682 Store_double_field(block, i, Double_val(*sp));
689 /* Access to components of blocks */
692 accu = Field(accu, 0); Next;
694 accu = Field(accu, 1); Next;
696 accu = Field(accu, 2); Next;
698 accu = Field(accu, 3); Next;
700 accu = Field(accu, *pc); pc++; Next;
701 Instruct(GETFLOATFIELD): {
702 double d = Double_field(accu, *pc);
703 Alloc_small(accu, Double_wosize, Double_tag);
704 Store_double_val(accu, d);
710 modify_dest = &Field(accu, 0);
711 modify_newval = *sp++;
713 Modify(modify_dest, modify_newval);
717 modify_dest = &Field(accu, 1);
718 modify_newval = *sp++;
721 modify_dest = &Field(accu, 2);
722 modify_newval = *sp++;
725 modify_dest = &Field(accu, 3);
726 modify_newval = *sp++;
729 modify_dest = &Field(accu, *pc);
731 modify_newval = *sp++;
733 Instruct(SETFLOATFIELD):
734 Store_double_field(accu, *pc, Double_val(*sp));
740 /* Array operations */
742 Instruct(VECTLENGTH): {
743 mlsize_t size = Wosize_val(accu);
744 if (Tag_val(accu) == Double_array_tag) size = size / Double_wosize;
745 accu = Val_long(size);
748 Instruct(GETVECTITEM):
749 accu = Field(accu, Long_val(sp[0]));
752 Instruct(SETVECTITEM):
753 modify_dest = &Field(accu, Long_val(sp[0]));
754 modify_newval = sp[1];
758 /* String operations */
760 Instruct(GETSTRINGCHAR):
761 accu = Val_int(Byte_u(accu, Long_val(sp[0])));
764 Instruct(SETSTRINGCHAR):
765 Byte_u(accu, Long_val(sp[0])) = Int_val(sp[1]);
770 /* Branches and conditional branches */
776 if (accu != Val_false) pc += *pc; else pc++;
778 Instruct(BRANCHIFNOT):
779 if (accu == Val_false) pc += *pc; else pc++;
782 uint32 sizes = *pc++;
783 if (Is_block(accu)) {
784 intnat index = Tag_val(accu);
785 Assert ((uintnat) index < (sizes >> 16));
786 pc += pc[(sizes & 0xFFFF) + index];
788 intnat index = Long_val(accu);
789 Assert ((uintnat) index < (sizes & 0xFFFF)) ;
795 accu = Val_not(accu);
802 Trap_pc(sp) = pc + *pc;
803 Trap_link(sp) = caml_trapsp;
805 sp[3] = Val_long(extra_args);
811 if (caml_something_to_do) {
812 /* We must check here so that if a signal is pending and its
813 handler triggers an exception, the exception is trapped
814 by the current try...with, not the enclosing one. */
815 pc--; /* restart the POPTRAP after processing the signal */
818 caml_trapsp = Trap_link(sp);
824 if (caml_trapsp >= caml_trap_barrier) caml_debugger(TRAP_BARRIER);
825 if (caml_backtrace_active) caml_stash_backtrace(accu, pc, sp);
826 if ((char *) caml_trapsp
827 >= (char *) caml_stack_high - initial_sp_offset) {
828 caml_external_raise = initial_external_raise;
829 caml_extern_sp = (value *) ((char *) caml_stack_high
830 - initial_sp_offset);
831 caml_callback_depth--;
832 return Make_exception_result(accu);
836 caml_trapsp = Trap_link(sp);
838 extra_args = Long_val(sp[3]);
845 if (sp < caml_stack_threshold) {
847 caml_realloc_stack(Stack_threshold / sizeof(value));
850 /* Fall through CHECK_SIGNALS */
852 /* Signal handling */
854 Instruct(CHECK_SIGNALS): /* accu not preserved */
855 if (caml_something_to_do) goto process_signal;
859 caml_something_to_do = 0;
861 caml_process_event();
865 /* Calling C functions */
869 accu = Primitive(*pc)(accu);
870 Restore_after_c_call;
875 accu = Primitive(*pc)(accu, sp[1]);
876 Restore_after_c_call;
882 accu = Primitive(*pc)(accu, sp[1], sp[2]);
883 Restore_after_c_call;
889 accu = Primitive(*pc)(accu, sp[1], sp[2], sp[3]);
890 Restore_after_c_call;
896 accu = Primitive(*pc)(accu, sp[1], sp[2], sp[3], sp[4]);
897 Restore_after_c_call;
905 accu = Primitive(*pc)(sp + 1, nargs);
906 Restore_after_c_call;
912 /* Integer constants */
915 accu = Val_int(0); Next;
917 accu = Val_int(1); Next;
919 accu = Val_int(2); Next;
921 accu = Val_int(3); Next;
923 Instruct(PUSHCONST0):
924 *--sp = accu; accu = Val_int(0); Next;
925 Instruct(PUSHCONST1):
926 *--sp = accu; accu = Val_int(1); Next;
927 Instruct(PUSHCONST2):
928 *--sp = accu; accu = Val_int(2); Next;
929 Instruct(PUSHCONST3):
930 *--sp = accu; accu = Val_int(3); Next;
932 Instruct(PUSHCONSTINT):
940 /* Integer arithmetic */
943 accu = (value)(2 - (intnat)accu); Next;
945 accu = (value)((intnat) accu + (intnat) *sp++ - 1); Next;
947 accu = (value)((intnat) accu - (intnat) *sp++ + 1); Next;
949 accu = Val_long(Long_val(accu) * Long_val(*sp++)); Next;
952 intnat divisor = Long_val(*sp++);
953 if (divisor == 0) { Setup_for_c_call; caml_raise_zero_divide(); }
954 #ifdef NONSTANDARD_DIV_MOD
955 accu = Val_long(caml_safe_div(Long_val(accu), divisor));
957 accu = Val_long(Long_val(accu) / divisor);
962 intnat divisor = Long_val(*sp++);
963 if (divisor == 0) { Setup_for_c_call; caml_raise_zero_divide(); }
964 #ifdef NONSTANDARD_DIV_MOD
965 accu = Val_long(caml_safe_mod(Long_val(accu), divisor));
967 accu = Val_long(Long_val(accu) % divisor);
972 accu = (value)((intnat) accu & (intnat) *sp++); Next;
974 accu = (value)((intnat) accu | (intnat) *sp++); Next;
976 accu = (value)(((intnat) accu ^ (intnat) *sp++) | 1); Next;
978 accu = (value)((((intnat) accu - 1) << Long_val(*sp++)) + 1); Next;
980 accu = (value)((((uintnat) accu - 1) >> Long_val(*sp++)) | 1);
983 accu = (value)((((intnat) accu - 1) >> Long_val(*sp++)) | 1); Next;
985 #define Integer_comparison(typ,opname,tst) \
987 accu = Val_int((typ) accu tst (typ) *sp++); Next;
989 Integer_comparison(intnat,EQ, ==)
990 Integer_comparison(intnat,NEQ, !=)
991 Integer_comparison(intnat,LTINT, <)
992 Integer_comparison(intnat,LEINT, <=)
993 Integer_comparison(intnat,GTINT, >)
994 Integer_comparison(intnat,GEINT, >=)
995 Integer_comparison(uintnat,ULTINT, <)
996 Integer_comparison(uintnat,UGEINT, >=)
998 #define Integer_branch_comparison(typ,opname,tst,debug) \
1000 if ( *pc++ tst (typ) Long_val(accu)) { \
1006 Integer_branch_comparison(intnat,BEQ, ==, "==")
1007 Integer_branch_comparison(intnat,BNEQ, !=, "!=")
1008 Integer_branch_comparison(intnat,BLTINT, <, "<")
1009 Integer_branch_comparison(intnat,BLEINT, <=, "<=")
1010 Integer_branch_comparison(intnat,BGTINT, >, ">")
1011 Integer_branch_comparison(intnat,BGEINT, >=, ">=")
1012 Integer_branch_comparison(uintnat,BULTINT, <, "<")
1013 Integer_branch_comparison(uintnat,BUGEINT, >=, ">=")
1015 Instruct(OFFSETINT):
1019 Instruct(OFFSETREF):
1020 Field(accu, 0) += *pc << 1;
1025 accu = Val_long(accu & 1);
1028 /* Object-oriented operations */
1030 #define Lookup(obj, lab) Field (Field (obj, 0), Int_val(lab))
1032 /* please don't forget to keep below code in sync with the
1033 functions caml_cache_public_method and
1034 caml_cache_public_method2 in obj.c */
1036 Instruct(GETMETHOD):
1037 accu = Lookup(sp[0], accu);
1040 #define CAML_METHOD_CACHE
1041 #ifdef CAML_METHOD_CACHE
1042 Instruct(GETPUBMET): {
1043 /* accu == object, pc[0] == tag, pc[1] == cache */
1044 value meths = Field (accu, 0);
1046 #ifdef CAML_TEST_CACHE
1047 static int calls = 0, hits = 0;
1048 if (calls >= 10000000) {
1049 fprintf(stderr, "cache hit = %d%%\n", hits / 100000);
1050 calls = 0; hits = 0;
1055 accu = Val_int(*pc++);
1056 ofs = *pc & Field(meths,1);
1057 if (*(value*)(((char*)&Field(meths,3)) + ofs) == accu) {
1058 #ifdef CAML_TEST_CACHE
1061 accu = *(value*)(((char*)&Field(meths,2)) + ofs);
1065 int li = 3, hi = Field(meths,0), mi;
1067 mi = ((li+hi) >> 1) | 1;
1068 if (accu < Field(meths,mi)) hi = mi-2;
1071 *pc = (li-3)*sizeof(value);
1072 accu = Field (meths, li-1);
1078 Instruct(GETPUBMET):
1080 accu = Val_int(*pc);
1084 Instruct(GETDYNMET): {
1085 /* accu == tag, sp[0] == object, *pc == cache */
1086 value meths = Field (sp[0], 0);
1087 int li = 3, hi = Field(meths,0), mi;
1089 mi = ((li+hi) >> 1) | 1;
1090 if (accu < Field(meths,mi)) hi = mi-2;
1093 accu = Field (meths, li-1);
1097 /* Debugging and machine control */
1100 caml_external_raise = initial_external_raise;
1101 caml_extern_sp = sp;
1102 caml_callback_depth--;
1106 if (--caml_event_count == 0) {
1108 caml_debugger(EVENT_COUNT);
1109 Restore_after_debugger;
1115 caml_debugger(BREAKPOINT);
1116 Restore_after_debugger;
1119 #ifndef THREADED_CODE
1121 #if _MSC_VER >= 1200
1124 caml_fatal_error_arg("Fatal error: bad opcode (%"
1125 ARCH_INTNAT_PRINTF_FORMAT "x)\n",
1133 void caml_prepare_bytecode(code_t prog, asize_t prog_size) {
1134 /* other implementations of the interpreter (such as an hypothetical
1135 JIT translator) might want to do something with a bytecode before
1138 Assert(prog_size>0);
1139 /* actually, the threading of the bytecode might be done here */
1142 void caml_release_bytecode(code_t prog, asize_t prog_size) {
1143 /* other implementations of the interpreter (such as an hypothetical
1144 JIT translator) might want to know when a bytecode is removed */
1145 /* check that we have a program */
1147 Assert(prog_size>0);