blob: 42261a6f8fff7ce23e7a7f0bc789008ae8928664 [file] [log] [blame]
/*
* Copyright (C) Igor Sysoev
* Copyright (C) NGINX, Inc.
*
* njs public header.
*/
#ifndef _NJS_H_INCLUDED_
#define _NJS_H_INCLUDED_
#include <njs_auto_config.h>
#define NJS_VERSION "0.5.1"
#include <unistd.h> /* STDOUT_FILENO, STDERR_FILENO */
#include <njs_types.h>
#include <njs_clang.h>
#include <njs_str.h>
#include <njs_lvlhsh.h>
#include <njs_sprintf.h>
typedef uintptr_t njs_index_t;
typedef struct njs_vm_s njs_vm_t;
typedef union njs_value_s njs_value_t;
typedef struct njs_function_s njs_function_t;
typedef struct njs_vm_shared_s njs_vm_shared_t;
typedef struct njs_object_prop_s njs_object_prop_t;
typedef struct njs_external_s njs_external_t;
typedef void * njs_external_proto_t;
/*
* njs_opaque_value_t is the external storage type for native njs_value_t type.
* sizeof(njs_opaque_value_t) == sizeof(njs_value_t).
*/
typedef struct {
uint64_t filler[2];
} njs_opaque_value_t;
/* sizeof(njs_value_t) is 16 bytes. */
#define njs_argument(args, n) \
(njs_value_t *) ((u_char *) args + (n) * 16)
extern const njs_value_t njs_value_undefined;
#define njs_arg(args, nargs, n) \
((n < nargs) ? njs_argument(args, n) \
: (njs_value_t *) &njs_value_undefined)
#define njs_value_assign(dst, src) \
memcpy(dst, src, sizeof(njs_opaque_value_t))
#define njs_value_arg(val) ((njs_value_t *) val)
#define njs_lvalue_arg(lvalue, args, nargs, n) \
((n < nargs) ? njs_argument(args, n) \
: (njs_value_assign(lvalue, &njs_value_undefined), lvalue))
#define njs_vm_error(vm, fmt, ...) \
njs_vm_value_error_set(vm, njs_vm_retval(vm), fmt, ##__VA_ARGS__)
/*
* njs_prop_handler_t operates as a property getter/setter or delete handler.
* - retval != NULL && setval == NULL - GET context.
* - retval != NULL && setval != NULL - SET context.
* - retval == NULL - DELETE context.
*
* njs_prop_handler_t is expected to return:
* NJS_OK - handler executed successfully;
* NJS_DECLINED - handler was applied to inappropriate object, retval
* contains undefined value;
* NJS_ERROR - some error, vm->retval contains appropriate exception.
*/
typedef njs_int_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
typedef njs_int_t (*njs_exotic_keys_t)(njs_vm_t *vm, njs_value_t *value,
njs_value_t *retval);
typedef njs_int_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t magic8);
typedef enum {
NJS_SYMBOL_INVALID,
NJS_SYMBOL_ASYNC_ITERATOR,
NJS_SYMBOL_HAS_INSTANCE,
NJS_SYMBOL_IS_CONCAT_SPREADABLE,
NJS_SYMBOL_ITERATOR,
NJS_SYMBOL_MATCH,
NJS_SYMBOL_MATCH_ALL,
NJS_SYMBOL_REPLACE,
NJS_SYMBOL_SEARCH,
NJS_SYMBOL_SPECIES,
NJS_SYMBOL_SPLIT,
NJS_SYMBOL_TO_PRIMITIVE,
NJS_SYMBOL_TO_STRING_TAG,
NJS_SYMBOL_UNSCOPABLES,
NJS_SYMBOL_KNOWN_MAX,
} njs_wellknown_symbol_t;
typedef enum {
NJS_EXTERN_PROPERTY = 0,
NJS_EXTERN_METHOD = 1,
NJS_EXTERN_OBJECT = 2,
NJS_EXTERN_SYMBOL = 4,
} njs_extern_flag_t;
struct njs_external_s {
njs_extern_flag_t flags;
union {
njs_str_t string;
uint32_t symbol;
} name;
unsigned writable;
unsigned configurable;
unsigned enumerable;
union {
struct {
const char value[15]; /* NJS_STRING_SHORT + 1. */
njs_prop_handler_t handler;
uint32_t magic32;
} property;
struct {
njs_function_native_t native;
uint8_t magic8;
} method;
struct {
njs_external_t *properties;
njs_uint_t nproperties;
unsigned writable;
unsigned configurable;
unsigned enumerable;
njs_prop_handler_t prop_handler;
uint32_t magic32;
njs_exotic_keys_t keys;
} object;
} u;
};
/*
* NJS and event loops.
*
* njs_vm_ops_t callbacks are used to interact with the event loop environment.
*
* Functions get an external object as the first argument. The external
* object is provided as the third argument to njs_vm_clone().
*
* The callbacks are expected to return to the VM the unique id of an
* underlying event. This id will be passed as the second argument to
* njs_event_destructor() at the moment the VM wants to destroy it.
*
* When an underlying events fires njs_vm_post_event() should be invoked with
* the value provided as vm_event.
*
* The events posted by njs_vm_post_event() are processed as soon as
* njs_vm_run() is invoked. njs_vm_run() returns NJS_AGAIN until pending events
* are present.
*/
typedef void * njs_vm_event_t;
typedef void * njs_host_event_t;
typedef void * njs_external_ptr_t;
typedef njs_host_event_t (*njs_set_timer_t)(njs_external_ptr_t external,
uint64_t delay, njs_vm_event_t vm_event);
typedef void (*njs_event_destructor_t)(njs_external_ptr_t external,
njs_host_event_t event);
typedef struct {
njs_set_timer_t set_timer;
njs_event_destructor_t clear_timer;
} njs_vm_ops_t;
typedef struct {
size_t size;
uintptr_t *values;
} njs_vm_meta_t;
typedef struct {
njs_external_ptr_t external;
njs_vm_shared_t *shared;
njs_vm_ops_t *ops;
njs_vm_meta_t *metas;
njs_str_t file;
char **argv;
njs_uint_t argc;
#define NJS_VM_OPT_UNHANDLED_REJECTION_IGNORE 0
#define NJS_VM_OPT_UNHANDLED_REJECTION_THROW 1
/*
* accumulative - enables "accumulative" mode to support incremental compiling.
* (REPL). Allows starting parent VM without cloning.
* disassemble - enables disassemble.
* backtrace - enables backtraces.
* quiet - removes filenames from backtraces. To produce comparable
test262 diffs.
* sandbox - "sandbox" mode. Disables file access.
* unsafe - enables unsafe language features:
* - Function constructors.
* module - ES6 "module" mode. Script mode is default.
* ast - print AST.
* unhandled_rejection IGNORE | THROW - tracks unhandled promise rejections:
* - throwing inside a Promise without a catch block.
* - throwing inside in a finally or catch block.
*/
uint8_t trailer; /* 1 bit */
uint8_t init; /* 1 bit */
uint8_t accumulative; /* 1 bit */
uint8_t disassemble; /* 1 bit */
uint8_t backtrace; /* 1 bit */
uint8_t quiet; /* 1 bit */
uint8_t sandbox; /* 1 bit */
uint8_t unsafe; /* 1 bit */
uint8_t module; /* 1 bit */
uint8_t ast; /* 1 bit */
uint8_t unhandled_rejection;
} njs_vm_opt_t;
NJS_EXPORT void njs_vm_opt_init(njs_vm_opt_t *options);
NJS_EXPORT njs_vm_t *njs_vm_create(njs_vm_opt_t *options);
NJS_EXPORT void njs_vm_destroy(njs_vm_t *vm);
NJS_EXPORT njs_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end);
NJS_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external);
NJS_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm,
njs_function_t *function, njs_uint_t once, njs_host_event_t host_ev,
njs_event_destructor_t destructor);
NJS_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event);
NJS_EXPORT njs_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event,
const njs_value_t *args, njs_uint_t nargs);
/*
* Returns 1 if async events are present.
*/
NJS_EXPORT njs_int_t njs_vm_waiting(njs_vm_t *vm);
/*
* Returns 1 if posted events are ready to be executed.
*/
NJS_EXPORT njs_int_t njs_vm_posted(njs_vm_t *vm);
#define njs_vm_pending(vm) (njs_vm_waiting(vm) || njs_vm_posted(vm))
/*
* Runs the specified function with provided arguments.
* NJS_OK successful run.
* NJS_ERROR some exception or internal error happens.
*
* njs_vm_retval(vm) can be used to get the retval or exception value.
*/
NJS_EXPORT njs_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *args, njs_uint_t nargs);
NJS_EXPORT njs_int_t njs_vm_invoke(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *args, njs_uint_t nargs, njs_index_t retval);
/*
* Runs posted events.
* NJS_OK successfully processed all posted events, no more events.
* NJS_AGAIN successfully processed all events, some posted events are
* still pending.
* NJS_ERROR some exception or internal error happens.
* njs_vm_retval(vm) can be used to get the retval or exception value.
*/
NJS_EXPORT njs_int_t njs_vm_run(njs_vm_t *vm);
/*
* Runs the global code.
* NJS_OK successful run.
* NJS_ERROR some exception or internal error happens.
*
* njs_vm_retval(vm) can be used to get the retval or exception value.
*/
NJS_EXPORT njs_int_t njs_vm_start(njs_vm_t *vm);
NJS_EXPORT njs_int_t njs_vm_add_path(njs_vm_t *vm, const njs_str_t *path);
NJS_EXPORT njs_external_proto_t njs_vm_external_prototype(njs_vm_t *vm,
const njs_external_t *definition, njs_uint_t n);
NJS_EXPORT njs_int_t njs_vm_external_create(njs_vm_t *vm, njs_value_t *value,
njs_external_proto_t proto, njs_external_ptr_t external, njs_bool_t shared);
NJS_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm,
const njs_value_t *value);
NJS_EXPORT uintptr_t njs_vm_meta(njs_vm_t *vm, njs_uint_t index);
NJS_EXPORT njs_function_t *njs_vm_function_alloc(njs_vm_t *vm,
njs_function_native_t native);
NJS_EXPORT void njs_disassembler(njs_vm_t *vm);
NJS_EXPORT njs_int_t njs_vm_bind(njs_vm_t *vm, const njs_str_t *var_name,
const njs_value_t *value, njs_bool_t shared);
NJS_EXPORT njs_int_t njs_vm_value(njs_vm_t *vm, const njs_str_t *path,
njs_value_t *retval);
NJS_EXPORT njs_function_t *njs_vm_function(njs_vm_t *vm, const njs_str_t *name);
NJS_EXPORT njs_value_t *njs_vm_retval(njs_vm_t *vm);
NJS_EXPORT void njs_vm_retval_set(njs_vm_t *vm, const njs_value_t *value);
/* Gets string value, no copy. */
NJS_EXPORT void njs_value_string_get(njs_value_t *value, njs_str_t *dst);
/*
* Sets a byte string value.
* start data is not copied and should not be freed.
*/
NJS_EXPORT njs_int_t njs_vm_value_string_set(njs_vm_t *vm, njs_value_t *value,
const u_char *start, uint32_t size);
NJS_EXPORT u_char *njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value,
uint32_t size);
NJS_EXPORT njs_int_t njs_vm_value_string_copy(njs_vm_t *vm, njs_str_t *retval,
njs_value_t *value, uintptr_t *next);
/*
* Sets a Buffer value.
* start data is not copied and should not be freed.
*/
NJS_EXPORT njs_int_t njs_vm_value_buffer_set(njs_vm_t *vm, njs_value_t *value,
const u_char *start, uint32_t size);
/*
* Converts a value to bytes.
*/
NJS_EXPORT njs_int_t njs_vm_value_to_bytes(njs_vm_t *vm, njs_str_t *dst,
njs_value_t *src);
/*
* Converts a value to string.
*/
NJS_EXPORT njs_int_t njs_vm_value_to_string(njs_vm_t *vm, njs_str_t *dst,
njs_value_t *src);
/*
* Calls njs_vm_value_to_string(), if exception was thrown adds backtrace.
*/
NJS_EXPORT njs_int_t njs_vm_value_string(njs_vm_t *vm, njs_str_t *dst,
njs_value_t *src);
NJS_EXPORT njs_int_t njs_vm_retval_string(njs_vm_t *vm, njs_str_t *dst);
NJS_EXPORT njs_int_t njs_vm_value_dump(njs_vm_t *vm, njs_str_t *dst,
njs_value_t *value, njs_uint_t console, njs_uint_t indent);
NJS_EXPORT njs_int_t njs_vm_retval_dump(njs_vm_t *vm, njs_str_t *dst,
njs_uint_t indent);
NJS_EXPORT void njs_vm_value_error_set(njs_vm_t *vm, njs_value_t *value,
const char *fmt, ...);
NJS_EXPORT void njs_vm_memory_error(njs_vm_t *vm);
NJS_EXPORT void njs_value_undefined_set(njs_value_t *value);
NJS_EXPORT void njs_value_boolean_set(njs_value_t *value, int yn);
NJS_EXPORT void njs_value_number_set(njs_value_t *value, double num);
NJS_EXPORT uint8_t njs_value_bool(const njs_value_t *value);
NJS_EXPORT double njs_value_number(const njs_value_t *value);
NJS_EXPORT njs_function_t *njs_value_function(const njs_value_t *value);
NJS_EXPORT uint16_t njs_vm_prop_magic16(njs_object_prop_t *prop);
NJS_EXPORT uint32_t njs_vm_prop_magic32(njs_object_prop_t *prop);
NJS_EXPORT njs_int_t njs_vm_prop_name(njs_vm_t *vm, njs_object_prop_t *prop,
njs_str_t *dst);
NJS_EXPORT njs_int_t njs_value_is_null(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_undefined(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_null_or_undefined(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_boolean(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_number(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_valid_number(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_string(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_object(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_array(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_function(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_buffer(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_vm_object_alloc(njs_vm_t *vm, njs_value_t *retval,
...);
NJS_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm,
njs_value_t *value, const njs_str_t *key, njs_opaque_value_t *retval);
NJS_EXPORT njs_int_t njs_vm_array_alloc(njs_vm_t *vm, njs_value_t *retval,
uint32_t spare);
NJS_EXPORT njs_int_t njs_vm_array_length(njs_vm_t *vm, njs_value_t *value,
int64_t *length);
NJS_EXPORT njs_value_t *njs_vm_array_start(njs_vm_t *vm, njs_value_t *value);
NJS_EXPORT njs_value_t *njs_vm_array_prop(njs_vm_t *vm,
njs_value_t *value, int64_t index, njs_opaque_value_t *retval);
NJS_EXPORT njs_value_t *njs_vm_array_push(njs_vm_t *vm, njs_value_t *value);
NJS_EXPORT njs_int_t njs_vm_json_parse(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs);
NJS_EXPORT njs_int_t njs_vm_json_stringify(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs);
NJS_EXPORT njs_int_t njs_vm_promise_create(njs_vm_t *vm, njs_value_t *retval,
njs_value_t *callbacks);
#endif /* _NJS_H_INCLUDED_ */