1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 * 6 * njs public header. 7 */ 8 9 #ifndef _NJS_H_INCLUDED_ 10 #define _NJS_H_INCLUDED_ 11 12 #include <njs_auto_config.h> 13 14 #define NJS_VERSION "0.7.1" 15 16 17 #include <unistd.h> /* STDOUT_FILENO, STDERR_FILENO */ 18 #include <njs_types.h> 19 #include <njs_clang.h> 20 #include <njs_str.h> 21 #include <njs_unicode.h> 22 #include <njs_utf8.h> 23 #include <njs_mp.h> 24 #include <njs_chb.h> 25 #include <njs_lvlhsh.h> 26 #include <njs_sprintf.h> 27 28 29 typedef uintptr_t njs_index_t; 30 typedef struct njs_vm_s njs_vm_t; 31 typedef union njs_value_s njs_value_t; 32 typedef struct njs_function_s njs_function_t; 33 typedef struct njs_vm_shared_s njs_vm_shared_t; 34 typedef struct njs_object_prop_s njs_object_prop_t; 35 typedef struct njs_external_s njs_external_t; 36 37 /* 38 * njs_opaque_value_t is the external storage type for native njs_value_t type. 39 * sizeof(njs_opaque_value_t) == sizeof(njs_value_t). 40 */ 41 42 typedef struct { 43 uint64_t filler[2]; 44 } njs_opaque_value_t; 45 46 47 /* sizeof(njs_value_t) is 16 bytes. */ 48 #define njs_argument(args, n) \ 49 (njs_value_t *) ((u_char *) args + (n) * 16) 50 51 52 extern const njs_value_t njs_value_undefined; 53 54 #define njs_arg(args, nargs, n) \ 55 ((n < nargs) ? njs_argument(args, n) \ 56 : (njs_value_t *) &njs_value_undefined) 57 58 #define njs_value_assign(dst, src) \ 59 memcpy(dst, src, sizeof(njs_opaque_value_t)) 60 61 #define njs_value_arg(val) ((njs_value_t *) val) 62 63 #define njs_lvalue_arg(lvalue, args, nargs, n) \ 64 ((n < nargs) ? njs_argument(args, n) \ 65 : (njs_value_assign(lvalue, &njs_value_undefined), lvalue)) 66 67 #define njs_vm_error(vm, fmt, ...) \ 68 njs_vm_value_error_set(vm, njs_vm_retval(vm), fmt, ##__VA_ARGS__) 69 70 71 /* 72 * njs_prop_handler_t operates as a property getter/setter or delete handler. 73 * - retval != NULL && setval == NULL - GET context. 74 * - retval != NULL && setval != NULL - SET context. 75 * - retval == NULL - DELETE context. 76 * 77 * njs_prop_handler_t is expected to return: 78 * NJS_OK - handler executed successfully; 79 * NJS_DECLINED - handler was applied to inappropriate object, retval 80 * contains undefined value; 81 * NJS_ERROR - some error, vm->retval contains appropriate exception. 82 */ 83 typedef njs_int_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_object_prop_t *prop, 84 njs_value_t *value, njs_value_t *setval, njs_value_t *retval); 85 typedef njs_int_t (*njs_exotic_keys_t)(njs_vm_t *vm, njs_value_t *value, 86 njs_value_t *retval); 87 typedef njs_int_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args, 88 njs_uint_t nargs, njs_index_t magic8); 89 90 91 typedef enum { 92 NJS_SYMBOL_INVALID, 93 NJS_SYMBOL_ASYNC_ITERATOR, 94 NJS_SYMBOL_HAS_INSTANCE, 95 NJS_SYMBOL_IS_CONCAT_SPREADABLE, 96 NJS_SYMBOL_ITERATOR, 97 NJS_SYMBOL_MATCH, 98 NJS_SYMBOL_MATCH_ALL, 99 NJS_SYMBOL_REPLACE, 100 NJS_SYMBOL_SEARCH, 101 NJS_SYMBOL_SPECIES, 102 NJS_SYMBOL_SPLIT, 103 NJS_SYMBOL_TO_PRIMITIVE, 104 NJS_SYMBOL_TO_STRING_TAG, 105 NJS_SYMBOL_UNSCOPABLES, 106 NJS_SYMBOL_KNOWN_MAX, 107 } njs_wellknown_symbol_t; 108 109 110 typedef enum { 111 NJS_EXTERN_PROPERTY = 0, 112 NJS_EXTERN_METHOD = 1, 113 NJS_EXTERN_OBJECT = 2, 114 NJS_EXTERN_SYMBOL = 4, 115 } njs_extern_flag_t; 116 117 118 struct njs_external_s { 119 njs_extern_flag_t flags; 120 121 union { 122 njs_str_t string; 123 uint32_t symbol; 124 } name; 125 126 unsigned writable; 127 unsigned configurable; 128 unsigned enumerable; 129 130 union { 131 struct { 132 const char value[15]; /* NJS_STRING_SHORT + 1. */ 133 njs_prop_handler_t handler; 134 uint32_t magic32; 135 } property; 136 137 struct { 138 njs_function_native_t native; 139 uint8_t magic8; 140 uint8_t ctor; 141 } method; 142 143 struct { 144 njs_external_t *properties; 145 njs_uint_t nproperties; 146 147 unsigned writable; 148 unsigned configurable; 149 unsigned enumerable; 150 njs_prop_handler_t prop_handler; 151 uint32_t magic32; 152 njs_exotic_keys_t keys; 153 } object; 154 } u; 155 }; 156 157 158 /* 159 * NJS and event loops. 160 * 161 * njs_vm_ops_t callbacks are used to interact with the event loop environment. 162 * 163 * Functions get an external object as the first argument. The external 164 * object is provided as the third argument to njs_vm_clone(). 165 * 166 * The callbacks are expected to return to the VM the unique id of an 167 * underlying event. This id will be passed as the second argument to 168 * njs_event_destructor() at the moment the VM wants to destroy it. 169 * 170 * When an underlying events fires njs_vm_post_event() should be invoked with 171 * the value provided as vm_event. 172 * 173 * The events posted by njs_vm_post_event() are processed as soon as 174 * njs_vm_run() is invoked. njs_vm_run() returns NJS_AGAIN until pending events 175 * are present. 176 */ 177 178 typedef void * njs_vm_event_t; 179 typedef void * njs_host_event_t; 180 typedef void * njs_external_ptr_t; 181 182 typedef njs_host_event_t (*njs_set_timer_t)(njs_external_ptr_t external, 183 uint64_t delay, njs_vm_event_t vm_event); 184 typedef void (*njs_event_destructor_t)(njs_external_ptr_t external, 185 njs_host_event_t event); 186 187 188 typedef struct { 189 njs_set_timer_t set_timer; 190 njs_event_destructor_t clear_timer; 191 } njs_vm_ops_t; 192 193 194 typedef struct { 195 size_t size; 196 uintptr_t *values; 197 } njs_vm_meta_t; 198 199 200 typedef njs_int_t (*njs_addon_init_pt)(njs_vm_t *vm); 201 202 typedef struct { 203 njs_str_t name; 204 njs_addon_init_pt init; 205 } njs_module_t; 206 207 208 typedef struct { 209 njs_external_ptr_t external; 210 njs_vm_shared_t *shared; 211 njs_vm_ops_t *ops; 212 njs_vm_meta_t *metas; 213 njs_module_t **addons; 214 njs_str_t file; 215 216 char **argv; 217 njs_uint_t argc; 218 219 #define NJS_VM_OPT_UNHANDLED_REJECTION_IGNORE 0 220 #define NJS_VM_OPT_UNHANDLED_REJECTION_THROW 1 221 222 /* 223 * interactive - enables "interactive" mode. 224 * (REPL). Allows starting parent VM without cloning. 225 * disassemble - enables disassemble. 226 * backtrace - enables backtraces. 227 * quiet - removes filenames from backtraces. To produce comparable 228 test262 diffs. 229 * sandbox - "sandbox" mode. Disables file access. 230 * unsafe - enables unsafe language features: 231 * - Function constructors. 232 * module - ES6 "module" mode. Script mode is default. 233 * ast - print AST. 234 * unhandled_rejection IGNORE | THROW - tracks unhandled promise rejections: 235 * - throwing inside a Promise without a catch block. 236 * - throwing inside in a finally or catch block. 237 */ 238 uint8_t interactive; /* 1 bit */ 239 uint8_t trailer; /* 1 bit */ 240 uint8_t init; /* 1 bit */ 241 uint8_t disassemble; /* 1 bit */ 242 uint8_t backtrace; /* 1 bit */ 243 uint8_t quiet; /* 1 bit */ 244 uint8_t sandbox; /* 1 bit */ 245 uint8_t unsafe; /* 1 bit */ 246 uint8_t module; /* 1 bit */ 247 uint8_t ast; /* 1 bit */ 248 uint8_t unhandled_rejection; 249 } njs_vm_opt_t; 250 251 252 NJS_EXPORT void njs_vm_opt_init(njs_vm_opt_t *options); 253 NJS_EXPORT njs_vm_t *njs_vm_create(njs_vm_opt_t *options); 254 NJS_EXPORT void njs_vm_destroy(njs_vm_t *vm); 255 256 NJS_EXPORT njs_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end); 257 NJS_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external); 258 259 NJS_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm, 260 njs_function_t *function, njs_uint_t once, njs_host_event_t host_ev, 261 njs_event_destructor_t destructor); 262 NJS_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event); 263 NJS_EXPORT njs_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, 264 const njs_value_t *args, njs_uint_t nargs); 265 266 /* 267 * Returns 1 if async events are present. 268 */ 269 NJS_EXPORT njs_int_t njs_vm_waiting(njs_vm_t *vm); 270 271 /* 272 * Returns 1 if posted events are ready to be executed. 273 */ 274 NJS_EXPORT njs_int_t njs_vm_posted(njs_vm_t *vm); 275 276 #define njs_vm_pending(vm) (njs_vm_waiting(vm) || njs_vm_posted(vm)) 277 278 #define njs_vm_unhandled_rejection(vm) \ 279 ((vm)->options.unhandled_rejection == NJS_VM_OPT_UNHANDLED_REJECTION_THROW \ 280 && (vm)->promise_reason != NULL && (vm)->promise_reason->length != 0) 281 282 /* 283 * Runs the specified function with provided arguments. 284 * NJS_OK successful run. 285 * NJS_ERROR some exception or internal error happens. 286 * 287 * njs_vm_retval(vm) can be used to get the retval or exception value. 288 */ 289 NJS_EXPORT njs_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function, 290 const njs_value_t *args, njs_uint_t nargs); 291 NJS_EXPORT njs_int_t njs_vm_invoke(njs_vm_t *vm, njs_function_t *function, 292 const njs_value_t *args, njs_uint_t nargs, njs_value_t *retval); 293 294 /* 295 * Runs posted events. 296 * NJS_OK successfully processed all posted events, no more events. 297 * NJS_AGAIN successfully processed all events, some posted events are 298 * still pending. 299 * NJS_ERROR some exception or internal error happens. 300 * njs_vm_retval(vm) can be used to get the retval or exception value. 301 */ 302 NJS_EXPORT njs_int_t njs_vm_run(njs_vm_t *vm); 303 304 /* 305 * Runs the global code. 306 * NJS_OK successful run. 307 * NJS_ERROR some exception or internal error happens. 308 * 309 * njs_vm_retval(vm) can be used to get the retval or exception value. 310 */ 311 NJS_EXPORT njs_int_t njs_vm_start(njs_vm_t *vm); 312 313 NJS_EXPORT njs_int_t njs_vm_add_path(njs_vm_t *vm, const njs_str_t *path); 314 315 #define NJS_PROTO_ID_ANY (-1) 316 317 NJS_EXPORT njs_int_t njs_vm_external_prototype(njs_vm_t *vm, 318 const njs_external_t *definition, njs_uint_t n); 319 NJS_EXPORT njs_int_t njs_vm_external_create(njs_vm_t *vm, njs_value_t *value, 320 njs_int_t proto_id, njs_external_ptr_t external, njs_bool_t shared); 321 NJS_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm, 322 njs_int_t proto_id, const njs_value_t *value); 323 NJS_EXPORT uintptr_t njs_vm_meta(njs_vm_t *vm, njs_uint_t index); 324 325 NJS_EXPORT njs_function_t *njs_vm_function_alloc(njs_vm_t *vm, 326 njs_function_native_t native); 327 328 NJS_EXPORT void njs_disassembler(njs_vm_t *vm); 329 330 NJS_EXPORT njs_int_t njs_vm_bind(njs_vm_t *vm, const njs_str_t *var_name, 331 const njs_value_t *value, njs_bool_t shared); 332 NJS_EXPORT njs_int_t njs_vm_value(njs_vm_t *vm, const njs_str_t *path, 333 njs_value_t *retval); 334 NJS_EXPORT njs_function_t *njs_vm_function(njs_vm_t *vm, const njs_str_t *name); 335 336 NJS_EXPORT njs_value_t *njs_vm_retval(njs_vm_t *vm); 337 NJS_EXPORT void njs_vm_retval_set(njs_vm_t *vm, const njs_value_t *value); 338 NJS_EXPORT njs_mp_t *njs_vm_memory_pool(njs_vm_t *vm); 339 340 /* Gets string value, no copy. */ 341 NJS_EXPORT void njs_value_string_get(njs_value_t *value, njs_str_t *dst); 342 /* 343 * Sets a byte string value. 344 * start data is not copied and should not be freed. 345 */ 346 NJS_EXPORT njs_int_t njs_vm_value_string_set(njs_vm_t *vm, njs_value_t *value, 347 const u_char *start, uint32_t size); 348 NJS_EXPORT u_char *njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value, 349 uint32_t size); 350 NJS_EXPORT njs_int_t njs_vm_value_string_copy(njs_vm_t *vm, njs_str_t *retval, 351 njs_value_t *value, uintptr_t *next); 352 353 NJS_EXPORT njs_int_t njs_vm_value_array_buffer_set(njs_vm_t *vm, 354 njs_value_t *value, const u_char *start, uint32_t size); 355 356 /* 357 * Sets a Buffer value. 358 * start data is not copied and should not be freed. 359 */ 360 NJS_EXPORT njs_int_t njs_vm_value_buffer_set(njs_vm_t *vm, njs_value_t *value, 361 const u_char *start, uint32_t size); 362 363 /* 364 * Converts a value to bytes. 365 */ 366 NJS_EXPORT njs_int_t njs_vm_value_to_bytes(njs_vm_t *vm, njs_str_t *dst, 367 njs_value_t *src); 368 369 /* 370 * Converts a value to string. 371 */ 372 NJS_EXPORT njs_int_t njs_vm_value_to_string(njs_vm_t *vm, njs_str_t *dst, 373 njs_value_t *src); 374 375 /* 376 * Calls njs_vm_value_to_string(), if exception was thrown adds backtrace. 377 */ 378 NJS_EXPORT njs_int_t njs_vm_value_string(njs_vm_t *vm, njs_str_t *dst, 379 njs_value_t *src); 380 NJS_EXPORT njs_int_t njs_vm_retval_string(njs_vm_t *vm, njs_str_t *dst); 381 382 NJS_EXPORT njs_int_t njs_vm_value_dump(njs_vm_t *vm, njs_str_t *dst, 383 njs_value_t *value, njs_uint_t console, njs_uint_t indent); 384 NJS_EXPORT njs_int_t njs_vm_retval_dump(njs_vm_t *vm, njs_str_t *dst, 385 njs_uint_t indent); 386 387 NJS_EXPORT void njs_vm_value_error_set(njs_vm_t *vm, njs_value_t *value, 388 const char *fmt, ...); 389 NJS_EXPORT void njs_vm_memory_error(njs_vm_t *vm); 390 391 NJS_EXPORT void njs_value_undefined_set(njs_value_t *value); 392 NJS_EXPORT void njs_value_null_set(njs_value_t *value); 393 NJS_EXPORT void njs_value_invalid_set(njs_value_t *value); 394 NJS_EXPORT void njs_value_boolean_set(njs_value_t *value, int yn); 395 NJS_EXPORT void njs_value_number_set(njs_value_t *value, double num); 396 397 NJS_EXPORT uint8_t njs_value_bool(const njs_value_t *value); 398 NJS_EXPORT double njs_value_number(const njs_value_t *value); 399 NJS_EXPORT njs_function_t *njs_value_function(const njs_value_t *value); 400 NJS_EXPORT njs_int_t njs_value_external_tag(const njs_value_t *value); 401 402 NJS_EXPORT uint16_t njs_vm_prop_magic16(njs_object_prop_t *prop); 403 NJS_EXPORT uint32_t njs_vm_prop_magic32(njs_object_prop_t *prop); 404 NJS_EXPORT njs_int_t njs_vm_prop_name(njs_vm_t *vm, njs_object_prop_t *prop, 405 njs_str_t *dst); 406 407 NJS_EXPORT njs_int_t njs_value_is_null(const njs_value_t *value); 408 NJS_EXPORT njs_int_t njs_value_is_undefined(const njs_value_t *value); 409 NJS_EXPORT njs_int_t njs_value_is_null_or_undefined(const njs_value_t *value); 410 NJS_EXPORT njs_int_t njs_value_is_valid(const njs_value_t *value); 411 NJS_EXPORT njs_int_t njs_value_is_boolean(const njs_value_t *value); 412 NJS_EXPORT njs_int_t njs_value_is_number(const njs_value_t *value); 413 NJS_EXPORT njs_int_t njs_value_is_valid_number(const njs_value_t *value); 414 NJS_EXPORT njs_int_t njs_value_is_string(const njs_value_t *value); 415 NJS_EXPORT njs_int_t njs_value_is_object(const njs_value_t *value); 416 NJS_EXPORT njs_int_t njs_value_is_array(const njs_value_t *value); 417 NJS_EXPORT njs_int_t njs_value_is_function(const njs_value_t *value); 418 NJS_EXPORT njs_int_t njs_value_is_buffer(const njs_value_t *value); 419 420 NJS_EXPORT njs_int_t njs_vm_object_alloc(njs_vm_t *vm, njs_value_t *retval, 421 ...); 422 NJS_EXPORT njs_value_t *njs_vm_object_keys(njs_vm_t *vm, njs_value_t *value, 423 njs_value_t *retval); 424 NJS_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm, 425 njs_value_t *value, const njs_str_t *key, njs_opaque_value_t *retval); 426 427 NJS_EXPORT njs_int_t njs_vm_array_alloc(njs_vm_t *vm, njs_value_t *retval, 428 uint32_t spare); 429 NJS_EXPORT njs_int_t njs_vm_array_length(njs_vm_t *vm, njs_value_t *value, 430 int64_t *length); 431 NJS_EXPORT njs_value_t *njs_vm_array_start(njs_vm_t *vm, njs_value_t *value); 432 NJS_EXPORT njs_value_t *njs_vm_array_prop(njs_vm_t *vm, 433 njs_value_t *value, int64_t index, njs_opaque_value_t *retval); 434 NJS_EXPORT njs_value_t *njs_vm_array_push(njs_vm_t *vm, njs_value_t *value); 435 436 NJS_EXPORT njs_int_t njs_vm_json_parse(njs_vm_t *vm, njs_value_t *args, 437 njs_uint_t nargs); 438 NJS_EXPORT njs_int_t njs_vm_json_stringify(njs_vm_t *vm, njs_value_t *args, 439 njs_uint_t nargs); 440 441 NJS_EXPORT njs_int_t njs_vm_promise_create(njs_vm_t *vm, njs_value_t *retval, 442 njs_value_t *callbacks); 443 444 445 #endif /* _NJS_H_INCLUDED_ */ 446