blob: 872762138c6dbe53d6d1e0d6a1862622105c7f99 [file] [log] [blame]
/*
* Copyright (C) Igor Sysoev
* Copyright (C) NGINX, Inc.
*/
#ifndef _NJS_VM_H_INCLUDED_
#define _NJS_VM_H_INCLUDED_
#define NJS_MAX_STACK_SIZE (256 * 1024)
/*
* NJS_PROPERTY_QUERY_GET must be less to NJS_PROPERTY_QUERY_SET
* and NJS_PROPERTY_QUERY_DELETE.
*/
#define NJS_PROPERTY_QUERY_GET 0
#define NJS_PROPERTY_QUERY_SET 1
#define NJS_PROPERTY_QUERY_DELETE 2
typedef struct njs_frame_s njs_frame_t;
typedef struct njs_native_frame_s njs_native_frame_t;
typedef struct njs_parser_s njs_parser_t;
typedef struct njs_parser_scope_s njs_parser_scope_t;
typedef struct njs_parser_node_s njs_parser_node_t;
typedef struct njs_generator_s njs_generator_t;
typedef enum {
NJS_SCOPE_ABSOLUTE = 0,
NJS_SCOPE_GLOBAL = 1,
NJS_SCOPE_CALLEE_ARGUMENTS = 2,
/*
* The argument and local VM scopes should be separated because a
* function may be called with any number of arguments.
*/
NJS_SCOPE_ARGUMENTS = 3,
NJS_SCOPE_LOCAL = 4,
NJS_SCOPE_FUNCTION = NJS_SCOPE_LOCAL,
NJS_SCOPE_CLOSURE = 5,
/*
* The block and shim scopes are not really VM scopes.
* They are used only on parsing phase.
*/
NJS_SCOPE_BLOCK = 16,
NJS_SCOPE_SHIM = 17,
} njs_scope_t;
/*
* The maximum possible function nesting level is (16 - NJS_SCOPE_CLOSURE),
* that is 11. The 8 is reasonable limit.
*/
#define NJS_MAX_NESTING 8
#define NJS_SCOPES (NJS_SCOPE_CLOSURE + NJS_MAX_NESTING)
#define NJS_SCOPE_SHIFT 4
#define NJS_SCOPE_MASK ((uintptr_t) ((1 << NJS_SCOPE_SHIFT) - 1))
#define NJS_INDEX_NONE ((njs_index_t) 0)
#define NJS_INDEX_ERROR ((njs_index_t) -1)
#define NJS_INDEX_THIS ((njs_index_t) (0 | NJS_SCOPE_ARGUMENTS))
#define njs_scope_type(index) \
((uintptr_t) (index) & NJS_SCOPE_MASK)
#define njs_is_callee_argument_index(index) \
(((index) & NJS_SCOPE_CALLEE_ARGUMENTS) == NJS_SCOPE_CALLEE_ARGUMENTS)
typedef enum {
NJS_OBJ_TYPE_OBJECT = 0,
NJS_OBJ_TYPE_ARRAY,
NJS_OBJ_TYPE_BOOLEAN,
NJS_OBJ_TYPE_NUMBER,
NJS_OBJ_TYPE_SYMBOL,
NJS_OBJ_TYPE_STRING,
NJS_OBJ_TYPE_FUNCTION,
NJS_OBJ_TYPE_REGEXP,
NJS_OBJ_TYPE_DATE,
NJS_OBJ_TYPE_PROMISE,
NJS_OBJ_TYPE_ARRAY_BUFFER,
NJS_OBJ_TYPE_DATA_VIEW,
NJS_OBJ_TYPE_TEXT_DECODER,
NJS_OBJ_TYPE_TEXT_ENCODER,
NJS_OBJ_TYPE_BUFFER,
#define NJS_OBJ_TYPE_HIDDEN_MIN (NJS_OBJ_TYPE_ITERATOR)
NJS_OBJ_TYPE_ITERATOR,
NJS_OBJ_TYPE_ARRAY_ITERATOR,
NJS_OBJ_TYPE_FS_DIRENT,
NJS_OBJ_TYPE_CRYPTO_HASH,
NJS_OBJ_TYPE_CRYPTO_HMAC,
NJS_OBJ_TYPE_TYPED_ARRAY,
#define NJS_OBJ_TYPE_HIDDEN_MAX (NJS_OBJ_TYPE_TYPED_ARRAY + 1)
#define NJS_OBJ_TYPE_NORMAL_MAX (NJS_OBJ_TYPE_HIDDEN_MAX)
#define NJS_OBJ_TYPE_TYPED_ARRAY_MIN (NJS_OBJ_TYPE_UINT8_ARRAY)
#define njs_typed_array_index(type) (type - NJS_OBJ_TYPE_TYPED_ARRAY_MIN)
NJS_OBJ_TYPE_UINT8_ARRAY,
NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY,
NJS_OBJ_TYPE_INT8_ARRAY,
NJS_OBJ_TYPE_UINT16_ARRAY,
NJS_OBJ_TYPE_INT16_ARRAY,
NJS_OBJ_TYPE_UINT32_ARRAY,
NJS_OBJ_TYPE_INT32_ARRAY,
NJS_OBJ_TYPE_FLOAT32_ARRAY,
NJS_OBJ_TYPE_FLOAT64_ARRAY,
#define NJS_OBJ_TYPE_TYPED_ARRAY_MAX (NJS_OBJ_TYPE_FLOAT64_ARRAY + 1)
#define NJS_OBJ_TYPE_TYPED_ARRAY_SIZE (NJS_OBJ_TYPE_TYPED_ARRAY_MAX \
- NJS_OBJ_TYPE_TYPED_ARRAY_MIN)
NJS_OBJ_TYPE_ERROR,
NJS_OBJ_TYPE_EVAL_ERROR,
NJS_OBJ_TYPE_INTERNAL_ERROR,
NJS_OBJ_TYPE_RANGE_ERROR,
NJS_OBJ_TYPE_REF_ERROR,
NJS_OBJ_TYPE_SYNTAX_ERROR,
NJS_OBJ_TYPE_TYPE_ERROR,
NJS_OBJ_TYPE_URI_ERROR,
NJS_OBJ_TYPE_MEMORY_ERROR,
NJS_OBJ_TYPE_MAX,
} njs_object_type_t;
#define njs_primitive_prototype_index(type) \
(NJS_OBJ_TYPE_BOOLEAN + ((type) - NJS_BOOLEAN))
#define njs_prototype_type(index) \
(index + NJS_OBJECT)
enum njs_object_e {
NJS_OBJECT_THIS = 0,
NJS_OBJECT_NJS,
NJS_OBJECT_PROCESS,
NJS_OBJECT_MATH,
NJS_OBJECT_JSON,
#ifdef NJS_TEST262
NJS_OBJECT_262,
#endif
NJS_OBJECT_MAX
};
#define njs_scope_index(value, type) \
((njs_index_t) (((value) << NJS_SCOPE_SHIFT) | (type)))
#define njs_global_scope_index(value) \
(njs_scope_index(value, NJS_SCOPE_GLOBAL))
#define NJS_INDEX_GLOBAL_OBJECT njs_global_scope_index(0)
#define NJS_INDEX_GLOBAL_OBJECT_OFFSET njs_scope_index(0, 0)
#define NJS_INDEX_GLOBAL_RETVAL njs_global_scope_index(1)
#define NJS_INDEX_GLOBAL_OFFSET njs_scope_index(1, 0)
#define njs_scope_offset(index) \
((uintptr_t) (index) & ~NJS_SCOPE_MASK)
#define njs_vmcode_operand(vm, index) \
((njs_value_t *) \
((u_char *) vm->scopes[(uintptr_t) (index) & NJS_SCOPE_MASK] \
+ njs_scope_offset(index)))
struct njs_vm_s {
/* njs_vm_t must be aligned to njs_value_t due to scratch value. */
njs_value_t retval;
njs_arr_t *paths;
njs_value_t *scopes[NJS_SCOPES];
njs_external_ptr_t external;
njs_native_frame_t *top_frame;
njs_frame_t *active_frame;
njs_rbtree_t *variables_hash;
njs_lvlhsh_t values_hash;
njs_arr_t *modules;
njs_lvlhsh_t modules_hash;
uint32_t event_id;
njs_lvlhsh_t events_hash;
njs_queue_t posted_events;
njs_queue_t promise_events;
njs_vm_opt_t options;
/*
* The prototypes and constructors arrays must be together because
* they are copied from njs_vm_shared_t by single memcpy()
* in njs_builtin_objects_clone().
*/
njs_object_prototype_t prototypes[NJS_OBJ_TYPE_MAX];
njs_function_t constructors[NJS_OBJ_TYPE_MAX];
njs_mp_t *mem_pool;
u_char *start;
njs_value_t *global_scope;
size_t scope_size;
size_t stack_size;
njs_vm_shared_t *shared;
njs_parser_t *parser;
njs_regex_context_t *regex_context;
njs_regex_match_data_t *single_match_data;
njs_array_t *promise_reason;
/*
* MemoryError is statically allocated immutable Error object
* with the InternalError prototype.
*/
njs_object_t memory_error_object;
njs_object_t string_object;
njs_object_t global_object;
njs_uint_t main_index;
njs_arr_t *codes; /* of njs_vm_code_t */
njs_arr_t *functions_name_cache;
njs_trace_t trace;
njs_random_t random;
uint64_t symbol_generator;
};
typedef struct {
uint32_t offset;
uint32_t line;
} njs_vm_line_num_t;
typedef struct {
u_char *start;
u_char *end;
njs_str_t file;
njs_str_t name;
njs_arr_t *lines; /* of njs_vm_line_num_t */
} njs_vm_code_t;
struct njs_vm_shared_s {
njs_lvlhsh_t keywords_hash;
njs_lvlhsh_t values_hash;
njs_lvlhsh_t array_instance_hash;
njs_lvlhsh_t string_instance_hash;
njs_lvlhsh_t function_instance_hash;
njs_lvlhsh_t arrow_instance_hash;
njs_lvlhsh_t arguments_object_instance_hash;
njs_lvlhsh_t regexp_instance_hash;
njs_lvlhsh_t modules_hash;
njs_lvlhsh_t env_hash;
njs_object_t string_object;
njs_object_t objects[NJS_OBJECT_MAX];
njs_exotic_slots_t global_slots;
/*
* The prototypes and constructors arrays must be togther because they are
* copied to njs_vm_t by single memcpy() in njs_builtin_objects_clone().
*/
njs_object_prototype_t prototypes[NJS_OBJ_TYPE_MAX];
njs_function_t constructors[NJS_OBJ_TYPE_MAX];
njs_regexp_pattern_t *empty_regexp_pattern;
};
void njs_vm_scopes_restore(njs_vm_t *vm, njs_native_frame_t *frame,
njs_native_frame_t *previous);
njs_int_t njs_builtin_objects_create(njs_vm_t *vm);
njs_int_t njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global);
njs_int_t njs_builtin_match_native_function(njs_vm_t *vm,
njs_function_t *function, njs_str_t *name);
njs_arr_t *njs_vm_completions(njs_vm_t *vm, njs_str_t *expression);
void *njs_lvlhsh_alloc(void *data, size_t size);
void njs_lvlhsh_free(void *data, void *p, size_t size);
extern const njs_str_t njs_entry_main;
extern const njs_str_t njs_entry_module;
extern const njs_str_t njs_entry_native;
extern const njs_str_t njs_entry_unknown;
extern const njs_str_t njs_entry_anonymous;
extern const njs_lvlhsh_proto_t njs_object_hash_proto;
#endif /* _NJS_VM_H_INCLUDED_ */