diff --git a/src/CHANGELOG b/src/CHANGELOG index 41b8e4fc7..7ba19d149 100644 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -247,6 +247,8 @@ ECL 0.9k: - TYPEP now can be optimized if the type argument is a constant. + - ECL's bytecode interpreter now uses indirect threading. + * System design: - We introduce a new kind of lisp objects, the stack frames. These are objects diff --git a/src/c/interpreter.d b/src/c/interpreter.d index 2c8cf4668..5831c2820 100644 --- a/src/c/interpreter.d +++ b/src/c/interpreter.d @@ -630,93 +630,100 @@ interpret_progv(cl_object bytecodes, cl_opcode *vector) { } void * -ecl_interpret(cl_object bytecodes, void *pc) { +ecl_interpret(cl_object bytecodes, void *pc) +{ + ECL_OFFSET_TABLE; cl_opcode *vector = pc; cl_object reg0 = VALUES(0), reg1; static int i = 0; i++; BEGIN: - switch (GET_OPCODE(vector)) { + BEGIN_SWITCH { + CASE(OP_NOP); { + VALUES(0) = reg0 = Cnil; + NVALUES = 0; + NEXT; + } /* OP_QUOTE Sets REG0 to an immediate value. */ - case OP_QUOTE: + CASE(OP_QUOTE); { reg0 = GET_DATA(vector, bytecodes); - break; - + NEXT; + } /* OP_VAR n{arg}, var{symbol} Sets REG0 to the value of the n-th local. VAR is the name of the variable for readability purposes. */ - case OP_VAR: { + CASE(OP_VAR); { int lex_env_index = GET_OPARG(vector); reg0 = ecl_lex_env_get_var(lex_env_index); - break; + NEXT; } /* OP_VARS var{symbol} Sets REG0 to the value of the symbol VAR. VAR should be either a special variable or a constant. */ - case OP_VARS: { + CASE(OP_VARS); { cl_object var_name = GET_DATA(vector, bytecodes); reg0 = search_global(var_name); - break; + NEXT; } /* OP_PUSH Pushes the object in VALUES(0). */ - case OP_PUSH: + CASE(OP_PUSH); { cl_stack_push(reg0); - break; - + NEXT; + } /* OP_PUSHV n{arg} Pushes the value of the n-th local onto the stack. */ - case OP_PUSHV: { + CASE(OP_PUSHV); { int lex_env_index = GET_OPARG(vector); cl_stack_push(ecl_lex_env_get_var(lex_env_index)); - break; + NEXT; } /* OP_PUSHVS var{symbol} Pushes the value of the symbol VAR onto the stack. VAR should be either a special variable or a constant. */ - case OP_PUSHVS: { + CASE(OP_PUSHVS); { cl_object var_name = GET_DATA(vector, bytecodes); cl_stack_push(search_global(var_name)); - break; + NEXT; } /* OP_PUSHQ value{object} Pushes "value" onto the stack. */ - case OP_PUSHQ: + CASE(OP_PUSHQ); { cl_stack_push(GET_DATA(vector, bytecodes)); - break; - + NEXT; + } /* OP_CALL n{arg} Calls the function in REG0 with N arguments which have been deposited in the stack. The output values are left in VALUES(...) */ - case OP_CALL: { + CASE(OP_CALL); { cl_fixnum n = GET_OPARG(vector); VALUES(0) = reg0 = interpret_funcall(n, reg0); - break; + NEXT; } /* OP_CALLG n{arg}, name{arg} Calls the function NAME with N arguments which have been deposited in the stack. The output values are left in VALUES. */ - case OP_CALLG: { + CASE(OP_CALLG); { cl_fixnum n = GET_OPARG(vector); cl_object f = GET_DATA(vector, bytecodes); VALUES(0) = reg0 = interpret_funcall(n, f); - break; + NEXT; } /* OP_FCALL n{arg} @@ -724,24 +731,24 @@ ecl_interpret(cl_object bytecodes, void *pc) { have been also deposited in the stack. The output values are left in VALUES(...) */ - case OP_FCALL: { + CASE(OP_FCALL); { cl_fixnum n = GET_OPARG(vector); cl_object fun = cl_env.stack_top[-n-1]; VALUES(0) = reg0 = interpret_funcall(n, fun); cl_stack_pop(); - break; + NEXT; } /* OP_MCALL Similar to FCALL, but gets the number of arguments from the stack (They all have been deposited by OP_PUSHVALUES) */ - case OP_MCALL: { + CASE(OP_MCALL); { cl_fixnum n = fix(cl_stack_pop()); cl_object fun = cl_env.stack_top[-n-1]; VALUES(0) = reg0 = interpret_funcall(n, fun); cl_stack_pop(); - break; + NEXT; } /* OP_PCALL n{arg} @@ -749,10 +756,10 @@ ecl_interpret(cl_object bytecodes, void *pc) { have been deposited in the stack. The first output value is pushed on the stack. */ - case OP_PCALL: { + CASE(OP_PCALL); { cl_fixnum n = GET_OPARG(vector); cl_stack_push(interpret_funcall(n, reg0)); - break; + NEXT; } /* OP_PCALLG n{arg}, name{arg} @@ -760,11 +767,11 @@ ecl_interpret(cl_object bytecodes, void *pc) { deposited in the stack. The first output value is pushed on the stack. */ - case OP_PCALLG: { + CASE(OP_PCALLG); { cl_fixnum n = GET_OPARG(vector); cl_object f = GET_DATA(vector, bytecodes); cl_stack_push(interpret_funcall(n, f)); - break; + NEXT; } /* OP_PFCALL n{arg} @@ -772,37 +779,38 @@ ecl_interpret(cl_object bytecodes, void *pc) { have been also deposited in the stack. The first output value is pushed on the stack. */ - case OP_PFCALL: { + CASE(OP_PFCALL); { cl_fixnum n = GET_OPARG(vector); cl_object fun = cl_env.stack_top[-n-1]; cl_object reg0 = interpret_funcall(n, fun); cl_env.stack_top[-1] = reg0; - break; + NEXT; } /* OP_EXIT Marks the end of a high level construct (BLOCK, CATCH...) or a function. */ - case OP_EXIT: + CASE(OP_EXIT); { return (char *)vector; - - case OP_FLET: + } + CASE(OP_FLET); { vector = interpret_flet(bytecodes, vector); - break; - case OP_LABELS: + NEXT; + } + CASE(OP_LABELS); { vector = interpret_labels(bytecodes, vector); - break; - + NEXT; + } /* OP_LFUNCTION n{arg}, function-name{symbol} Calls the local or global function with N arguments which have been deposited in the stack. */ - case OP_LFUNCTION: { + CASE(OP_LFUNCTION); { int lex_env_index = GET_OPARG(vector); cl_object fun_record = ecl_lex_env_get_record(lex_env_index); reg0 = CAR(fun_record); - break; + NEXT; } /* OP_FUNCTION name{symbol} @@ -810,19 +818,19 @@ ecl_interpret(cl_object bytecodes, void *pc) { may be defined in the global environment or in the local environment. This last value takes precedence. */ - case OP_FUNCTION: + CASE(OP_FUNCTION); reg0 = ecl_fdefinition(GET_DATA(vector, bytecodes)); - break; + NEXT; /* OP_CLOSE name{symbol} Extracts the function associated to a symbol. The function may be defined in the global environment or in the local environment. This last value takes precedence. */ - case OP_CLOSE: { + CASE(OP_CLOSE); { cl_object function_object = GET_DATA(vector, bytecodes); reg0 = close_around(function_object, cl_env.lex_env); - break; + NEXT; } /* OP_GO n{arg} OP_QUOTE tag-name{symbol} @@ -830,33 +838,33 @@ ecl_interpret(cl_object bytecodes, void *pc) { the lexical environment. TAG-NAME is kept for debugging purposes. */ - case OP_GO: { + CASE(OP_GO); { cl_object id = ecl_lex_env_get_tag(GET_OPARG(vector)); cl_object tag_name = GET_DATA(vector, bytecodes); cl_go(id, tag_name); - break; + NEXT; } /* OP_RETURN n{arg} Returns from the block whose record in the lexical environment occuppies the n-th position. */ - case OP_RETURN: { + CASE(OP_RETURN); { int lex_env_index = GET_OPARG(vector); cl_object block_record = ecl_lex_env_get_record(lex_env_index); cl_object id = CAR(block_record); cl_object block_name = CDR(block_record); cl_return_from(id, block_name); - break; + NEXT; } /* OP_THROW Jumps to an enclosing CATCH form whose tag matches the one of the THROW. The tag is taken from the stack, while the output values are left in VALUES(...). */ - case OP_THROW: { + CASE(OP_THROW); { cl_object tag_name = cl_stack_pop(); cl_throw(tag_name); - break; + NEXT; } /* OP_JMP label{arg} OP_JNIL label{arg} @@ -866,58 +874,59 @@ ecl_interpret(cl_object bytecodes, void *pc) { Direct or conditional jumps. The conditional jumps are made comparing with the value of REG0. */ - case OP_JMP: { + CASE(OP_JMP); { cl_oparg jump = GET_OPARG(vector); vector += jump - OPARG_SIZE; - break; + NEXT; } - case OP_JNIL: { + CASE(OP_JNIL); { cl_oparg jump = GET_OPARG(vector); NVALUES = 1; if (Null(VALUES(0))) vector += jump - OPARG_SIZE; - break; + NEXT; } - case OP_JT: { + CASE(OP_JT); { cl_oparg jump = GET_OPARG(vector); NVALUES = 1; if (!Null(VALUES(0))) vector += jump - OPARG_SIZE; - break; + NEXT; } - case OP_JEQL: { + CASE(OP_JEQL); { cl_oparg value = GET_OPARG(vector); cl_oparg jump = GET_OPARG(vector); if (ecl_eql(reg0, bytecodes->bytecodes.data[value])) vector += jump - OPARG_SIZE; - break; + NEXT; } - case OP_JNEQL: { + CASE(OP_JNEQL); { cl_oparg value = GET_OPARG(vector); cl_oparg jump = GET_OPARG(vector); if (!ecl_eql(reg0, bytecodes->bytecodes.data[value])) vector += jump - OPARG_SIZE; - break; + NEXT; } - case OP_NOT: + CASE(OP_NOT); { reg0 = (reg0 == Cnil)? Ct : Cnil; - break; + NEXT; + } /* OP_UNBIND n{arg} Undo "n" local bindings. */ - case OP_UNBIND: { + CASE(OP_UNBIND); { cl_index n = GET_OPARG(vector); while (n--) cl_env.lex_env = CDR(cl_env.lex_env); - break; + NEXT; } /* OP_UNBINDS n{arg} Undo "n" bindings of special variables. */ - case OP_UNBINDS: { + CASE(OP_UNBINDS); { cl_index n = GET_OPARG(vector); bds_unwind_n(n); - break; + NEXT; } /* OP_BIND name{symbol} OP_PBIND name{symbol} @@ -926,41 +935,41 @@ ecl_interpret(cl_object bytecodes, void *pc) { Binds a lexical or special variable to the either the value of REG0 or the first value of the stack. */ - case OP_BIND: { + CASE(OP_BIND); { cl_object var_name = GET_DATA(vector, bytecodes); bind_var(var_name, reg0); - break; + NEXT; } - case OP_PBIND: { + CASE(OP_PBIND); { cl_object var_name = GET_DATA(vector, bytecodes); cl_object value = cl_stack_pop(); bind_var(var_name, value); - break; + NEXT; } - case OP_VBIND: { + CASE(OP_VBIND); { cl_index n = GET_OPARG(vector); cl_object var_name = GET_DATA(vector, bytecodes); cl_object value = (n < NVALUES) ? VALUES(n) : Cnil; bind_var(var_name, value); - break; + NEXT; } - case OP_BINDS: { + CASE(OP_BINDS); { cl_object var_name = GET_DATA(vector, bytecodes); bds_bind(var_name, reg0); - break; + NEXT; } - case OP_PBINDS: { + CASE(OP_PBINDS); { cl_object var_name = GET_DATA(vector, bytecodes); cl_object value = cl_stack_pop(); bds_bind(var_name, value); - break; + NEXT; } - case OP_VBINDS: { + CASE(OP_VBINDS); { cl_index n = GET_OPARG(vector); cl_object var_name = GET_DATA(vector, bytecodes); cl_object value = (n < NVALUES) ? VALUES(n) : Cnil; bds_bind(var_name, value); - break; + NEXT; } /* OP_SETQ n{arg} OP_PSETQ n{arg} @@ -970,31 +979,31 @@ ecl_interpret(cl_object bytecodes, void *pc) { to either the value in REG0 (OP_SETQ[S]) or to the first value on the stack (OP_PSETQ[S]). */ - case OP_SETQ: { + CASE(OP_SETQ); { int lex_env_index = GET_OPARG(vector); ecl_lex_env_set_var(lex_env_index, reg0); - break; + NEXT; } - case OP_SETQS: { + CASE(OP_SETQS); { cl_object var = GET_DATA(vector, bytecodes); /* INV: Not NIL, and of type t_symbol */ if (var->symbol.stype & stp_constant) FEassignment_to_constant(var); ECL_SETQ(var, reg0); - break; + NEXT; } - case OP_PSETQ: { + CASE(OP_PSETQ); { int lex_env_index = GET_OPARG(vector); ecl_lex_env_set_var(lex_env_index, cl_stack_pop()); - break; + NEXT; } - case OP_PSETQS: { + CASE(OP_PSETQS); { cl_object var = GET_DATA(vector, bytecodes); /* INV: Not NIL, and of type t_symbol */ if (var->symbol.stype & stp_constant) FEassignment_to_constant(var); ECL_SETQ(var, cl_stack_pop()); - break; + NEXT; } /* OP_BLOCK label{arg} @@ -1005,10 +1014,11 @@ ecl_interpret(cl_object bytecodes, void *pc) { Executes the enclosed code in a named block. LABEL points to the first instruction after OP_EXIT. */ - case OP_BLOCK: + CASE(OP_BLOCK); { reg0 = GET_DATA(vector, bytecodes); reg1 = new_frame_id(); goto DO_BLOCK; + } /* OP_CATCH label{arg} ... OP_EXIT_FRAME @@ -1017,9 +1027,10 @@ ecl_interpret(cl_object bytecodes, void *pc) { Sets a catch point using the tag in VALUES(0). LABEL points to the first instruction after the end (OP_EXIT) of the block */ - case OP_CATCH: + CASE(OP_CATCH); { reg1 = reg0; goto DO_BLOCK; + } /* OP_DO label ... ; code executed within a NIL block OP_EXIT_FRAME @@ -1027,9 +1038,10 @@ ecl_interpret(cl_object bytecodes, void *pc) { High level construct for the DO and BLOCK forms. */ - case OP_DO: + CASE(OP_DO); { reg0 = Cnil; reg1 = new_frame_id(); + } DO_BLOCK: { cl_opcode *exit; GET_LABEL(exit, vector); @@ -1042,14 +1054,15 @@ ecl_interpret(cl_object bytecodes, void *pc) { frs_pop(); vector = (cl_opcode *)cl_stack_pop(); /* FIXME! */ } - break; - } - case OP_EXIT_FRAME: + NEXT; + } + CASE(OP_EXIT_FRAME); { bds_unwind(cl_env.frs_top->frs_bds_top); cl_env.lex_env = cl_env.frs_top->frs_lex; frs_pop(); cl_stack_pop(); - break; + NEXT; + } /* OP_TAGBODY n{arg} label1 ... @@ -1062,7 +1075,7 @@ ecl_interpret(cl_object bytecodes, void *pc) { High level construct for the TAGBODY form. */ - case OP_TAGBODY: { + CASE(OP_TAGBODY); { cl_object id = new_frame_id(); int n = GET_OPARG(vector); /* Here we save the location of the jump table */ @@ -1083,67 +1096,70 @@ ecl_interpret(cl_object bytecodes, void *pc) { vector = table + *(cl_oparg *)table; cl_env.lex_env = cl_env.frs_top->frs_lex; } - break; + NEXT; } - case OP_EXIT_TAGBODY: + CASE(OP_EXIT_TAGBODY); { cl_env.lex_env = CDR(cl_env.frs_top->frs_lex); frs_pop(); cl_stack_pop(); - case OP_NIL: + } + CASE(OP_NIL); { reg0 = Cnil; - break; - case OP_PUSHNIL: + NEXT; + } + CASE(OP_PUSHNIL); { cl_stack_push(Cnil); - break; - case OP_VALUEREG0: + NEXT; + } + CASE(OP_VALUEREG0); { VALUES(0) = reg0; NVALUES = 1; - break; - case OP_NOP: - VALUES(0) = reg0 = Cnil; - NVALUES = 0; - break; - case OP_MSETQ: + NEXT; + } + CASE(OP_MSETQ); { vector = interpret_msetq(bytecodes, vector); reg0 = VALUES(0); - break; - case OP_PROGV: + NEXT; + } + CASE(OP_PROGV); { vector = interpret_progv(bytecodes, vector); reg0 = VALUES(0); - break; + NEXT; + } /* OP_PUSHVALUES Pushes the values output by the last form, plus the number of values. */ PUSH_VALUES: - case OP_PUSHVALUES: { + CASE(OP_PUSHVALUES); { cl_index i; for (i=0; ifrs_bds_top); cl_env.lex_env = cl_env.frs_top->frs_lex; frs_pop(); cl_stack_pop(); cl_stack_push(MAKE_FIXNUM(1)); goto PUSH_VALUES; - case OP_PROTECT_EXIT: { + } + CASE(OP_PROTECT_EXIT); { volatile cl_fixnum n = NVALUES = fix(cl_stack_pop()); while (n--) VALUES(n) = cl_stack_pop(); @@ -1221,9 +1238,9 @@ ecl_interpret(cl_object bytecodes, void *pc) { n = fix(cl_stack_pop()); if (n <= 0) ecl_unwind(cl_env.frs_top + n); - break; + NEXT; } - case OP_STEPIN: { + CASE(OP_STEPIN); { cl_object form = GET_DATA(vector, bytecodes); cl_object a = SYM_VAL(@'si::*step-action*'); cl_index n = cl_stack_push_values(); @@ -1244,9 +1261,9 @@ ecl_interpret(cl_object bytecodes, void *pc) { * actually never happen. */ } cl_stack_pop_values(n); - break; + NEXT; } - case OP_STEPCALL: { + CASE(OP_STEPCALL); { /* We are going to call a function. However, we would * like to step _in_ the function. STEPPER takes care of * that. */ @@ -1257,7 +1274,7 @@ ecl_interpret(cl_object bytecodes, void *pc) { } reg0 = interpret_funcall(n, reg0); } - case OP_STEPOUT: { + CASE(OP_STEPOUT); { cl_object a = SYM_VAL(@'si::*step-action*'); cl_index n = cl_stack_push_values(); if (a == Ct) { @@ -1274,14 +1291,9 @@ ecl_interpret(cl_object bytecodes, void *pc) { /* Not stepping, nothing to be done. */ } cl_stack_pop_values(n); - break; + NEXT; } - - default: - FEerror("Internal error: Unknown code ~S", - 1, MAKE_FIXNUM(*(vector-1))); } - goto BEGIN; } @(defun si::interpreter_stack () diff --git a/src/h/bytecodes.h b/src/h/bytecodes.h index 21e49ecda..853355123 100644 --- a/src/h/bytecodes.h +++ b/src/h/bytecodes.h @@ -1,4 +1,11 @@ /* -*- mode: c; c-basic-offset: 8 -*- */ +/********************************************************************** + *** + *** IMPORTANT: ANY CHANGE IN THIS FILE MUST BE MATCHED BY + *** APPROPRIATE CHANGES IN THE INTERPRETER AND COMPILER + *** IN PARTICULAR, IT MAY HURT THE THREADED INTERPRETER + *** CODE. + **********************************************************************/ /* OP_BLOCK block-name{obj} ... @@ -203,3 +210,105 @@ typedef int16_t cl_oparg; #define GET_OPARG(v) (*((cl_oparg *)(v)++)) #define GET_DATA(v,b) (b->bytecodes.data[GET_OPARG(v)]) #define GET_LABEL(pc,v) {pc = (v) + READ_OPARG(v); v += OPARG_SIZE;} + +/********************************************************************** + * THREADED INTERPRETER CODE + * + * By using labels as values, we can build a variant of the + * interpreter code that leads to better performance because (i) it + * saves a range check on the opcode size and (ii) each opcode has a + * dispatch instruction at the end, so that the processor may better + * predict jumps. + */ +#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +#define ECL_THREADED_INTERPRETER +#endif + +#ifdef ECL_THREADED_INTERPRETER +#define BEGIN_SWITCH \ + NEXT; +#define CASE(name) \ + LBL_##name: +#define NEXT \ + goto *(&&LBL_OP_NOP + offsets[GET_OPCODE(vector)]) +#else +#define BEGIN_SWITCH \ + switch (GET_OPCODE(vector)) +#define NEXT \ + goto BEGIN +#define CASE(name) \ + case name: +#endif + +#if !defined(ECL_THREADED_INTERPRETER) +#define ECL_OFFSET_TABLE +#else +#define ECL_OFFSET_TABLE \ + static const int offsets[] = {\ + &&LBL_OP_NOP - &&LBL_OP_NOP,\ + &&LBL_OP_QUOTE - &&LBL_OP_NOP,\ + &&LBL_OP_VAR - &&LBL_OP_NOP,\ + &&LBL_OP_VARS - &&LBL_OP_NOP,\ + &&LBL_OP_PUSH - &&LBL_OP_NOP,\ + &&LBL_OP_PUSHV - &&LBL_OP_NOP,\ + &&LBL_OP_PUSHVS - &&LBL_OP_NOP,\ + &&LBL_OP_PUSHQ - &&LBL_OP_NOP,\ + &&LBL_OP_CALLG - &&LBL_OP_NOP,\ + &&LBL_OP_CALL - &&LBL_OP_NOP,\ + &&LBL_OP_FCALL - &&LBL_OP_NOP,\ + &&LBL_OP_PCALLG - &&LBL_OP_NOP,\ + &&LBL_OP_PCALL - &&LBL_OP_NOP,\ + &&LBL_OP_PFCALL - &&LBL_OP_NOP,\ + &&LBL_OP_MCALL - &&LBL_OP_NOP,\ + &&LBL_OP_EXIT - &&LBL_OP_NOP,\ + &&LBL_OP_FLET - &&LBL_OP_NOP,\ + &&LBL_OP_LABELS - &&LBL_OP_NOP,\ + &&LBL_OP_LFUNCTION - &&LBL_OP_NOP,\ + &&LBL_OP_FUNCTION - &&LBL_OP_NOP,\ + &&LBL_OP_CLOSE - &&LBL_OP_NOP,\ + &&LBL_OP_GO - &&LBL_OP_NOP,\ + &&LBL_OP_RETURN - &&LBL_OP_NOP,\ + &&LBL_OP_THROW - &&LBL_OP_NOP,\ + &&LBL_OP_JMP - &&LBL_OP_NOP,\ + &&LBL_OP_JNIL - &&LBL_OP_NOP,\ + &&LBL_OP_JT - &&LBL_OP_NOP,\ + &&LBL_OP_JEQL - &&LBL_OP_NOP,\ + &&LBL_OP_JNEQL - &&LBL_OP_NOP,\ + &&LBL_OP_UNBIND - &&LBL_OP_NOP,\ + &&LBL_OP_UNBINDS - &&LBL_OP_NOP,\ + &&LBL_OP_BIND - &&LBL_OP_NOP,\ + &&LBL_OP_PBIND - &&LBL_OP_NOP,\ + &&LBL_OP_VBIND - &&LBL_OP_NOP,\ + &&LBL_OP_BINDS - &&LBL_OP_NOP,\ + &&LBL_OP_PBINDS - &&LBL_OP_NOP,\ + &&LBL_OP_VBINDS - &&LBL_OP_NOP,\ + &&LBL_OP_SETQ - &&LBL_OP_NOP,\ + &&LBL_OP_SETQS - &&LBL_OP_NOP,\ + &&LBL_OP_PSETQ - &&LBL_OP_NOP,\ + &&LBL_OP_PSETQS - &&LBL_OP_NOP,\ + &&LBL_OP_BLOCK - &&LBL_OP_NOP,\ + &&LBL_OP_DO - &&LBL_OP_NOP,\ + &&LBL_OP_CATCH - &&LBL_OP_NOP,\ + &&LBL_OP_TAGBODY - &&LBL_OP_NOP,\ + &&LBL_OP_EXIT_TAGBODY - &&LBL_OP_NOP,\ + &&LBL_OP_EXIT_FRAME - &&LBL_OP_NOP,\ + &&LBL_OP_PROTECT - &&LBL_OP_NOP,\ + &&LBL_OP_PROTECT_NORMAL - &&LBL_OP_NOP,\ + &&LBL_OP_PROTECT_EXIT - &&LBL_OP_NOP,\ + &&LBL_OP_MSETQ - &&LBL_OP_NOP,\ + &&LBL_OP_PROGV - &&LBL_OP_NOP,\ + &&LBL_OP_PUSHVALUES - &&LBL_OP_NOP,\ + &&LBL_OP_POP - &&LBL_OP_NOP,\ + &&LBL_OP_POPVALUES - &&LBL_OP_NOP,\ + &&LBL_OP_PUSHMOREVALUES - &&LBL_OP_NOP,\ + &&LBL_OP_VALUES - &&LBL_OP_NOP,\ + &&LBL_OP_VALUEREG0 - &&LBL_OP_NOP,\ + &&LBL_OP_NTHVAL - &&LBL_OP_NOP,\ + &&LBL_OP_NIL - &&LBL_OP_NOP,\ + &&LBL_OP_NOT - &&LBL_OP_NOP,\ + &&LBL_OP_PUSHNIL - &&LBL_OP_NOP,\ + &&LBL_OP_STEPIN - &&LBL_OP_NOP,\ + &&LBL_OP_STEPCALL - &&LBL_OP_NOP,\ + &&LBL_OP_STEPOUT - &&LBL_OP_NOP\ + } +#endif