/*
 *  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 */
