
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) NGINX, Inc.
 */

#ifndef _NJS_VMCODE_H_INCLUDED_
#define _NJS_VMCODE_H_INCLUDED_


/*
 * Negative return values handled by nJSVM interpreter as special events.
 * The values must be in range from -1 to -11, because -12 is minimal jump
 * offset on 32-bit platforms.
 *    0  (NJS_OK)   :  njs_vmcode_stop() has stopped execution,
 *                          execution successfully finished
 *    -1 (NJS_ERROR):  error or exception;
 *    -2 .. -11:                 not used.
 */

/* The last return value which preempts execution. */
#define NJS_PREEMPT                     (-11)


typedef intptr_t                        njs_jump_off_t;
typedef uint8_t                         njs_vmcode_t;


enum {
    NJS_VMCODE_PUT_ARG = 0,
    NJS_VMCODE_STOP,
    NJS_VMCODE_JUMP,
    NJS_VMCODE_PROPERTY_ATOM_SET,
    NJS_VMCODE_PROPERTY_SET,
    NJS_VMCODE_PROPERTY_ACCESSOR,
    NJS_VMCODE_IF_TRUE_JUMP,
    NJS_VMCODE_IF_FALSE_JUMP,
    NJS_VMCODE_IF_EQUAL_JUMP,
    NJS_VMCODE_PROPERTY_INIT,
    NJS_VMCODE_RETURN,
    NJS_VMCODE_FUNCTION_FRAME,
    NJS_VMCODE_METHOD_FRAME,
    NJS_VMCODE_FUNCTION_CALL,
    NJS_VMCODE_PROPERTY_NEXT,
    NJS_VMCODE_ARGUMENTS,
    NJS_VMCODE_PROTO_INIT,
    NJS_VMCODE_TO_PROPERTY_KEY,
    NJS_VMCODE_TO_PROPERTY_KEY_CHK,
    NJS_VMCODE_SET_FUNCTION_NAME,
    NJS_VMCODE_IMPORT,
    NJS_VMCODE_AWAIT,
    NJS_VMCODE_TRY_START,
    NJS_VMCODE_THROW,
    NJS_VMCODE_TRY_BREAK,
    NJS_VMCODE_TRY_CONTINUE,
    NJS_VMCODE_TRY_END,
    NJS_VMCODE_CATCH,
    NJS_VMCODE_FINALLY,
    NJS_VMCODE_LET,
    NJS_VMCODE_LET_UPDATE,
    NJS_VMCODE_INITIALIZATION_TEST,
    NJS_VMCODE_NOT_INITIALIZED,
    NJS_VMCODE_ASSIGNMENT_ERROR,
    NJS_VMCODE_ERROR,
    NJS_VMCODE_MOVE,
    NJS_VMCODE_PROPERTY_ATOM_GET,
    NJS_VMCODE_PROPERTY_GET,
    NJS_VMCODE_INCREMENT,
    NJS_VMCODE_POST_INCREMENT,
    NJS_VMCODE_DECREMENT,
    NJS_VMCODE_POST_DECREMENT,
    NJS_VMCODE_TRY_RETURN,
    NJS_VMCODE_GLOBAL_GET,
    NJS_VMCODE_LESS,
    NJS_VMCODE_GREATER,
    NJS_VMCODE_LESS_OR_EQUAL,
    NJS_VMCODE_GREATER_OR_EQUAL,
    NJS_VMCODE_ADDITION,
    NJS_VMCODE_EQUAL,
    NJS_VMCODE_NOT_EQUAL,
    NJS_VMCODE_SUBTRACTION,
    NJS_VMCODE_MULTIPLICATION,
    NJS_VMCODE_EXPONENTIATION,
    NJS_VMCODE_DIVISION,
    NJS_VMCODE_REMAINDER,
    NJS_VMCODE_BITWISE_AND,
    NJS_VMCODE_BITWISE_OR,
    NJS_VMCODE_BITWISE_XOR,
    NJS_VMCODE_LEFT_SHIFT,
    NJS_VMCODE_RIGHT_SHIFT,
    NJS_VMCODE_UNSIGNED_RIGHT_SHIFT,
    NJS_VMCODE_TEMPLATE_LITERAL,
    NJS_VMCODE_PROPERTY_IN,
    NJS_VMCODE_PROPERTY_DELETE,
    NJS_VMCODE_PROPERTY_FOREACH,
    NJS_VMCODE_STRICT_EQUAL,
    NJS_VMCODE_STRICT_NOT_EQUAL,
    NJS_VMCODE_TEST_IF_TRUE,
    NJS_VMCODE_TEST_IF_FALSE,
    NJS_VMCODE_COALESCE,
    NJS_VMCODE_UNARY_PLUS,
    NJS_VMCODE_UNARY_NEGATION,
    NJS_VMCODE_BITWISE_NOT,
    NJS_VMCODE_LOGICAL_NOT,
    NJS_VMCODE_OBJECT,
    NJS_VMCODE_ARRAY,
    NJS_VMCODE_FUNCTION,
    NJS_VMCODE_REGEXP,
    NJS_VMCODE_INSTANCE_OF,
    NJS_VMCODE_TYPEOF,
    NJS_VMCODE_VOID,
    NJS_VMCODE_DELETE,
    NJS_VMCODE_DEBUGGER,
    NJS_VMCODES
};


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                operand1;
    njs_index_t                operand2;
    njs_index_t                operand3;
} njs_vmcode_generic_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                index;
} njs_vmcode_1addr_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                dst;
    njs_index_t                src;
} njs_vmcode_2addr_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                dst;
    njs_index_t                src1;
    njs_index_t                src2;
} njs_vmcode_3addr_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                dst;
    njs_index_t                src;
} njs_vmcode_move_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
} njs_vmcode_object_t;


