/* * ECMAScript bytecode */ #if !defined(DUK_JS_BYTECODE_H_INCLUDED) #define DUK_JS_BYTECODE_H_INCLUDED /* * Bytecode instruction layout * =========================== * * Instructions are unsigned 32-bit integers divided as follows: * * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! * +-----------------------------------------------+---------------+ * ! C ! B ! A ! OP ! * +-----------------------------------------------+---------------+ * * OP (8 bits): opcode (DUK_OP_*), access should be fastest * consecutive opcodes allocated when opcode needs flags * A (8 bits): typically a target register number * B (8 bits): typically first source register/constant number * C (8 bits): typically second source register/constant number * * Some instructions combine BC or ABC together for larger parameter values. * Signed integers (e.g. jump offsets) are encoded as unsigned, with an * opcode specific bias. * * Some opcodes have flags which are handled by allocating consecutive * opcodes to make space for 1-N flags. Flags can also be e.g. in the 'A' * field when there's room for the specific opcode. * * For example, if three flags were needed, they could be allocated from * the opcode field as follows: * * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! * +-----------------------------------------------+---------------+ * ! C ! B ! A ! OP !Z!Y!X! * +-----------------------------------------------+---------------+ * * Some opcodes accept a reg/const argument which is handled by allocating * flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST(). The * following convention is shared by most opcodes, so that the compiler * can handle reg/const flagging without opcode specific code paths: * * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0! * +-----------------------------------------------+---------------+ * ! C ! B ! A ! OP !Y!X! * +-----------------------------------------------+---------------+ * * X 1=B is const, 0=B is reg * Y 1=C is const, 0=C is reg * * In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the * 8-bit opcode space for a single logical opcode. The base opcode * number should be divisible by 4. If the opcode is called 'FOO' * the following opcode constants would be defined: * * DUK_OP_FOO 100 // base opcode number * DUK_OP_FOO_RR 100 // FOO, B=reg, C=reg * DUK_OP_FOO_CR 101 // FOO, B=const, C=reg * DUK_OP_FOO_RC 102 // FOO, B=reg, C=const * DUK_OP_FOO_CC 103 // FOO, B=const, C=const * * If only B or C is a reg/const, the unused opcode combinations can be * used for other opcodes (which take no reg/const argument). However, * such opcode values are initially reserved, at least while opcode space * is available. For example, if 'BAR' uses B for a register field and * C is a reg/const: * * DUK_OP_BAR 116 // base opcode number * DUK_OP_BAR_RR 116 // BAR, B=reg, C=reg * DUK_OP_BAR_CR_UNUSED 117 // unused, could be repurposed * DUK_OP_BAR_RC 118 // BAR, B=reg, C=const * DUK_OP_BAR_CC_UNUSED 119 // unused, could be repurposed * * Macro naming is a bit misleading, e.g. "ABC" in macro name but the * field layout is concretely "CBA" in the register. */ typedef duk_uint32_t duk_instr_t; #define DUK_BC_SHIFT_OP 0 #define DUK_BC_SHIFT_A 8 #define DUK_BC_SHIFT_B 16 #define DUK_BC_SHIFT_C 24 #define DUK_BC_SHIFT_BC DUK_BC_SHIFT_B #define DUK_BC_SHIFT_ABC DUK_BC_SHIFT_A #define DUK_BC_UNSHIFTED_MASK_OP 0xffUL #define DUK_BC_UNSHIFTED_MASK_A 0xffUL #define DUK_BC_UNSHIFTED_MASK_B 0xffUL #define DUK_BC_UNSHIFTED_MASK_C 0xffUL #define DUK_BC_UNSHIFTED_MASK_BC 0xffffUL #define DUK_BC_UNSHIFTED_MASK_ABC 0xffffffUL #define DUK_BC_SHIFTED_MASK_OP (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP) #define DUK_BC_SHIFTED_MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A) #define DUK_BC_SHIFTED_MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B) #define DUK_BC_SHIFTED_MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C) #define DUK_BC_SHIFTED_MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC) #define DUK_BC_SHIFTED_MASK_ABC (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC) #define DUK_DEC_OP(x) ((x) & 0xffUL) #define DUK_DEC_A(x) (((x) >> 8) & 0xffUL) #define DUK_DEC_B(x) (((x) >> 16) & 0xffUL) #define DUK_DEC_C(x) (((x) >> 24) & 0xffUL) #define DUK_DEC_BC(x) (((x) >> 16) & 0xffffUL) #define DUK_DEC_ABC(x) (((x) >> 8) & 0xffffffUL) #define DUK_ENC_OP(op) ((duk_instr_t) (op)) #define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \ (((duk_instr_t) (abc)) << 8) | \ ((duk_instr_t) (op)) \ )) #define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \ (((duk_instr_t) (bc)) << 16) | \ (((duk_instr_t) (a)) << 8) | \ ((duk_instr_t) (op)) \ )) #define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \ (((duk_instr_t) (c)) << 24) | \ (((duk_instr_t) (b)) << 16) | \ (((duk_instr_t) (a)) << 8) | \ ((duk_instr_t) (op)) \ )) #define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C((op),(a),(b),0) #define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C((op),(a),0,0) #define DUK_ENC_OP_BC(op,bc) DUK_ENC_OP_A_BC((op),0,(bc)) /* Get opcode base value with B/C reg/const flags cleared. */ #define DUK_BC_NOREGCONST_OP(op) ((op) & 0xfc) /* Constants should be signed so that signed arithmetic involving them * won't cause values to be coerced accidentally to unsigned. */ #define DUK_BC_OP_MIN 0 #define DUK_BC_OP_MAX 0xffL #define DUK_BC_A_MIN 0 #define DUK_BC_A_MAX 0xffL #define DUK_BC_B_MIN 0 #define DUK_BC_B_MAX 0xffL #define DUK_BC_C_MIN 0 #define DUK_BC_C_MAX 0xffL #define DUK_BC_BC_MIN 0 #define DUK_BC_BC_MAX 0xffffL #define DUK_BC_ABC_MIN 0 #define DUK_BC_ABC_MAX 0xffffffL /* Masks for B/C reg/const indicator in opcode field. */ #define DUK_BC_REGCONST_B (0x01UL) #define DUK_BC_REGCONST_C (0x02UL) /* Misc. masks for opcode field. */ #define DUK_BC_INCDECP_FLAG_DEC (0x04UL) #define DUK_BC_INCDECP_FLAG_POST (0x08UL) /* Opcodes. */ #define DUK_OP_LDREG 0 #define DUK_OP_STREG 1 #define DUK_OP_JUMP 2 #define DUK_OP_LDCONST 3 #define DUK_OP_LDINT 4 #define DUK_OP_LDINTX 5 #define DUK_OP_LDTHIS 6 #define DUK_OP_LDUNDEF 7 #define DUK_OP_LDNULL 8 #define DUK_OP_LDTRUE 9 #define DUK_OP_LDFALSE 10 #define DUK_OP_GETVAR 11 #define DUK_OP_BNOT 12 #define DUK_OP_LNOT 13 #define DUK_OP_UNM 14 #define DUK_OP_UNP 15 #define DUK_OP_EQ 16 #define DUK_OP_EQ_RR 16 #define DUK_OP_EQ_CR 17 #define DUK_OP_EQ_RC 18 #define DUK_OP_EQ_CC 19 #define DUK_OP_NEQ 20 #define DUK_OP_NEQ_RR 20 #define DUK_OP_NEQ_CR 21 #define DUK_OP_NEQ_RC 22 #define DUK_OP_NEQ_CC 23 #define DUK_OP_SEQ 24 #define DUK_OP_SEQ_RR 24 #define DUK_OP_SEQ_CR 25 #define DUK_OP_SEQ_RC 26 #define DUK_OP_SEQ_CC 27 #define DUK_OP_SNEQ 28 #define DUK_OP_SNEQ_RR 28 #define DUK_OP_SNEQ_CR 29 #define DUK_OP_SNEQ_RC 30 #define DUK_OP_SNEQ_CC 31 #define DUK_OP_GT 32 #define DUK_OP_GT_RR 32 #define DUK_OP_GT_CR 33 #define DUK_OP_GT_RC 34 #define DUK_OP_GT_CC 35 #define DUK_OP_GE 36 #define DUK_OP_GE_RR 36 #define DUK_OP_GE_CR 37 #define DUK_OP_GE_RC 38 #define DUK_OP_GE_CC 39 #define DUK_OP_LT 40 #define DUK_OP_LT_RR 40 #define DUK_OP_LT_CR 41 #define DUK_OP_LT_RC 42 #define DUK_OP_LT_CC 43 #define DUK_OP_LE 44 #define DUK_OP_LE_RR 44 #define DUK_OP_LE_CR 45 #define DUK_OP_LE_RC 46 #define DUK_OP_LE_CC 47 #define DUK_OP_IFTRUE 48 #define DUK_OP_IFTRUE_R 48 #define DUK_OP_IFTRUE_C 49 #define DUK_OP_IFFALSE 50 #define DUK_OP_IFFALSE_R 50 #define DUK_OP_IFFALSE_C 51 #define DUK_OP_ADD 52 #define DUK_OP_ADD_RR 52 #define DUK_OP_ADD_CR 53 #define DUK_OP_ADD_RC 54 #define DUK_OP_ADD_CC 55 #define DUK_OP_SUB 56 #define DUK_OP_SUB_RR 56 #define DUK_OP_SUB_CR 57 #define DUK_OP_SUB_RC 58 #define DUK_OP_SUB_CC 59 #define DUK_OP_MUL 60 #define DUK_OP_MUL_RR 60 #define DUK_OP_MUL_CR 61 #define DUK_OP_MUL_RC 62 #define DUK_OP_MUL_CC 63 #define DUK_OP_DIV 64 #define DUK_OP_DIV_RR 64 #define DUK_OP_DIV_CR 65 #define DUK_OP_DIV_RC 66 #define DUK_OP_DIV_CC 67 #define DUK_OP_MOD 68 #define DUK_OP_MOD_RR 68 #define DUK_OP_MOD_CR 69 #define DUK_OP_MOD_RC 70 #define DUK_OP_MOD_CC 71 #define DUK_OP_EXP 72 #define DUK_OP_EXP_RR 72 #define DUK_OP_EXP_CR 73 #define DUK_OP_EXP_RC 74 #define DUK_OP_EXP_CC 75 #define DUK_OP_BAND 76 #define DUK_OP_BAND_RR 76 #define DUK_OP_BAND_CR 77 #define DUK_OP_BAND_RC 78 #define DUK_OP_BAND_CC 79 #define DUK_OP_BOR 80 #define DUK_OP_BOR_RR 80 #define DUK_OP_BOR_CR 81 #define DUK_OP_BOR_RC 82 #define DUK_OP_BOR_CC 83 #define DUK_OP_BXOR 84 #define DUK_OP_BXOR_RR 84 #define DUK_OP_BXOR_CR 85 #define DUK_OP_BXOR_RC 86 #define DUK_OP_BXOR_CC 87 #define DUK_OP_BASL 88 #define DUK_OP_BASL_RR 88 #define DUK_OP_BASL_CR 89 #define DUK_OP_BASL_RC 90 #define DUK_OP_BASL_CC 91 #define DUK_OP_BLSR 92 #define DUK_OP_BLSR_RR 92 #define DUK_OP_BLSR_CR 93 #define DUK_OP_BLSR_RC 94 #define DUK_OP_BLSR_CC 95 #define DUK_OP_BASR 96 #define DUK_OP_BASR_RR 96 #define DUK_OP_BASR_CR 97 #define DUK_OP_BASR_RC 98 #define DUK_OP_BASR_CC 99 #define DUK_OP_INSTOF 100 #define DUK_OP_INSTOF_RR 100 #define DUK_OP_INSTOF_CR 101 #define DUK_OP_INSTOF_RC 102 #define DUK_OP_INSTOF_CC 103 #define DUK_OP_IN 104 #define DUK_OP_IN_RR 104 #define DUK_OP_IN_CR 105 #define DUK_OP_IN_RC 106 #define DUK_OP_IN_CC 107 #define DUK_OP_GETPROP 108 #define DUK_OP_GETPROP_RR 108 #define DUK_OP_GETPROP_CR 109 #define DUK_OP_GETPROP_RC 110 #define DUK_OP_GETPROP_CC 111 #define DUK_OP_PUTPROP 112 #define DUK_OP_PUTPROP_RR 112 #define DUK_OP_PUTPROP_CR 113 #define DUK_OP_PUTPROP_RC 114 #define DUK_OP_PUTPROP_CC 115 #define DUK_OP_DELPROP 116 #define DUK_OP_DELPROP_RR 116 #define DUK_OP_DELPROP_CR_UNUSED 117 /* unused now */ #define DUK_OP_DELPROP_RC 118 #define DUK_OP_DELPROP_CC_UNUSED 119 /* unused now */ #define DUK_OP_PREINCR 120 /* pre/post opcode values have constraints, */ #define DUK_OP_PREDECR 121 /* see duk_js_executor.c and duk_js_compiler.c. */ #define DUK_OP_POSTINCR 122 #define DUK_OP_POSTDECR 123 #define DUK_OP_PREINCV 124 #define DUK_OP_PREDECV 125 #define DUK_OP_POSTINCV 126 #define DUK_OP_POSTDECV 127 #define DUK_OP_PREINCP 128 /* pre/post inc/dec prop opcodes have constraints */ #define DUK_OP_PREINCP_RR 128 #define DUK_OP_PREINCP_CR 129 #define DUK_OP_PREINCP_RC 130 #define DUK_OP_PREINCP_CC 131 #define DUK_OP_PREDECP 132 #define DUK_OP_PREDECP_RR 132 #define DUK_OP_PREDECP_CR 133 #define DUK_OP_PREDECP_RC 134 #define DUK_OP_PREDECP_CC 135 #define DUK_OP_POSTINCP 136 #define DUK_OP_POSTINCP_RR 136 #define DUK_OP_POSTINCP_CR 137 #define DUK_OP_POSTINCP_RC 138 #define DUK_OP_POSTINCP_CC 139 #define DUK_OP_POSTDECP 140 #define DUK_OP_POSTDECP_RR 140 #define DUK_OP_POSTDECP_CR 141 #define DUK_OP_POSTDECP_RC 142 #define DUK_OP_POSTDECP_CC 143 #define DUK_OP_DECLVAR 144 #define DUK_OP_DECLVAR_RR 144 #define DUK_OP_DECLVAR_CR 145 #define DUK_OP_DECLVAR_RC 146 #define DUK_OP_DECLVAR_CC 147 #define DUK_OP_REGEXP 148 #define DUK_OP_REGEXP_RR 148 #define DUK_OP_REGEXP_CR 149 #define DUK_OP_REGEXP_RC 150 #define DUK_OP_REGEXP_CC 151 #define DUK_OP_CLOSURE 152 #define DUK_OP_TYPEOF 153 #define DUK_OP_TYPEOFID 154 #define DUK_OP_PUTVAR 155 #define DUK_OP_DELVAR 156 #define DUK_OP_RETREG 157 #define DUK_OP_RETUNDEF 158 #define DUK_OP_RETCONST 159 #define DUK_OP_RETCONSTN 160 /* return const without incref (e.g. number) */ #define DUK_OP_LABEL 161 #define DUK_OP_ENDLABEL 162 #define DUK_OP_BREAK 163 #define DUK_OP_CONTINUE 164 #define DUK_OP_TRYCATCH 165 #define DUK_OP_ENDTRY 166 #define DUK_OP_ENDCATCH 167 #define DUK_OP_ENDFIN 168 #define DUK_OP_THROW 169 #define DUK_OP_INVLHS 170 #define DUK_OP_CSREG 171 #define DUK_OP_CSVAR 172 #define DUK_OP_CSVAR_RR 172 #define DUK_OP_CSVAR_CR 173 #define DUK_OP_CSVAR_RC 174 #define DUK_OP_CSVAR_CC 175 #define DUK_OP_CALL0 176 /* DUK_OP_CALL0 & 0x0F must be zero. */ #define DUK_OP_CALL1 177 #define DUK_OP_CALL2 178 #define DUK_OP_CALL3 179 #define DUK_OP_CALL4 180 #define DUK_OP_CALL5 181 #define DUK_OP_CALL6 182 #define DUK_OP_CALL7 183 #define DUK_OP_CALL8 184 #define DUK_OP_CALL9 185 #define DUK_OP_CALL10 186 #define DUK_OP_CALL11 187 #define DUK_OP_CALL12 188 #define DUK_OP_CALL13 189 #define DUK_OP_CALL14 190 #define DUK_OP_CALL15 191 #define DUK_OP_NEWOBJ 192 #define DUK_OP_NEWARR 193 #define DUK_OP_MPUTOBJ 194 #define DUK_OP_MPUTOBJI 195 #define DUK_OP_INITSET 196 #define DUK_OP_INITGET 197 #define DUK_OP_MPUTARR 198 #define DUK_OP_MPUTARRI 199 #define DUK_OP_SETALEN 200 #define DUK_OP_INITENUM 201 #define DUK_OP_NEXTENUM 202 #define DUK_OP_NEWTARGET 203 #define DUK_OP_DEBUGGER 204 #define DUK_OP_NOP 205 #define DUK_OP_INVALID 206 #define DUK_OP_UNUSED207 207 #define DUK_OP_GETPROPC 208 #define DUK_OP_GETPROPC_RR 208 #define DUK_OP_GETPROPC_CR 209 #define DUK_OP_GETPROPC_RC 210 #define DUK_OP_GETPROPC_CC 211 #define DUK_OP_UNUSED212 212 #define DUK_OP_UNUSED213 213 #define DUK_OP_UNUSED214 214 #define DUK_OP_UNUSED215 215 #define DUK_OP_UNUSED216 216 #define DUK_OP_UNUSED217 217 #define DUK_OP_UNUSED218 218 #define DUK_OP_UNUSED219 219 #define DUK_OP_UNUSED220 220 #define DUK_OP_UNUSED221 221 #define DUK_OP_UNUSED222 222 #define DUK_OP_UNUSED223 223 #define DUK_OP_UNUSED224 224 #define DUK_OP_UNUSED225 225 #define DUK_OP_UNUSED226 226 #define DUK_OP_UNUSED227 227 #define DUK_OP_UNUSED228 228 #define DUK_OP_UNUSED229 229 #define DUK_OP_UNUSED230 230 #define DUK_OP_UNUSED231 231 #define DUK_OP_UNUSED232 232 #define DUK_OP_UNUSED233 233 #define DUK_OP_UNUSED234 234 #define DUK_OP_UNUSED235 235 #define DUK_OP_UNUSED236 236 #define DUK_OP_UNUSED237 237 #define DUK_OP_UNUSED238 238 #define DUK_OP_UNUSED239 239 #define DUK_OP_UNUSED240 240 #define DUK_OP_UNUSED241 241 #define DUK_OP_UNUSED242 242 #define DUK_OP_UNUSED243 243 #define DUK_OP_UNUSED244 244 #define DUK_OP_UNUSED245 245 #define DUK_OP_UNUSED246 246 #define DUK_OP_UNUSED247 247 #define DUK_OP_UNUSED248 248 #define DUK_OP_UNUSED249 249 #define DUK_OP_UNUSED250 250 #define DUK_OP_UNUSED251 251 #define DUK_OP_UNUSED252 252 #define DUK_OP_UNUSED253 253 #define DUK_OP_UNUSED254 254 #define DUK_OP_UNUSED255 255 #define DUK_OP_NONE 256 /* dummy value used as marker (doesn't fit in 8-bit field) */ /* XXX: Allocate flags from opcode field? Would take 16 opcode slots * but avoids shuffling in more cases. Maybe not worth it. */ /* DUK_OP_TRYCATCH flags in A. */ #define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1U << 0) #define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1U << 1) #define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1U << 2) #define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1U << 3) /* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags * (DUK_PROPDESC_FLAG_XXX). */ #define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1U << 4) /* function declaration */ /* DUK_OP_CALLn flags, part of opcode field. Three lowest bits must match * DUK_CALL_FLAG_xxx directly. */ #define DUK_BC_CALL_FLAG_TAILCALL (1U << 0) #define DUK_BC_CALL_FLAG_CONSTRUCT (1U << 1) #define DUK_BC_CALL_FLAG_CALLED_AS_EVAL (1U << 2) #define DUK_BC_CALL_FLAG_INDIRECT (1U << 3) /* Misc constants and helper macros. */ #define DUK_BC_LDINT_BIAS (1L << 15) #define DUK_BC_LDINTX_SHIFT 16 #define DUK_BC_JUMP_BIAS (1L << 23) #endif /* DUK_JS_BYTECODE_H_INCLUDED */