/* Beware: Alloc_small can only invoked for allocations smaller than Max_young_wosize,whichisusually256.Forlargerallocations, caml_alloc_shrneedstobeusedinstead,andtheblockneedstobefilled usingcaml_initialize.NotethatthesetwofunctionsnevertriggeraGC, socallingSetup_for_gcisnotneeded.
*/
/* If there is an asynchronous exception, we reset the vm */ #define Handle_potential_exception(res) \ if (Is_exception_result(res)) { \
rocq_sp = rocq_stack_high; \
caml_raise(Extract_exception(res)); \
}
/* We should also check "Code_val(v) == accumulate" to be sure,
but Is_accu is only used in places where closures cannot occur. */ #define Is_accu(v) (Is_block(v) && Tag_val(v) == Closure_tag)
/* Beware: we cannot use caml_copy_double here as it doesn't use Alloc_small,hencedoesn'tprotectthestackvia
Setup_for_gc/Restore_after_gc. */ #define Rocq_copy_double(val) do{ \ double Rocq_copy_double_f__ = (val); \
Rocq_alloc_small(accu, Double_wosize, Double_tag);\
Store_double_val(accu, Rocq_copy_double_f__); \
}while(0);
/* Turn a code pointer into a stack value usable as a return address, and conversely. Theleastsignificantbitissetto1sothattheGCdoesnotmistakereturn
addresses for heap pointers. */ #define StoreRA(p) ((value)(p) + 1) #define LoadRA(p) ((code_t)((value)(p) - 1))
#if OCAML_VERSION < 41000 /* For signal handling, we hijack some code from the caml runtime */
value rocq_subst_instance(value arg, value tosubst)
{ staticconst value * closure_f = NULL; if (closure_f == NULL) { /* First time around, look up by name */
closure_f = caml_named_value("rocq_subst_instance");
} return caml_callback2_exn(*closure_f, arg, tosubst);
}
/* The interpreter itself */
value rocq_interprete
(code_t rocq_pc, value rocq_accu, value rocq_atom_tbl, value rocq_global_data, value rocq_env, long rocq_extra_args)
{ /* rocq_accu is not allocated on the OCaml heap */
CAMLparam2(rocq_atom_tbl, rocq_global_data);
/*Declaration des variables */ #ifdef PC_REG register code_t pc PC_REG; register value * sp SP_REG; register value accu ACCU_REG; #else register code_t pc; register value * sp; register value accu; #endif #ifdefined(THREADED_CODE) && defined(ARCH_SIXTYFOUR) && !defined(ARCH_CODE32) #ifdef JUMPTBL_BASE_REG registerchar * rocq_jumptbl_base JUMPTBL_BASE_REG; #else registerchar * rocq_jumptbl_base; #endif #endif #ifdef THREADED_CODE staticvoid * rocq_jumptable[] = { # include "rocq_jumptbl.h"
}; #else
opcode_t curr_instr; #endif
print_instr("Enter Interpreter"); if (rocq_pc == NULL) { /* Interpreter is initializing */
print_instr("Interpreter is initializing"); #ifdef THREADED_CODE
rocq_init_thread_code(rocq_jumptable, rocq_Jumptbl_base); #endif
CAMLreturn(Val_unit);
} #ifdefined(THREADED_CODE) && defined(ARCH_SIXTYFOUR) && !defined(ARCH_CODE32)
rocq_jumptbl_base = rocq_Jumptbl_base; #endif
check_stack:
print_instr("check_stack");
CHECK_STACK(0); /* We also check for signals */ #if OCAML_VERSION >= 50000 if (Caml_check_gc_interrupt(Caml_state)) {
Setup_for_gc;
value res = caml_process_pending_actions_exn();
Handle_potential_exception(res);
Restore_after_gc;
} #elif OCAML_VERSION >= 41000 if (caml_something_to_do) {
Setup_for_gc;
value res = caml_process_pending_actions_exn();
Handle_potential_exception(res);
Restore_after_gc;
} #else if (caml_signals_are_pending) { /* If there's a Ctrl-C, we reset the vm */
intnat sigint = caml_pending_signals[SIGINT]; if (sigint) { rocq_sp = rocq_stack_high; }
Setup_for_gc;
caml_process_pending_signals();
Restore_after_gc; if (sigint) {
caml_failwith("Rocq VM: Fatal error: SIGINT signal detected " "but no exception was raised");
}
} #endif
Next;
Instruct(ENSURESTACKCAPACITY) {
print_instr("ENSURESTACKCAPACITY"); int size = *pc++; /* CHECK_STACK may trigger here a useless allocation because of the threshold,butcheck_stack:oftendoesitanyway,sowepreferto
factorize the code. */
CHECK_STACK(size);
Next;
}
Instruct(APPTERM) { int nargs = *pc++; int slotsize = *pc;
value * newsp; int i;
print_instr("APPTERM"); /* Slide the nargs bottom words of the current frame to the top
of the frame, and discard the remainder of the frame */
newsp = sp + slotsize - nargs; for (i = nargs - 1; i >= 0; i--) newsp[i] = sp[i];
sp = newsp;
pc = Code_val(accu);
rocq_env = accu;
rocq_extra_args += nargs - 1; goto check_stack;
}
Instruct(APPTERM1) {
value arg1 = sp[0];
print_instr("APPTERM1");
sp = sp + *pc - 1;
sp[0] = arg1;
pc = Code_val(accu);
rocq_env = accu; goto check_stack;
}
Instruct(APPTERM2) {
value arg1 = sp[0];
value arg2 = sp[1];
print_instr("APPTERM2");
sp = sp + *pc - 2;
sp[0] = arg1;
sp[1] = arg2;
pc = Code_val(accu);
rocq_env = accu;
rocq_extra_args += 1; goto check_stack;
}
Instruct(APPTERM3) {
value arg1 = sp[0];
value arg2 = sp[1];
value arg3 = sp[2];
print_instr("APPTERM3");
sp = sp + *pc - 3;
sp[0] = arg1;
sp[1] = arg2;
sp[2] = arg3;
pc = Code_val(accu);
rocq_env = accu;
rocq_extra_args += 2; goto check_stack;
}
Instruct(RESTART) { int num_args = Wosize_val(rocq_env) - 3; int i;
print_instr("RESTART");
CHECK_STACK(num_args);
sp -= num_args; for (i = 0; i < num_args; i++) sp[i] = Field(rocq_env, i + 3);
rocq_env = Field(rocq_env, 2);
rocq_extra_args += num_args;
Next;
}
Instruct(GRAB) { int required = *pc++;
print_instr("GRAB"); /* printf("GRAB %d\n",required); */ if (rocq_extra_args >= required) {
rocq_extra_args -= required;
} else {
mlsize_t num_args, i;
num_args = 1 + rocq_extra_args; /* arg1 + extra args */
Rocq_alloc_small(accu, num_args + 3, Closure_tag);
Field(accu, 1) = Val_int(2);
Field(accu, 2) = rocq_env; for (i = 0; i < num_args; i++) Field(accu, i + 3) = sp[i];
Code_val(accu) = pc - 3; /* Point to the preceding RESTART instr. */
sp += num_args;
pc = LoadRA(sp[0]);
rocq_env = sp[1];
rocq_extra_args = Long_val(sp[2]);
sp += 3;
}
Next;
}
Instruct(GRABREC) { int rec_pos = *pc++; /* commence a zero */
print_instr("GRABREC"); if (rec_pos <= rocq_extra_args && !Is_accu(sp[rec_pos])) {
pc++; /* Skip the next RESTART, then point rocq_env at the free variables. */
rocq_env = rocq_env + (Int_val(Field(rocq_env, 1)) - 2) * sizeof(value);
} else { if (rocq_extra_args < rec_pos) { /* Partial application */
mlsize_t num_args, i;
num_args = 1 + rocq_extra_args; /* arg1 + extra args */
Rocq_alloc_small(accu, num_args + 3, Closure_tag);
Code_val(accu) = pc - 3; /* Point to the preceding RESTART instr. */
Field(accu, 1) = Val_int(2);
Field(accu, 2) = rocq_env; for (i = 0; i < num_args; i++) Field(accu, i + 3) = sp[i];
sp += num_args;
pc = LoadRA(sp[0]);
rocq_env = sp[1];
rocq_extra_args = Long_val(sp[2]);
sp += 3;
} else { /* The recursive argument is an accumulator */
mlsize_t num_args, sz, i;
value block; /* Construction of fixpoint applied to its [rec_pos-1] first arguments */
Rocq_alloc_small(accu, rec_pos + 3, Closure_tag);
Code_val(accu) = pc; /* Point to the next RESTART instr. */
Field(accu, 1) = Val_int(2);
Field(accu, 2) = rocq_env; // We store the fixpoint in the first field for (i = 0; i < rec_pos; i++) Field(accu, i + 3) = *sp++; // Storing args /* Construction of the atom */
Rocq_alloc_small(block, 2, ATOM_FIX_TAG);
Field(block, 0) = *sp++;
Field(block, 1) = accu;
accu = block; /* Construction of the accumulator */
num_args = rocq_extra_args - rec_pos;
sz = 3 + num_args; if (sz <= Max_young_wosize) {
Rocq_alloc_small(block, sz, Closure_tag);
Field(block, 2) = accu; for (i = 3; i < sz; ++i)
Field(block, i) = *sp++;
} else {
block = caml_alloc_shr(sz, Closure_tag);
caml_initialize(&Field(block, 2), accu); for (i = 3; i < sz; ++i)
caml_initialize(&Field(block, i), *sp++);
}
Code_val(block) = accumulate;
Field(block, 1) = Val_int(2);
accu = block;
pc = LoadRA(sp[0]);
rocq_env = sp[1];
rocq_extra_args = Long_val(sp[2]);
sp += 3;
}
}
Next;
}
Instruct(CLOSURE) { int nvars = *pc++; int i;
print_instr("CLOSURE");
print_int(nvars); if (nvars > 0) *--sp = accu;
Rocq_alloc_small(accu, 2 + nvars, Closure_tag);
Field(accu, 1) = Val_int(2);
Code_val(accu) = pc + *pc;
pc++; for (i = 0; i < nvars; i++) {
print_lint(sp[i]);
Field(accu, i + 2) = sp[i];
}
sp += nvars;
Next;
}
Instruct(CLOSUREREC) { int nfuncs = *pc++; int nvars = *pc++; int start = *pc++; int i;
value * p;
print_instr("CLOSUREREC"); if (nvars > 0) *--sp = accu; /* construction du vecteur de type */
Rocq_alloc_small(accu, nfuncs, Abstract_tag); for(i = 0; i < nfuncs; i++) {
Field(accu,i) = (value)(pc+pc[i]);
}
pc += nfuncs;
*--sp=accu;
Rocq_alloc_small(accu, nfuncs * 3 + nvars, Closure_tag);
Field(accu, nfuncs * 3 + nvars - 1) = *sp++;
p = (value *) &Field(accu, 0);
*p++ = (value) (pc + pc[0]);
*p++ = Val_int(nfuncs * 3 - 1); for (i = 1; i < nfuncs; i++) {
*p++ = Make_header(i * 3, Infix_tag, 0); /* color irrelevant. */
*p++ = (value) (pc + pc[i]);
*p++ = Val_int((nfuncs - i) * 3 - 1);
} for (i = 0; i < nvars; i++) *p++ = *sp++;
pc += nfuncs;
accu = accu + start * 3 * sizeof(value);
Next;
}
Instruct(CLOSURECOFIX){ int nfunc = *pc++; int nvars = *pc++; int start = *pc++; int i, j , size;
value * p;
print_instr("CLOSURECOFIX"); if (nvars > 0) *--sp = accu; /* construction du vecteur de type */
Rocq_alloc_small(accu, nfunc, Abstract_tag); for(i = 0; i < nfunc; i++) {
Field(accu,i) = (value)(pc+pc[i]);
}
pc += nfunc;
*--sp=accu;
/* Creation des blocks accumulate */ for(i=0; i < nfunc; i++) {
Rocq_alloc_small(accu, 3, Closure_tag);
Code_val(accu) = accumulate;
Field(accu, 1) = Val_int(2);
Field(accu, 2) = Val_int(1);
*--sp=accu;
} /* creation des fonction cofix */
Instruct(SWITCH) {
uint32_t sizes = *pc++;
print_instr("SWITCH"); if (Is_block(accu)) { long index = Tag_val(accu); if (index == Closure_tag) index = 0;
print_instr("block");
print_lint(index);
pc += pc[(sizes >> 8) + index];
} else { long index = Long_val(accu);
print_instr("constant");
print_lint(index);
pc += pc[index];
}
Next;
}
Instruct(PUSHFIELDS){ int i; int size = *pc++;
print_instr("PUSHFIELDS");
sp -= size; for(i=0;i<size;i++)sp[i] = Field(accu,i);
Next;
}
/* Special operations for reduction of open term */
Instruct(ACCUMULATE) {
mlsize_t i, size, sz;
print_instr("ACCUMULATE");
size = Wosize_val(rocq_env);
sz = size + rocq_extra_args + 1; if (sz <= Max_young_wosize) {
Rocq_alloc_small(accu, sz, Closure_tag); for (i = 0; i < size; ++i)
Field(accu, i) = Field(rocq_env, i); for (i = size; i < sz; ++i)
Field(accu, i) = *sp++;
} else {
accu = caml_alloc_shr(sz, Closure_tag); for (i = 0; i < size; ++i)
caml_initialize(&Field(accu, i), Field(rocq_env, i)); for (i = size; i < sz; ++i)
caml_initialize(&Field(accu, i), *sp++);
}
pc = LoadRA(sp[0]);
rocq_env = sp[1];
rocq_extra_args = Long_val(sp[2]);
sp += 3;
Next;
}
Instruct(MAKESWITCHBLOCK) {
print_instr("MAKESWITCHBLOCK");
*--sp = accu; // Save matched block on stack
accu = Field(accu, 2); // Save atom to accu register switch (Tag_val(accu)) { case ATOM_COFIX_TAG: // We are forcing a cofix
{
mlsize_t i, nargs;
print_instr("COFIX_TAG");
sp-=2;
pc++; // Push the return address
sp[0] = StoreRA(pc + *pc);
sp[1] = rocq_env;
rocq_env = Field(accu,0); // Pointer to suspension
accu = sp[2]; // Save accumulator to accu register
sp[2] = Val_long(rocq_extra_args); // Push number of args for return
nargs = Wosize_val(accu) - 3; // Number of args = size of accumulator - 2 (accumulator closure) - 1 (atom) // Push arguments to stack
CHECK_STACK(nargs+1);
sp -= nargs; for (i = 0; i < nargs; i++) sp[i] = Field(accu, i + 3);
*--sp = accu; // Leftmost argument is the pointer to the suspension
print_lint(nargs);
rocq_extra_args = nargs;
pc = Code_val(rocq_env); // Trigger evaluation goto check_stack;
} case ATOM_COFIXEVALUATED_TAG:
{
print_instr("COFIX_EVAL_TAG");
accu = Field(accu,1);
pc++;
pc = pc + *pc;
sp++;
Next;
} default:
{
mlsize_t sz; int i, annot;
code_t typlbl,swlbl;
value block;
print_instr("MAKESWITCHBLOCK");
typlbl = (code_t)pc + *pc;
pc++;
swlbl = (code_t)pc + *pc;
pc++;
annot = *pc++;
sz = *pc++;
*--sp=Field(rocq_global_data, annot); /* We save the stack */ if (sz == 0) accu = Atom(0); elseif (sz <= Max_young_wosize) {
Rocq_alloc_small(accu, sz, Default_tag); if (Is_tailrec_switch(*sp)) { for (i = 0; i < sz; i++) Field(accu, i) = sp[i+2];
}else{ for (i = 0; i < sz; i++) Field(accu, i) = sp[i+5];
}
} else {
accu = caml_alloc_shr(sz, Default_tag); if (Is_tailrec_switch(*sp)) { for (i = 0; i < sz; i++) caml_initialize(&Field(accu, i), sp[i+2]);
}else{ for (i = 0; i < sz; i++) caml_initialize(&Field(accu, i), sp[i+5]);
}
}
*--sp = accu; /* Create bytecode wrappers */
Rocq_alloc_small(accu, 1, Abstract_tag);
Code_val(accu) = typlbl;
*--sp = accu;
Rocq_alloc_small(accu, 1, Abstract_tag);
Code_val(accu) = swlbl; /* We create the switch zipper */
Rocq_alloc_small(block, 5, Default_tag);
Field(block, 0) = sp[0];
Field(block, 1) = accu;
Field(block, 2) = sp[2];
Field(block, 3) = sp[1];
Field(block, 4) = rocq_env;
sp += 3;
accu = block; /* We create the atom */
Rocq_alloc_small(block, 2, ATOM_SWITCH_TAG);
Field(block, 0) = *sp++;
Field(block, 1) = accu;
accu = block; /* We create the accumulator */
Rocq_alloc_small(block, 3, Closure_tag);
Code_val(block) = accumulate;
Field(block, 1) = Val_int(2);
Field(block, 2) = accu;
accu = block;
}
}
Next;
}
Instruct(MAKEACCU) {
mlsize_t i, sz;
print_instr("MAKEACCU");
sz = rocq_extra_args + 4; if (sz <= Max_young_wosize) {
Rocq_alloc_small(accu, sz, Closure_tag);
Field(accu, 2) = Field(rocq_atom_tbl, *pc); for (i = 3; i < sz; ++i)
Field(accu, i) = *sp++;
} else {
accu = caml_alloc_shr(sz, Closure_tag);
caml_initialize(&Field(accu, 2), Field(rocq_atom_tbl, *pc)); for (i = 3; i < sz; ++i)
caml_initialize(&Field(accu, i), *sp++);
}
Code_val(accu) = accumulate;
Field(accu, 1) = Val_int(2);
pc = LoadRA(sp[0]);
rocq_env = sp[1];
rocq_extra_args = Long_val(sp[2]);
sp += 3;
Next;
}
Instruct(BRANCH) { /* unconditional branching */
print_instr("BRANCH");
pc += *pc; /* pc = (code_t)(pc+*pc); */
Next;
}
Instruct(CHECKADDINT63){
print_instr("CHECKADDINT63");
CheckInt2(); /* Adds the integer in the accumulator with
the one ontop of the stack (which is poped)*/
Uint63_add(accu, *sp++);
Next;
}
Instruct (CHECKADDCINT63) {
print_instr("CHECKADDCINT63");
CheckInt2(); /* returns the sum with a carry */ int c;
Uint63_add(accu, *sp);
Uint63_lt(c, accu, *sp);
Swap_accu_sp;
AllocCarry(c);
Field(accu, 0) = *sp++;
Next;
}
Instruct (CHECKADDCARRYCINT63) {
print_instr("ADDCARRYCINT63");
CheckInt2(); /* returns the sum plus one with a carry */ int c;
Uint63_addcarry(accu, *sp);
Uint63_leq(c, accu, *sp);
Swap_accu_sp;
AllocCarry(c);
Field(accu, 0) = *sp++;
Next;
}
Instruct (CHECKSUBCINT63) {
print_instr("SUBCINT63");
CheckInt2(); /* returns the subtraction with a carry */ int c;
Uint63_lt(c, accu, *sp);
Uint63_sub(accu, *sp);
Swap_accu_sp;
AllocCarry(c);
Field(accu, 0) = *sp++;
Next;
}
Instruct (CHECKSUBCARRYCINT63) {
print_instr("SUBCARRYCINT63");
CheckInt2(); /* returns the subtraction minus one with a carry */ int c;
Uint63_leq(c,accu,*sp);
Uint63_subcarry(accu,*sp);
Swap_accu_sp;
AllocCarry(c);
Field(accu, 0) = *sp++;
Next;
}
Instruct (CHECKMULCINT63) { /*returns the multiplication on a pair */
print_instr("MULCINT63");
CheckInt2();
Uint63_mulc(accu, *sp, sp);
*--sp = accu;
AllocPair();
Field(accu, 1) = *sp++;
Field(accu, 0) = *sp++;
Next;
}
Instruct(CHECKDIVINT63) {
print_instr("CHEKDIVINT63");
CheckInt2(); /* spiwack: a priori no need of the NON_STANDARD_DIV_MOD flag sinceitprobablyonlyconcernsnegativenumber.
needs to be checked at this point */ int b;
Uint63_eq0(b, *sp); if (b) {
accu = *sp++;
} else {
Uint63_div(accu, *sp++);
}
Next;
}
Instruct(CHECKMODINT63) {
print_instr("CHEKMODINT63");
CheckInt2(); int b;
Uint63_eq0(b, *sp); if (b) {
sp++;
} else {
Uint63_mod(accu,*sp++);
}
Next;
}
Instruct (CHECKDIVEUCLINT63) {
print_instr("DIVEUCLINT63");
CheckInt2(); /* spiwack: a priori no need of the NON_STANDARD_DIV_MOD flag sinceitprobablyonlyconcernsnegativenumber.
needs to be checked at this point */ int b;
Uint63_eq0(b, *sp); if (b) {
value block;
Rocq_alloc_small(block, 2, rocq_tag_pair);
Field(block, 0) = *sp++;
Field(block, 1) = accu;
accu = block;
} else {
*--sp = accu;
Uint63_div(sp[0],sp[1]);
Swap_accu_sp;
Uint63_mod(accu,sp[1]);
sp[1] = sp[0];
Swap_accu_sp;
AllocPair();
Field(accu, 0) = sp[1];
Field(accu, 1) = sp[0];
sp += 2;
}
Next;
}
Instruct (CHECKEQUALFLOAT) { double x, y;
print_instr("CHECKEQUALFLOAT");
CheckFloat2();
x = Double_val(accu);
y = Double_val(*sp++); if (x == y) {
accu = (x != 0 || !signbit(x) == !signbit(y)) ? rocq_true : rocq_false; /* note that the spec of signbit only promises a "nonzero value"
so we need to normalize booleans with ! before comparing them */
} else {
accu = (x != x && y != y) ? rocq_true : rocq_false; /* is_nan(x) && is_nan(y) */
}
Next;
}
value rocq_push_arguments(value args) { int nargs,i;
value * sp = rocq_sp;
nargs = Wosize_val(args) - 3;
CHECK_STACK(nargs);
rocq_sp -= nargs;
print_instr("push_args");print_int(nargs); for (i = 0; i < nargs; i++) rocq_sp[i] = Field(args, i + 3); return Val_unit;
}
value rocq_push_vstack(value stk, value max_stack_size) { int len,i;
value * sp = rocq_sp;
len = Wosize_val(stk);
CHECK_STACK(len);
rocq_sp -= len;
print_instr("push_vstack");print_int(len); for(i = 0; i < len; i++) rocq_sp[i] = Field(stk,i);
sp = rocq_sp;
CHECK_STACK(uint_of_value(max_stack_size)); return Val_unit;
}
value rocq_interprete_ml(value tcode, value a, value t, value g, value e, value ea) { // Registering the other arguments w.r.t. the OCaml GC is done by rocq_interprete
CAMLparam1(tcode);
print_instr("rocq_interprete");
value res = rocq_interprete(Code_val(tcode), a, t, g, e, Long_val(ea));
print_instr("end rocq_interprete");
CAMLreturn(res);
}
value rocq_interprete_byte(value* argv, int argn){ return rocq_interprete_ml(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.33 Sekunden
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.