typedef struct {
     njs_vmcode_t              code;
     njs_index_t               dst;
} njs_vmcode_this_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                dst;
} njs_vmcode_arguments_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
    uintptr_t                  length;
    uint8_t                    ctor;       /* 1 bit  */
} njs_vmcode_array_t;


typedef struct {
     njs_vmcode_t              code;
     njs_index_t               retval;
} njs_vmcode_template_literal_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
    njs_function_lambda_t      *lambda;
    njs_bool_t                 async;
} njs_vmcode_function_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
    njs_regexp_pattern_t       *pattern;
} njs_vmcode_regexp_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
    njs_index_t                object;
} njs_vmcode_object_copy_t;


typedef struct {
    njs_vmcode_t               code;
    njs_jump_off_t             offset;
} njs_vmcode_jump_t;


typedef struct {
    njs_vmcode_t               code;
    njs_jump_off_t             offset;
    njs_index_t                cond;
} njs_vmcode_cond_jump_t;


typedef struct {
    njs_vmcode_t               code;
    njs_jump_off_t             offset;
    njs_index_t                value1;
    njs_index_t                value2;
} njs_vmcode_equal_jump_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
    njs_index_t                value;
    njs_jump_off_t             offset;
} njs_vmcode_test_jump_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                value;
    njs_index_t                object;
    njs_index_t                property;
} njs_vmcode_prop_get_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                value;
    njs_index_t                object;
    njs_index_t                property;
} njs_vmcode_prop_set_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                value;
    njs_index_t                object;
    njs_index_t                property;
    uint8_t                    type;
} njs_vmcode_prop_accessor_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                next;
    njs_index_t                object;
    njs_jump_off_t             offset;
} njs_vmcode_prop_foreach_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
    njs_index_t                object;
    njs_index_t                next;
    njs_jump_off_t             offset;
} njs_vmcode_prop_next_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                value;
    njs_index_t                constructor;
    njs_index_t                object;
} njs_vmcode_instance_of_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                nargs;
    njs_index_t                name;
    uint8_t                    ctor;       /* 1 bit  */
} njs_vmcode_function_frame_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                nargs;
    njs_index_t                object;
    njs_index_t                method;
    uint8_t                    ctor;       /* 1 bit  */
} njs_vmcode_method_frame_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
} njs_vmcode_function_call_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
} njs_vmcode_return_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
} njs_vmcode_stop_t;


typedef struct {
    njs_vmcode_t               code;
    njs_jump_off_t             offset;
    njs_index_t                exception_value;
    njs_index_t                exit_value;
} njs_vmcode_try_start_t;


typedef struct {
    njs_vmcode_t               code;
    njs_jump_off_t             offset;
    njs_index_t                exit_value;
} njs_vmcode_try_trampoline_t;


typedef struct {
    njs_vmcode_t               code;
    njs_jump_off_t             offset;
    njs_index_t                exception;
} njs_vmcode_catch_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
} njs_vmcode_throw_t;


typedef struct {
    njs_vmcode_t               code;
    njs_jump_off_t             offset;
} njs_vmcode_try_end_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                save;
    njs_index_t                retval;
    njs_jump_off_t             offset;
} njs_vmcode_try_return_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
    njs_index_t                exit_value;
    njs_jump_off_t             continue_offset;
    njs_jump_off_t             break_offset;
} njs_vmcode_finally_t;


typedef struct {
    njs_vmcode_t               code;
    njs_object_type_t          type;
    union {
        njs_str_t              name;
        njs_str_t              message;
    } u;
} njs_vmcode_error_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
    njs_mod_t                  *module;
} njs_vmcode_import_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                dst;
} njs_vmcode_variable_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
} njs_vmcode_debugger_t;


typedef struct {
    njs_vmcode_t               code;
    njs_index_t                retval;
} njs_vmcode_await_t;


njs_int_t njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc, njs_value_t *retval,
    void *promise_cap, void *async_ctx);

njs_object_t *njs_function_new_object(njs_vm_t *vm, njs_value_t *constructor);

#ifdef NJS_DEBUG_OPCODE
#define njs_vmcode_debug(vm, pc, prefix) {                                    \
        if (vm->options.opcode_debug) do {                                    \
            njs_vm_code_t  *code;                                             \
                                                                              \
            code = njs_lookup_code(vm, pc);                                   \
                                                                              \
            njs_printf("%s %V\n", prefix,                                     \
                       (code != NULL) ? &code->name : &njs_entry_unknown);    \
        } while (0);                                                          \
    }

#define njs_vmcode_debug_opcode()                                             \
    if (vm->options.opcode_debug) {                                           \
        njs_disassemble(pc, NULL, 1, NULL);                                   \
    }
#else
#define njs_vmcode_debug(vm, pc, prefix)
#define njs_vmcode_debug_opcode()
#endif

#endif /* _NJS_VMCODE_H_INCLUDED_ */
