From f351905cf8b2a2961c287721f18800808662d33f Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 2 Jul 2024 17:40:35 -0700 Subject: [PATCH 1/9] Add `qjsc -r` flag to output raw bytecode I want to allow users to ship a raw `.jsc` bytecode file for faster bootup times. --- qjsc.c | 75 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/qjsc.c b/qjsc.c index f9a07db57..2fea5ca71 100644 --- a/qjsc.c +++ b/qjsc.c @@ -151,7 +151,8 @@ static void dump_hex(FILE *f, const uint8_t *buf, size_t len) static void output_object_code(JSContext *ctx, FILE *fo, JSValue obj, const char *c_name, - BOOL load_only) + BOOL load_only, + BOOL raw) { uint8_t *out_buf; size_t out_buf_len; @@ -171,12 +172,19 @@ static void output_object_code(JSContext *ctx, namelist_add(&cname_list, c_name, NULL, load_only); - fprintf(fo, "const uint32_t %s_size = %u;\n\n", - c_name, (unsigned int)out_buf_len); - fprintf(fo, "const uint8_t %s[%u] = {\n", - c_name, (unsigned int)out_buf_len); - dump_hex(fo, out_buf, out_buf_len); - fprintf(fo, "};\n\n"); + if (raw) + { + fwrite(out_buf, 1, out_buf_len, fo); + } + else + { + fprintf(fo, "const uint32_t %s_size = %u;\n\n", + c_name, (unsigned int)out_buf_len); + fprintf(fo, "const uint8_t %s[%u] = {\n", + c_name, (unsigned int)out_buf_len); + dump_hex(fo, out_buf, out_buf_len); + fprintf(fo, "};\n\n"); + } js_free(ctx, out_buf); } @@ -250,7 +258,7 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, if (namelist_find(&cname_list, cname)) { find_unique_cname(cname, sizeof(cname)); } - output_object_code(ctx, outfile, func_val, cname, TRUE); + output_object_code(ctx, outfile, func_val, cname, TRUE, raw); /* the module is already referenced, so we must free it */ m = JS_VALUE_GET_PTR(func_val); @@ -262,7 +270,8 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, static void compile_file(JSContext *ctx, FILE *fo, const char *filename, const char *c_name1, - int module) + int module, + BOOL raw) { uint8_t *buf; char c_name[1024]; @@ -295,7 +304,7 @@ static void compile_file(JSContext *ctx, FILE *fo, } else { get_c_name(c_name, sizeof(c_name), filename); } - output_object_code(ctx, fo, obj, c_name, FALSE); + output_object_code(ctx, fo, obj, c_name, FALSE, raw); JS_FreeValue(ctx, obj); } @@ -341,6 +350,7 @@ void help(void) typedef enum { OUTPUT_C, OUTPUT_C_MAIN, + OUTPUT_RAW, } OutputTypeEnum; int main(int argc, char **argv) @@ -416,6 +426,9 @@ int main(int argc, char **argv) case 'p': c_ident_prefix = optarg; break; + case 'r': + output_type = OUTPUT_RAW; + break; case 'S': stack_size = (size_t)strtod(optarg, NULL); break; @@ -443,37 +456,46 @@ int main(int argc, char **argv) ctx = JS_NewContext(rt); /* loader for ES6 modules */ - JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL); - - fprintf(fo, "/* File generated automatically by the QuickJS-ng compiler. */\n" - "\n" - ); + OutputTypeEnum *output_type_ptr = (OutputTypeEnum *)js_malloc(ctx, sizeof(OutputTypeEnum)); + *output_type_ptr = output_type; + JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, output_type_ptr); + + if (output_type != OUTPUT_RAW) + { + fprintf(fo, "/* File generated automatically by the QuickJS-ng compiler. */\n" + "\n"); + } - if (output_type != OUTPUT_C) { + if (output_type == OUTPUT_C_MAIN) + { fprintf(fo, "#include \"quickjs-libc.h\"\n" - "\n" - ); - } else { + "\n"); + } + else if (output_type == OUTPUT_C) + { fprintf(fo, "#include \n" - "\n" - ); + "\n"); } - for(i = optind; i < argc; i++) { + for (i = optind; i < argc; i++) + { const char *filename = argv[i]; - compile_file(ctx, fo, filename, cname, module); + compile_file(ctx, fo, filename, cname, module, output_type == OUTPUT_RAW); cname = NULL; } - for(i = 0; i < dynamic_module_list.count; i++) { - if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) { + for (i = 0; i < dynamic_module_list.count; i++) + { + if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) + { fprintf(stderr, "Could not load dynamic module '%s'\n", dynamic_module_list.array[i].name); exit(1); } } - if (output_type != OUTPUT_C) { + if (output_type == OUTPUT_C_MAIN) + { fprintf(fo, "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" "{\n" @@ -528,6 +550,7 @@ int main(int argc, char **argv) fputs(main_c_template2, fo); } + js_free(ctx, output_type_ptr); JS_FreeContext(ctx); JS_FreeRuntime(rt); From 220feab82f90a5c07b5b54111cb5bcf759fa7505 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 2 Jul 2024 17:43:10 -0700 Subject: [PATCH 2/9] Add help --- qjsc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qjsc.c b/qjsc.c index 2fea5ca71..a41cb6b8c 100644 --- a/qjsc.c +++ b/qjsc.c @@ -341,6 +341,7 @@ void help(void) "-D module_name compile a dynamically loaded module or worker\n" "-M module_name[,cname] add initialization code for an external C module\n" "-p prefix set the prefix of the generated C names\n" + "-r output raw bytecode instead of C code\n" "-S n set the maximum stack size to 'n' bytes (default=%d)\n", JS_GetVersion(), JS_DEFAULT_STACK_SIZE); From 93c2e890f1e57c6d7f7526b8f6a4f418b59167a2 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 2 Jul 2024 17:47:17 -0700 Subject: [PATCH 3/9] Revert formatting changes --- qjsc.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/qjsc.c b/qjsc.c index a41cb6b8c..9bbd8a94f 100644 --- a/qjsc.c +++ b/qjsc.c @@ -172,12 +172,9 @@ static void output_object_code(JSContext *ctx, namelist_add(&cname_list, c_name, NULL, load_only); - if (raw) - { + if (raw) { fwrite(out_buf, 1, out_buf_len, fo); - } - else - { + } else { fprintf(fo, "const uint32_t %s_size = %u;\n\n", c_name, (unsigned int)out_buf_len); fprintf(fo, "const uint8_t %s[%u] = {\n", @@ -461,42 +458,37 @@ int main(int argc, char **argv) *output_type_ptr = output_type; JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, output_type_ptr); - if (output_type != OUTPUT_RAW) - { + if (output_type != OUTPUT_RAW) { fprintf(fo, "/* File generated automatically by the QuickJS-ng compiler. */\n" - "\n"); + "\n" + ); } - if (output_type == OUTPUT_C_MAIN) - { + if (output_type == OUTPUT_C_MAIN) { fprintf(fo, "#include \"quickjs-libc.h\"\n" - "\n"); - } - else if (output_type == OUTPUT_C) - { + "\n" + ); + } else if (output_type == OUTPUT_C) { fprintf(fo, "#include \n" - "\n"); + "\n" + ); } - for (i = optind; i < argc; i++) - { + for(i = optind; i < argc; i++) { const char *filename = argv[i]; compile_file(ctx, fo, filename, cname, module, output_type == OUTPUT_RAW); cname = NULL; } - for (i = 0; i < dynamic_module_list.count; i++) - { - if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) - { + for (i = 0; i < dynamic_module_list.count; i++) { + if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) { fprintf(stderr, "Could not load dynamic module '%s'\n", dynamic_module_list.array[i].name); exit(1); } } - if (output_type == OUTPUT_C_MAIN) - { + if (output_type == OUTPUT_C_MAIN) { fprintf(fo, "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" "{\n" From 82f22c536079a0f0d6d4e477c2d4fb679acd1a68 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 2 Jul 2024 17:48:19 -0700 Subject: [PATCH 4/9] . --- qjsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qjsc.c b/qjsc.c index 9bbd8a94f..1b146d992 100644 --- a/qjsc.c +++ b/qjsc.c @@ -480,7 +480,7 @@ int main(int argc, char **argv) cname = NULL; } - for (i = 0; i < dynamic_module_list.count; i++) { + for(i = 0; i < dynamic_module_list.count; i++) { if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) { fprintf(stderr, "Could not load dynamic module '%s'\n", dynamic_module_list.array[i].name); From 23a47cddf780442f4416512a92556f61d8229d24 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 2 Jul 2024 18:20:10 -0700 Subject: [PATCH 5/9] Fix --- qjsc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qjsc.c b/qjsc.c index 1b146d992..0d768facb 100644 --- a/qjsc.c +++ b/qjsc.c @@ -220,6 +220,7 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, { JSModuleDef *m; namelist_entry_t *e; + BOOL raw = *(BOOL *)opaque; /* check if it is a declared C or system module */ e = namelist_find(&cmodule_list, module_name); From 3b8f3da6f25a83e56ceb8644477f7d373d4b75db Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 2 Jul 2024 18:22:06 -0700 Subject: [PATCH 6/9] . --- qjsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qjsc.c b/qjsc.c index 0d768facb..6400a0fec 100644 --- a/qjsc.c +++ b/qjsc.c @@ -379,7 +379,7 @@ int main(int argc, char **argv) namelist_add(&cmodule_list, "os", "os", 0); for(;;) { - c = getopt(argc, argv, "ho:N:mxesvM:p:S:D:"); + c = getopt(argc, argv, "ho:N:mrxesvM:p:S:D:"); if (c == -1) break; switch(c) { From e440af5cd8735e0f90bb287334e38898216dee32 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 2 Jul 2024 21:02:21 -0700 Subject: [PATCH 7/9] Fix --- qjsc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/qjsc.c b/qjsc.c index 6400a0fec..f54ccdd1a 100644 --- a/qjsc.c +++ b/qjsc.c @@ -39,6 +39,12 @@ #include "cutils.h" #include "quickjs-libc.h" +typedef enum { + OUTPUT_C, + OUTPUT_C_MAIN, + OUTPUT_RAW, +} OutputTypeEnum; + typedef struct { char *name; char *short_name; @@ -220,7 +226,7 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, { JSModuleDef *m; namelist_entry_t *e; - BOOL raw = *(BOOL *)opaque; + BOOL raw = *(BOOL *)opaque == OUTPUT_RAW; /* check if it is a declared C or system module */ e = namelist_find(&cmodule_list, module_name); @@ -346,12 +352,6 @@ void help(void) exit(1); } -typedef enum { - OUTPUT_C, - OUTPUT_C_MAIN, - OUTPUT_RAW, -} OutputTypeEnum; - int main(int argc, char **argv) { int c, i, verbose; From 02dfbac0a77ed5ba98a5f7269814ce7d34701c58 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 3 Jul 2024 16:12:06 -0700 Subject: [PATCH 8/9] Use static var --- qjsc.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/qjsc.c b/qjsc.c index 805b3cc9d..b335aaeba 100644 --- a/qjsc.c +++ b/qjsc.c @@ -60,6 +60,7 @@ typedef struct namelist_t { static namelist_t cname_list; static namelist_t cmodule_list; static namelist_t init_module_list; +static OutputTypeEnum output_type; static FILE *outfile; static const char *c_ident_prefix = "qjsc_"; static int strip; @@ -157,8 +158,7 @@ static void dump_hex(FILE *f, const uint8_t *buf, size_t len) static void output_object_code(JSContext *ctx, FILE *fo, JSValue obj, const char *c_name, - BOOL load_only, - BOOL raw) + BOOL load_only) { uint8_t *out_buf; size_t out_buf_len; @@ -178,7 +178,7 @@ static void output_object_code(JSContext *ctx, namelist_add(&cname_list, c_name, NULL, load_only); - if (raw) { + if (output_type == OUTPUT_RAW) { fwrite(out_buf, 1, out_buf_len, fo); } else { fprintf(fo, "const uint32_t %s_size = %u;\n\n", @@ -226,7 +226,6 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, { JSModuleDef *m; namelist_entry_t *e; - BOOL raw = *(BOOL *)opaque == OUTPUT_RAW; /* check if it is a declared C or system module */ e = namelist_find(&cmodule_list, module_name); @@ -262,7 +261,7 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, if (namelist_find(&cname_list, cname)) { find_unique_cname(cname, sizeof(cname)); } - output_object_code(ctx, outfile, func_val, cname, TRUE, raw); + output_object_code(ctx, outfile, func_val, cname, TRUE); /* the module is already referenced, so we must free it */ m = JS_VALUE_GET_PTR(func_val); @@ -275,8 +274,7 @@ static void compile_file(JSContext *ctx, FILE *fo, const char *filename, const char *script_name, const char *c_name1, - int module, - BOOL raw) + int module) { uint8_t *buf; char c_name[1024]; @@ -309,7 +307,7 @@ static void compile_file(JSContext *ctx, FILE *fo, } else { get_c_name(c_name, sizeof(c_name), filename); } - output_object_code(ctx, fo, obj, c_name, FALSE, raw); + output_object_code(ctx, fo, obj, c_name, FALSE); JS_FreeValue(ctx, obj); } @@ -364,7 +362,6 @@ int main(int argc, char **argv) JSRuntime *rt; JSContext *ctx; int module; - OutputTypeEnum output_type; size_t stack_size; namelist_t dynamic_module_list; @@ -462,9 +459,7 @@ int main(int argc, char **argv) ctx = JS_NewContext(rt); /* loader for ES6 modules */ - OutputTypeEnum *output_type_ptr = (OutputTypeEnum *)js_malloc(ctx, sizeof(OutputTypeEnum)); - *output_type_ptr = output_type; - JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, output_type_ptr); + JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL); if (output_type != OUTPUT_RAW) { fprintf(fo, "/* File generated automatically by the QuickJS-ng compiler. */\n" @@ -484,7 +479,7 @@ int main(int argc, char **argv) for(i = optind; i < argc; i++) { const char *filename = argv[i]; - compile_file(ctx, fo, filename, script_name, cname, module, output_type == OUTPUT_RAW); + compile_file(ctx, fo, filename, script_name, cname, module); cname = NULL; } From 391140d21091f906c62a66472f76311ba9dca10a Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Wed, 3 Jul 2024 16:12:54 -0700 Subject: [PATCH 9/9] . --- qjsc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/qjsc.c b/qjsc.c index b335aaeba..88917e741 100644 --- a/qjsc.c +++ b/qjsc.c @@ -546,7 +546,6 @@ int main(int argc, char **argv) fputs(main_c_template2, fo); } - js_free(ctx, output_type_ptr); JS_FreeContext(ctx); JS_FreeRuntime(rt);