├── VERSION ├── toolchains └── linux_aarch64.cmake ├── .gitignore ├── .gitpod.yml ├── src ├── libregexp-opcode.h ├── libregexp.h ├── list.h ├── libunicode.h ├── cutils.h ├── quickjs-atom.h ├── quickjs-opcode.h ├── qjs.c ├── libbf.h ├── cutils.c └── qjsc.c ├── include ├── quickjs-libc.h └── quickjs.h ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── .github └── workflows │ └── quickjs-build.yml ├── README.md ├── LICENSE └── CHANGELOG.md /VERSION: -------------------------------------------------------------------------------- 1 | 2022-03-07 2 | -------------------------------------------------------------------------------- /toolchains/linux_aarch64.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Linux) 2 | set(CMAKE_SYSTEM_PROCESSOR aarch64) 3 | 4 | set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc") 5 | set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++") 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | _deps 12 | .vscode 13 | .idea 14 | build 15 | .DS_Store 16 | cmake-build-debug/ 17 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | # Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart 6 | 7 | tasks: 8 | - init: cmake . 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/libregexp-opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Regular Expression Engine 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifdef DEF 26 | 27 | DEF(invalid, 1) /* never used */ 28 | DEF(char, 3) 29 | DEF(char32, 5) 30 | DEF(dot, 1) 31 | DEF(any, 1) /* same as dot but match any character including line terminator */ 32 | DEF(line_start, 1) 33 | DEF(line_end, 1) 34 | DEF(goto, 5) 35 | DEF(split_goto_first, 5) 36 | DEF(split_next_first, 5) 37 | DEF(match, 1) 38 | DEF(save_start, 2) /* save start position */ 39 | DEF(save_end, 2) /* save end position, must come after saved_start */ 40 | DEF(save_reset, 3) /* reset save positions */ 41 | DEF(loop, 5) /* decrement the top the stack and goto if != 0 */ 42 | DEF(push_i32, 5) /* push integer on the stack */ 43 | DEF(drop, 1) 44 | DEF(word_boundary, 1) 45 | DEF(not_word_boundary, 1) 46 | DEF(back_reference, 2) 47 | DEF(backward_back_reference, 2) /* must come after back_reference */ 48 | DEF(range, 3) /* variable length */ 49 | DEF(range32, 3) /* variable length */ 50 | DEF(lookahead, 5) 51 | DEF(negative_lookahead, 5) 52 | DEF(push_char_pos, 1) /* push the character position on the stack */ 53 | DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character 54 | position */ 55 | DEF(prev, 1) /* go to the previous char */ 56 | DEF(simple_greedy_quant, 17) 57 | 58 | #endif /* DEF */ 59 | -------------------------------------------------------------------------------- /include/quickjs-libc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS C library 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef QUICKJS_LIBC_H 25 | #define QUICKJS_LIBC_H 26 | 27 | #include 28 | #include 29 | 30 | #include "quickjs.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); 37 | JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); 38 | void js_std_add_helpers(JSContext *ctx, int argc, char **argv); 39 | void js_std_loop(JSContext *ctx); 40 | void js_std_init_handlers(JSRuntime *rt); 41 | void js_std_free_handlers(JSRuntime *rt); 42 | void js_std_dump_error(JSContext *ctx); 43 | uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); 44 | int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, 45 | JS_BOOL use_realpath, JS_BOOL is_main); 46 | JSModuleDef *js_module_loader(JSContext *ctx, 47 | const char *module_name, void *opaque); 48 | void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, 49 | int flags); 50 | void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, 51 | JSValueConst reason, 52 | JS_BOOL is_handled, void *opaque); 53 | void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); 54 | 55 | #ifdef __cplusplus 56 | } /* extern "C" { */ 57 | #endif 58 | 59 | #endif /* QUICKJS_LIBC_H */ 60 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(quickjs LANGUAGES C) 4 | 5 | # static linking of libwinpthread-1.dll in mingw 6 | if(WIN32) 7 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static") 8 | endif() 9 | 10 | set(qjs_cflags -Wall -D_GNU_SOURCE) 11 | if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") 12 | list( 13 | APPEND 14 | qjs_cflags 15 | -Wextra 16 | -Wno-sign-compare 17 | -Wno-missing-field-initializers 18 | -Wno-unused-parameter 19 | -Wno-unused-variable 20 | -funsigned-char) 21 | else() 22 | list(APPEND qjs_cflags -Wno-array-bounds -Wno-unused-variable 23 | -Wno-unused-but-set-variable) 24 | endif() 25 | 26 | file(STRINGS "VERSION" QJS_VERSION_STR) 27 | 28 | message( 29 | STATUS 30 | "summary of build options: 31 | Target system: ${CMAKE_SYSTEM_NAME} 32 | Compiler: 33 | C compiler: ${CMAKE_C_COMPILER} 34 | CFLAGS: ${qjs_cflags} 35 | ") 36 | 37 | add_library(qjs STATIC src/cutils.c src/libbf.c src/libregexp.c 38 | src/libunicode.c src/quickjs.c src/quickjs-libc.c) 39 | set_target_properties(qjs PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON) 40 | target_compile_options(qjs PRIVATE ${qjs_cflags}) 41 | target_compile_definitions(qjs PUBLIC QJS_VERSION_STR="${QJS_VERSION_STR}") 42 | target_compile_definitions(qjs PUBLIC CONFIG_BIGNUM 43 | CONFIG_VERSION="${QJS_VERSION_STR}") 44 | if(CMAKE_BUILD_TYPE MATCHES Debug) 45 | target_compile_definitions(qjs PRIVATE DUMP_LEAKS) 46 | endif() 47 | 48 | target_include_directories(qjs PUBLIC include) 49 | target_include_directories(qjs PRIVATE src) 50 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 51 | target_link_libraries(qjs atomic) 52 | endif() 53 | 54 | if(UNIX) 55 | target_link_libraries(qjs PRIVATE m dl pthread) 56 | endif() 57 | 58 | add_executable(qjsc src/qjsc.c) 59 | target_link_libraries(qjsc PUBLIC qjs) 60 | 61 | if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") 62 | add_custom_command( 63 | OUTPUT repl.c qjscalc.c 64 | COMMAND 65 | qemu-aarch64 -L /usr/aarch64-linux-gnu/ qjsc -c -o 66 | ${CMAKE_CURRENT_BINARY_DIR}/repl.c -m 67 | ${CMAKE_CURRENT_SOURCE_DIR}/src/repl.js 68 | COMMAND 69 | qemu-aarch64 -L /usr/aarch64-linux-gnu/ qjsc -c -o 70 | ${CMAKE_CURRENT_BINARY_DIR}/qjscalc.c -m 71 | ${CMAKE_CURRENT_SOURCE_DIR}/src/qjscalc.js 72 | DEPENDS qjsc) 73 | else() 74 | add_custom_command( 75 | OUTPUT repl.c qjscalc.c 76 | COMMAND qjsc -c -o ${CMAKE_CURRENT_BINARY_DIR}/repl.c -m 77 | ${CMAKE_CURRENT_SOURCE_DIR}/src/repl.js 78 | COMMAND qjsc -c -o ${CMAKE_CURRENT_BINARY_DIR}/qjscalc.c -m 79 | ${CMAKE_CURRENT_SOURCE_DIR}/src/qjscalc.js 80 | DEPENDS qjsc) 81 | 82 | endif() 83 | 84 | add_executable(quickjs src/qjs.c ${CMAKE_CURRENT_BINARY_DIR}/qjscalc.c 85 | ${CMAKE_CURRENT_BINARY_DIR}/repl.c) 86 | 87 | target_link_libraries(quickjs PUBLIC qjs) 88 | 89 | add_executable(run-test262 src/run-test262.c) 90 | target_link_libraries(run-test262 PUBLIC qjs) 91 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | education, socio-economic status, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at nicoladelgobbo@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /src/libregexp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Regular Expression Engine 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBREGEXP_H 25 | #define LIBREGEXP_H 26 | 27 | #include 28 | 29 | #include "libunicode.h" 30 | 31 | #define LRE_BOOL int /* for documentation purposes */ 32 | 33 | #define LRE_FLAG_GLOBAL (1 << 0) 34 | #define LRE_FLAG_IGNORECASE (1 << 1) 35 | #define LRE_FLAG_MULTILINE (1 << 2) 36 | #define LRE_FLAG_DOTALL (1 << 3) 37 | #define LRE_FLAG_UTF16 (1 << 4) 38 | #define LRE_FLAG_STICKY (1 << 5) 39 | 40 | #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ 41 | 42 | uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, 43 | const char *buf, size_t buf_len, int re_flags, 44 | void *opaque); 45 | int lre_get_capture_count(const uint8_t *bc_buf); 46 | int lre_get_flags(const uint8_t *bc_buf); 47 | const char *lre_get_groupnames(const uint8_t *bc_buf); 48 | int lre_exec(uint8_t **capture, 49 | const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, 50 | int cbuf_type, void *opaque); 51 | 52 | int lre_parse_escape(const uint8_t **pp, int allow_utf16); 53 | LRE_BOOL lre_is_space(int c); 54 | 55 | /* must be provided by the user */ 56 | LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size); 57 | void *lre_realloc(void *opaque, void *ptr, size_t size); 58 | 59 | /* JS identifier test */ 60 | extern uint32_t const lre_id_start_table_ascii[4]; 61 | extern uint32_t const lre_id_continue_table_ascii[4]; 62 | 63 | static inline int lre_js_is_ident_first(int c) 64 | { 65 | if ((uint32_t)c < 128) { 66 | return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1; 67 | } else { 68 | #ifdef CONFIG_ALL_UNICODE 69 | return lre_is_id_start(c); 70 | #else 71 | return !lre_is_space(c); 72 | #endif 73 | } 74 | } 75 | 76 | static inline int lre_js_is_ident_next(int c) 77 | { 78 | if ((uint32_t)c < 128) { 79 | return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1; 80 | } else { 81 | /* ZWNJ and ZWJ are accepted in identifiers */ 82 | #ifdef CONFIG_ALL_UNICODE 83 | return lre_is_id_continue(c) || c == 0x200C || c == 0x200D; 84 | #else 85 | return !lre_is_space(c) || c == 0x200C || c == 0x200D; 86 | #endif 87 | } 88 | } 89 | 90 | #undef LRE_BOOL 91 | 92 | #endif /* LIBREGEXP_H */ 93 | -------------------------------------------------------------------------------- /src/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Linux klist like system 3 | * 4 | * Copyright (c) 2016-2017 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIST_H 25 | #define LIST_H 26 | 27 | #ifndef NULL 28 | #include 29 | #endif 30 | 31 | struct list_head { 32 | struct list_head *prev; 33 | struct list_head *next; 34 | }; 35 | 36 | #define LIST_HEAD_INIT(el) { &(el), &(el) } 37 | 38 | /* return the pointer of type 'type *' containing 'el' as field 'member' */ 39 | #define list_entry(el, type, member) \ 40 | ((type *)((uint8_t *)(el) - offsetof(type, member))) 41 | 42 | static inline void init_list_head(struct list_head *head) 43 | { 44 | head->prev = head; 45 | head->next = head; 46 | } 47 | 48 | /* insert 'el' between 'prev' and 'next' */ 49 | static inline void __list_add(struct list_head *el, 50 | struct list_head *prev, struct list_head *next) 51 | { 52 | prev->next = el; 53 | el->prev = prev; 54 | el->next = next; 55 | next->prev = el; 56 | } 57 | 58 | /* add 'el' at the head of the list 'head' (= after element head) */ 59 | static inline void list_add(struct list_head *el, struct list_head *head) 60 | { 61 | __list_add(el, head, head->next); 62 | } 63 | 64 | /* add 'el' at the end of the list 'head' (= before element head) */ 65 | static inline void list_add_tail(struct list_head *el, struct list_head *head) 66 | { 67 | __list_add(el, head->prev, head); 68 | } 69 | 70 | static inline void list_del(struct list_head *el) 71 | { 72 | struct list_head *prev, *next; 73 | prev = el->prev; 74 | next = el->next; 75 | prev->next = next; 76 | next->prev = prev; 77 | el->prev = NULL; /* fail safe */ 78 | el->next = NULL; /* fail safe */ 79 | } 80 | 81 | static inline int list_empty(struct list_head *el) 82 | { 83 | return el->next == el; 84 | } 85 | 86 | #define list_for_each(el, head) \ 87 | for(el = (head)->next; el != (head); el = el->next) 88 | 89 | #define list_for_each_safe(el, el1, head) \ 90 | for(el = (head)->next, el1 = el->next; el != (head); \ 91 | el = el1, el1 = el->next) 92 | 93 | #define list_for_each_prev(el, head) \ 94 | for(el = (head)->prev; el != (head); el = el->prev) 95 | 96 | #define list_for_each_prev_safe(el, el1, head) \ 97 | for(el = (head)->prev, el1 = el->prev; el != (head); \ 98 | el = el1, el1 = el->prev) 99 | 100 | #endif /* LIST_H */ 101 | -------------------------------------------------------------------------------- /src/libunicode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode utilities 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBUNICODE_H 25 | #define LIBUNICODE_H 26 | 27 | #include 28 | 29 | #define LRE_BOOL int /* for documentation purposes */ 30 | 31 | /* define it to include all the unicode tables (40KB larger) */ 32 | #define CONFIG_ALL_UNICODE 33 | 34 | #define LRE_CC_RES_LEN_MAX 3 35 | 36 | typedef enum { 37 | UNICODE_NFC, 38 | UNICODE_NFD, 39 | UNICODE_NFKC, 40 | UNICODE_NFKD, 41 | } UnicodeNormalizationEnum; 42 | 43 | int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); 44 | LRE_BOOL lre_is_cased(uint32_t c); 45 | LRE_BOOL lre_is_case_ignorable(uint32_t c); 46 | 47 | /* char ranges */ 48 | 49 | typedef struct { 50 | int len; /* in points, always even */ 51 | int size; 52 | uint32_t *points; /* points sorted by increasing value */ 53 | void *mem_opaque; 54 | void *(*realloc_func)(void *opaque, void *ptr, size_t size); 55 | } CharRange; 56 | 57 | typedef enum { 58 | CR_OP_UNION, 59 | CR_OP_INTER, 60 | CR_OP_XOR, 61 | } CharRangeOpEnum; 62 | 63 | void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); 64 | void cr_free(CharRange *cr); 65 | int cr_realloc(CharRange *cr, int size); 66 | int cr_copy(CharRange *cr, const CharRange *cr1); 67 | 68 | static inline int cr_add_point(CharRange *cr, uint32_t v) 69 | { 70 | if (cr->len >= cr->size) { 71 | if (cr_realloc(cr, cr->len + 1)) 72 | return -1; 73 | } 74 | cr->points[cr->len++] = v; 75 | return 0; 76 | } 77 | 78 | static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2) 79 | { 80 | if ((cr->len + 2) > cr->size) { 81 | if (cr_realloc(cr, cr->len + 2)) 82 | return -1; 83 | } 84 | cr->points[cr->len++] = c1; 85 | cr->points[cr->len++] = c2; 86 | return 0; 87 | } 88 | 89 | int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len); 90 | 91 | static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2) 92 | { 93 | uint32_t b_pt[2]; 94 | b_pt[0] = c1; 95 | b_pt[1] = c2 + 1; 96 | return cr_union1(cr, b_pt, 2); 97 | } 98 | 99 | int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, 100 | const uint32_t *b_pt, int b_len, int op); 101 | 102 | int cr_invert(CharRange *cr); 103 | 104 | #ifdef CONFIG_ALL_UNICODE 105 | 106 | LRE_BOOL lre_is_id_start(uint32_t c); 107 | LRE_BOOL lre_is_id_continue(uint32_t c); 108 | 109 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, 110 | UnicodeNormalizationEnum n_type, 111 | void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); 112 | 113 | /* Unicode character range functions */ 114 | 115 | int unicode_script(CharRange *cr, 116 | const char *script_name, LRE_BOOL is_ext); 117 | int unicode_general_category(CharRange *cr, const char *gc_name); 118 | int unicode_prop(CharRange *cr, const char *prop_name); 119 | 120 | #endif /* CONFIG_ALL_UNICODE */ 121 | 122 | #undef LRE_BOOL 123 | 124 | #endif /* LIBUNICODE_H */ 125 | -------------------------------------------------------------------------------- /.github/workflows/quickjs-build.yml: -------------------------------------------------------------------------------- 1 | name: QuickJS Build Matrix 2 | 3 | on: [push, pull_request, release] 4 | 5 | jobs: 6 | build: 7 | name: ${{ matrix.config.name }} 8 | runs-on: ${{ matrix.config.os }} 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | config: 13 | - { 14 | name: "Windows", 15 | os: "windows-latest", 16 | artifact: "qjs-windows", 17 | build_type: "Release", 18 | generator: "MinGW Makefiles", 19 | archiver: "7z" 20 | } 21 | - { 22 | name: "Ubuntu 20.04", 23 | os: "ubuntu-20.04", 24 | artifact: "qjs-ubuntu-20_04", 25 | build_type: "Release", 26 | generator: "Unix Makefiles", 27 | archiver: "7z" 28 | } 29 | - { 30 | name: "Linux arm64", 31 | os: "ubuntu-20.04", 32 | artifact: "qjs-linux-arm64", 33 | build_type: "Release", 34 | generator: "Unix Makefiles", 35 | cmake_extra: "-DCMAKE_TOOLCHAIN_FILE=./toolchains/linux_aarch64.cmake", 36 | archiver: "7z" 37 | } 38 | - { 39 | name: "Ubuntu 18.04", 40 | os: "ubuntu-18.04", 41 | artifact: "qjs-ubuntu-18_04", 42 | build_type: "Release", 43 | generator: "Unix Makefiles", 44 | cmake_extra: "", 45 | archiver: "7z" 46 | } 47 | - { 48 | name: "macOS", 49 | os: "macos-latest", 50 | artifact: "qjs-macOS", 51 | build_type: "Release", 52 | generator: "Unix Makefiles", 53 | cmake_extra: "", 54 | archiver: "7z" 55 | } 56 | steps: 57 | - uses: actions/checkout@v2 58 | - name: Print environment 59 | run: | 60 | echo "Name: ${{ matrix.config.name }}" 61 | echo "OS: ${{ matrix.config.os }}" 62 | echo "Generator: ${{ matrix.config.generator }}" 63 | echo "Archiver: ${{ matrix.config.archiver }}" 64 | echo "Artifact: ${{ matrix.config.artifact }}" 65 | - name: Install dependencies on Windows 66 | if: startsWith(matrix.config.os, 'windows') 67 | run: | 68 | echo "Install for windows ..." 69 | cmake --version 70 | ${{ matrix.config.archiver }} 71 | - name: Install dependencies on Linux 72 | if: startsWith(matrix.config.os, 'ubuntu') 73 | run: | 74 | echo "Install for Linux ..." 75 | sudo apt-get update 76 | sudo apt-get install build-essential -y 77 | sudo apt-get install g++-aarch64-linux-gnu qemu qemu-user -y 78 | sudo apt-get install p7zip-full -y 79 | gcc --version 80 | cmake --version 81 | make --version 82 | - name: Install dependencies on macOS 83 | if: startsWith(matrix.config.os, 'macos') 84 | run: | 85 | echo "Install for macOs ..." 86 | brew install p7zip cmake 87 | cmake --version 88 | make --version 89 | - name: Configure on Unix system 90 | if: startsWith(matrix.config.os, 'macos') || startsWith(matrix.config.os, 'ubuntu') 91 | shell: bash 92 | run: | 93 | mkdir ./build 94 | cmake \ 95 | -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ 96 | ${{ matrix.config.cmake_extra }} \ 97 | -G "${{ matrix.config.generator }}" \ 98 | -S ./ \ 99 | -B ./build 100 | - name: Configure on Windows 101 | if: startsWith(matrix.config.os, 'windows') 102 | shell: cmd 103 | run: | 104 | mkdir ./build 105 | setx PATH "%PATH%;C:\msys64\mingw64\bin" 106 | cmake -G "${{ matrix.config.generator }}" -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -S ./ -B ./build 107 | - name: Build 108 | shell: bash 109 | run: cmake --build ./build --config ${{ matrix.config.build_type }} 110 | - name: "Prepare" 111 | shell: bash 112 | run: | 113 | mkdir ./qjs 114 | cp ./build/libqjs.a ./qjs/libqjs.a 115 | cp ./build/qjsc ./qjs/qjsc 116 | cp ./build/quickjs ./qjs/quickjs 117 | cp ./build/run-test262 ./qjs/run-test262 118 | cp -R ./include ./qjs/include 119 | cd ./qjs 120 | ${{ matrix.config.archiver }} a -tzip ../${{ matrix.config.artifact }}.zip . 121 | - name: Upload artifact 122 | uses: actions/upload-artifact@v2 123 | with: 124 | path: ./${{ matrix.config.artifact }}.zip 125 | name: ${{ matrix.config.artifact }} 126 | - name: Release 127 | if: github.event_name == 'release' && (github.event.action == 'published') 128 | uses: actions/upload-release-asset@v1 129 | env: 130 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 131 | with: 132 | upload_url: ${{ github.event.release.upload_url }} 133 | asset_path: ./${{ matrix.config.artifact }}.zip 134 | asset_name: ${{ matrix.config.artifact }}.zip 135 | asset_content_type: application/zip 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuickJS JavaScript Engine 2 | 3 | ![QuickJS Build Matrix](https://github.com/napi-bindings/quickjs-build/workflows/QuickJS%20Build%20Matrix/badge.svg?branch=master) 4 | 5 | ## Version 2022-03-07 6 | 7 | - [Introduction](#introduction) 8 | - [Building](#building) 9 | - [Code of conduct](CODE_OF_CONDUCT) 10 | - [Team](#team) 11 | - [References](#references) 12 | - [Acknowledgments](#acknowledgements) 13 | - [License](#license) 14 | 15 | ## Introduction 16 | 17 | **QuickJS** is a small and embeddable Javascript engine. It supports the **[ES2020](https://tc39.github.io/ecma262/)** 18 | specification including modules, asynchronous generators, proxies and BigInt. 19 | 20 | It optionally supports mathematical extensions such as big decimal floating point 21 | numbers (BigDecimal), big binary floating point numbers (BigFloat) and operator 22 | overloading. 23 | 24 | ### Main Features: 25 | 26 | - Small and easily embeddable: just a few **C** files, no external dependency, 27 | **210 KiB** of x86 code for a simple hello world program. 28 | - Fast interpreter with very low startup time: runs the 69000 tests of the 29 | **[ECMAScript Test Suite](https://github.com/tc39/test262)** in about 95 seconds on a 30 | single core of a desktop PC. The complete life cycle of a runtime instance 31 | completes in less than 300 microseconds. 32 | - Almost complete **[ES2020](https://tc39.github.io/ecma262/)** support including 33 | modules, asynchronous generators and full Annex B support (legacy web 34 | compatibility). 35 | - Passes nearly 100% of the 36 | **[ECMAScript Test Suite](https://github.com/tc39/test262)** tests when selecting the 37 | ES2020 features. 38 | - Can compile Javascript sources to executables with no external dependency. 39 | - Garbage collection using reference counting (to reduce memory usage and have 40 | deterministic behavior) with cycle removal. 41 | - Mathematical extensions: **BigDecimal**, **BigFloat**, **operator overloading**, 42 | **bigint mode**, **math mode**. 43 | - Command line interpreter with contextual colorization implemented in Javascript. 44 | - Small built-in standard library with **C** library wrappers. 45 | 46 | This reposistory is a mrirror of the original work that you can find **[here](https://bellard.org/quickjs/)**. 47 | 48 | ## Building 49 | 50 | The main purpose of this reposistory is to build **QuickJS** static library 51 | that you could include on your **C / C++** project. 52 | On release you can find the build for the following operating systems: 53 | 54 | - **Windows** 55 | - **Ubuntu 20.04** 56 | - **Ubuntu 18.04** 57 | - **Linux arm64** 58 | - **macOS** 59 | 60 | If you want to build the QuickJS library on your own the first step is to clone 61 | this repository: 62 | 63 | `> git clone https://github.com/napi-bindings/quickjs-build.git` 64 | 65 | ### Building on Windows 66 | 67 | You will need to install **GCC** for Windows and **CMake**. 68 | 69 | #### Install GCC compiler 70 | 71 | - Download the mingw from this **[link](https://sourceforge.net/projects/mingw-w64/)**. 72 | - Be sure that **gcc** in in your path of execution. 73 | 74 | #### Install CMake 75 | 76 | - Download the right version for your system from this **[link](https://cmake.org/download/)**. 77 | - Be sure that **cmake** is in your path of execution. 78 | 79 | #### Configure and build 80 | 81 | Open your shell and execute the commands reported below: 82 | 83 | ``` 84 | mkdir ./build 85 | cmake \ 86 | -DCMAKE_BUILD_TYPE=Release \ 87 | -G "MinGW Makefiles" \ 88 | -S ./ \ 89 | -B ./build 90 | cmake --build ./build 91 | ``` 92 | 93 | `-DCMAKE_BUILD_TYPE` could be set with one of the following two values: 94 | 95 | - Release 96 | - Debug 97 | 98 | ### Building on Unix-like platform 99 | 100 | You will need to install **C / C++** compiler and **CMake**. 101 | 102 | #### Prerequisistes to build on Linux 103 | 104 | These steps were tested on: 105 | 106 | - **Ubuntu 18.04** 107 | - **Ubuntu 20.04** 108 | 109 | First, you will need to install dependencies: 110 | 111 | ``` 112 | sudo apt-get update 113 | sudo apt-get install build-essential -y 114 | sudo apt-get install cmake -y 115 | ``` 116 | 117 | #### Prerequisites to build on macOS 118 | 119 | These steps were tested on macOS Catalina (10.15). 120 | 121 | First, you will need to install dependencies: 122 | 123 | - Install [Xcode](https://developer.apple.com/xcode/download/) 124 | - You also need to install the `XCode Command Line Tools` by running 125 | `xcode-select --install`. Alternatively, if you already have the full Xcode 126 | installed, you can find them under the menu 127 | `Xcode -> Open Developer Tool -> More Developer Tools...`. This step will 128 | install `clang`, `clang++`, and `make`. 129 | - Install [Homebrew](https://brew.sh/) 130 | - Install and `cmake` running the following command: 131 | ``` 132 | brew install cmake 133 | ``` 134 | 135 | #### Configure and build 136 | 137 | Open your shell and execute the commands reported below: 138 | 139 | ``` 140 | mkdir ./build 141 | cmake \ 142 | -DCMAKE_BUILD_TYPE=Release \ 143 | -G "Unix Makefiles" \ 144 | -S ./ \ 145 | -B ./build 146 | cmake --build ./build 147 | ``` 148 | 149 | `-DCMAKE_BUILD_TYPE` could be set with one of the following two values: 150 | 151 | - Release 152 | - Debug 153 | 154 | ## References 155 | 156 | - **QuickJS** documentation [HTML version](https://bellard.org/quickjs/quickjs.html), [PDF version](https://bellard.org/quickjs/quickjs.pdf). 157 | - Specification of the JavaScript **Bignum Extensions**: [HTML version](https://bellard.org/quickjs/jsbignum.html), [PDF version](https://bellard.org/quickjs/jsbignum.pdf). 158 | - [Writing native modules in C for QuickJS](https://medium.com/@calbertts/writing-native-modules-in-c-for-quickjs-engine-49043587f2e2). 159 | - [How to create asynchronous code for QuickJS](https://medium.com/@calbertts/how-to-create-asynchronous-apis-for-quickjs-8aca5488bb2e). 160 | 161 | ## Team 162 | 163 | ### Nicola Del Gobbo 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | ## Acknowledgements 172 | 173 | Thank you to all people that encourage me every day. 174 | 175 | ## License 176 | 177 | Licensed under [Apache license V2](./LICENSE) 178 | -------------------------------------------------------------------------------- /src/cutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * C utilities 3 | * 4 | * Copyright (c) 2017 Fabrice Bellard 5 | * Copyright (c) 2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #ifndef CUTILS_H 26 | #define CUTILS_H 27 | 28 | #include 29 | #include 30 | 31 | /* set if CPU is big endian */ 32 | #undef WORDS_BIGENDIAN 33 | 34 | #define likely(x) __builtin_expect(!!(x), 1) 35 | #define unlikely(x) __builtin_expect(!!(x), 0) 36 | #define force_inline inline __attribute__((always_inline)) 37 | #define no_inline __attribute__((noinline)) 38 | #define __maybe_unused __attribute__((unused)) 39 | 40 | #define xglue(x, y) x ## y 41 | #define glue(x, y) xglue(x, y) 42 | #define stringify(s) tostring(s) 43 | #define tostring(s) #s 44 | 45 | #ifndef offsetof 46 | #define offsetof(type, field) ((size_t) &((type *)0)->field) 47 | #endif 48 | #ifndef countof 49 | #define countof(x) (sizeof(x) / sizeof((x)[0])) 50 | #endif 51 | 52 | typedef int BOOL; 53 | 54 | #ifndef FALSE 55 | enum { 56 | FALSE = 0, 57 | TRUE = 1, 58 | }; 59 | #endif 60 | 61 | void pstrcpy(char *buf, int buf_size, const char *str); 62 | char *pstrcat(char *buf, int buf_size, const char *s); 63 | int strstart(const char *str, const char *val, const char **ptr); 64 | int has_suffix(const char *str, const char *suffix); 65 | 66 | static inline int max_int(int a, int b) 67 | { 68 | if (a > b) 69 | return a; 70 | else 71 | return b; 72 | } 73 | 74 | static inline int min_int(int a, int b) 75 | { 76 | if (a < b) 77 | return a; 78 | else 79 | return b; 80 | } 81 | 82 | static inline uint32_t max_uint32(uint32_t a, uint32_t b) 83 | { 84 | if (a > b) 85 | return a; 86 | else 87 | return b; 88 | } 89 | 90 | static inline uint32_t min_uint32(uint32_t a, uint32_t b) 91 | { 92 | if (a < b) 93 | return a; 94 | else 95 | return b; 96 | } 97 | 98 | static inline int64_t max_int64(int64_t a, int64_t b) 99 | { 100 | if (a > b) 101 | return a; 102 | else 103 | return b; 104 | } 105 | 106 | static inline int64_t min_int64(int64_t a, int64_t b) 107 | { 108 | if (a < b) 109 | return a; 110 | else 111 | return b; 112 | } 113 | 114 | /* WARNING: undefined if a = 0 */ 115 | static inline int clz32(unsigned int a) 116 | { 117 | return __builtin_clz(a); 118 | } 119 | 120 | /* WARNING: undefined if a = 0 */ 121 | static inline int clz64(uint64_t a) 122 | { 123 | return __builtin_clzll(a); 124 | } 125 | 126 | /* WARNING: undefined if a = 0 */ 127 | static inline int ctz32(unsigned int a) 128 | { 129 | return __builtin_ctz(a); 130 | } 131 | 132 | /* WARNING: undefined if a = 0 */ 133 | static inline int ctz64(uint64_t a) 134 | { 135 | return __builtin_ctzll(a); 136 | } 137 | 138 | struct __attribute__((packed)) packed_u64 { 139 | uint64_t v; 140 | }; 141 | 142 | struct __attribute__((packed)) packed_u32 { 143 | uint32_t v; 144 | }; 145 | 146 | struct __attribute__((packed)) packed_u16 { 147 | uint16_t v; 148 | }; 149 | 150 | static inline uint64_t get_u64(const uint8_t *tab) 151 | { 152 | return ((const struct packed_u64 *)tab)->v; 153 | } 154 | 155 | static inline int64_t get_i64(const uint8_t *tab) 156 | { 157 | return (int64_t)((const struct packed_u64 *)tab)->v; 158 | } 159 | 160 | static inline void put_u64(uint8_t *tab, uint64_t val) 161 | { 162 | ((struct packed_u64 *)tab)->v = val; 163 | } 164 | 165 | static inline uint32_t get_u32(const uint8_t *tab) 166 | { 167 | return ((const struct packed_u32 *)tab)->v; 168 | } 169 | 170 | static inline int32_t get_i32(const uint8_t *tab) 171 | { 172 | return (int32_t)((const struct packed_u32 *)tab)->v; 173 | } 174 | 175 | static inline void put_u32(uint8_t *tab, uint32_t val) 176 | { 177 | ((struct packed_u32 *)tab)->v = val; 178 | } 179 | 180 | static inline uint32_t get_u16(const uint8_t *tab) 181 | { 182 | return ((const struct packed_u16 *)tab)->v; 183 | } 184 | 185 | static inline int32_t get_i16(const uint8_t *tab) 186 | { 187 | return (int16_t)((const struct packed_u16 *)tab)->v; 188 | } 189 | 190 | static inline void put_u16(uint8_t *tab, uint16_t val) 191 | { 192 | ((struct packed_u16 *)tab)->v = val; 193 | } 194 | 195 | static inline uint32_t get_u8(const uint8_t *tab) 196 | { 197 | return *tab; 198 | } 199 | 200 | static inline int32_t get_i8(const uint8_t *tab) 201 | { 202 | return (int8_t)*tab; 203 | } 204 | 205 | static inline void put_u8(uint8_t *tab, uint8_t val) 206 | { 207 | *tab = val; 208 | } 209 | 210 | static inline uint16_t bswap16(uint16_t x) 211 | { 212 | return (x >> 8) | (x << 8); 213 | } 214 | 215 | static inline uint32_t bswap32(uint32_t v) 216 | { 217 | return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) | 218 | ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24); 219 | } 220 | 221 | static inline uint64_t bswap64(uint64_t v) 222 | { 223 | return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | 224 | ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | 225 | ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | 226 | ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | 227 | ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | 228 | ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | 229 | ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | 230 | ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8)); 231 | } 232 | 233 | /* XXX: should take an extra argument to pass slack information to the caller */ 234 | typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size); 235 | 236 | typedef struct DynBuf { 237 | uint8_t *buf; 238 | size_t size; 239 | size_t allocated_size; 240 | BOOL error; /* true if a memory allocation error occurred */ 241 | DynBufReallocFunc *realloc_func; 242 | void *opaque; /* for realloc_func */ 243 | } DynBuf; 244 | 245 | void dbuf_init(DynBuf *s); 246 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func); 247 | int dbuf_realloc(DynBuf *s, size_t new_size); 248 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len); 249 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len); 250 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len); 251 | int dbuf_putc(DynBuf *s, uint8_t c); 252 | int dbuf_putstr(DynBuf *s, const char *str); 253 | static inline int dbuf_put_u16(DynBuf *s, uint16_t val) 254 | { 255 | return dbuf_put(s, (uint8_t *)&val, 2); 256 | } 257 | static inline int dbuf_put_u32(DynBuf *s, uint32_t val) 258 | { 259 | return dbuf_put(s, (uint8_t *)&val, 4); 260 | } 261 | static inline int dbuf_put_u64(DynBuf *s, uint64_t val) 262 | { 263 | return dbuf_put(s, (uint8_t *)&val, 8); 264 | } 265 | int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, 266 | const char *fmt, ...); 267 | void dbuf_free(DynBuf *s); 268 | static inline BOOL dbuf_error(DynBuf *s) { 269 | return s->error; 270 | } 271 | static inline void dbuf_set_error(DynBuf *s) 272 | { 273 | s->error = TRUE; 274 | } 275 | 276 | #define UTF8_CHAR_LEN_MAX 6 277 | 278 | int unicode_to_utf8(uint8_t *buf, unsigned int c); 279 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp); 280 | 281 | static inline int from_hex(int c) 282 | { 283 | if (c >= '0' && c <= '9') 284 | return c - '0'; 285 | else if (c >= 'A' && c <= 'F') 286 | return c - 'A' + 10; 287 | else if (c >= 'a' && c <= 'f') 288 | return c - 'a' + 10; 289 | else 290 | return -1; 291 | } 292 | 293 | void rqsort(void *base, size_t nmemb, size_t size, 294 | int (*cmp)(const void *, const void *, void *), 295 | void *arg); 296 | 297 | #endif /* CUTILS_H */ 298 | -------------------------------------------------------------------------------- /src/quickjs-atom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS atom definitions 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * Copyright (c) 2017-2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | #ifdef DEF 27 | 28 | /* Note: first atoms are considered as keywords in the parser */ 29 | DEF(null, "null") /* must be first */ 30 | DEF(false, "false") 31 | DEF(true, "true") 32 | DEF(if, "if") 33 | DEF(else, "else") 34 | DEF(return, "return") 35 | DEF(var, "var") 36 | DEF(this, "this") 37 | DEF(delete, "delete") 38 | DEF(void, "void") 39 | DEF(typeof, "typeof") 40 | DEF(new, "new") 41 | DEF(in, "in") 42 | DEF(instanceof, "instanceof") 43 | DEF(do, "do") 44 | DEF(while, "while") 45 | DEF(for, "for") 46 | DEF(break, "break") 47 | DEF(continue, "continue") 48 | DEF(switch, "switch") 49 | DEF(case, "case") 50 | DEF(default, "default") 51 | DEF(throw, "throw") 52 | DEF(try, "try") 53 | DEF(catch, "catch") 54 | DEF(finally, "finally") 55 | DEF(function, "function") 56 | DEF(debugger, "debugger") 57 | DEF(with, "with") 58 | /* FutureReservedWord */ 59 | DEF(class, "class") 60 | DEF(const, "const") 61 | DEF(enum, "enum") 62 | DEF(export, "export") 63 | DEF(extends, "extends") 64 | DEF(import, "import") 65 | DEF(super, "super") 66 | /* FutureReservedWords when parsing strict mode code */ 67 | DEF(implements, "implements") 68 | DEF(interface, "interface") 69 | DEF(let, "let") 70 | DEF(package, "package") 71 | DEF(private, "private") 72 | DEF(protected, "protected") 73 | DEF(public, "public") 74 | DEF(static, "static") 75 | DEF(yield, "yield") 76 | DEF(await, "await") 77 | 78 | /* empty string */ 79 | DEF(empty_string, "") 80 | /* identifiers */ 81 | DEF(length, "length") 82 | DEF(fileName, "fileName") 83 | DEF(lineNumber, "lineNumber") 84 | DEF(message, "message") 85 | DEF(errors, "errors") 86 | DEF(stack, "stack") 87 | DEF(name, "name") 88 | DEF(toString, "toString") 89 | DEF(toLocaleString, "toLocaleString") 90 | DEF(valueOf, "valueOf") 91 | DEF(eval, "eval") 92 | DEF(prototype, "prototype") 93 | DEF(constructor, "constructor") 94 | DEF(configurable, "configurable") 95 | DEF(writable, "writable") 96 | DEF(enumerable, "enumerable") 97 | DEF(value, "value") 98 | DEF(get, "get") 99 | DEF(set, "set") 100 | DEF(of, "of") 101 | DEF(__proto__, "__proto__") 102 | DEF(undefined, "undefined") 103 | DEF(number, "number") 104 | DEF(boolean, "boolean") 105 | DEF(string, "string") 106 | DEF(object, "object") 107 | DEF(symbol, "symbol") 108 | DEF(integer, "integer") 109 | DEF(unknown, "unknown") 110 | DEF(arguments, "arguments") 111 | DEF(callee, "callee") 112 | DEF(caller, "caller") 113 | DEF(_eval_, "") 114 | DEF(_ret_, "") 115 | DEF(_var_, "") 116 | DEF(_arg_var_, "") 117 | DEF(_with_, "") 118 | DEF(lastIndex, "lastIndex") 119 | DEF(target, "target") 120 | DEF(index, "index") 121 | DEF(input, "input") 122 | DEF(defineProperties, "defineProperties") 123 | DEF(apply, "apply") 124 | DEF(join, "join") 125 | DEF(concat, "concat") 126 | DEF(split, "split") 127 | DEF(construct, "construct") 128 | DEF(getPrototypeOf, "getPrototypeOf") 129 | DEF(setPrototypeOf, "setPrototypeOf") 130 | DEF(isExtensible, "isExtensible") 131 | DEF(preventExtensions, "preventExtensions") 132 | DEF(has, "has") 133 | DEF(deleteProperty, "deleteProperty") 134 | DEF(defineProperty, "defineProperty") 135 | DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") 136 | DEF(ownKeys, "ownKeys") 137 | DEF(add, "add") 138 | DEF(done, "done") 139 | DEF(next, "next") 140 | DEF(values, "values") 141 | DEF(source, "source") 142 | DEF(flags, "flags") 143 | DEF(global, "global") 144 | DEF(unicode, "unicode") 145 | DEF(raw, "raw") 146 | DEF(new_target, "new.target") 147 | DEF(this_active_func, "this.active_func") 148 | DEF(home_object, "") 149 | DEF(computed_field, "") 150 | DEF(static_computed_field, "") /* must come after computed_fields */ 151 | DEF(class_fields_init, "") 152 | DEF(brand, "") 153 | DEF(hash_constructor, "#constructor") 154 | DEF(as, "as") 155 | DEF(from, "from") 156 | DEF(meta, "meta") 157 | DEF(_default_, "*default*") 158 | DEF(_star_, "*") 159 | DEF(Module, "Module") 160 | DEF(then, "then") 161 | DEF(resolve, "resolve") 162 | DEF(reject, "reject") 163 | DEF(promise, "promise") 164 | DEF(proxy, "proxy") 165 | DEF(revoke, "revoke") 166 | DEF(async, "async") 167 | DEF(exec, "exec") 168 | DEF(groups, "groups") 169 | DEF(status, "status") 170 | DEF(reason, "reason") 171 | DEF(globalThis, "globalThis") 172 | #ifdef CONFIG_BIGNUM 173 | DEF(bigint, "bigint") 174 | DEF(bigfloat, "bigfloat") 175 | DEF(bigdecimal, "bigdecimal") 176 | DEF(roundingMode, "roundingMode") 177 | DEF(maximumSignificantDigits, "maximumSignificantDigits") 178 | DEF(maximumFractionDigits, "maximumFractionDigits") 179 | #endif 180 | #ifdef CONFIG_ATOMICS 181 | DEF(not_equal, "not-equal") 182 | DEF(timed_out, "timed-out") 183 | DEF(ok, "ok") 184 | #endif 185 | DEF(toJSON, "toJSON") 186 | /* class names */ 187 | DEF(Object, "Object") 188 | DEF(Array, "Array") 189 | DEF(Error, "Error") 190 | DEF(Number, "Number") 191 | DEF(String, "String") 192 | DEF(Boolean, "Boolean") 193 | DEF(Symbol, "Symbol") 194 | DEF(Arguments, "Arguments") 195 | DEF(Math, "Math") 196 | DEF(JSON, "JSON") 197 | DEF(Date, "Date") 198 | DEF(Function, "Function") 199 | DEF(GeneratorFunction, "GeneratorFunction") 200 | DEF(ForInIterator, "ForInIterator") 201 | DEF(RegExp, "RegExp") 202 | DEF(ArrayBuffer, "ArrayBuffer") 203 | DEF(SharedArrayBuffer, "SharedArrayBuffer") 204 | /* must keep same order as class IDs for typed arrays */ 205 | DEF(Uint8ClampedArray, "Uint8ClampedArray") 206 | DEF(Int8Array, "Int8Array") 207 | DEF(Uint8Array, "Uint8Array") 208 | DEF(Int16Array, "Int16Array") 209 | DEF(Uint16Array, "Uint16Array") 210 | DEF(Int32Array, "Int32Array") 211 | DEF(Uint32Array, "Uint32Array") 212 | #ifdef CONFIG_BIGNUM 213 | DEF(BigInt64Array, "BigInt64Array") 214 | DEF(BigUint64Array, "BigUint64Array") 215 | #endif 216 | DEF(Float32Array, "Float32Array") 217 | DEF(Float64Array, "Float64Array") 218 | DEF(DataView, "DataView") 219 | #ifdef CONFIG_BIGNUM 220 | DEF(BigInt, "BigInt") 221 | DEF(BigFloat, "BigFloat") 222 | DEF(BigFloatEnv, "BigFloatEnv") 223 | DEF(BigDecimal, "BigDecimal") 224 | DEF(OperatorSet, "OperatorSet") 225 | DEF(Operators, "Operators") 226 | #endif 227 | DEF(Map, "Map") 228 | DEF(Set, "Set") /* Map + 1 */ 229 | DEF(WeakMap, "WeakMap") /* Map + 2 */ 230 | DEF(WeakSet, "WeakSet") /* Map + 3 */ 231 | DEF(Map_Iterator, "Map Iterator") 232 | DEF(Set_Iterator, "Set Iterator") 233 | DEF(Array_Iterator, "Array Iterator") 234 | DEF(String_Iterator, "String Iterator") 235 | DEF(RegExp_String_Iterator, "RegExp String Iterator") 236 | DEF(Generator, "Generator") 237 | DEF(Proxy, "Proxy") 238 | DEF(Promise, "Promise") 239 | DEF(PromiseResolveFunction, "PromiseResolveFunction") 240 | DEF(PromiseRejectFunction, "PromiseRejectFunction") 241 | DEF(AsyncFunction, "AsyncFunction") 242 | DEF(AsyncFunctionResolve, "AsyncFunctionResolve") 243 | DEF(AsyncFunctionReject, "AsyncFunctionReject") 244 | DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction") 245 | DEF(AsyncGenerator, "AsyncGenerator") 246 | DEF(EvalError, "EvalError") 247 | DEF(RangeError, "RangeError") 248 | DEF(ReferenceError, "ReferenceError") 249 | DEF(SyntaxError, "SyntaxError") 250 | DEF(TypeError, "TypeError") 251 | DEF(URIError, "URIError") 252 | DEF(InternalError, "InternalError") 253 | /* private symbols */ 254 | DEF(Private_brand, "") 255 | /* symbols */ 256 | DEF(Symbol_toPrimitive, "Symbol.toPrimitive") 257 | DEF(Symbol_iterator, "Symbol.iterator") 258 | DEF(Symbol_match, "Symbol.match") 259 | DEF(Symbol_matchAll, "Symbol.matchAll") 260 | DEF(Symbol_replace, "Symbol.replace") 261 | DEF(Symbol_search, "Symbol.search") 262 | DEF(Symbol_split, "Symbol.split") 263 | DEF(Symbol_toStringTag, "Symbol.toStringTag") 264 | DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") 265 | DEF(Symbol_hasInstance, "Symbol.hasInstance") 266 | DEF(Symbol_species, "Symbol.species") 267 | DEF(Symbol_unscopables, "Symbol.unscopables") 268 | DEF(Symbol_asyncIterator, "Symbol.asyncIterator") 269 | #ifdef CONFIG_BIGNUM 270 | DEF(Symbol_operatorSet, "Symbol.operatorSet") 271 | #endif 272 | 273 | #endif /* DEF */ 274 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # quickjs-build changelog 2 | 3 | ## 2023-04-28 Version 6.0.0, @NickNaso 4 | 5 | ### Notable changes 6 | 7 | * Update QuickJS to version 2022-03-07. 8 | * Fixed error build for Windows. 9 | 10 | ### Commits 11 | 12 | * \[[`b28783c9be`](https://github.com/nodejs/node/commit/b28783c9be)] - Merge pull request #14 from gengjiawen/feat/bump (Nicola Del Gobbo) 13 | * \[[`c7cf621319`](https://github.com/nodejs/node/commit/c7cf621319)] - update README (Jiawen Geng) 14 | * \[[`720973720f`](https://github.com/nodejs/node/commit/720973720f)] - Update quickjs-build.yml (Jiawen Geng) 15 | * \[[`bc86489e59`](https://github.com/nodejs/node/commit/bc86489e59)] - **fix**: windows (gengjiawen) 16 | * \[[`fc4f6fc14b`](https://github.com/nodejs/node/commit/fc4f6fc14b)] - **feat**: sync quickjs to 20220307 (gengjiawen) 17 | 18 | ## 2021-08-25 Version 5.3.0, @NickNaso 19 | 20 | ### Notable changes 21 | 22 | - Added linux arm64 build. 23 | - Removed ubuntu 16.04 from CI. 24 | - Some minor fixes. 25 | 26 | ### Commits 27 | 28 | * [[`8b10f47212`](https://github.com/napi-bindings/quickjs-build/commit/8b10f47212)] - Fixed documentation. (NickNaso) 29 | * [[`316368db2e`](https://github.com/napi-bindings/quickjs-build/commit/316368db2e)] - Removed ubuntu 16.04 from CI. (NickNaso) 30 | * [[`e0a280c34f`](https://github.com/napi-bindings/quickjs-build/commit/e0a280c34f)] - Merge pull request #10 from gengjiawen/arm64 (Nicola Del Gobbo) 31 | * [[`6551f61377`](https://github.com/napi-bindings/quickjs-build/commit/6551f61377)] - **feat**: add linux arm64 build (Jiawen Geng) 32 | 33 | ## 2021-04-12 Version 5.2.0, @NickNaso 34 | 35 | ### Notable changes 36 | 37 | * Added executable for `run-test262`. 38 | * Auto source generation. 39 | 40 | ### Commits 41 | 42 | * [[`105860f2d1`](https://github.com/napi-bindings/quickjs-build/commit/105860f2d1)] - Some little fixes on documentations. (NickNaso) 43 | * [[`3788bef240`](https://github.com/napi-bindings/quickjs-build/commit/3788bef240)] - Create LICENSE (Nicola Del Gobbo) 44 | * [[`fd7ca724ae`](https://github.com/napi-bindings/quickjs-build/commit/fd7ca724ae)] - Merge pull request #8 from gengjiawen/feat/test-262 (Nicola Del Gobbo) 45 | * [[`6614794560`](https://github.com/napi-bindings/quickjs-build/commit/6614794560)] - Merge pull request #7 from gengjiawen/feature/atuo (Nicola Del Gobbo) 46 | 47 | ## 2021-04-10 Version 5.1.0, @NickNaso 48 | 49 | ### Notable changes 50 | 51 | * Added executable for `quickjs` and `qjsc`. 52 | 53 | ### Commits 54 | 55 | * [[`0b46a3f067`](https://github.com/napi-bindings/quickjs-build/commit/0b46a3f067)] - Prepare new release 5.1.0. (NickNaso) 56 | * [[`c9ab43c489`](https://github.com/napi-bindings/quickjs-build/commit/c9ab43c489)] - Merge pull request #6 from gengjiawen/feat/binary (Nicola Del Gobbo) 57 | * [[`97fe3599bf`](https://github.com/napi-bindings/quickjs-build/commit/97fe3599bf)] - use mingw on windows (Jiawen Geng) 58 | * [[`c6719fecd5`](https://github.com/napi-bindings/quickjs-build/commit/c6719fecd5)] - **feat**: add quickjs and qjsc (Jiawen Geng) 59 | 60 | ## 2021-03-28 Version 5.0.0, @NickNaso 61 | 62 | ### Notable changes 63 | 64 | * Fixed the build on *nix systems. 65 | * QuickJS version 2021-03-27. 66 | 67 | ### QuickJS changes: 68 | 69 | * Faster Array.prototype.push and Array.prototype.unshift. 70 | * Added JS_UpdateStackTop(). 71 | * Fixed Windows console. 72 | * Misc bug fixes. 73 | 74 | ### Commits 75 | 76 | * [[`222c1964d2`](https://github.com/napi-bindings/quickjs-build/commit/222c1964d2)] - Prepare release for version 2021-03-27. (Nicola Del Gobbo) 77 | * [[`db6da63495`](https://github.com/napi-bindings/quickjs-build/commit/db6da63495)] - Fixed build on linux. (Nicola Del Gobbo) 78 | * [[`c04a298c35`](https://github.com/napi-bindings/quickjs-build/commit/c04a298c35)] - Prepare new version 2021-03-27. (NickNaso) 79 | 80 | ## 2020-11-08 Version 4.0.0, @NickNaso 81 | 82 | ### Notable changes 83 | 84 | - QuickJS version 2020-11-08. 85 | 86 | ### QuickJS changes 87 | 88 | * Improved function parameter initializers. 89 | * Added `std.setenv()`, `std.unsetenv()` and `std.getenviron()`. 90 | * Added JS_EvalThis(). 91 | * Misc bug fixes. 92 | 93 | ### Commits 94 | 95 | * [[`693ec349bc`](https://github.com/napi-bindings/quickjs-build/commit/693ec349bc)] - Prepare new version 2020-11-08. (NickNaso) 96 | 97 | ## 2020-09-10 Version 3.0.0, @NickNaso 98 | 99 | ### Notable changes 100 | 101 | * Update the assets for the release only when the release has been published. 102 | * QuickJS version 2020-09-06. 103 | 104 | ### QuickJS changes 105 | 106 | * Added logical assignment operators. 107 | * Added IsHTMLDDA support. 108 | * Faster for-of loops. 109 | * os.Worker now takes a module filename as parameter. 110 | * qjsc: added -D option to compile dynamically loaded modules or workers. 111 | * Misc bug fixes. 112 | 113 | ### Commits 114 | 115 | * [[`305934fc7e`](https://github.com/napi-bindings/quickjs-build/commit/305934fc7e)] - Prepare new version 2020-09-06. (NickNaso) 116 | * [[`46a395c6ad`](https://github.com/napi-bindings/quickjs-build/commit/46a395c6ad)] - Update quickjs-build.yml (Nicola Del Gobbo) 117 | 118 | ## 2020-09-04 Version 2.0.0, @NickNaso 119 | 120 | ### Notable changes 121 | 122 | * QuickJS version 2020-07-05. 123 | 124 | ### QuickJS changes 125 | 126 | * Modified JS_GetPrototype() to return a live value. 127 | * REPL: support unicode characters larger than 16 bits. 128 | * Added os.Worker. 129 | * Improved object serialization. 130 | * Added std.parseExtJSON. 131 | * Misc bug fixes. 132 | 133 | ### Commits 134 | 135 | * [[`3f68062b99`](https://github.com/napi-bindings/quickjs-build/commit/3f68062b99)] - Prepare new version 2020-07-05. (NickNaso) 136 | 137 | ## 2020-06-08 Version 1.0.0, @NickNaso 138 | 139 | ### Notable changes 140 | 141 | * Initial implementation for the project. 142 | * QuickJS version 2020-07-05. 143 | 144 | ### Commits 145 | 146 | * [[`b25571e2e6`](https://github.com/napi-bindings/quickjs-build/commit/b25571e2e6)] - Added changelog. (NickNaso) 147 | * [[`a1c5a374d2`](https://github.com/napi-bindings/quickjs-build/commit/a1c5a374d2)] - Added code of conduct. (NickNaso) 148 | * [[`59738019be`](https://github.com/napi-bindings/quickjs-build/commit/59738019be)] - Remove unused parameters. (NickNaso) 149 | * [[`c96ed22f3f`](https://github.com/napi-bindings/quickjs-build/commit/c96ed22f3f)] - Added buil instructions for unix-like systems. (NickNaso) 150 | * [[`ba204590fa`](https://github.com/napi-bindings/quickjs-build/commit/ba204590fa)] - Added references section. (NickNaso) 151 | * [[`9a7344fbe5`](https://github.com/napi-bindings/quickjs-build/commit/9a7344fbe5)] - Added build instruction for Windows. (NickNaso) 152 | * [[`cb575c3d52`](https://github.com/napi-bindings/quickjs-build/commit/cb575c3d52)] - Excluded build folder. (NickNaso) 153 | * [[`ed3ec16353`](https://github.com/napi-bindings/quickjs-build/commit/ed3ec16353)] - Base instruction to build quickjs. (NickNaso) 154 | * [[`56e0695c0b`](https://github.com/napi-bindings/quickjs-build/commit/56e0695c0b)] - Merge branch 'master' of https://github.com/napi-bindings/quickjs-build (NickNaso) 155 | * [[`568d0054c8`](https://github.com/napi-bindings/quickjs-build/commit/568d0054c8)] - Some format sugar. (NickNaso) 156 | * [[`e3c3f93b99`](https://github.com/napi-bindings/quickjs-build/commit/e3c3f93b99)] - Update README.md (Nicola Del Gobbo) 157 | * [[`2c240fbac6`](https://github.com/napi-bindings/quickjs-build/commit/2c240fbac6)] - Added introduction on readme. (NickNaso) 158 | * [[`2b75403d2b`](https://github.com/napi-bindings/quickjs-build/commit/2b75403d2b)] - Added badges. (NickNaso) 159 | * [[`a2b771e731`](https://github.com/napi-bindings/quickjs-build/commit/a2b771e731)] - Handle release event. (NickNaso) 160 | * [[`17b872447a`](https://github.com/napi-bindings/quickjs-build/commit/17b872447a)] - Fixed cflags for windows. (NickNaso) 161 | * [[`4a4539f0f9`](https://github.com/napi-bindings/quickjs-build/commit/4a4539f0f9)] - Added cflag for windows. (NickNaso) 162 | * [[`ad65bbbf3a`](https://github.com/napi-bindings/quickjs-build/commit/ad65bbbf3a)] - Remove unnecessary commands. (NickNaso) 163 | * [[`c03f57309b`](https://github.com/napi-bindings/quickjs-build/commit/c03f57309b)] - Fixed artifact name on macOS. (NickNaso) 164 | * [[`d754d944d3`](https://github.com/napi-bindings/quickjs-build/commit/d754d944d3)] - Fixed artifacts. (NickNaso) 165 | * [[`f50c74ab7d`](https://github.com/napi-bindings/quickjs-build/commit/f50c74ab7d)] - Fixed typo. (NickNaso) 166 | * [[`97d4081a0c`](https://github.com/napi-bindings/quickjs-build/commit/97d4081a0c)] - Print artifacts. (NickNaso) 167 | * [[`4cf28567a7`](https://github.com/napi-bindings/quickjs-build/commit/4cf28567a7)] - Fixed compiler options. (NickNaso) 168 | * [[`279620809a`](https://github.com/napi-bindings/quickjs-build/commit/279620809a)] - Fixed configurations. (NickNaso) 169 | * [[`98a8f91de8`](https://github.com/napi-bindings/quickjs-build/commit/98a8f91de8)] - Parametric value for compiler. (NickNaso) 170 | * [[`88383ad863`](https://github.com/napi-bindings/quickjs-build/commit/88383ad863)] - Comment for unused parameters. (NickNaso) 171 | * [[`586b97de5e`](https://github.com/napi-bindings/quickjs-build/commit/586b97de5e)] - Fixed path compiler. (NickNaso) 172 | * [[`c3c1ab64f7`](https://github.com/napi-bindings/quickjs-build/commit/c3c1ab64f7)] - Fixed path. (NickNaso) 173 | * [[`4e634e4f81`](https://github.com/napi-bindings/quickjs-build/commit/4e634e4f81)] - Fixed path. (NickNaso) 174 | * [[`a3c74cdfb8`](https://github.com/napi-bindings/quickjs-build/commit/a3c74cdfb8)] - Fixed compiler installartion for windows. (NickNaso) 175 | * [[`d0a67ef816`](https://github.com/napi-bindings/quickjs-build/commit/d0a67ef816)] - List compiler folder. (NickNaso) 176 | * [[`6a13e6d0dd`](https://github.com/napi-bindings/quickjs-build/commit/6a13e6d0dd)] - List root folders. (NickNaso) 177 | * [[`bf5865b896`](https://github.com/napi-bindings/quickjs-build/commit/bf5865b896)] - Fixed cmake options. (NickNaso) 178 | * [[`ede84d97d5`](https://github.com/napi-bindings/quickjs-build/commit/ede84d97d5)] - Added cmake options. (NickNaso) 179 | * [[`9c01856429`](https://github.com/napi-bindings/quickjs-build/commit/9c01856429)] - Extract compiler. (NickNaso) 180 | * [[`9fdff3ef87`](https://github.com/napi-bindings/quickjs-build/commit/9fdff3ef87)] - Remove build filder. (NickNaso) 181 | * [[`f2aa910713`](https://github.com/napi-bindings/quickjs-build/commit/f2aa910713)] - Install dependencies for windows. (NickNaso) 182 | * [[`07fa5a545f`](https://github.com/napi-bindings/quickjs-build/commit/07fa5a545f)] - Install windows depencencies. (NickNaso) 183 | * [[`391c51a1e0`](https://github.com/napi-bindings/quickjs-build/commit/391c51a1e0)] - Install dependencies on windows. (NickNaso) 184 | * [[`cebb8a2f8b`](https://github.com/napi-bindings/quickjs-build/commit/cebb8a2f8b)] - Install dependencies for windows. (NickNaso) 185 | * [[`c85dfe9e77`](https://github.com/napi-bindings/quickjs-build/commit/c85dfe9e77)] - Install dependencies on windows. (NickNaso) 186 | * [[`fc9b365a8e`](https://github.com/napi-bindings/quickjs-build/commit/fc9b365a8e)] - Install dependencies on Windows. (NickNaso) 187 | * [[`ef53415ff6`](https://github.com/napi-bindings/quickjs-build/commit/ef53415ff6)] - Install dependencies on windows. (NickNaso) 188 | * [[`86469b3b15`](https://github.com/napi-bindings/quickjs-build/commit/86469b3b15)] - Install windows dependencies. (NickNaso) 189 | * [[`568fd88755`](https://github.com/napi-bindings/quickjs-build/commit/568fd88755)] - Install Windows dependencies. (NickNaso) 190 | * [[`345b03ae35`](https://github.com/napi-bindings/quickjs-build/commit/345b03ae35)] - Install windows dependencies. (NickNaso) 191 | * [[`6c6494ed59`](https://github.com/napi-bindings/quickjs-build/commit/6c6494ed59)] - Install Windows dependencies. (NickNaso) 192 | * [[`a07b8e4540`](https://github.com/napi-bindings/quickjs-build/commit/a07b8e4540)] - Install depencendies for WIndows. (NickNaso) 193 | * [[`afe92477ed`](https://github.com/napi-bindings/quickjs-build/commit/afe92477ed)] - Re enable windows on matrix. (NickNaso) 194 | * [[`3092849294`](https://github.com/napi-bindings/quickjs-build/commit/3092849294)] - Remove unnecessary steps. (NickNaso) 195 | * [[`84c9159870`](https://github.com/napi-bindings/quickjs-build/commit/84c9159870)] - Remove windows from matrix (NickNaso) 196 | * [[`34049bf0cf`](https://github.com/napi-bindings/quickjs-build/commit/34049bf0cf)] - Remove unnecessary folders. (NickNaso) 197 | * [[`24ea136acf`](https://github.com/napi-bindings/quickjs-build/commit/24ea136acf)] - Cleanup. (NickNaso) 198 | * [[`3b3680bfb4`](https://github.com/napi-bindings/quickjs-build/commit/3b3680bfb4)] - Cleanup. (NickNaso) 199 | * [[`5162fb2908`](https://github.com/napi-bindings/quickjs-build/commit/5162fb2908)] - Added upload artifacts. (NickNaso) 200 | * [[`84e1c5f2d8`](https://github.com/napi-bindings/quickjs-build/commit/84e1c5f2d8)] - Change working diorectory on prepare artifacts. (NickNaso) 201 | * [[`98e3e24159`](https://github.com/napi-bindings/quickjs-build/commit/98e3e24159)] - Prepare artifacts. (NickNaso) 202 | * [[`bfaf01dc51`](https://github.com/napi-bindings/quickjs-build/commit/bfaf01dc51)] - Added script to configure, to build and to prepare. (NickNaso) 203 | * [[`5b6c19c44f`](https://github.com/napi-bindings/quickjs-build/commit/5b6c19c44f)] - Install dependecies for macOS. (NickNaso) 204 | * [[`159f61a954`](https://github.com/napi-bindings/quickjs-build/commit/159f61a954)] - Install dependencies on Windows. (NickNaso) 205 | * [[`a2fc3018ef`](https://github.com/napi-bindings/quickjs-build/commit/a2fc3018ef)] - Install dependecies for Linux. (NickNaso) 206 | * [[`521f4ee63f`](https://github.com/napi-bindings/quickjs-build/commit/521f4ee63f)] - Scaffolding to handle the dependencies installation. (NickNaso) 207 | * [[`21f2d7466b`](https://github.com/napi-bindings/quickjs-build/commit/21f2d7466b)] - Ognore .vscode and .idea folders. (NickNaso) 208 | * [[`6bbda2152b`](https://github.com/napi-bindings/quickjs-build/commit/6bbda2152b)] - Update quickjs-build.yml (Nicola Del Gobbo) 209 | * [[`889ebffe4f`](https://github.com/napi-bindings/quickjs-build/commit/889ebffe4f)] - Update quickjs-build.yml (Nicola Del Gobbo) 210 | * [[`376b7ee533`](https://github.com/napi-bindings/quickjs-build/commit/376b7ee533)] - Update quickjs-build.yml (Nicola Del Gobbo) 211 | * [[`fd40c2b0ea`](https://github.com/napi-bindings/quickjs-build/commit/fd40c2b0ea)] - Update README.md (Nicola Del Gobbo) 212 | * [[`eb1e0edf86`](https://github.com/napi-bindings/quickjs-build/commit/eb1e0edf86)] - Update README.md (Nicola Del Gobbo) 213 | * [[`df2799b9ab`](https://github.com/napi-bindings/quickjs-build/commit/df2799b9ab)] - Update quickjs-build.yml (Nicola Del Gobbo) 214 | * [[`d5d122297f`](https://github.com/napi-bindings/quickjs-build/commit/d5d122297f)] - Update quickjs-build.yml (Nicola Del Gobbo) 215 | * [[`58bf4b7d14`](https://github.com/napi-bindings/quickjs-build/commit/58bf4b7d14)] - Update quickjs-build.yml (Nicola Del Gobbo) 216 | * [[`876cebe69e`](https://github.com/napi-bindings/quickjs-build/commit/876cebe69e)] - Rename c-cpp.yml to quickjs-build.yml (Nicola Del Gobbo) 217 | * [[`378649639f`](https://github.com/napi-bindings/quickjs-build/commit/378649639f)] - Update c-cpp.yml (Nicola Del Gobbo) 218 | * [[`b01ba4b8d2`](https://github.com/napi-bindings/quickjs-build/commit/b01ba4b8d2)] - Update c-cpp.yml (Nicola Del Gobbo) 219 | * [[`65f4a05f0b`](https://github.com/napi-bindings/quickjs-build/commit/65f4a05f0b)] - Update c-cpp.yml (Nicola Del Gobbo) 220 | * [[`526444b3f9`](https://github.com/napi-bindings/quickjs-build/commit/526444b3f9)] - Initial set for build the project. (Nicola Del Gobbo) 221 | * [[`ea73f2c78e`](https://github.com/napi-bindings/quickjs-build/commit/ea73f2c78e)] - initial commit for the project. (NickNaso) 222 | * [[`a6cb06817f`](https://github.com/napi-bindings/quickjs-build/commit/a6cb06817f)] - Initial commit (Nicola Del Gobbo) 223 | -------------------------------------------------------------------------------- /src/quickjs-opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS opcode definitions 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * Copyright (c) 2017-2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | #ifdef FMT 27 | FMT(none) 28 | FMT(none_int) 29 | FMT(none_loc) 30 | FMT(none_arg) 31 | FMT(none_var_ref) 32 | FMT(u8) 33 | FMT(i8) 34 | FMT(loc8) 35 | FMT(const8) 36 | FMT(label8) 37 | FMT(u16) 38 | FMT(i16) 39 | FMT(label16) 40 | FMT(npop) 41 | FMT(npopx) 42 | FMT(npop_u16) 43 | FMT(loc) 44 | FMT(arg) 45 | FMT(var_ref) 46 | FMT(u32) 47 | FMT(i32) 48 | FMT(const) 49 | FMT(label) 50 | FMT(atom) 51 | FMT(atom_u8) 52 | FMT(atom_u16) 53 | FMT(atom_label_u8) 54 | FMT(atom_label_u16) 55 | FMT(label_u16) 56 | #undef FMT 57 | #endif /* FMT */ 58 | 59 | #ifdef DEF 60 | 61 | #ifndef def 62 | #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f) 63 | #endif 64 | 65 | DEF(invalid, 1, 0, 0, none) /* never emitted */ 66 | 67 | /* push values */ 68 | DEF( push_i32, 5, 0, 1, i32) 69 | DEF( push_const, 5, 0, 1, const) 70 | DEF( fclosure, 5, 0, 1, const) /* must follow push_const */ 71 | DEF(push_atom_value, 5, 0, 1, atom) 72 | DEF( private_symbol, 5, 0, 1, atom) 73 | DEF( undefined, 1, 0, 1, none) 74 | DEF( null, 1, 0, 1, none) 75 | DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */ 76 | DEF( push_false, 1, 0, 1, none) 77 | DEF( push_true, 1, 0, 1, none) 78 | DEF( object, 1, 0, 1, none) 79 | DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */ 80 | DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */ 81 | 82 | DEF( drop, 1, 1, 0, none) /* a -> */ 83 | DEF( nip, 1, 2, 1, none) /* a b -> b */ 84 | DEF( nip1, 1, 3, 2, none) /* a b c -> b c */ 85 | DEF( dup, 1, 1, 2, none) /* a -> a a */ 86 | DEF( dup1, 1, 2, 3, none) /* a b -> a a b */ 87 | DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */ 88 | DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */ 89 | DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */ 90 | DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */ 91 | DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */ 92 | DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */ 93 | DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */ 94 | DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */ 95 | DEF( swap, 1, 2, 2, none) /* a b -> b a */ 96 | DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */ 97 | DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */ 98 | DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */ 99 | DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */ 100 | DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */ 101 | 102 | DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */ 103 | DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */ 104 | DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */ 105 | DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */ 106 | DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */ 107 | DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */ 108 | DEF( apply, 3, 3, 1, u16) 109 | DEF( return, 1, 1, 0, none) 110 | DEF( return_undef, 1, 0, 0, none) 111 | DEF(check_ctor_return, 1, 1, 2, none) 112 | DEF( check_ctor, 1, 0, 0, none) 113 | DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */ 114 | DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */ 115 | DEF( return_async, 1, 1, 0, none) 116 | DEF( throw, 1, 1, 0, none) 117 | DEF( throw_error, 6, 0, 0, atom_u8) 118 | DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ 119 | DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ 120 | DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a 121 | bytecode string */ 122 | DEF( get_super, 1, 1, 1, none) 123 | DEF( import, 1, 1, 1, none) /* dynamic module import */ 124 | 125 | DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */ 126 | DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */ 127 | DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */ 128 | DEF( put_var, 5, 1, 0, atom) /* must come after get_var */ 129 | DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */ 130 | DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */ 131 | 132 | DEF( get_ref_value, 1, 2, 3, none) 133 | DEF( put_ref_value, 1, 3, 0, none) 134 | 135 | DEF( define_var, 6, 0, 0, atom_u8) 136 | DEF(check_define_var, 6, 0, 0, atom_u8) 137 | DEF( define_func, 6, 1, 0, atom_u8) 138 | DEF( get_field, 5, 1, 1, atom) 139 | DEF( get_field2, 5, 1, 2, atom) 140 | DEF( put_field, 5, 2, 0, atom) 141 | DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */ 142 | DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */ 143 | DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */ 144 | DEF( get_array_el, 1, 2, 1, none) 145 | DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */ 146 | DEF( put_array_el, 1, 3, 0, none) 147 | DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */ 148 | DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */ 149 | DEF( define_field, 5, 2, 1, atom) 150 | DEF( set_name, 5, 1, 1, atom) 151 | DEF(set_name_computed, 1, 2, 2, none) 152 | DEF( set_proto, 1, 2, 1, none) 153 | DEF(set_home_object, 1, 2, 2, none) 154 | DEF(define_array_el, 1, 3, 2, none) 155 | DEF( append, 1, 3, 2, none) /* append enumerated object, update length */ 156 | DEF(copy_data_properties, 2, 3, 3, u8) 157 | DEF( define_method, 6, 2, 1, atom_u8) 158 | DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */ 159 | DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */ 160 | DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */ 161 | 162 | DEF( get_loc, 3, 0, 1, loc) 163 | DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */ 164 | DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */ 165 | DEF( get_arg, 3, 0, 1, arg) 166 | DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */ 167 | DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */ 168 | DEF( get_var_ref, 3, 0, 1, var_ref) 169 | DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */ 170 | DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */ 171 | DEF(set_loc_uninitialized, 3, 0, 0, loc) 172 | DEF( get_loc_check, 3, 0, 1, loc) 173 | DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ 174 | DEF( put_loc_check_init, 3, 1, 0, loc) 175 | DEF(get_var_ref_check, 3, 0, 1, var_ref) 176 | DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ 177 | DEF(put_var_ref_check_init, 3, 1, 0, var_ref) 178 | DEF( close_loc, 3, 0, 0, loc) 179 | DEF( if_false, 5, 1, 0, label) 180 | DEF( if_true, 5, 1, 0, label) /* must come after if_false */ 181 | DEF( goto, 5, 0, 0, label) /* must come after if_true */ 182 | DEF( catch, 5, 0, 1, label) 183 | DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ 184 | DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ 185 | 186 | DEF( to_object, 1, 1, 1, none) 187 | //DEF( to_string, 1, 1, 1, none) 188 | DEF( to_propkey, 1, 1, 1, none) 189 | DEF( to_propkey2, 1, 2, 2, none) 190 | 191 | DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 192 | DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */ 193 | DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 194 | DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 195 | DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 196 | DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8) 197 | 198 | DEF( make_loc_ref, 7, 0, 2, atom_u16) 199 | DEF( make_arg_ref, 7, 0, 2, atom_u16) 200 | DEF(make_var_ref_ref, 7, 0, 2, atom_u16) 201 | DEF( make_var_ref, 5, 0, 2, atom) 202 | 203 | DEF( for_in_start, 1, 1, 1, none) 204 | DEF( for_of_start, 1, 1, 3, none) 205 | DEF(for_await_of_start, 1, 1, 3, none) 206 | DEF( for_in_next, 1, 1, 3, none) 207 | DEF( for_of_next, 2, 3, 5, u8) 208 | DEF(iterator_check_object, 1, 1, 1, none) 209 | DEF(iterator_get_value_done, 1, 1, 2, none) 210 | DEF( iterator_close, 1, 3, 0, none) 211 | DEF(iterator_close_return, 1, 4, 4, none) 212 | DEF( iterator_next, 1, 4, 4, none) 213 | DEF( iterator_call, 2, 4, 5, u8) 214 | DEF( initial_yield, 1, 0, 0, none) 215 | DEF( yield, 1, 1, 2, none) 216 | DEF( yield_star, 1, 1, 2, none) 217 | DEF(async_yield_star, 1, 1, 2, none) 218 | DEF( await, 1, 1, 1, none) 219 | 220 | /* arithmetic/logic operations */ 221 | DEF( neg, 1, 1, 1, none) 222 | DEF( plus, 1, 1, 1, none) 223 | DEF( dec, 1, 1, 1, none) 224 | DEF( inc, 1, 1, 1, none) 225 | DEF( post_dec, 1, 1, 2, none) 226 | DEF( post_inc, 1, 1, 2, none) 227 | DEF( dec_loc, 2, 0, 0, loc8) 228 | DEF( inc_loc, 2, 0, 0, loc8) 229 | DEF( add_loc, 2, 1, 0, loc8) 230 | DEF( not, 1, 1, 1, none) 231 | DEF( lnot, 1, 1, 1, none) 232 | DEF( typeof, 1, 1, 1, none) 233 | DEF( delete, 1, 2, 1, none) 234 | DEF( delete_var, 5, 0, 1, atom) 235 | 236 | DEF( mul, 1, 2, 1, none) 237 | DEF( div, 1, 2, 1, none) 238 | DEF( mod, 1, 2, 1, none) 239 | DEF( add, 1, 2, 1, none) 240 | DEF( sub, 1, 2, 1, none) 241 | DEF( pow, 1, 2, 1, none) 242 | DEF( shl, 1, 2, 1, none) 243 | DEF( sar, 1, 2, 1, none) 244 | DEF( shr, 1, 2, 1, none) 245 | DEF( lt, 1, 2, 1, none) 246 | DEF( lte, 1, 2, 1, none) 247 | DEF( gt, 1, 2, 1, none) 248 | DEF( gte, 1, 2, 1, none) 249 | DEF( instanceof, 1, 2, 1, none) 250 | DEF( in, 1, 2, 1, none) 251 | DEF( eq, 1, 2, 1, none) 252 | DEF( neq, 1, 2, 1, none) 253 | DEF( strict_eq, 1, 2, 1, none) 254 | DEF( strict_neq, 1, 2, 1, none) 255 | DEF( and, 1, 2, 1, none) 256 | DEF( xor, 1, 2, 1, none) 257 | DEF( or, 1, 2, 1, none) 258 | DEF(is_undefined_or_null, 1, 1, 1, none) 259 | #ifdef CONFIG_BIGNUM 260 | DEF( mul_pow10, 1, 2, 1, none) 261 | DEF( math_mod, 1, 2, 1, none) 262 | #endif 263 | /* must be the last non short and non temporary opcode */ 264 | DEF( nop, 1, 0, 0, none) 265 | 266 | /* temporary opcodes: never emitted in the final bytecode */ 267 | 268 | def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ 269 | def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ 270 | 271 | def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ 272 | 273 | def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 274 | def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 275 | def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ 276 | def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 277 | def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ 278 | def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ 279 | def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ 280 | def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ 281 | def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ 282 | def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ 283 | 284 | def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ 285 | 286 | def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ 287 | 288 | #if SHORT_OPCODES 289 | DEF( push_minus1, 1, 0, 1, none_int) 290 | DEF( push_0, 1, 0, 1, none_int) 291 | DEF( push_1, 1, 0, 1, none_int) 292 | DEF( push_2, 1, 0, 1, none_int) 293 | DEF( push_3, 1, 0, 1, none_int) 294 | DEF( push_4, 1, 0, 1, none_int) 295 | DEF( push_5, 1, 0, 1, none_int) 296 | DEF( push_6, 1, 0, 1, none_int) 297 | DEF( push_7, 1, 0, 1, none_int) 298 | DEF( push_i8, 2, 0, 1, i8) 299 | DEF( push_i16, 3, 0, 1, i16) 300 | DEF( push_const8, 2, 0, 1, const8) 301 | DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */ 302 | DEF(push_empty_string, 1, 0, 1, none) 303 | 304 | DEF( get_loc8, 2, 0, 1, loc8) 305 | DEF( put_loc8, 2, 1, 0, loc8) 306 | DEF( set_loc8, 2, 1, 1, loc8) 307 | 308 | DEF( get_loc0, 1, 0, 1, none_loc) 309 | DEF( get_loc1, 1, 0, 1, none_loc) 310 | DEF( get_loc2, 1, 0, 1, none_loc) 311 | DEF( get_loc3, 1, 0, 1, none_loc) 312 | DEF( put_loc0, 1, 1, 0, none_loc) 313 | DEF( put_loc1, 1, 1, 0, none_loc) 314 | DEF( put_loc2, 1, 1, 0, none_loc) 315 | DEF( put_loc3, 1, 1, 0, none_loc) 316 | DEF( set_loc0, 1, 1, 1, none_loc) 317 | DEF( set_loc1, 1, 1, 1, none_loc) 318 | DEF( set_loc2, 1, 1, 1, none_loc) 319 | DEF( set_loc3, 1, 1, 1, none_loc) 320 | DEF( get_arg0, 1, 0, 1, none_arg) 321 | DEF( get_arg1, 1, 0, 1, none_arg) 322 | DEF( get_arg2, 1, 0, 1, none_arg) 323 | DEF( get_arg3, 1, 0, 1, none_arg) 324 | DEF( put_arg0, 1, 1, 0, none_arg) 325 | DEF( put_arg1, 1, 1, 0, none_arg) 326 | DEF( put_arg2, 1, 1, 0, none_arg) 327 | DEF( put_arg3, 1, 1, 0, none_arg) 328 | DEF( set_arg0, 1, 1, 1, none_arg) 329 | DEF( set_arg1, 1, 1, 1, none_arg) 330 | DEF( set_arg2, 1, 1, 1, none_arg) 331 | DEF( set_arg3, 1, 1, 1, none_arg) 332 | DEF( get_var_ref0, 1, 0, 1, none_var_ref) 333 | DEF( get_var_ref1, 1, 0, 1, none_var_ref) 334 | DEF( get_var_ref2, 1, 0, 1, none_var_ref) 335 | DEF( get_var_ref3, 1, 0, 1, none_var_ref) 336 | DEF( put_var_ref0, 1, 1, 0, none_var_ref) 337 | DEF( put_var_ref1, 1, 1, 0, none_var_ref) 338 | DEF( put_var_ref2, 1, 1, 0, none_var_ref) 339 | DEF( put_var_ref3, 1, 1, 0, none_var_ref) 340 | DEF( set_var_ref0, 1, 1, 1, none_var_ref) 341 | DEF( set_var_ref1, 1, 1, 1, none_var_ref) 342 | DEF( set_var_ref2, 1, 1, 1, none_var_ref) 343 | DEF( set_var_ref3, 1, 1, 1, none_var_ref) 344 | 345 | DEF( get_length, 1, 1, 1, none) 346 | 347 | DEF( if_false8, 2, 1, 0, label8) 348 | DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */ 349 | DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */ 350 | DEF( goto16, 3, 0, 0, label16) 351 | 352 | DEF( call0, 1, 1, 1, npopx) 353 | DEF( call1, 1, 1, 1, npopx) 354 | DEF( call2, 1, 1, 1, npopx) 355 | DEF( call3, 1, 1, 1, npopx) 356 | 357 | DEF( is_undefined, 1, 1, 1, none) 358 | DEF( is_null, 1, 1, 1, none) 359 | DEF(typeof_is_undefined, 1, 1, 1, none) 360 | DEF( typeof_is_function, 1, 1, 1, none) 361 | #endif 362 | 363 | #undef DEF 364 | #undef def 365 | #endif /* DEF */ 366 | -------------------------------------------------------------------------------- /src/qjs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS stand alone interpreter 3 | * 4 | * Copyright (c) 2017-2021 Fabrice Bellard 5 | * Copyright (c) 2017-2021 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #if defined(__APPLE__) 36 | #include 37 | #elif defined(__linux__) 38 | #include 39 | #endif 40 | 41 | #include "cutils.h" 42 | #include "quickjs-libc.h" 43 | 44 | extern const uint8_t qjsc_repl[]; 45 | extern const uint32_t qjsc_repl_size; 46 | #ifdef CONFIG_BIGNUM 47 | extern const uint8_t qjsc_qjscalc[]; 48 | extern const uint32_t qjsc_qjscalc_size; 49 | static int bignum_ext; 50 | #endif 51 | 52 | static int eval_buf(JSContext *ctx, const void *buf, int buf_len, 53 | const char *filename, int eval_flags) 54 | { 55 | JSValue val; 56 | int ret; 57 | 58 | if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { 59 | /* for the modules, we compile then run to be able to set 60 | import.meta */ 61 | val = JS_Eval(ctx, buf, buf_len, filename, 62 | eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); 63 | if (!JS_IsException(val)) { 64 | js_module_set_import_meta(ctx, val, TRUE, TRUE); 65 | val = JS_EvalFunction(ctx, val); 66 | } 67 | } else { 68 | val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); 69 | } 70 | if (JS_IsException(val)) { 71 | js_std_dump_error(ctx); 72 | ret = -1; 73 | } else { 74 | ret = 0; 75 | } 76 | JS_FreeValue(ctx, val); 77 | return ret; 78 | } 79 | 80 | static int eval_file(JSContext *ctx, const char *filename, int module) 81 | { 82 | uint8_t *buf; 83 | int ret, eval_flags; 84 | size_t buf_len; 85 | 86 | buf = js_load_file(ctx, &buf_len, filename); 87 | if (!buf) { 88 | perror(filename); 89 | exit(1); 90 | } 91 | 92 | if (module < 0) { 93 | module = (has_suffix(filename, ".mjs") || 94 | JS_DetectModule((const char *)buf, buf_len)); 95 | } 96 | if (module) 97 | eval_flags = JS_EVAL_TYPE_MODULE; 98 | else 99 | eval_flags = JS_EVAL_TYPE_GLOBAL; 100 | ret = eval_buf(ctx, buf, buf_len, filename, eval_flags); 101 | js_free(ctx, buf); 102 | return ret; 103 | } 104 | 105 | /* also used to initialize the worker context */ 106 | static JSContext *JS_NewCustomContext(JSRuntime *rt) 107 | { 108 | JSContext *ctx; 109 | ctx = JS_NewContext(rt); 110 | if (!ctx) 111 | return NULL; 112 | #ifdef CONFIG_BIGNUM 113 | if (bignum_ext) { 114 | JS_AddIntrinsicBigFloat(ctx); 115 | JS_AddIntrinsicBigDecimal(ctx); 116 | JS_AddIntrinsicOperators(ctx); 117 | JS_EnableBignumExt(ctx, TRUE); 118 | } 119 | #endif 120 | /* system modules */ 121 | js_init_module_std(ctx, "std"); 122 | js_init_module_os(ctx, "os"); 123 | return ctx; 124 | } 125 | 126 | #if defined(__APPLE__) 127 | #define MALLOC_OVERHEAD 0 128 | #else 129 | #define MALLOC_OVERHEAD 8 130 | #endif 131 | 132 | struct trace_malloc_data { 133 | uint8_t *base; 134 | }; 135 | 136 | static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr, 137 | struct trace_malloc_data *dp) 138 | { 139 | return ptr - dp->base; 140 | } 141 | 142 | /* default memory allocation functions with memory limitation */ 143 | static inline size_t js_trace_malloc_usable_size(void *ptr) 144 | { 145 | #if defined(__APPLE__) 146 | return malloc_size(ptr); 147 | #elif defined(_WIN32) 148 | return _msize(ptr); 149 | #elif defined(EMSCRIPTEN) 150 | return 0; 151 | #elif defined(__linux__) 152 | return malloc_usable_size(ptr); 153 | #else 154 | /* change this to `return 0;` if compilation fails */ 155 | return malloc_usable_size(ptr); 156 | #endif 157 | } 158 | 159 | static void 160 | #ifdef _WIN32 161 | /* mingw printf is used */ 162 | __attribute__((format(gnu_printf, 2, 3))) 163 | #else 164 | __attribute__((format(printf, 2, 3))) 165 | #endif 166 | js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...) 167 | { 168 | va_list ap; 169 | int c; 170 | 171 | va_start(ap, fmt); 172 | while ((c = *fmt++) != '\0') { 173 | if (c == '%') { 174 | /* only handle %p and %zd */ 175 | if (*fmt == 'p') { 176 | uint8_t *ptr = va_arg(ap, void *); 177 | if (ptr == NULL) { 178 | printf("NULL"); 179 | } else { 180 | printf("H%+06lld.%zd", 181 | js_trace_malloc_ptr_offset(ptr, s->opaque), 182 | js_trace_malloc_usable_size(ptr)); 183 | } 184 | fmt++; 185 | continue; 186 | } 187 | if (fmt[0] == 'z' && fmt[1] == 'd') { 188 | size_t sz = va_arg(ap, size_t); 189 | printf("%zd", sz); 190 | fmt += 2; 191 | continue; 192 | } 193 | } 194 | putc(c, stdout); 195 | } 196 | va_end(ap); 197 | } 198 | 199 | static void js_trace_malloc_init(struct trace_malloc_data *s) 200 | { 201 | free(s->base = malloc(8)); 202 | } 203 | 204 | static void *js_trace_malloc(JSMallocState *s, size_t size) 205 | { 206 | void *ptr; 207 | 208 | /* Do not allocate zero bytes: behavior is platform dependent */ 209 | assert(size != 0); 210 | 211 | if (unlikely(s->malloc_size + size > s->malloc_limit)) 212 | return NULL; 213 | ptr = malloc(size); 214 | js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr); 215 | if (ptr) { 216 | s->malloc_count++; 217 | s->malloc_size += js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD; 218 | } 219 | return ptr; 220 | } 221 | 222 | static void js_trace_free(JSMallocState *s, void *ptr) 223 | { 224 | if (!ptr) 225 | return; 226 | 227 | js_trace_malloc_printf(s, "F %p\n", ptr); 228 | s->malloc_count--; 229 | s->malloc_size -= js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD; 230 | free(ptr); 231 | } 232 | 233 | static void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size) 234 | { 235 | size_t old_size; 236 | 237 | if (!ptr) { 238 | if (size == 0) 239 | return NULL; 240 | return js_trace_malloc(s, size); 241 | } 242 | old_size = js_trace_malloc_usable_size(ptr); 243 | if (size == 0) { 244 | js_trace_malloc_printf(s, "R %zd %p\n", size, ptr); 245 | s->malloc_count--; 246 | s->malloc_size -= old_size + MALLOC_OVERHEAD; 247 | free(ptr); 248 | return NULL; 249 | } 250 | if (s->malloc_size + size - old_size > s->malloc_limit) 251 | return NULL; 252 | 253 | js_trace_malloc_printf(s, "R %zd %p", size, ptr); 254 | 255 | ptr = realloc(ptr, size); 256 | js_trace_malloc_printf(s, " -> %p\n", ptr); 257 | if (ptr) { 258 | s->malloc_size += js_trace_malloc_usable_size(ptr) - old_size; 259 | } 260 | return ptr; 261 | } 262 | 263 | static const JSMallocFunctions trace_mf = { 264 | js_trace_malloc, 265 | js_trace_free, 266 | js_trace_realloc, 267 | #if defined(__APPLE__) 268 | malloc_size, 269 | #elif defined(_WIN32) 270 | (size_t (*)(const void *))_msize, 271 | #elif defined(EMSCRIPTEN) 272 | NULL, 273 | #elif defined(__linux__) 274 | (size_t (*)(const void *))malloc_usable_size, 275 | #else 276 | /* change this to `NULL,` if compilation fails */ 277 | malloc_usable_size, 278 | #endif 279 | }; 280 | 281 | #define PROG_NAME "qjs" 282 | 283 | void help(void) 284 | { 285 | printf("QuickJS version " CONFIG_VERSION "\n" 286 | "usage: " PROG_NAME " [options] [file [args]]\n" 287 | "-h --help list options\n" 288 | "-e --eval EXPR evaluate EXPR\n" 289 | "-i --interactive go to interactive mode\n" 290 | "-m --module load as ES6 module (default=autodetect)\n" 291 | " --script load as ES6 script (default=autodetect)\n" 292 | "-I --include file include an additional file\n" 293 | " --std make 'std' and 'os' available to the loaded script\n" 294 | #ifdef CONFIG_BIGNUM 295 | " --bignum enable the bignum extensions (BigFloat, BigDecimal)\n" 296 | " --qjscalc load the QJSCalc runtime (default if invoked as qjscalc)\n" 297 | #endif 298 | "-T --trace trace memory allocation\n" 299 | "-d --dump dump the memory usage stats\n" 300 | " --memory-limit n limit the memory usage to 'n' bytes\n" 301 | " --stack-size n limit the stack size to 'n' bytes\n" 302 | " --unhandled-rejection dump unhandled promise rejections\n" 303 | "-q --quit just instantiate the interpreter and quit\n"); 304 | exit(1); 305 | } 306 | 307 | int main(int argc, char **argv) 308 | { 309 | JSRuntime *rt; 310 | JSContext *ctx; 311 | struct trace_malloc_data trace_data = { NULL }; 312 | int optind; 313 | char *expr = NULL; 314 | int interactive = 0; 315 | int dump_memory = 0; 316 | int trace_memory = 0; 317 | int empty_run = 0; 318 | int module = -1; 319 | int load_std = 0; 320 | int dump_unhandled_promise_rejection = 0; 321 | size_t memory_limit = 0; 322 | char *include_list[32]; 323 | int i, include_count = 0; 324 | #ifdef CONFIG_BIGNUM 325 | int load_jscalc; 326 | #endif 327 | size_t stack_size = 0; 328 | 329 | #ifdef CONFIG_BIGNUM 330 | /* load jscalc runtime if invoked as 'qjscalc' */ 331 | { 332 | const char *p, *exename; 333 | exename = argv[0]; 334 | p = strrchr(exename, '/'); 335 | if (p) 336 | exename = p + 1; 337 | load_jscalc = !strcmp(exename, "qjscalc"); 338 | } 339 | #endif 340 | 341 | /* cannot use getopt because we want to pass the command line to 342 | the script */ 343 | optind = 1; 344 | while (optind < argc && *argv[optind] == '-') { 345 | char *arg = argv[optind] + 1; 346 | const char *longopt = ""; 347 | /* a single - is not an option, it also stops argument scanning */ 348 | if (!*arg) 349 | break; 350 | optind++; 351 | if (*arg == '-') { 352 | longopt = arg + 1; 353 | arg += strlen(arg); 354 | /* -- stops argument scanning */ 355 | if (!*longopt) 356 | break; 357 | } 358 | for (; *arg || *longopt; longopt = "") { 359 | char opt = *arg; 360 | if (opt) 361 | arg++; 362 | if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { 363 | help(); 364 | continue; 365 | } 366 | if (opt == 'e' || !strcmp(longopt, "eval")) { 367 | if (*arg) { 368 | expr = arg; 369 | break; 370 | } 371 | if (optind < argc) { 372 | expr = argv[optind++]; 373 | break; 374 | } 375 | fprintf(stderr, "qjs: missing expression for -e\n"); 376 | exit(2); 377 | } 378 | if (opt == 'I' || !strcmp(longopt, "include")) { 379 | if (optind >= argc) { 380 | fprintf(stderr, "expecting filename"); 381 | exit(1); 382 | } 383 | if (include_count >= countof(include_list)) { 384 | fprintf(stderr, "too many included files"); 385 | exit(1); 386 | } 387 | include_list[include_count++] = argv[optind++]; 388 | continue; 389 | } 390 | if (opt == 'i' || !strcmp(longopt, "interactive")) { 391 | interactive++; 392 | continue; 393 | } 394 | if (opt == 'm' || !strcmp(longopt, "module")) { 395 | module = 1; 396 | continue; 397 | } 398 | if (!strcmp(longopt, "script")) { 399 | module = 0; 400 | continue; 401 | } 402 | if (opt == 'd' || !strcmp(longopt, "dump")) { 403 | dump_memory++; 404 | continue; 405 | } 406 | if (opt == 'T' || !strcmp(longopt, "trace")) { 407 | trace_memory++; 408 | continue; 409 | } 410 | if (!strcmp(longopt, "std")) { 411 | load_std = 1; 412 | continue; 413 | } 414 | if (!strcmp(longopt, "unhandled-rejection")) { 415 | dump_unhandled_promise_rejection = 1; 416 | continue; 417 | } 418 | #ifdef CONFIG_BIGNUM 419 | if (!strcmp(longopt, "bignum")) { 420 | bignum_ext = 1; 421 | continue; 422 | } 423 | if (!strcmp(longopt, "qjscalc")) { 424 | load_jscalc = 1; 425 | continue; 426 | } 427 | #endif 428 | if (opt == 'q' || !strcmp(longopt, "quit")) { 429 | empty_run++; 430 | continue; 431 | } 432 | if (!strcmp(longopt, "memory-limit")) { 433 | if (optind >= argc) { 434 | fprintf(stderr, "expecting memory limit"); 435 | exit(1); 436 | } 437 | memory_limit = (size_t)strtod(argv[optind++], NULL); 438 | continue; 439 | } 440 | if (!strcmp(longopt, "stack-size")) { 441 | if (optind >= argc) { 442 | fprintf(stderr, "expecting stack size"); 443 | exit(1); 444 | } 445 | stack_size = (size_t)strtod(argv[optind++], NULL); 446 | continue; 447 | } 448 | if (opt) { 449 | fprintf(stderr, "qjs: unknown option '-%c'\n", opt); 450 | } else { 451 | fprintf(stderr, "qjs: unknown option '--%s'\n", longopt); 452 | } 453 | help(); 454 | } 455 | } 456 | 457 | if (load_jscalc) 458 | bignum_ext = 1; 459 | 460 | if (trace_memory) { 461 | js_trace_malloc_init(&trace_data); 462 | rt = JS_NewRuntime2(&trace_mf, &trace_data); 463 | } else { 464 | rt = JS_NewRuntime(); 465 | } 466 | if (!rt) { 467 | fprintf(stderr, "qjs: cannot allocate JS runtime\n"); 468 | exit(2); 469 | } 470 | if (memory_limit != 0) 471 | JS_SetMemoryLimit(rt, memory_limit); 472 | if (stack_size != 0) 473 | JS_SetMaxStackSize(rt, stack_size); 474 | js_std_set_worker_new_context_func(JS_NewCustomContext); 475 | js_std_init_handlers(rt); 476 | ctx = JS_NewCustomContext(rt); 477 | if (!ctx) { 478 | fprintf(stderr, "qjs: cannot allocate JS context\n"); 479 | exit(2); 480 | } 481 | 482 | /* loader for ES6 modules */ 483 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 484 | 485 | if (dump_unhandled_promise_rejection) { 486 | JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, 487 | NULL); 488 | } 489 | 490 | if (!empty_run) { 491 | #ifdef CONFIG_BIGNUM 492 | if (load_jscalc) { 493 | js_std_eval_binary(ctx, qjsc_qjscalc, qjsc_qjscalc_size, 0); 494 | } 495 | #endif 496 | js_std_add_helpers(ctx, argc - optind, argv + optind); 497 | 498 | /* make 'std' and 'os' visible to non module code */ 499 | if (load_std) { 500 | const char *str = "import * as std from 'std';\n" 501 | "import * as os from 'os';\n" 502 | "globalThis.std = std;\n" 503 | "globalThis.os = os;\n"; 504 | eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); 505 | } 506 | 507 | for(i = 0; i < include_count; i++) { 508 | if (eval_file(ctx, include_list[i], module)) 509 | goto fail; 510 | } 511 | 512 | if (expr) { 513 | if (eval_buf(ctx, expr, strlen(expr), "", 0)) 514 | goto fail; 515 | } else 516 | if (optind >= argc) { 517 | /* interactive mode */ 518 | interactive = 1; 519 | } else { 520 | const char *filename; 521 | filename = argv[optind]; 522 | if (eval_file(ctx, filename, module)) 523 | goto fail; 524 | } 525 | if (interactive) { 526 | js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0); 527 | } 528 | js_std_loop(ctx); 529 | } 530 | 531 | if (dump_memory) { 532 | JSMemoryUsage stats; 533 | JS_ComputeMemoryUsage(rt, &stats); 534 | JS_DumpMemoryUsage(stdout, &stats, rt); 535 | } 536 | js_std_free_handlers(rt); 537 | JS_FreeContext(ctx); 538 | JS_FreeRuntime(rt); 539 | 540 | if (empty_run && dump_memory) { 541 | clock_t t[5]; 542 | double best[5]; 543 | int i, j; 544 | for (i = 0; i < 100; i++) { 545 | t[0] = clock(); 546 | rt = JS_NewRuntime(); 547 | t[1] = clock(); 548 | ctx = JS_NewContext(rt); 549 | t[2] = clock(); 550 | JS_FreeContext(ctx); 551 | t[3] = clock(); 552 | JS_FreeRuntime(rt); 553 | t[4] = clock(); 554 | for (j = 4; j > 0; j--) { 555 | double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC; 556 | if (i == 0 || best[j] > ms) 557 | best[j] = ms; 558 | } 559 | } 560 | printf("\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\n", 561 | best[1] + best[2] + best[3] + best[4], 562 | best[1], best[2], best[3], best[4]); 563 | } 564 | return 0; 565 | fail: 566 | js_std_free_handlers(rt); 567 | JS_FreeContext(ctx); 568 | JS_FreeRuntime(rt); 569 | return 1; 570 | } 571 | -------------------------------------------------------------------------------- /src/libbf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tiny arbitrary precision floating point library 3 | * 4 | * Copyright (c) 2017-2021 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBBF_H 25 | #define LIBBF_H 26 | 27 | #include 28 | #include 29 | 30 | #if INTPTR_MAX >= INT64_MAX 31 | #define LIMB_LOG2_BITS 6 32 | #else 33 | #define LIMB_LOG2_BITS 5 34 | #endif 35 | 36 | #define LIMB_BITS (1 << LIMB_LOG2_BITS) 37 | 38 | #if LIMB_BITS == 64 39 | typedef __int128 int128_t; 40 | typedef unsigned __int128 uint128_t; 41 | typedef int64_t slimb_t; 42 | typedef uint64_t limb_t; 43 | typedef uint128_t dlimb_t; 44 | #define BF_RAW_EXP_MIN INT64_MIN 45 | #define BF_RAW_EXP_MAX INT64_MAX 46 | 47 | #define LIMB_DIGITS 19 48 | #define BF_DEC_BASE UINT64_C(10000000000000000000) 49 | 50 | #else 51 | 52 | typedef int32_t slimb_t; 53 | typedef uint32_t limb_t; 54 | typedef uint64_t dlimb_t; 55 | #define BF_RAW_EXP_MIN INT32_MIN 56 | #define BF_RAW_EXP_MAX INT32_MAX 57 | 58 | #define LIMB_DIGITS 9 59 | #define BF_DEC_BASE 1000000000U 60 | 61 | #endif 62 | 63 | /* in bits */ 64 | /* minimum number of bits for the exponent */ 65 | #define BF_EXP_BITS_MIN 3 66 | /* maximum number of bits for the exponent */ 67 | #define BF_EXP_BITS_MAX (LIMB_BITS - 3) 68 | /* extended range for exponent, used internally */ 69 | #define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1) 70 | /* minimum possible precision */ 71 | #define BF_PREC_MIN 2 72 | /* minimum possible precision */ 73 | #define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2) 74 | /* some operations support infinite precision */ 75 | #define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */ 76 | 77 | #if LIMB_BITS == 64 78 | #define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197)) 79 | #else 80 | #define BF_CHKSUM_MOD 975620677U 81 | #endif 82 | 83 | #define BF_EXP_ZERO BF_RAW_EXP_MIN 84 | #define BF_EXP_INF (BF_RAW_EXP_MAX - 1) 85 | #define BF_EXP_NAN BF_RAW_EXP_MAX 86 | 87 | /* +/-zero is represented with expn = BF_EXP_ZERO and len = 0, 88 | +/-infinity is represented with expn = BF_EXP_INF and len = 0, 89 | NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored) 90 | */ 91 | typedef struct { 92 | struct bf_context_t *ctx; 93 | int sign; 94 | slimb_t expn; 95 | limb_t len; 96 | limb_t *tab; 97 | } bf_t; 98 | 99 | typedef struct { 100 | /* must be kept identical to bf_t */ 101 | struct bf_context_t *ctx; 102 | int sign; 103 | slimb_t expn; 104 | limb_t len; 105 | limb_t *tab; 106 | } bfdec_t; 107 | 108 | typedef enum { 109 | BF_RNDN, /* round to nearest, ties to even */ 110 | BF_RNDZ, /* round to zero */ 111 | BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */ 112 | BF_RNDU, /* round to +inf */ 113 | BF_RNDNA, /* round to nearest, ties away from zero */ 114 | BF_RNDA, /* round away from zero */ 115 | BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU, 116 | inexact flag is always set) */ 117 | } bf_rnd_t; 118 | 119 | /* allow subnormal numbers. Only available if the number of exponent 120 | bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */ 121 | #define BF_FLAG_SUBNORMAL (1 << 3) 122 | /* 'prec' is the precision after the radix point instead of the whole 123 | mantissa. Can only be used with bf_round() and 124 | bfdec_[add|sub|mul|div|sqrt|round](). */ 125 | #define BF_FLAG_RADPNT_PREC (1 << 4) 126 | 127 | #define BF_RND_MASK 0x7 128 | #define BF_EXP_BITS_SHIFT 5 129 | #define BF_EXP_BITS_MASK 0x3f 130 | 131 | /* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */ 132 | #define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT) 133 | 134 | /* contains the rounding mode and number of exponents bits */ 135 | typedef uint32_t bf_flags_t; 136 | 137 | typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size); 138 | 139 | typedef struct { 140 | bf_t val; 141 | limb_t prec; 142 | } BFConstCache; 143 | 144 | typedef struct bf_context_t { 145 | void *realloc_opaque; 146 | bf_realloc_func_t *realloc_func; 147 | BFConstCache log2_cache; 148 | BFConstCache pi_cache; 149 | struct BFNTTState *ntt_state; 150 | } bf_context_t; 151 | 152 | static inline int bf_get_exp_bits(bf_flags_t flags) 153 | { 154 | int e; 155 | e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK; 156 | if (e == BF_EXP_BITS_MASK) 157 | return BF_EXP_BITS_MAX + 1; 158 | else 159 | return BF_EXP_BITS_MAX - e; 160 | } 161 | 162 | static inline bf_flags_t bf_set_exp_bits(int n) 163 | { 164 | return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT; 165 | } 166 | 167 | /* returned status */ 168 | #define BF_ST_INVALID_OP (1 << 0) 169 | #define BF_ST_DIVIDE_ZERO (1 << 1) 170 | #define BF_ST_OVERFLOW (1 << 2) 171 | #define BF_ST_UNDERFLOW (1 << 3) 172 | #define BF_ST_INEXACT (1 << 4) 173 | /* indicate that a memory allocation error occured. NaN is returned */ 174 | #define BF_ST_MEM_ERROR (1 << 5) 175 | 176 | #define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */ 177 | 178 | static inline slimb_t bf_max(slimb_t a, slimb_t b) 179 | { 180 | if (a > b) 181 | return a; 182 | else 183 | return b; 184 | } 185 | 186 | static inline slimb_t bf_min(slimb_t a, slimb_t b) 187 | { 188 | if (a < b) 189 | return a; 190 | else 191 | return b; 192 | } 193 | 194 | void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func, 195 | void *realloc_opaque); 196 | void bf_context_end(bf_context_t *s); 197 | /* free memory allocated for the bf cache data */ 198 | void bf_clear_cache(bf_context_t *s); 199 | 200 | static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size) 201 | { 202 | return s->realloc_func(s->realloc_opaque, ptr, size); 203 | } 204 | 205 | /* 'size' must be != 0 */ 206 | static inline void *bf_malloc(bf_context_t *s, size_t size) 207 | { 208 | return bf_realloc(s, NULL, size); 209 | } 210 | 211 | static inline void bf_free(bf_context_t *s, void *ptr) 212 | { 213 | /* must test ptr otherwise equivalent to malloc(0) */ 214 | if (ptr) 215 | bf_realloc(s, ptr, 0); 216 | } 217 | 218 | void bf_init(bf_context_t *s, bf_t *r); 219 | 220 | static inline void bf_delete(bf_t *r) 221 | { 222 | bf_context_t *s = r->ctx; 223 | /* we accept to delete a zeroed bf_t structure */ 224 | if (s && r->tab) { 225 | bf_realloc(s, r->tab, 0); 226 | } 227 | } 228 | 229 | static inline void bf_neg(bf_t *r) 230 | { 231 | r->sign ^= 1; 232 | } 233 | 234 | static inline int bf_is_finite(const bf_t *a) 235 | { 236 | return (a->expn < BF_EXP_INF); 237 | } 238 | 239 | static inline int bf_is_nan(const bf_t *a) 240 | { 241 | return (a->expn == BF_EXP_NAN); 242 | } 243 | 244 | static inline int bf_is_zero(const bf_t *a) 245 | { 246 | return (a->expn == BF_EXP_ZERO); 247 | } 248 | 249 | static inline void bf_memcpy(bf_t *r, const bf_t *a) 250 | { 251 | *r = *a; 252 | } 253 | 254 | int bf_set_ui(bf_t *r, uint64_t a); 255 | int bf_set_si(bf_t *r, int64_t a); 256 | void bf_set_nan(bf_t *r); 257 | void bf_set_zero(bf_t *r, int is_neg); 258 | void bf_set_inf(bf_t *r, int is_neg); 259 | int bf_set(bf_t *r, const bf_t *a); 260 | void bf_move(bf_t *r, bf_t *a); 261 | int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode); 262 | int bf_set_float64(bf_t *a, double d); 263 | 264 | int bf_cmpu(const bf_t *a, const bf_t *b); 265 | int bf_cmp_full(const bf_t *a, const bf_t *b); 266 | int bf_cmp(const bf_t *a, const bf_t *b); 267 | static inline int bf_cmp_eq(const bf_t *a, const bf_t *b) 268 | { 269 | return bf_cmp(a, b) == 0; 270 | } 271 | 272 | static inline int bf_cmp_le(const bf_t *a, const bf_t *b) 273 | { 274 | return bf_cmp(a, b) <= 0; 275 | } 276 | 277 | static inline int bf_cmp_lt(const bf_t *a, const bf_t *b) 278 | { 279 | return bf_cmp(a, b) < 0; 280 | } 281 | 282 | int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); 283 | int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); 284 | int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); 285 | int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); 286 | int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags); 287 | int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, 288 | bf_flags_t flags); 289 | int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags); 290 | int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); 291 | #define BF_DIVREM_EUCLIDIAN BF_RNDF 292 | int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, 293 | limb_t prec, bf_flags_t flags, int rnd_mode); 294 | int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, 295 | bf_flags_t flags, int rnd_mode); 296 | int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, 297 | bf_flags_t flags, int rnd_mode); 298 | /* round to integer with infinite precision */ 299 | int bf_rint(bf_t *r, int rnd_mode); 300 | int bf_round(bf_t *r, limb_t prec, bf_flags_t flags); 301 | int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a); 302 | int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 303 | slimb_t bf_get_exp_min(const bf_t *a); 304 | int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b); 305 | int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b); 306 | int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b); 307 | 308 | /* additional flags for bf_atof */ 309 | /* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */ 310 | #define BF_ATOF_NO_HEX (1 << 16) 311 | /* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */ 312 | #define BF_ATOF_BIN_OCT (1 << 17) 313 | /* Do not parse NaN or Inf */ 314 | #define BF_ATOF_NO_NAN_INF (1 << 18) 315 | /* return the exponent separately */ 316 | #define BF_ATOF_EXPONENT (1 << 19) 317 | 318 | int bf_atof(bf_t *a, const char *str, const char **pnext, int radix, 319 | limb_t prec, bf_flags_t flags); 320 | /* this version accepts prec = BF_PREC_INF and returns the radix 321 | exponent */ 322 | int bf_atof2(bf_t *r, slimb_t *pexponent, 323 | const char *str, const char **pnext, int radix, 324 | limb_t prec, bf_flags_t flags); 325 | int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, 326 | slimb_t expn, limb_t prec, bf_flags_t flags); 327 | 328 | 329 | /* Conversion of floating point number to string. Return a null 330 | terminated string or NULL if memory error. *plen contains its 331 | length if plen != NULL. The exponent letter is "e" for base 10, 332 | "p" for bases 2, 8, 16 with a binary exponent and "@" for the other 333 | bases. */ 334 | 335 | #define BF_FTOA_FORMAT_MASK (3 << 16) 336 | 337 | /* fixed format: prec significant digits rounded with (flags & 338 | BF_RND_MASK). Exponential notation is used if too many zeros are 339 | needed.*/ 340 | #define BF_FTOA_FORMAT_FIXED (0 << 16) 341 | /* fractional format: prec digits after the decimal point rounded with 342 | (flags & BF_RND_MASK) */ 343 | #define BF_FTOA_FORMAT_FRAC (1 << 16) 344 | /* free format: 345 | 346 | For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum 347 | number of digits to represent 'a'. The precision and the rounding 348 | mode are ignored. 349 | 350 | For the non binary radices with bf_ftoa(): use as many digits as 351 | necessary so that bf_atof() return the same number when using 352 | precision 'prec', rounding to nearest and the subnormal 353 | configuration of 'flags'. The result is meaningful only if 'a' is 354 | already rounded to 'prec' bits. If the subnormal flag is set, the 355 | exponent in 'flags' must also be set to the desired exponent range. 356 | */ 357 | #define BF_FTOA_FORMAT_FREE (2 << 16) 358 | /* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits 359 | (takes more computation time). Identical to BF_FTOA_FORMAT_FREE for 360 | binary radices with bf_ftoa() and for bfdec_ftoa(). */ 361 | #define BF_FTOA_FORMAT_FREE_MIN (3 << 16) 362 | 363 | /* force exponential notation for fixed or free format */ 364 | #define BF_FTOA_FORCE_EXP (1 << 20) 365 | /* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for 366 | base 2 if non zero value */ 367 | #define BF_FTOA_ADD_PREFIX (1 << 21) 368 | /* return "Infinity" instead of "Inf" and add a "+" for positive 369 | exponents */ 370 | #define BF_FTOA_JS_QUIRKS (1 << 22) 371 | 372 | char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec, 373 | bf_flags_t flags); 374 | 375 | /* modulo 2^n instead of saturation. NaN and infinity return 0 */ 376 | #define BF_GET_INT_MOD (1 << 0) 377 | int bf_get_int32(int *pres, const bf_t *a, int flags); 378 | int bf_get_int64(int64_t *pres, const bf_t *a, int flags); 379 | int bf_get_uint64(uint64_t *pres, const bf_t *a); 380 | 381 | /* the following functions are exported for testing only. */ 382 | void mp_print_str(const char *str, const limb_t *tab, limb_t n); 383 | void bf_print_str(const char *str, const bf_t *a); 384 | int bf_resize(bf_t *r, limb_t len); 385 | int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len); 386 | int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags); 387 | int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k); 388 | slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, 389 | int is_ceil1); 390 | int mp_mul(bf_context_t *s, limb_t *result, 391 | const limb_t *op1, limb_t op1_size, 392 | const limb_t *op2, limb_t op2_size); 393 | limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, 394 | limb_t n, limb_t carry); 395 | limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n); 396 | int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n); 397 | int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n); 398 | limb_t bf_isqrt(limb_t a); 399 | 400 | /* transcendental functions */ 401 | int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags); 402 | int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags); 403 | int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 404 | int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 405 | #define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */ 406 | int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags); 407 | int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 408 | int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 409 | int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 410 | int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 411 | int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x, 412 | limb_t prec, bf_flags_t flags); 413 | int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 414 | int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 415 | 416 | /* decimal floating point */ 417 | 418 | static inline void bfdec_init(bf_context_t *s, bfdec_t *r) 419 | { 420 | bf_init(s, (bf_t *)r); 421 | } 422 | static inline void bfdec_delete(bfdec_t *r) 423 | { 424 | bf_delete((bf_t *)r); 425 | } 426 | 427 | static inline void bfdec_neg(bfdec_t *r) 428 | { 429 | r->sign ^= 1; 430 | } 431 | 432 | static inline int bfdec_is_finite(const bfdec_t *a) 433 | { 434 | return (a->expn < BF_EXP_INF); 435 | } 436 | 437 | static inline int bfdec_is_nan(const bfdec_t *a) 438 | { 439 | return (a->expn == BF_EXP_NAN); 440 | } 441 | 442 | static inline int bfdec_is_zero(const bfdec_t *a) 443 | { 444 | return (a->expn == BF_EXP_ZERO); 445 | } 446 | 447 | static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a) 448 | { 449 | bf_memcpy((bf_t *)r, (const bf_t *)a); 450 | } 451 | 452 | int bfdec_set_ui(bfdec_t *r, uint64_t a); 453 | int bfdec_set_si(bfdec_t *r, int64_t a); 454 | 455 | static inline void bfdec_set_nan(bfdec_t *r) 456 | { 457 | bf_set_nan((bf_t *)r); 458 | } 459 | static inline void bfdec_set_zero(bfdec_t *r, int is_neg) 460 | { 461 | bf_set_zero((bf_t *)r, is_neg); 462 | } 463 | static inline void bfdec_set_inf(bfdec_t *r, int is_neg) 464 | { 465 | bf_set_inf((bf_t *)r, is_neg); 466 | } 467 | static inline int bfdec_set(bfdec_t *r, const bfdec_t *a) 468 | { 469 | return bf_set((bf_t *)r, (bf_t *)a); 470 | } 471 | static inline void bfdec_move(bfdec_t *r, bfdec_t *a) 472 | { 473 | bf_move((bf_t *)r, (bf_t *)a); 474 | } 475 | static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b) 476 | { 477 | return bf_cmpu((const bf_t *)a, (const bf_t *)b); 478 | } 479 | static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b) 480 | { 481 | return bf_cmp_full((const bf_t *)a, (const bf_t *)b); 482 | } 483 | static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b) 484 | { 485 | return bf_cmp((const bf_t *)a, (const bf_t *)b); 486 | } 487 | static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b) 488 | { 489 | return bfdec_cmp(a, b) == 0; 490 | } 491 | static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b) 492 | { 493 | return bfdec_cmp(a, b) <= 0; 494 | } 495 | static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b) 496 | { 497 | return bfdec_cmp(a, b) < 0; 498 | } 499 | 500 | int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, 501 | bf_flags_t flags); 502 | int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, 503 | bf_flags_t flags); 504 | int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec, 505 | bf_flags_t flags); 506 | int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, 507 | bf_flags_t flags); 508 | int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec, 509 | bf_flags_t flags); 510 | int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, 511 | bf_flags_t flags); 512 | int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, 513 | limb_t prec, bf_flags_t flags, int rnd_mode); 514 | int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, 515 | bf_flags_t flags, int rnd_mode); 516 | int bfdec_rint(bfdec_t *r, int rnd_mode); 517 | int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags); 518 | int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags); 519 | int bfdec_get_int32(int *pres, const bfdec_t *a); 520 | int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b); 521 | 522 | char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags); 523 | int bfdec_atof(bfdec_t *r, const char *str, const char **pnext, 524 | limb_t prec, bf_flags_t flags); 525 | 526 | /* the following functions are exported for testing only. */ 527 | extern const limb_t mp_pow_dec[LIMB_DIGITS + 1]; 528 | void bfdec_print_str(const char *str, const bfdec_t *a); 529 | static inline int bfdec_resize(bfdec_t *r, limb_t len) 530 | { 531 | return bf_resize((bf_t *)r, len); 532 | } 533 | int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags); 534 | 535 | #endif /* LIBBF_H */ 536 | -------------------------------------------------------------------------------- /src/cutils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * C utilities 3 | * 4 | * Copyright (c) 2017 Fabrice Bellard 5 | * Copyright (c) 2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "cutils.h" 31 | 32 | void pstrcpy(char *buf, int buf_size, const char *str) 33 | { 34 | int c; 35 | char *q = buf; 36 | 37 | if (buf_size <= 0) 38 | return; 39 | 40 | for(;;) { 41 | c = *str++; 42 | if (c == 0 || q >= buf + buf_size - 1) 43 | break; 44 | *q++ = c; 45 | } 46 | *q = '\0'; 47 | } 48 | 49 | /* strcat and truncate. */ 50 | char *pstrcat(char *buf, int buf_size, const char *s) 51 | { 52 | int len; 53 | len = strlen(buf); 54 | if (len < buf_size) 55 | pstrcpy(buf + len, buf_size - len, s); 56 | return buf; 57 | } 58 | 59 | int strstart(const char *str, const char *val, const char **ptr) 60 | { 61 | const char *p, *q; 62 | p = str; 63 | q = val; 64 | while (*q != '\0') { 65 | if (*p != *q) 66 | return 0; 67 | p++; 68 | q++; 69 | } 70 | if (ptr) 71 | *ptr = p; 72 | return 1; 73 | } 74 | 75 | int has_suffix(const char *str, const char *suffix) 76 | { 77 | size_t len = strlen(str); 78 | size_t slen = strlen(suffix); 79 | return (len >= slen && !memcmp(str + len - slen, suffix, slen)); 80 | } 81 | 82 | /* Dynamic buffer package */ 83 | 84 | static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size) 85 | { 86 | return realloc(ptr, size); 87 | } 88 | 89 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func) 90 | { 91 | memset(s, 0, sizeof(*s)); 92 | if (!realloc_func) 93 | realloc_func = dbuf_default_realloc; 94 | s->opaque = opaque; 95 | s->realloc_func = realloc_func; 96 | } 97 | 98 | void dbuf_init(DynBuf *s) 99 | { 100 | dbuf_init2(s, NULL, NULL); 101 | } 102 | 103 | /* return < 0 if error */ 104 | int dbuf_realloc(DynBuf *s, size_t new_size) 105 | { 106 | size_t size; 107 | uint8_t *new_buf; 108 | if (new_size > s->allocated_size) { 109 | if (s->error) 110 | return -1; 111 | size = s->allocated_size * 3 / 2; 112 | if (size > new_size) 113 | new_size = size; 114 | new_buf = s->realloc_func(s->opaque, s->buf, new_size); 115 | if (!new_buf) { 116 | s->error = TRUE; 117 | return -1; 118 | } 119 | s->buf = new_buf; 120 | s->allocated_size = new_size; 121 | } 122 | return 0; 123 | } 124 | 125 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) 126 | { 127 | size_t end; 128 | end = offset + len; 129 | if (dbuf_realloc(s, end)) 130 | return -1; 131 | memcpy(s->buf + offset, data, len); 132 | if (end > s->size) 133 | s->size = end; 134 | return 0; 135 | } 136 | 137 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len) 138 | { 139 | if (unlikely((s->size + len) > s->allocated_size)) { 140 | if (dbuf_realloc(s, s->size + len)) 141 | return -1; 142 | } 143 | memcpy(s->buf + s->size, data, len); 144 | s->size += len; 145 | return 0; 146 | } 147 | 148 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len) 149 | { 150 | if (unlikely((s->size + len) > s->allocated_size)) { 151 | if (dbuf_realloc(s, s->size + len)) 152 | return -1; 153 | } 154 | memcpy(s->buf + s->size, s->buf + offset, len); 155 | s->size += len; 156 | return 0; 157 | } 158 | 159 | int dbuf_putc(DynBuf *s, uint8_t c) 160 | { 161 | return dbuf_put(s, &c, 1); 162 | } 163 | 164 | int dbuf_putstr(DynBuf *s, const char *str) 165 | { 166 | return dbuf_put(s, (const uint8_t *)str, strlen(str)); 167 | } 168 | 169 | int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, 170 | const char *fmt, ...) 171 | { 172 | va_list ap; 173 | char buf[128]; 174 | int len; 175 | 176 | va_start(ap, fmt); 177 | len = vsnprintf(buf, sizeof(buf), fmt, ap); 178 | va_end(ap); 179 | if (len < sizeof(buf)) { 180 | /* fast case */ 181 | return dbuf_put(s, (uint8_t *)buf, len); 182 | } else { 183 | if (dbuf_realloc(s, s->size + len + 1)) 184 | return -1; 185 | va_start(ap, fmt); 186 | vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size, 187 | fmt, ap); 188 | va_end(ap); 189 | s->size += len; 190 | } 191 | return 0; 192 | } 193 | 194 | void dbuf_free(DynBuf *s) 195 | { 196 | /* we test s->buf as a fail safe to avoid crashing if dbuf_free() 197 | is called twice */ 198 | if (s->buf) { 199 | s->realloc_func(s->opaque, s->buf, 0); 200 | } 201 | memset(s, 0, sizeof(*s)); 202 | } 203 | 204 | /* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes 205 | are output. */ 206 | int unicode_to_utf8(uint8_t *buf, unsigned int c) 207 | { 208 | uint8_t *q = buf; 209 | 210 | if (c < 0x80) { 211 | *q++ = c; 212 | } else { 213 | if (c < 0x800) { 214 | *q++ = (c >> 6) | 0xc0; 215 | } else { 216 | if (c < 0x10000) { 217 | *q++ = (c >> 12) | 0xe0; 218 | } else { 219 | if (c < 0x00200000) { 220 | *q++ = (c >> 18) | 0xf0; 221 | } else { 222 | if (c < 0x04000000) { 223 | *q++ = (c >> 24) | 0xf8; 224 | } else if (c < 0x80000000) { 225 | *q++ = (c >> 30) | 0xfc; 226 | *q++ = ((c >> 24) & 0x3f) | 0x80; 227 | } else { 228 | return 0; 229 | } 230 | *q++ = ((c >> 18) & 0x3f) | 0x80; 231 | } 232 | *q++ = ((c >> 12) & 0x3f) | 0x80; 233 | } 234 | *q++ = ((c >> 6) & 0x3f) | 0x80; 235 | } 236 | *q++ = (c & 0x3f) | 0x80; 237 | } 238 | return q - buf; 239 | } 240 | 241 | static const unsigned int utf8_min_code[5] = { 242 | 0x80, 0x800, 0x10000, 0x00200000, 0x04000000, 243 | }; 244 | 245 | static const unsigned char utf8_first_code_mask[5] = { 246 | 0x1f, 0xf, 0x7, 0x3, 0x1, 247 | }; 248 | 249 | /* return -1 if error. *pp is not updated in this case. max_len must 250 | be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */ 251 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) 252 | { 253 | int l, c, b, i; 254 | 255 | c = *p++; 256 | if (c < 0x80) { 257 | *pp = p; 258 | return c; 259 | } 260 | switch(c) { 261 | case 0xc0: case 0xc1: case 0xc2: case 0xc3: 262 | case 0xc4: case 0xc5: case 0xc6: case 0xc7: 263 | case 0xc8: case 0xc9: case 0xca: case 0xcb: 264 | case 0xcc: case 0xcd: case 0xce: case 0xcf: 265 | case 0xd0: case 0xd1: case 0xd2: case 0xd3: 266 | case 0xd4: case 0xd5: case 0xd6: case 0xd7: 267 | case 0xd8: case 0xd9: case 0xda: case 0xdb: 268 | case 0xdc: case 0xdd: case 0xde: case 0xdf: 269 | l = 1; 270 | break; 271 | case 0xe0: case 0xe1: case 0xe2: case 0xe3: 272 | case 0xe4: case 0xe5: case 0xe6: case 0xe7: 273 | case 0xe8: case 0xe9: case 0xea: case 0xeb: 274 | case 0xec: case 0xed: case 0xee: case 0xef: 275 | l = 2; 276 | break; 277 | case 0xf0: case 0xf1: case 0xf2: case 0xf3: 278 | case 0xf4: case 0xf5: case 0xf6: case 0xf7: 279 | l = 3; 280 | break; 281 | case 0xf8: case 0xf9: case 0xfa: case 0xfb: 282 | l = 4; 283 | break; 284 | case 0xfc: case 0xfd: 285 | l = 5; 286 | break; 287 | default: 288 | return -1; 289 | } 290 | /* check that we have enough characters */ 291 | if (l > (max_len - 1)) 292 | return -1; 293 | c &= utf8_first_code_mask[l - 1]; 294 | for(i = 0; i < l; i++) { 295 | b = *p++; 296 | if (b < 0x80 || b >= 0xc0) 297 | return -1; 298 | c = (c << 6) | (b & 0x3f); 299 | } 300 | if (c < utf8_min_code[l - 1]) 301 | return -1; 302 | *pp = p; 303 | return c; 304 | } 305 | 306 | #if 0 307 | 308 | #if defined(EMSCRIPTEN) || defined(__ANDROID__) 309 | 310 | static void *rqsort_arg; 311 | static int (*rqsort_cmp)(const void *, const void *, void *); 312 | 313 | static int rqsort_cmp2(const void *p1, const void *p2) 314 | { 315 | return rqsort_cmp(p1, p2, rqsort_arg); 316 | } 317 | 318 | /* not reentrant, but not needed with emscripten */ 319 | void rqsort(void *base, size_t nmemb, size_t size, 320 | int (*cmp)(const void *, const void *, void *), 321 | void *arg) 322 | { 323 | rqsort_arg = arg; 324 | rqsort_cmp = cmp; 325 | qsort(base, nmemb, size, rqsort_cmp2); 326 | } 327 | 328 | #endif 329 | 330 | #else 331 | 332 | typedef void (*exchange_f)(void *a, void *b, size_t size); 333 | typedef int (*cmp_f)(const void *, const void *, void *opaque); 334 | 335 | static void exchange_bytes(void *a, void *b, size_t size) { 336 | uint8_t *ap = (uint8_t *)a; 337 | uint8_t *bp = (uint8_t *)b; 338 | 339 | while (size-- != 0) { 340 | uint8_t t = *ap; 341 | *ap++ = *bp; 342 | *bp++ = t; 343 | } 344 | } 345 | 346 | static void exchange_one_byte(void *a, void *b, size_t size) { 347 | uint8_t *ap = (uint8_t *)a; 348 | uint8_t *bp = (uint8_t *)b; 349 | uint8_t t = *ap; 350 | *ap = *bp; 351 | *bp = t; 352 | } 353 | 354 | static void exchange_int16s(void *a, void *b, size_t size) { 355 | uint16_t *ap = (uint16_t *)a; 356 | uint16_t *bp = (uint16_t *)b; 357 | 358 | for (size /= sizeof(uint16_t); size-- != 0;) { 359 | uint16_t t = *ap; 360 | *ap++ = *bp; 361 | *bp++ = t; 362 | } 363 | } 364 | 365 | static void exchange_one_int16(void *a, void *b, size_t size) { 366 | uint16_t *ap = (uint16_t *)a; 367 | uint16_t *bp = (uint16_t *)b; 368 | uint16_t t = *ap; 369 | *ap = *bp; 370 | *bp = t; 371 | } 372 | 373 | static void exchange_int32s(void *a, void *b, size_t size) { 374 | uint32_t *ap = (uint32_t *)a; 375 | uint32_t *bp = (uint32_t *)b; 376 | 377 | for (size /= sizeof(uint32_t); size-- != 0;) { 378 | uint32_t t = *ap; 379 | *ap++ = *bp; 380 | *bp++ = t; 381 | } 382 | } 383 | 384 | static void exchange_one_int32(void *a, void *b, size_t size) { 385 | uint32_t *ap = (uint32_t *)a; 386 | uint32_t *bp = (uint32_t *)b; 387 | uint32_t t = *ap; 388 | *ap = *bp; 389 | *bp = t; 390 | } 391 | 392 | static void exchange_int64s(void *a, void *b, size_t size) { 393 | uint64_t *ap = (uint64_t *)a; 394 | uint64_t *bp = (uint64_t *)b; 395 | 396 | for (size /= sizeof(uint64_t); size-- != 0;) { 397 | uint64_t t = *ap; 398 | *ap++ = *bp; 399 | *bp++ = t; 400 | } 401 | } 402 | 403 | static void exchange_one_int64(void *a, void *b, size_t size) { 404 | uint64_t *ap = (uint64_t *)a; 405 | uint64_t *bp = (uint64_t *)b; 406 | uint64_t t = *ap; 407 | *ap = *bp; 408 | *bp = t; 409 | } 410 | 411 | static void exchange_int128s(void *a, void *b, size_t size) { 412 | uint64_t *ap = (uint64_t *)a; 413 | uint64_t *bp = (uint64_t *)b; 414 | 415 | for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) { 416 | uint64_t t = ap[0]; 417 | uint64_t u = ap[1]; 418 | ap[0] = bp[0]; 419 | ap[1] = bp[1]; 420 | bp[0] = t; 421 | bp[1] = u; 422 | } 423 | } 424 | 425 | static void exchange_one_int128(void *a, void *b, size_t size) { 426 | uint64_t *ap = (uint64_t *)a; 427 | uint64_t *bp = (uint64_t *)b; 428 | uint64_t t = ap[0]; 429 | uint64_t u = ap[1]; 430 | ap[0] = bp[0]; 431 | ap[1] = bp[1]; 432 | bp[0] = t; 433 | bp[1] = u; 434 | } 435 | 436 | static inline exchange_f exchange_func(const void *base, size_t size) { 437 | switch (((uintptr_t)base | (uintptr_t)size) & 15) { 438 | case 0: 439 | if (size == sizeof(uint64_t) * 2) 440 | return exchange_one_int128; 441 | else 442 | return exchange_int128s; 443 | case 8: 444 | if (size == sizeof(uint64_t)) 445 | return exchange_one_int64; 446 | else 447 | return exchange_int64s; 448 | case 4: 449 | case 12: 450 | if (size == sizeof(uint32_t)) 451 | return exchange_one_int32; 452 | else 453 | return exchange_int32s; 454 | case 2: 455 | case 6: 456 | case 10: 457 | case 14: 458 | if (size == sizeof(uint16_t)) 459 | return exchange_one_int16; 460 | else 461 | return exchange_int16s; 462 | default: 463 | if (size == 1) 464 | return exchange_one_byte; 465 | else 466 | return exchange_bytes; 467 | } 468 | } 469 | 470 | static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) 471 | { 472 | uint8_t *basep = (uint8_t *)base; 473 | size_t i, n, c, r; 474 | exchange_f swap = exchange_func(base, size); 475 | 476 | if (nmemb > 1) { 477 | i = (nmemb / 2) * size; 478 | n = nmemb * size; 479 | 480 | while (i > 0) { 481 | i -= size; 482 | for (r = i; (c = r * 2 + size) < n; r = c) { 483 | if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0) 484 | c += size; 485 | if (cmp(basep + r, basep + c, opaque) > 0) 486 | break; 487 | swap(basep + r, basep + c, size); 488 | } 489 | } 490 | for (i = n - size; i > 0; i -= size) { 491 | swap(basep, basep + i, size); 492 | 493 | for (r = 0; (c = r * 2 + size) < i; r = c) { 494 | if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0) 495 | c += size; 496 | if (cmp(basep + r, basep + c, opaque) > 0) 497 | break; 498 | swap(basep + r, basep + c, size); 499 | } 500 | } 501 | } 502 | } 503 | 504 | static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque) 505 | { 506 | return cmp(a, b, opaque) < 0 ? 507 | (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) : 508 | (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c )); 509 | } 510 | 511 | /* pointer based version with local stack and insertion sort threshhold */ 512 | void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) 513 | { 514 | struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack; 515 | uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m; 516 | size_t m4, i, lt, gt, span, span2; 517 | int c, depth; 518 | exchange_f swap = exchange_func(base, size); 519 | exchange_f swap_block = exchange_func(base, size | 128); 520 | 521 | if (nmemb < 2 || size <= 0) 522 | return; 523 | 524 | sp->base = (uint8_t *)base; 525 | sp->count = nmemb; 526 | sp->depth = 0; 527 | sp++; 528 | 529 | while (sp > stack) { 530 | sp--; 531 | ptr = sp->base; 532 | nmemb = sp->count; 533 | depth = sp->depth; 534 | 535 | while (nmemb > 6) { 536 | if (++depth > 50) { 537 | /* depth check to ensure worst case logarithmic time */ 538 | heapsortx(ptr, nmemb, size, cmp, opaque); 539 | nmemb = 0; 540 | break; 541 | } 542 | /* select median of 3 from 1/4, 1/2, 3/4 positions */ 543 | /* should use median of 5 or 9? */ 544 | m4 = (nmemb >> 2) * size; 545 | m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque); 546 | swap(ptr, m, size); /* move the pivot to the start or the array */ 547 | i = lt = 1; 548 | pi = plt = ptr + size; 549 | gt = nmemb; 550 | pj = pgt = top = ptr + nmemb * size; 551 | for (;;) { 552 | while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) { 553 | if (c == 0) { 554 | swap(plt, pi, size); 555 | lt++; 556 | plt += size; 557 | } 558 | i++; 559 | pi += size; 560 | } 561 | while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) { 562 | if (c == 0) { 563 | gt--; 564 | pgt -= size; 565 | swap(pgt, pj, size); 566 | } 567 | } 568 | if (pi >= pj) 569 | break; 570 | swap(pi, pj, size); 571 | i++; 572 | pi += size; 573 | } 574 | /* array has 4 parts: 575 | * from 0 to lt excluded: elements identical to pivot 576 | * from lt to pi excluded: elements smaller than pivot 577 | * from pi to gt excluded: elements greater than pivot 578 | * from gt to n excluded: elements identical to pivot 579 | */ 580 | /* move elements identical to pivot in the middle of the array: */ 581 | /* swap values in ranges [0..lt[ and [i-lt..i[ 582 | swapping the smallest span between lt and i-lt is sufficient 583 | */ 584 | span = plt - ptr; 585 | span2 = pi - plt; 586 | lt = i - lt; 587 | if (span > span2) 588 | span = span2; 589 | swap_block(ptr, pi - span, span); 590 | /* swap values in ranges [gt..top[ and [i..top-(top-gt)[ 591 | swapping the smallest span between top-gt and gt-i is sufficient 592 | */ 593 | span = top - pgt; 594 | span2 = pgt - pi; 595 | pgt = top - span2; 596 | gt = nmemb - (gt - i); 597 | if (span > span2) 598 | span = span2; 599 | swap_block(pi, top - span, span); 600 | 601 | /* now array has 3 parts: 602 | * from 0 to lt excluded: elements smaller than pivot 603 | * from lt to gt excluded: elements identical to pivot 604 | * from gt to n excluded: elements greater than pivot 605 | */ 606 | /* stack the larger segment and keep processing the smaller one 607 | to minimize stack use for pathological distributions */ 608 | if (lt > nmemb - gt) { 609 | sp->base = ptr; 610 | sp->count = lt; 611 | sp->depth = depth; 612 | sp++; 613 | ptr = pgt; 614 | nmemb -= gt; 615 | } else { 616 | sp->base = pgt; 617 | sp->count = nmemb - gt; 618 | sp->depth = depth; 619 | sp++; 620 | nmemb = lt; 621 | } 622 | } 623 | /* Use insertion sort for small fragments */ 624 | for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) { 625 | for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size) 626 | swap(pj, pj - size, size); 627 | } 628 | } 629 | } 630 | 631 | #endif 632 | -------------------------------------------------------------------------------- /src/qjsc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS command line compiler 3 | * 4 | * Copyright (c) 2018-2021 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #if !defined(_WIN32) 33 | #include 34 | #endif 35 | 36 | #include "cutils.h" 37 | #include "quickjs-libc.h" 38 | 39 | typedef struct { 40 | char *name; 41 | char *short_name; 42 | int flags; 43 | } namelist_entry_t; 44 | 45 | typedef struct namelist_t { 46 | namelist_entry_t *array; 47 | int count; 48 | int size; 49 | } namelist_t; 50 | 51 | typedef struct { 52 | const char *option_name; 53 | const char *init_name; 54 | } FeatureEntry; 55 | 56 | static namelist_t cname_list; 57 | static namelist_t cmodule_list; 58 | static namelist_t init_module_list; 59 | static uint64_t feature_bitmap; 60 | static FILE *outfile; 61 | static BOOL byte_swap; 62 | static BOOL dynamic_export; 63 | static const char *c_ident_prefix = "qjsc_"; 64 | 65 | #define FE_ALL (-1) 66 | 67 | static const FeatureEntry feature_list[] = { 68 | { "date", "Date" }, 69 | { "eval", "Eval" }, 70 | { "string-normalize", "StringNormalize" }, 71 | { "regexp", "RegExp" }, 72 | { "json", "JSON" }, 73 | { "proxy", "Proxy" }, 74 | { "map", "MapSet" }, 75 | { "typedarray", "TypedArrays" }, 76 | { "promise", "Promise" }, 77 | #define FE_MODULE_LOADER 9 78 | { "module-loader", NULL }, 79 | #ifdef CONFIG_BIGNUM 80 | { "bigint", "BigInt" }, 81 | #endif 82 | }; 83 | 84 | void namelist_add(namelist_t *lp, const char *name, const char *short_name, 85 | int flags) 86 | { 87 | namelist_entry_t *e; 88 | if (lp->count == lp->size) { 89 | size_t newsize = lp->size + (lp->size >> 1) + 4; 90 | namelist_entry_t *a = 91 | realloc(lp->array, sizeof(lp->array[0]) * newsize); 92 | /* XXX: check for realloc failure */ 93 | lp->array = a; 94 | lp->size = newsize; 95 | } 96 | e = &lp->array[lp->count++]; 97 | e->name = strdup(name); 98 | if (short_name) 99 | e->short_name = strdup(short_name); 100 | else 101 | e->short_name = NULL; 102 | e->flags = flags; 103 | } 104 | 105 | void namelist_free(namelist_t *lp) 106 | { 107 | while (lp->count > 0) { 108 | namelist_entry_t *e = &lp->array[--lp->count]; 109 | free(e->name); 110 | free(e->short_name); 111 | } 112 | free(lp->array); 113 | lp->array = NULL; 114 | lp->size = 0; 115 | } 116 | 117 | namelist_entry_t *namelist_find(namelist_t *lp, const char *name) 118 | { 119 | int i; 120 | for(i = 0; i < lp->count; i++) { 121 | namelist_entry_t *e = &lp->array[i]; 122 | if (!strcmp(e->name, name)) 123 | return e; 124 | } 125 | return NULL; 126 | } 127 | 128 | static void get_c_name(char *buf, size_t buf_size, const char *file) 129 | { 130 | const char *p, *r; 131 | size_t len, i; 132 | int c; 133 | char *q; 134 | 135 | p = strrchr(file, '/'); 136 | if (!p) 137 | p = file; 138 | else 139 | p++; 140 | r = strrchr(p, '.'); 141 | if (!r) 142 | len = strlen(p); 143 | else 144 | len = r - p; 145 | pstrcpy(buf, buf_size, c_ident_prefix); 146 | q = buf + strlen(buf); 147 | for(i = 0; i < len; i++) { 148 | c = p[i]; 149 | if (!((c >= '0' && c <= '9') || 150 | (c >= 'A' && c <= 'Z') || 151 | (c >= 'a' && c <= 'z'))) { 152 | c = '_'; 153 | } 154 | if ((q - buf) < buf_size - 1) 155 | *q++ = c; 156 | } 157 | *q = '\0'; 158 | } 159 | 160 | static void dump_hex(FILE *f, const uint8_t *buf, size_t len) 161 | { 162 | size_t i, col; 163 | col = 0; 164 | for(i = 0; i < len; i++) { 165 | fprintf(f, " 0x%02x,", buf[i]); 166 | if (++col == 8) { 167 | fprintf(f, "\n"); 168 | col = 0; 169 | } 170 | } 171 | if (col != 0) 172 | fprintf(f, "\n"); 173 | } 174 | 175 | static void output_object_code(JSContext *ctx, 176 | FILE *fo, JSValueConst obj, const char *c_name, 177 | BOOL load_only) 178 | { 179 | uint8_t *out_buf; 180 | size_t out_buf_len; 181 | int flags; 182 | flags = JS_WRITE_OBJ_BYTECODE; 183 | if (byte_swap) 184 | flags |= JS_WRITE_OBJ_BSWAP; 185 | out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags); 186 | if (!out_buf) { 187 | js_std_dump_error(ctx); 188 | exit(1); 189 | } 190 | 191 | namelist_add(&cname_list, c_name, NULL, load_only); 192 | 193 | fprintf(fo, "const uint32_t %s_size = %u;\n\n", 194 | c_name, (unsigned int)out_buf_len); 195 | fprintf(fo, "const uint8_t %s[%u] = {\n", 196 | c_name, (unsigned int)out_buf_len); 197 | dump_hex(fo, out_buf, out_buf_len); 198 | fprintf(fo, "};\n\n"); 199 | 200 | js_free(ctx, out_buf); 201 | } 202 | 203 | static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m) 204 | { 205 | /* should never be called when compiling JS code */ 206 | abort(); 207 | } 208 | 209 | static void find_unique_cname(char *cname, size_t cname_size) 210 | { 211 | char cname1[1024]; 212 | int suffix_num; 213 | size_t len, max_len; 214 | assert(cname_size >= 32); 215 | /* find a C name not matching an existing module C name by 216 | adding a numeric suffix */ 217 | len = strlen(cname); 218 | max_len = cname_size - 16; 219 | if (len > max_len) 220 | cname[max_len] = '\0'; 221 | suffix_num = 1; 222 | for(;;) { 223 | snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num); 224 | if (!namelist_find(&cname_list, cname1)) 225 | break; 226 | suffix_num++; 227 | } 228 | pstrcpy(cname, cname_size, cname1); 229 | } 230 | 231 | JSModuleDef *jsc_module_loader(JSContext *ctx, 232 | const char *module_name, void *opaque) 233 | { 234 | JSModuleDef *m; 235 | namelist_entry_t *e; 236 | 237 | /* check if it is a declared C or system module */ 238 | e = namelist_find(&cmodule_list, module_name); 239 | if (e) { 240 | /* add in the static init module list */ 241 | namelist_add(&init_module_list, e->name, e->short_name, 0); 242 | /* create a dummy module */ 243 | m = JS_NewCModule(ctx, module_name, js_module_dummy_init); 244 | } else if (has_suffix(module_name, ".so")) { 245 | fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name); 246 | /* create a dummy module */ 247 | m = JS_NewCModule(ctx, module_name, js_module_dummy_init); 248 | /* the resulting executable will export its symbols for the 249 | dynamic library */ 250 | dynamic_export = TRUE; 251 | } else { 252 | size_t buf_len; 253 | uint8_t *buf; 254 | JSValue func_val; 255 | char cname[1024]; 256 | 257 | buf = js_load_file(ctx, &buf_len, module_name); 258 | if (!buf) { 259 | JS_ThrowReferenceError(ctx, "could not load module filename '%s'", 260 | module_name); 261 | return NULL; 262 | } 263 | 264 | /* compile the module */ 265 | func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, 266 | JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); 267 | js_free(ctx, buf); 268 | if (JS_IsException(func_val)) 269 | return NULL; 270 | get_c_name(cname, sizeof(cname), module_name); 271 | if (namelist_find(&cname_list, cname)) { 272 | find_unique_cname(cname, sizeof(cname)); 273 | } 274 | output_object_code(ctx, outfile, func_val, cname, TRUE); 275 | 276 | /* the module is already referenced, so we must free it */ 277 | m = JS_VALUE_GET_PTR(func_val); 278 | JS_FreeValue(ctx, func_val); 279 | } 280 | return m; 281 | } 282 | 283 | static void compile_file(JSContext *ctx, FILE *fo, 284 | const char *filename, 285 | const char *c_name1, 286 | int module) 287 | { 288 | uint8_t *buf; 289 | char c_name[1024]; 290 | int eval_flags; 291 | JSValue obj; 292 | size_t buf_len; 293 | 294 | buf = js_load_file(ctx, &buf_len, filename); 295 | if (!buf) { 296 | fprintf(stderr, "Could not load '%s'\n", filename); 297 | exit(1); 298 | } 299 | eval_flags = JS_EVAL_FLAG_COMPILE_ONLY; 300 | if (module < 0) { 301 | module = (has_suffix(filename, ".mjs") || 302 | JS_DetectModule((const char *)buf, buf_len)); 303 | } 304 | if (module) 305 | eval_flags |= JS_EVAL_TYPE_MODULE; 306 | else 307 | eval_flags |= JS_EVAL_TYPE_GLOBAL; 308 | obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags); 309 | if (JS_IsException(obj)) { 310 | js_std_dump_error(ctx); 311 | exit(1); 312 | } 313 | js_free(ctx, buf); 314 | if (c_name1) { 315 | pstrcpy(c_name, sizeof(c_name), c_name1); 316 | } else { 317 | get_c_name(c_name, sizeof(c_name), filename); 318 | } 319 | output_object_code(ctx, fo, obj, c_name, FALSE); 320 | JS_FreeValue(ctx, obj); 321 | } 322 | 323 | static const char main_c_template1[] = 324 | "int main(int argc, char **argv)\n" 325 | "{\n" 326 | " JSRuntime *rt;\n" 327 | " JSContext *ctx;\n" 328 | " rt = JS_NewRuntime();\n" 329 | " js_std_set_worker_new_context_func(JS_NewCustomContext);\n" 330 | " js_std_init_handlers(rt);\n" 331 | ; 332 | 333 | static const char main_c_template2[] = 334 | " js_std_loop(ctx);\n" 335 | " JS_FreeContext(ctx);\n" 336 | " JS_FreeRuntime(rt);\n" 337 | " return 0;\n" 338 | "}\n"; 339 | 340 | #define PROG_NAME "qjsc" 341 | 342 | void help(void) 343 | { 344 | printf("QuickJS Compiler version " CONFIG_VERSION "\n" 345 | "usage: " PROG_NAME " [options] [files]\n" 346 | "\n" 347 | "options are:\n" 348 | "-c only output bytecode in a C file\n" 349 | "-e output main() and bytecode in a C file (default = executable output)\n" 350 | "-o output set the output filename\n" 351 | "-N cname set the C name of the generated data\n" 352 | "-m compile as Javascript module (default=autodetect)\n" 353 | "-D module_name compile a dynamically loaded module or worker\n" 354 | "-M module_name[,cname] add initialization code for an external C module\n" 355 | "-x byte swapped output\n" 356 | "-p prefix set the prefix of the generated C names\n" 357 | "-S n set the maximum stack size to 'n' bytes (default=%d)\n", 358 | JS_DEFAULT_STACK_SIZE); 359 | #ifdef CONFIG_LTO 360 | { 361 | int i; 362 | printf("-flto use link time optimization\n"); 363 | printf("-fbignum enable bignum extensions\n"); 364 | printf("-fno-["); 365 | for(i = 0; i < countof(feature_list); i++) { 366 | if (i != 0) 367 | printf("|"); 368 | printf("%s", feature_list[i].option_name); 369 | } 370 | printf("]\n" 371 | " disable selected language features (smaller code size)\n"); 372 | } 373 | #endif 374 | exit(1); 375 | } 376 | 377 | #if defined(CONFIG_CC) && !defined(_WIN32) 378 | 379 | int exec_cmd(char **argv) 380 | { 381 | int pid, status, ret; 382 | 383 | pid = fork(); 384 | if (pid == 0) { 385 | execvp(argv[0], argv); 386 | exit(1); 387 | } 388 | 389 | for(;;) { 390 | ret = waitpid(pid, &status, 0); 391 | if (ret == pid && WIFEXITED(status)) 392 | break; 393 | } 394 | return WEXITSTATUS(status); 395 | } 396 | 397 | static int output_executable(const char *out_filename, const char *cfilename, 398 | BOOL use_lto, BOOL verbose, const char *exename) 399 | { 400 | const char *argv[64]; 401 | const char **arg, *bn_suffix, *lto_suffix; 402 | char libjsname[1024]; 403 | char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; 404 | int ret; 405 | 406 | /* get the directory of the executable */ 407 | pstrcpy(exe_dir, sizeof(exe_dir), exename); 408 | p = strrchr(exe_dir, '/'); 409 | if (p) { 410 | *p = '\0'; 411 | } else { 412 | pstrcpy(exe_dir, sizeof(exe_dir), "."); 413 | } 414 | 415 | /* if 'quickjs.h' is present at the same path as the executable, we 416 | use it as include and lib directory */ 417 | snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir); 418 | if (access(buf, R_OK) == 0) { 419 | pstrcpy(inc_dir, sizeof(inc_dir), exe_dir); 420 | pstrcpy(lib_dir, sizeof(lib_dir), exe_dir); 421 | } else { 422 | snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX); 423 | snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX); 424 | } 425 | 426 | lto_suffix = ""; 427 | bn_suffix = ""; 428 | 429 | arg = argv; 430 | *arg++ = CONFIG_CC; 431 | *arg++ = "-O2"; 432 | #ifdef CONFIG_LTO 433 | if (use_lto) { 434 | *arg++ = "-flto"; 435 | lto_suffix = ".lto"; 436 | } 437 | #endif 438 | /* XXX: use the executable path to find the includes files and 439 | libraries */ 440 | *arg++ = "-D"; 441 | *arg++ = "_GNU_SOURCE"; 442 | *arg++ = "-I"; 443 | *arg++ = inc_dir; 444 | *arg++ = "-o"; 445 | *arg++ = out_filename; 446 | if (dynamic_export) 447 | *arg++ = "-rdynamic"; 448 | *arg++ = cfilename; 449 | snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a", 450 | lib_dir, bn_suffix, lto_suffix); 451 | *arg++ = libjsname; 452 | *arg++ = "-lm"; 453 | *arg++ = "-ldl"; 454 | *arg++ = "-lpthread"; 455 | *arg = NULL; 456 | 457 | if (verbose) { 458 | for(arg = argv; *arg != NULL; arg++) 459 | printf("%s ", *arg); 460 | printf("\n"); 461 | } 462 | 463 | ret = exec_cmd((char **)argv); 464 | unlink(cfilename); 465 | return ret; 466 | } 467 | #else 468 | static int output_executable(const char *out_filename, const char *cfilename, 469 | BOOL use_lto, BOOL verbose, const char *exename) 470 | { 471 | fprintf(stderr, "Executable output is not supported for this target\n"); 472 | exit(1); 473 | return 0; 474 | } 475 | #endif 476 | 477 | 478 | typedef enum { 479 | OUTPUT_C, 480 | OUTPUT_C_MAIN, 481 | OUTPUT_EXECUTABLE, 482 | } OutputTypeEnum; 483 | 484 | int main(int argc, char **argv) 485 | { 486 | int c, i, verbose; 487 | const char *out_filename, *cname; 488 | char cfilename[1024]; 489 | FILE *fo; 490 | JSRuntime *rt; 491 | JSContext *ctx; 492 | BOOL use_lto; 493 | int module; 494 | OutputTypeEnum output_type; 495 | size_t stack_size; 496 | #ifdef CONFIG_BIGNUM 497 | BOOL bignum_ext = FALSE; 498 | #endif 499 | namelist_t dynamic_module_list; 500 | 501 | out_filename = NULL; 502 | output_type = OUTPUT_EXECUTABLE; 503 | cname = NULL; 504 | feature_bitmap = FE_ALL; 505 | module = -1; 506 | byte_swap = FALSE; 507 | verbose = 0; 508 | use_lto = FALSE; 509 | stack_size = 0; 510 | memset(&dynamic_module_list, 0, sizeof(dynamic_module_list)); 511 | 512 | /* add system modules */ 513 | namelist_add(&cmodule_list, "std", "std", 0); 514 | namelist_add(&cmodule_list, "os", "os", 0); 515 | 516 | for(;;) { 517 | c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:"); 518 | if (c == -1) 519 | break; 520 | switch(c) { 521 | case 'h': 522 | help(); 523 | case 'o': 524 | out_filename = optarg; 525 | break; 526 | case 'c': 527 | output_type = OUTPUT_C; 528 | break; 529 | case 'e': 530 | output_type = OUTPUT_C_MAIN; 531 | break; 532 | case 'N': 533 | cname = optarg; 534 | break; 535 | case 'f': 536 | { 537 | const char *p; 538 | p = optarg; 539 | if (!strcmp(optarg, "lto")) { 540 | use_lto = TRUE; 541 | } else if (strstart(p, "no-", &p)) { 542 | use_lto = TRUE; 543 | for(i = 0; i < countof(feature_list); i++) { 544 | if (!strcmp(p, feature_list[i].option_name)) { 545 | feature_bitmap &= ~((uint64_t)1 << i); 546 | break; 547 | } 548 | } 549 | if (i == countof(feature_list)) 550 | goto bad_feature; 551 | } else 552 | #ifdef CONFIG_BIGNUM 553 | if (!strcmp(optarg, "bignum")) { 554 | bignum_ext = TRUE; 555 | } else 556 | #endif 557 | { 558 | bad_feature: 559 | fprintf(stderr, "unsupported feature: %s\n", optarg); 560 | exit(1); 561 | } 562 | } 563 | break; 564 | case 'm': 565 | module = 1; 566 | break; 567 | case 'M': 568 | { 569 | char *p; 570 | char path[1024]; 571 | char cname[1024]; 572 | pstrcpy(path, sizeof(path), optarg); 573 | p = strchr(path, ','); 574 | if (p) { 575 | *p = '\0'; 576 | pstrcpy(cname, sizeof(cname), p + 1); 577 | } else { 578 | get_c_name(cname, sizeof(cname), path); 579 | } 580 | namelist_add(&cmodule_list, path, cname, 0); 581 | } 582 | break; 583 | case 'D': 584 | namelist_add(&dynamic_module_list, optarg, NULL, 0); 585 | break; 586 | case 'x': 587 | byte_swap = TRUE; 588 | break; 589 | case 'v': 590 | verbose++; 591 | break; 592 | case 'p': 593 | c_ident_prefix = optarg; 594 | break; 595 | case 'S': 596 | stack_size = (size_t)strtod(optarg, NULL); 597 | break; 598 | default: 599 | break; 600 | } 601 | } 602 | 603 | if (optind >= argc) 604 | help(); 605 | 606 | if (!out_filename) { 607 | if (output_type == OUTPUT_EXECUTABLE) { 608 | out_filename = "a.out"; 609 | } else { 610 | out_filename = "out.c"; 611 | } 612 | } 613 | 614 | if (output_type == OUTPUT_EXECUTABLE) { 615 | #if defined(_WIN32) || defined(__ANDROID__) 616 | /* XXX: find a /tmp directory ? */ 617 | snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid()); 618 | #else 619 | snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid()); 620 | #endif 621 | } else { 622 | pstrcpy(cfilename, sizeof(cfilename), out_filename); 623 | } 624 | 625 | fo = fopen(cfilename, "w"); 626 | if (!fo) { 627 | perror(cfilename); 628 | exit(1); 629 | } 630 | outfile = fo; 631 | 632 | rt = JS_NewRuntime(); 633 | ctx = JS_NewContext(rt); 634 | #ifdef CONFIG_BIGNUM 635 | if (bignum_ext) { 636 | JS_AddIntrinsicBigFloat(ctx); 637 | JS_AddIntrinsicBigDecimal(ctx); 638 | JS_AddIntrinsicOperators(ctx); 639 | JS_EnableBignumExt(ctx, TRUE); 640 | } 641 | #endif 642 | 643 | /* loader for ES6 modules */ 644 | JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL); 645 | 646 | fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n" 647 | "\n" 648 | ); 649 | 650 | if (output_type != OUTPUT_C) { 651 | fprintf(fo, "#include \"quickjs-libc.h\"\n" 652 | "\n" 653 | ); 654 | } else { 655 | fprintf(fo, "#include \n" 656 | "\n" 657 | ); 658 | } 659 | 660 | for(i = optind; i < argc; i++) { 661 | const char *filename = argv[i]; 662 | compile_file(ctx, fo, filename, cname, module); 663 | cname = NULL; 664 | } 665 | 666 | for(i = 0; i < dynamic_module_list.count; i++) { 667 | if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) { 668 | fprintf(stderr, "Could not load dynamic module '%s'\n", 669 | dynamic_module_list.array[i].name); 670 | exit(1); 671 | } 672 | } 673 | 674 | if (output_type != OUTPUT_C) { 675 | fprintf(fo, 676 | "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" 677 | "{\n" 678 | " JSContext *ctx = JS_NewContextRaw(rt);\n" 679 | " if (!ctx)\n" 680 | " return NULL;\n"); 681 | /* add the basic objects */ 682 | fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n"); 683 | for(i = 0; i < countof(feature_list); i++) { 684 | if ((feature_bitmap & ((uint64_t)1 << i)) && 685 | feature_list[i].init_name) { 686 | fprintf(fo, " JS_AddIntrinsic%s(ctx);\n", 687 | feature_list[i].init_name); 688 | } 689 | } 690 | #ifdef CONFIG_BIGNUM 691 | if (bignum_ext) { 692 | fprintf(fo, 693 | " JS_AddIntrinsicBigFloat(ctx);\n" 694 | " JS_AddIntrinsicBigDecimal(ctx);\n" 695 | " JS_AddIntrinsicOperators(ctx);\n" 696 | " JS_EnableBignumExt(ctx, 1);\n"); 697 | } 698 | #endif 699 | /* add the precompiled modules (XXX: could modify the module 700 | loader instead) */ 701 | for(i = 0; i < init_module_list.count; i++) { 702 | namelist_entry_t *e = &init_module_list.array[i]; 703 | /* initialize the static C modules */ 704 | 705 | fprintf(fo, 706 | " {\n" 707 | " extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n" 708 | " js_init_module_%s(ctx, \"%s\");\n" 709 | " }\n", 710 | e->short_name, e->short_name, e->name); 711 | } 712 | for(i = 0; i < cname_list.count; i++) { 713 | namelist_entry_t *e = &cname_list.array[i]; 714 | if (e->flags) { 715 | fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n", 716 | e->name, e->name); 717 | } 718 | } 719 | fprintf(fo, 720 | " return ctx;\n" 721 | "}\n\n"); 722 | 723 | fputs(main_c_template1, fo); 724 | 725 | if (stack_size != 0) { 726 | fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n", 727 | (unsigned int)stack_size); 728 | } 729 | 730 | /* add the module loader if necessary */ 731 | if (feature_bitmap & (1 << FE_MODULE_LOADER)) { 732 | fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n"); 733 | } 734 | 735 | fprintf(fo, 736 | " ctx = JS_NewCustomContext(rt);\n" 737 | " js_std_add_helpers(ctx, argc, argv);\n"); 738 | 739 | for(i = 0; i < cname_list.count; i++) { 740 | namelist_entry_t *e = &cname_list.array[i]; 741 | if (!e->flags) { 742 | fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n", 743 | e->name, e->name); 744 | } 745 | } 746 | fputs(main_c_template2, fo); 747 | } 748 | 749 | JS_FreeContext(ctx); 750 | JS_FreeRuntime(rt); 751 | 752 | fclose(fo); 753 | 754 | if (output_type == OUTPUT_EXECUTABLE) { 755 | return output_executable(out_filename, cfilename, use_lto, verbose, 756 | argv[0]); 757 | } 758 | namelist_free(&cname_list); 759 | namelist_free(&cmodule_list); 760 | namelist_free(&init_module_list); 761 | return 0; 762 | } 763 | -------------------------------------------------------------------------------- /include/quickjs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS Javascript Engine 3 | * 4 | * Copyright (c) 2017-2021 Fabrice Bellard 5 | * Copyright (c) 2017-2021 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #ifndef QUICKJS_H 26 | #define QUICKJS_H 27 | 28 | #include 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #if defined(__GNUC__) || defined(__clang__) 36 | #define js_likely(x) __builtin_expect(!!(x), 1) 37 | #define js_unlikely(x) __builtin_expect(!!(x), 0) 38 | #define js_force_inline inline __attribute__((always_inline)) 39 | #define __js_printf_like(f, a) __attribute__((format(printf, f, a))) 40 | #else 41 | #define js_likely(x) (x) 42 | #define js_unlikely(x) (x) 43 | #define js_force_inline inline 44 | #define __js_printf_like(a, b) 45 | #endif 46 | 47 | #define JS_BOOL int 48 | 49 | typedef struct JSRuntime JSRuntime; 50 | typedef struct JSContext JSContext; 51 | typedef struct JSObject JSObject; 52 | typedef struct JSClass JSClass; 53 | typedef uint32_t JSClassID; 54 | typedef uint32_t JSAtom; 55 | 56 | #if INTPTR_MAX >= INT64_MAX 57 | #define JS_PTR64 58 | #define JS_PTR64_DEF(a) a 59 | #else 60 | #define JS_PTR64_DEF(a) 61 | #endif 62 | 63 | #ifndef JS_PTR64 64 | #define JS_NAN_BOXING 65 | #endif 66 | 67 | enum { 68 | /* all tags with a reference count are negative */ 69 | JS_TAG_FIRST = -11, /* first negative tag */ 70 | JS_TAG_BIG_DECIMAL = -11, 71 | JS_TAG_BIG_INT = -10, 72 | JS_TAG_BIG_FLOAT = -9, 73 | JS_TAG_SYMBOL = -8, 74 | JS_TAG_STRING = -7, 75 | JS_TAG_MODULE = -3, /* used internally */ 76 | JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */ 77 | JS_TAG_OBJECT = -1, 78 | 79 | JS_TAG_INT = 0, 80 | JS_TAG_BOOL = 1, 81 | JS_TAG_NULL = 2, 82 | JS_TAG_UNDEFINED = 3, 83 | JS_TAG_UNINITIALIZED = 4, 84 | JS_TAG_CATCH_OFFSET = 5, 85 | JS_TAG_EXCEPTION = 6, 86 | JS_TAG_FLOAT64 = 7, 87 | /* any larger tag is FLOAT64 if JS_NAN_BOXING */ 88 | }; 89 | 90 | typedef struct JSRefCountHeader { 91 | int ref_count; 92 | } JSRefCountHeader; 93 | 94 | #define JS_FLOAT64_NAN NAN 95 | 96 | #ifdef CONFIG_CHECK_JSVALUE 97 | /* JSValue consistency : it is not possible to run the code in this 98 | mode, but it is useful to detect simple reference counting 99 | errors. It would be interesting to modify a static C analyzer to 100 | handle specific annotations (clang has such annotations but only 101 | for objective C) */ 102 | typedef struct __JSValue *JSValue; 103 | typedef const struct __JSValue *JSValueConst; 104 | 105 | #define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf) 106 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 107 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 108 | #define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4) 109 | #define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v) 110 | #define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v) 111 | #define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf) 112 | 113 | #define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag)) 114 | #define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag)) 115 | 116 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 117 | 118 | #define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1) 119 | 120 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 121 | { 122 | return JS_MKVAL(JS_TAG_FLOAT64, (int)d); 123 | } 124 | 125 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 126 | { 127 | return 0; 128 | } 129 | 130 | #elif defined(JS_NAN_BOXING) 131 | 132 | typedef uint64_t JSValue; 133 | 134 | #define JSValueConst JSValue 135 | 136 | #define JS_VALUE_GET_TAG(v) (int)((v) >> 32) 137 | #define JS_VALUE_GET_INT(v) (int)(v) 138 | #define JS_VALUE_GET_BOOL(v) (int)(v) 139 | #define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v) 140 | 141 | #define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val)) 142 | #define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr)) 143 | 144 | #define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */ 145 | 146 | static inline double JS_VALUE_GET_FLOAT64(JSValue v) 147 | { 148 | union { 149 | JSValue v; 150 | double d; 151 | } u; 152 | u.v = v; 153 | u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32; 154 | return u.d; 155 | } 156 | 157 | #define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32)) 158 | 159 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 160 | { 161 | union { 162 | double d; 163 | uint64_t u64; 164 | } u; 165 | JSValue v; 166 | u.d = d; 167 | /* normalize NaN */ 168 | if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)) 169 | v = JS_NAN; 170 | else 171 | v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32); 172 | return v; 173 | } 174 | 175 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST)) 176 | 177 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 178 | static inline int JS_VALUE_GET_NORM_TAG(JSValue v) 179 | { 180 | uint32_t tag; 181 | tag = JS_VALUE_GET_TAG(v); 182 | if (JS_TAG_IS_FLOAT64(tag)) 183 | return JS_TAG_FLOAT64; 184 | else 185 | return tag; 186 | } 187 | 188 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 189 | { 190 | uint32_t tag; 191 | tag = JS_VALUE_GET_TAG(v); 192 | return tag == (JS_NAN >> 32); 193 | } 194 | 195 | #else /* !JS_NAN_BOXING */ 196 | 197 | typedef union JSValueUnion { 198 | int32_t int32; 199 | double float64; 200 | void *ptr; 201 | } JSValueUnion; 202 | 203 | typedef struct JSValue { 204 | JSValueUnion u; 205 | int64_t tag; 206 | } JSValue; 207 | 208 | #define JSValueConst JSValue 209 | 210 | #define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag) 211 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 212 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 213 | #define JS_VALUE_GET_INT(v) ((v).u.int32) 214 | #define JS_VALUE_GET_BOOL(v) ((v).u.int32) 215 | #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64) 216 | #define JS_VALUE_GET_PTR(v) ((v).u.ptr) 217 | 218 | #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag } 219 | #define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag } 220 | 221 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 222 | 223 | #define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 } 224 | 225 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 226 | { 227 | JSValue v; 228 | v.tag = JS_TAG_FLOAT64; 229 | v.u.float64 = d; 230 | return v; 231 | } 232 | 233 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 234 | { 235 | union { 236 | double d; 237 | uint64_t u64; 238 | } u; 239 | if (v.tag != JS_TAG_FLOAT64) 240 | return 0; 241 | u.d = v.u.float64; 242 | return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000; 243 | } 244 | 245 | #endif /* !JS_NAN_BOXING */ 246 | 247 | #define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0) 248 | #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) 249 | 250 | #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) 251 | #define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) 252 | #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) 253 | 254 | /* special values */ 255 | #define JS_NULL JS_MKVAL(JS_TAG_NULL, 0) 256 | #define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0) 257 | #define JS_FALSE JS_MKVAL(JS_TAG_BOOL, 0) 258 | #define JS_TRUE JS_MKVAL(JS_TAG_BOOL, 1) 259 | #define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0) 260 | #define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0) 261 | 262 | /* flags for object properties */ 263 | #define JS_PROP_CONFIGURABLE (1 << 0) 264 | #define JS_PROP_WRITABLE (1 << 1) 265 | #define JS_PROP_ENUMERABLE (1 << 2) 266 | #define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE) 267 | #define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */ 268 | #define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */ 269 | #define JS_PROP_NORMAL (0 << 4) 270 | #define JS_PROP_GETSET (1 << 4) 271 | #define JS_PROP_VARREF (2 << 4) /* used internally */ 272 | #define JS_PROP_AUTOINIT (3 << 4) /* used internally */ 273 | 274 | /* flags for JS_DefineProperty */ 275 | #define JS_PROP_HAS_SHIFT 8 276 | #define JS_PROP_HAS_CONFIGURABLE (1 << 8) 277 | #define JS_PROP_HAS_WRITABLE (1 << 9) 278 | #define JS_PROP_HAS_ENUMERABLE (1 << 10) 279 | #define JS_PROP_HAS_GET (1 << 11) 280 | #define JS_PROP_HAS_SET (1 << 12) 281 | #define JS_PROP_HAS_VALUE (1 << 13) 282 | 283 | /* throw an exception if false would be returned 284 | (JS_DefineProperty/JS_SetProperty) */ 285 | #define JS_PROP_THROW (1 << 14) 286 | /* throw an exception if false would be returned in strict mode 287 | (JS_SetProperty) */ 288 | #define JS_PROP_THROW_STRICT (1 << 15) 289 | 290 | #define JS_PROP_NO_ADD (1 << 16) /* internal use */ 291 | #define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */ 292 | 293 | #define JS_DEFAULT_STACK_SIZE (256 * 1024) 294 | 295 | /* JS_Eval() flags */ 296 | #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ 297 | #define JS_EVAL_TYPE_MODULE (1 << 0) /* module code */ 298 | #define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */ 299 | #define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */ 300 | #define JS_EVAL_TYPE_MASK (3 << 0) 301 | 302 | #define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */ 303 | #define JS_EVAL_FLAG_STRIP (1 << 4) /* force 'strip' mode */ 304 | /* compile but do not run. The result is an object with a 305 | JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed 306 | with JS_EvalFunction(). */ 307 | #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) 308 | /* don't include the stack frames before this eval in the Error() backtraces */ 309 | #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) 310 | 311 | typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 312 | typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 313 | typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); 314 | 315 | typedef struct JSMallocState { 316 | size_t malloc_count; 317 | size_t malloc_size; 318 | size_t malloc_limit; 319 | void *opaque; /* user opaque */ 320 | } JSMallocState; 321 | 322 | typedef struct JSMallocFunctions { 323 | void *(*js_malloc)(JSMallocState *s, size_t size); 324 | void (*js_free)(JSMallocState *s, void *ptr); 325 | void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size); 326 | size_t (*js_malloc_usable_size)(const void *ptr); 327 | } JSMallocFunctions; 328 | 329 | typedef struct JSGCObjectHeader JSGCObjectHeader; 330 | 331 | JSRuntime *JS_NewRuntime(void); 332 | /* info lifetime must exceed that of rt */ 333 | void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); 334 | void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); 335 | void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); 336 | /* use 0 to disable maximum stack size check */ 337 | void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); 338 | /* should be called when changing thread to update the stack top value 339 | used to check stack overflow. */ 340 | void JS_UpdateStackTop(JSRuntime *rt); 341 | JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); 342 | void JS_FreeRuntime(JSRuntime *rt); 343 | void *JS_GetRuntimeOpaque(JSRuntime *rt); 344 | void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque); 345 | typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); 346 | void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); 347 | void JS_RunGC(JSRuntime *rt); 348 | JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); 349 | 350 | JSContext *JS_NewContext(JSRuntime *rt); 351 | void JS_FreeContext(JSContext *s); 352 | JSContext *JS_DupContext(JSContext *ctx); 353 | void *JS_GetContextOpaque(JSContext *ctx); 354 | void JS_SetContextOpaque(JSContext *ctx, void *opaque); 355 | JSRuntime *JS_GetRuntime(JSContext *ctx); 356 | void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); 357 | JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); 358 | 359 | /* the following functions are used to select the intrinsic object to 360 | save memory */ 361 | JSContext *JS_NewContextRaw(JSRuntime *rt); 362 | void JS_AddIntrinsicBaseObjects(JSContext *ctx); 363 | void JS_AddIntrinsicDate(JSContext *ctx); 364 | void JS_AddIntrinsicEval(JSContext *ctx); 365 | void JS_AddIntrinsicStringNormalize(JSContext *ctx); 366 | void JS_AddIntrinsicRegExpCompiler(JSContext *ctx); 367 | void JS_AddIntrinsicRegExp(JSContext *ctx); 368 | void JS_AddIntrinsicJSON(JSContext *ctx); 369 | void JS_AddIntrinsicProxy(JSContext *ctx); 370 | void JS_AddIntrinsicMapSet(JSContext *ctx); 371 | void JS_AddIntrinsicTypedArrays(JSContext *ctx); 372 | void JS_AddIntrinsicPromise(JSContext *ctx); 373 | void JS_AddIntrinsicBigInt(JSContext *ctx); 374 | void JS_AddIntrinsicBigFloat(JSContext *ctx); 375 | void JS_AddIntrinsicBigDecimal(JSContext *ctx); 376 | /* enable operator overloading */ 377 | void JS_AddIntrinsicOperators(JSContext *ctx); 378 | /* enable "use math" */ 379 | void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable); 380 | 381 | JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, 382 | int argc, JSValueConst *argv); 383 | 384 | void *js_malloc_rt(JSRuntime *rt, size_t size); 385 | void js_free_rt(JSRuntime *rt, void *ptr); 386 | void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size); 387 | size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr); 388 | void *js_mallocz_rt(JSRuntime *rt, size_t size); 389 | 390 | void *js_malloc(JSContext *ctx, size_t size); 391 | void js_free(JSContext *ctx, void *ptr); 392 | void *js_realloc(JSContext *ctx, void *ptr, size_t size); 393 | size_t js_malloc_usable_size(JSContext *ctx, const void *ptr); 394 | void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack); 395 | void *js_mallocz(JSContext *ctx, size_t size); 396 | char *js_strdup(JSContext *ctx, const char *str); 397 | char *js_strndup(JSContext *ctx, const char *s, size_t n); 398 | 399 | typedef struct JSMemoryUsage { 400 | int64_t malloc_size, malloc_limit, memory_used_size; 401 | int64_t malloc_count; 402 | int64_t memory_used_count; 403 | int64_t atom_count, atom_size; 404 | int64_t str_count, str_size; 405 | int64_t obj_count, obj_size; 406 | int64_t prop_count, prop_size; 407 | int64_t shape_count, shape_size; 408 | int64_t js_func_count, js_func_size, js_func_code_size; 409 | int64_t js_func_pc2line_count, js_func_pc2line_size; 410 | int64_t c_func_count, array_count; 411 | int64_t fast_array_count, fast_array_elements; 412 | int64_t binary_object_count, binary_object_size; 413 | } JSMemoryUsage; 414 | 415 | void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); 416 | void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); 417 | 418 | /* atom support */ 419 | #define JS_ATOM_NULL 0 420 | 421 | JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); 422 | JSAtom JS_NewAtom(JSContext *ctx, const char *str); 423 | JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); 424 | JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); 425 | void JS_FreeAtom(JSContext *ctx, JSAtom v); 426 | void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); 427 | JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); 428 | JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); 429 | const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); 430 | JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val); 431 | 432 | /* object class support */ 433 | 434 | typedef struct JSPropertyEnum { 435 | JS_BOOL is_enumerable; 436 | JSAtom atom; 437 | } JSPropertyEnum; 438 | 439 | typedef struct JSPropertyDescriptor { 440 | int flags; 441 | JSValue value; 442 | JSValue getter; 443 | JSValue setter; 444 | } JSPropertyDescriptor; 445 | 446 | typedef struct JSClassExoticMethods { 447 | /* Return -1 if exception (can only happen in case of Proxy object), 448 | FALSE if the property does not exists, TRUE if it exists. If 1 is 449 | returned, the property descriptor 'desc' is filled if != NULL. */ 450 | int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, 451 | JSValueConst obj, JSAtom prop); 452 | /* '*ptab' should hold the '*plen' property keys. Return 0 if OK, 453 | -1 if exception. The 'is_enumerable' field is ignored. 454 | */ 455 | int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, 456 | uint32_t *plen, 457 | JSValueConst obj); 458 | /* return < 0 if exception, or TRUE/FALSE */ 459 | int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); 460 | /* return < 0 if exception or TRUE/FALSE */ 461 | int (*define_own_property)(JSContext *ctx, JSValueConst this_obj, 462 | JSAtom prop, JSValueConst val, 463 | JSValueConst getter, JSValueConst setter, 464 | int flags); 465 | /* The following methods can be emulated with the previous ones, 466 | so they are usually not needed */ 467 | /* return < 0 if exception or TRUE/FALSE */ 468 | int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); 469 | JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 470 | JSValueConst receiver); 471 | /* return < 0 if exception or TRUE/FALSE */ 472 | int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 473 | JSValueConst value, JSValueConst receiver, int flags); 474 | } JSClassExoticMethods; 475 | 476 | typedef void JSClassFinalizer(JSRuntime *rt, JSValue val); 477 | typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val, 478 | JS_MarkFunc *mark_func); 479 | #define JS_CALL_FLAG_CONSTRUCTOR (1 << 0) 480 | typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj, 481 | JSValueConst this_val, int argc, JSValueConst *argv, 482 | int flags); 483 | 484 | typedef struct JSClassDef { 485 | const char *class_name; 486 | JSClassFinalizer *finalizer; 487 | JSClassGCMark *gc_mark; 488 | /* if call != NULL, the object is a function. If (flags & 489 | JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a 490 | constructor. In this case, 'this_val' is new.target. A 491 | constructor call only happens if the object constructor bit is 492 | set (see JS_SetConstructorBit()). */ 493 | JSClassCall *call; 494 | /* XXX: suppress this indirection ? It is here only to save memory 495 | because only a few classes need these methods */ 496 | JSClassExoticMethods *exotic; 497 | } JSClassDef; 498 | 499 | JSClassID JS_NewClassID(JSClassID *pclass_id); 500 | int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); 501 | int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); 502 | 503 | /* value handling */ 504 | 505 | static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val) 506 | { 507 | return JS_MKVAL(JS_TAG_BOOL, (val != 0)); 508 | } 509 | 510 | static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val) 511 | { 512 | return JS_MKVAL(JS_TAG_INT, val); 513 | } 514 | 515 | static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) 516 | { 517 | return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); 518 | } 519 | 520 | static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val) 521 | { 522 | JSValue v; 523 | if (val == (int32_t)val) { 524 | v = JS_NewInt32(ctx, val); 525 | } else { 526 | v = __JS_NewFloat64(ctx, val); 527 | } 528 | return v; 529 | } 530 | 531 | static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) 532 | { 533 | JSValue v; 534 | if (val <= 0x7fffffff) { 535 | v = JS_NewInt32(ctx, val); 536 | } else { 537 | v = __JS_NewFloat64(ctx, val); 538 | } 539 | return v; 540 | } 541 | 542 | JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); 543 | JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); 544 | 545 | static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d) 546 | { 547 | JSValue v; 548 | int32_t val; 549 | union { 550 | double d; 551 | uint64_t u; 552 | } u, t; 553 | u.d = d; 554 | val = (int32_t)d; 555 | t.d = val; 556 | /* -0 cannot be represented as integer, so we compare the bit 557 | representation */ 558 | if (u.u == t.u) { 559 | v = JS_MKVAL(JS_TAG_INT, val); 560 | } else { 561 | v = __JS_NewFloat64(ctx, d); 562 | } 563 | return v; 564 | } 565 | 566 | static inline JS_BOOL JS_IsNumber(JSValueConst v) 567 | { 568 | int tag = JS_VALUE_GET_TAG(v); 569 | return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag); 570 | } 571 | 572 | static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v) 573 | { 574 | int tag = JS_VALUE_GET_TAG(v); 575 | return tag == JS_TAG_BIG_INT; 576 | } 577 | 578 | static inline JS_BOOL JS_IsBigFloat(JSValueConst v) 579 | { 580 | int tag = JS_VALUE_GET_TAG(v); 581 | return tag == JS_TAG_BIG_FLOAT; 582 | } 583 | 584 | static inline JS_BOOL JS_IsBigDecimal(JSValueConst v) 585 | { 586 | int tag = JS_VALUE_GET_TAG(v); 587 | return tag == JS_TAG_BIG_DECIMAL; 588 | } 589 | 590 | static inline JS_BOOL JS_IsBool(JSValueConst v) 591 | { 592 | return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL; 593 | } 594 | 595 | static inline JS_BOOL JS_IsNull(JSValueConst v) 596 | { 597 | return JS_VALUE_GET_TAG(v) == JS_TAG_NULL; 598 | } 599 | 600 | static inline JS_BOOL JS_IsUndefined(JSValueConst v) 601 | { 602 | return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED; 603 | } 604 | 605 | static inline JS_BOOL JS_IsException(JSValueConst v) 606 | { 607 | return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION); 608 | } 609 | 610 | static inline JS_BOOL JS_IsUninitialized(JSValueConst v) 611 | { 612 | return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED); 613 | } 614 | 615 | static inline JS_BOOL JS_IsString(JSValueConst v) 616 | { 617 | return JS_VALUE_GET_TAG(v) == JS_TAG_STRING; 618 | } 619 | 620 | static inline JS_BOOL JS_IsSymbol(JSValueConst v) 621 | { 622 | return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; 623 | } 624 | 625 | static inline JS_BOOL JS_IsObject(JSValueConst v) 626 | { 627 | return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; 628 | } 629 | 630 | JSValue JS_Throw(JSContext *ctx, JSValue obj); 631 | JSValue JS_GetException(JSContext *ctx); 632 | JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); 633 | void JS_ResetUncatchableError(JSContext *ctx); 634 | JSValue JS_NewError(JSContext *ctx); 635 | JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...); 636 | JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); 637 | JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...); 638 | JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...); 639 | JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); 640 | JSValue JS_ThrowOutOfMemory(JSContext *ctx); 641 | 642 | void __JS_FreeValue(JSContext *ctx, JSValue v); 643 | static inline void JS_FreeValue(JSContext *ctx, JSValue v) 644 | { 645 | if (JS_VALUE_HAS_REF_COUNT(v)) { 646 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 647 | if (--p->ref_count <= 0) { 648 | __JS_FreeValue(ctx, v); 649 | } 650 | } 651 | } 652 | void __JS_FreeValueRT(JSRuntime *rt, JSValue v); 653 | static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v) 654 | { 655 | if (JS_VALUE_HAS_REF_COUNT(v)) { 656 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 657 | if (--p->ref_count <= 0) { 658 | __JS_FreeValueRT(rt, v); 659 | } 660 | } 661 | } 662 | 663 | static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) 664 | { 665 | if (JS_VALUE_HAS_REF_COUNT(v)) { 666 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 667 | p->ref_count++; 668 | } 669 | return (JSValue)v; 670 | } 671 | 672 | static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) 673 | { 674 | if (JS_VALUE_HAS_REF_COUNT(v)) { 675 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 676 | p->ref_count++; 677 | } 678 | return (JSValue)v; 679 | } 680 | 681 | int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ 682 | int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); 683 | static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) 684 | { 685 | return JS_ToInt32(ctx, (int32_t*)pres, val); 686 | } 687 | int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 688 | int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); 689 | int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); 690 | /* return an exception if 'val' is a Number */ 691 | int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 692 | /* same as JS_ToInt64() but allow BigInt */ 693 | int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val); 694 | 695 | JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); 696 | JSValue JS_NewString(JSContext *ctx, const char *str); 697 | JSValue JS_NewAtomString(JSContext *ctx, const char *str); 698 | JSValue JS_ToString(JSContext *ctx, JSValueConst val); 699 | JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val); 700 | const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8); 701 | static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1) 702 | { 703 | return JS_ToCStringLen2(ctx, plen, val1, 0); 704 | } 705 | static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1) 706 | { 707 | return JS_ToCStringLen2(ctx, NULL, val1, 0); 708 | } 709 | void JS_FreeCString(JSContext *ctx, const char *ptr); 710 | 711 | JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id); 712 | JSValue JS_NewObjectClass(JSContext *ctx, int class_id); 713 | JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); 714 | JSValue JS_NewObject(JSContext *ctx); 715 | 716 | JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); 717 | JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); 718 | JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val); 719 | 720 | JSValue JS_NewArray(JSContext *ctx); 721 | int JS_IsArray(JSContext *ctx, JSValueConst val); 722 | 723 | JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, 724 | JSAtom prop, JSValueConst receiver, 725 | JS_BOOL throw_ref_error); 726 | static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, 727 | JSAtom prop) 728 | { 729 | return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0); 730 | } 731 | JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, 732 | const char *prop); 733 | JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 734 | uint32_t idx); 735 | 736 | int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, 737 | JSAtom prop, JSValue val, 738 | int flags); 739 | static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, 740 | JSAtom prop, JSValue val) 741 | { 742 | return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); 743 | } 744 | int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 745 | uint32_t idx, JSValue val); 746 | int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, 747 | int64_t idx, JSValue val); 748 | int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, 749 | const char *prop, JSValue val); 750 | int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); 751 | int JS_IsExtensible(JSContext *ctx, JSValueConst obj); 752 | int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); 753 | int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); 754 | int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); 755 | JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val); 756 | 757 | #define JS_GPN_STRING_MASK (1 << 0) 758 | #define JS_GPN_SYMBOL_MASK (1 << 1) 759 | #define JS_GPN_PRIVATE_MASK (1 << 2) 760 | /* only include the enumerable properties */ 761 | #define JS_GPN_ENUM_ONLY (1 << 4) 762 | /* set theJSPropertyEnum.is_enumerable field */ 763 | #define JS_GPN_SET_ENUM (1 << 5) 764 | 765 | int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, 766 | uint32_t *plen, JSValueConst obj, int flags); 767 | int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, 768 | JSValueConst obj, JSAtom prop); 769 | 770 | JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, 771 | int argc, JSValueConst *argv); 772 | JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, 773 | int argc, JSValueConst *argv); 774 | JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, 775 | int argc, JSValueConst *argv); 776 | JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, 777 | JSValueConst new_target, 778 | int argc, JSValueConst *argv); 779 | JS_BOOL JS_DetectModule(const char *input, size_t input_len); 780 | /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ 781 | JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, 782 | const char *filename, int eval_flags); 783 | /* same as JS_Eval() but with an explicit 'this_obj' parameter */ 784 | JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, 785 | const char *input, size_t input_len, 786 | const char *filename, int eval_flags); 787 | JSValue JS_GetGlobalObject(JSContext *ctx); 788 | int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj); 789 | int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, 790 | JSAtom prop, JSValueConst val, 791 | JSValueConst getter, JSValueConst setter, int flags); 792 | int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, 793 | JSAtom prop, JSValue val, int flags); 794 | int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, 795 | uint32_t idx, JSValue val, int flags); 796 | int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, 797 | const char *prop, JSValue val, int flags); 798 | int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, 799 | JSAtom prop, JSValue getter, JSValue setter, 800 | int flags); 801 | void JS_SetOpaque(JSValue obj, void *opaque); 802 | void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); 803 | void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); 804 | 805 | /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ 806 | JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, 807 | const char *filename); 808 | #define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */ 809 | JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, 810 | const char *filename, int flags); 811 | JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, 812 | JSValueConst replacer, JSValueConst space0); 813 | 814 | typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr); 815 | JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, 816 | JSFreeArrayBufferDataFunc *free_func, void *opaque, 817 | JS_BOOL is_shared); 818 | JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); 819 | void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); 820 | uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); 821 | JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, 822 | size_t *pbyte_offset, 823 | size_t *pbyte_length, 824 | size_t *pbytes_per_element); 825 | typedef struct { 826 | void *(*sab_alloc)(void *opaque, size_t size); 827 | void (*sab_free)(void *opaque, void *ptr); 828 | void (*sab_dup)(void *opaque, void *ptr); 829 | void *sab_opaque; 830 | } JSSharedArrayBufferFunctions; 831 | void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, 832 | const JSSharedArrayBufferFunctions *sf); 833 | 834 | JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); 835 | 836 | /* is_handled = TRUE means that the rejection is handled */ 837 | typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, 838 | JSValueConst reason, 839 | JS_BOOL is_handled, void *opaque); 840 | void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); 841 | 842 | /* return != 0 if the JS code needs to be interrupted */ 843 | typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); 844 | void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); 845 | /* if can_block is TRUE, Atomics.wait() can be used */ 846 | void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); 847 | /* set the [IsHTMLDDA] internal slot */ 848 | void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj); 849 | 850 | typedef struct JSModuleDef JSModuleDef; 851 | 852 | /* return the module specifier (allocated with js_malloc()) or NULL if 853 | exception */ 854 | typedef char *JSModuleNormalizeFunc(JSContext *ctx, 855 | const char *module_base_name, 856 | const char *module_name, void *opaque); 857 | typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx, 858 | const char *module_name, void *opaque); 859 | 860 | /* module_normalize = NULL is allowed and invokes the default module 861 | filename normalizer */ 862 | void JS_SetModuleLoaderFunc(JSRuntime *rt, 863 | JSModuleNormalizeFunc *module_normalize, 864 | JSModuleLoaderFunc *module_loader, void *opaque); 865 | /* return the import.meta object of a module */ 866 | JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); 867 | JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); 868 | 869 | /* JS Job support */ 870 | 871 | typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv); 872 | int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv); 873 | 874 | JS_BOOL JS_IsJobPending(JSRuntime *rt); 875 | int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); 876 | 877 | /* Object Writer/Reader (currently only used to handle precompiled code) */ 878 | #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ 879 | #define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ 880 | #define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ 881 | #define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to 882 | encode arbitrary object 883 | graph */ 884 | uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, 885 | int flags); 886 | uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, 887 | int flags, uint8_t ***psab_tab, size_t *psab_tab_len); 888 | 889 | #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ 890 | #define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ 891 | #define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ 892 | #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */ 893 | JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, 894 | int flags); 895 | /* instantiate and evaluate a bytecode function. Only used when 896 | reading a script or module with JS_ReadObject() */ 897 | JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj); 898 | /* load the dependencies of the module 'obj'. Useful when JS_ReadObject() 899 | returns a module. */ 900 | int JS_ResolveModule(JSContext *ctx, JSValueConst obj); 901 | 902 | /* only exported for os.Worker() */ 903 | JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); 904 | /* only exported for os.Worker() */ 905 | JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, 906 | const char *filename); 907 | 908 | /* C function definition */ 909 | typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ 910 | JS_CFUNC_generic, 911 | JS_CFUNC_generic_magic, 912 | JS_CFUNC_constructor, 913 | JS_CFUNC_constructor_magic, 914 | JS_CFUNC_constructor_or_func, 915 | JS_CFUNC_constructor_or_func_magic, 916 | JS_CFUNC_f_f, 917 | JS_CFUNC_f_f_f, 918 | JS_CFUNC_getter, 919 | JS_CFUNC_setter, 920 | JS_CFUNC_getter_magic, 921 | JS_CFUNC_setter_magic, 922 | JS_CFUNC_iterator_next, 923 | } JSCFunctionEnum; 924 | 925 | typedef union JSCFunctionType { 926 | JSCFunction *generic; 927 | JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 928 | JSCFunction *constructor; 929 | JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); 930 | JSCFunction *constructor_or_func; 931 | double (*f_f)(double); 932 | double (*f_f_f)(double, double); 933 | JSValue (*getter)(JSContext *ctx, JSValueConst this_val); 934 | JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val); 935 | JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic); 936 | JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic); 937 | JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val, 938 | int argc, JSValueConst *argv, int *pdone, int magic); 939 | } JSCFunctionType; 940 | 941 | JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, 942 | const char *name, 943 | int length, JSCFunctionEnum cproto, int magic); 944 | JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, 945 | int length, int magic, int data_len, 946 | JSValueConst *data); 947 | 948 | static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, 949 | int length) 950 | { 951 | return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0); 952 | } 953 | 954 | static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, 955 | const char *name, 956 | int length, JSCFunctionEnum cproto, int magic) 957 | { 958 | return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic); 959 | } 960 | void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, 961 | JSValueConst proto); 962 | 963 | /* C property definition */ 964 | 965 | typedef struct JSCFunctionListEntry { 966 | const char *name; 967 | uint8_t prop_flags; 968 | uint8_t def_type; 969 | int16_t magic; 970 | union { 971 | struct { 972 | uint8_t length; /* XXX: should move outside union */ 973 | uint8_t cproto; /* XXX: should move outside union */ 974 | JSCFunctionType cfunc; 975 | } func; 976 | struct { 977 | JSCFunctionType get; 978 | JSCFunctionType set; 979 | } getset; 980 | struct { 981 | const char *name; 982 | int base; 983 | } alias; 984 | struct { 985 | const struct JSCFunctionListEntry *tab; 986 | int len; 987 | } prop_list; 988 | const char *str; 989 | int32_t i32; 990 | int64_t i64; 991 | double f64; 992 | } u; 993 | } JSCFunctionListEntry; 994 | 995 | #define JS_DEF_CFUNC 0 996 | #define JS_DEF_CGETSET 1 997 | #define JS_DEF_CGETSET_MAGIC 2 998 | #define JS_DEF_PROP_STRING 3 999 | #define JS_DEF_PROP_INT32 4 1000 | #define JS_DEF_PROP_INT64 5 1001 | #define JS_DEF_PROP_DOUBLE 6 1002 | #define JS_DEF_PROP_UNDEFINED 7 1003 | #define JS_DEF_OBJECT 8 1004 | #define JS_DEF_ALIAS 9 1005 | 1006 | /* Note: c++ does not like nested designators */ 1007 | #define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } 1008 | #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } 1009 | #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } 1010 | #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } } 1011 | #define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } 1012 | #define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } } 1013 | #define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } } 1014 | #define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } } 1015 | #define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } } 1016 | #define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } } 1017 | #define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } 1018 | #define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } } 1019 | #define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } } 1020 | #define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } } 1021 | 1022 | void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, 1023 | const JSCFunctionListEntry *tab, 1024 | int len); 1025 | 1026 | /* C module definition */ 1027 | 1028 | typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m); 1029 | 1030 | JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, 1031 | JSModuleInitFunc *func); 1032 | /* can only be called before the module is instantiated */ 1033 | int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str); 1034 | int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, 1035 | const JSCFunctionListEntry *tab, int len); 1036 | /* can only be called after the module is instantiated */ 1037 | int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, 1038 | JSValue val); 1039 | int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, 1040 | const JSCFunctionListEntry *tab, int len); 1041 | 1042 | #undef js_unlikely 1043 | #undef js_force_inline 1044 | 1045 | #ifdef __cplusplus 1046 | } /* extern "C" { */ 1047 | #endif 1048 | 1049 | #endif /* QUICKJS_H */ 1050 | --------------------------------------------------------------------------------