quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

qjsc.c (22271B)


      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 <stdlib.h>
     25 #include <stdio.h>
     26 #include <stdarg.h>
     27 #include <inttypes.h>
     28 #include <string.h>
     29 #include <assert.h>
     30 #include <unistd.h>
     31 #include <errno.h>
     32 #if !defined(_WIN32)
     33 #include <sys/wait.h>
     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     { "bigint", "BigInt" },
     80 };
     81 
     82 void namelist_add(namelist_t *lp, const char *name, const char *short_name,
     83                   int flags)
     84 {
     85     namelist_entry_t *e;
     86     if (lp->count == lp->size) {
     87         size_t newsize = lp->size + (lp->size >> 1) + 4;
     88         namelist_entry_t *a =
     89             realloc(lp->array, sizeof(lp->array[0]) * newsize);
     90         /* XXX: check for realloc failure */
     91         lp->array = a;
     92         lp->size = newsize;
     93     }
     94     e =  &lp->array[lp->count++];
     95     e->name = strdup(name);
     96     if (short_name)
     97         e->short_name = strdup(short_name);
     98     else
     99         e->short_name = NULL;
    100     e->flags = flags;
    101 }
    102 
    103 void namelist_free(namelist_t *lp)
    104 {
    105     while (lp->count > 0) {
    106         namelist_entry_t *e = &lp->array[--lp->count];
    107         free(e->name);
    108         free(e->short_name);
    109     }
    110     free(lp->array);
    111     lp->array = NULL;
    112     lp->size = 0;
    113 }
    114 
    115 namelist_entry_t *namelist_find(namelist_t *lp, const char *name)
    116 {
    117     int i;
    118     for(i = 0; i < lp->count; i++) {
    119         namelist_entry_t *e = &lp->array[i];
    120         if (!strcmp(e->name, name))
    121             return e;
    122     }
    123     return NULL;
    124 }
    125 
    126 static void get_c_name(char *buf, size_t buf_size, const char *file)
    127 {
    128     const char *p, *r;
    129     size_t len, i;
    130     int c;
    131     char *q;
    132 
    133     p = strrchr(file, '/');
    134     if (!p)
    135         p = file;
    136     else
    137         p++;
    138     r = strrchr(p, '.');
    139     if (!r)
    140         len = strlen(p);
    141     else
    142         len = r - p;
    143     pstrcpy(buf, buf_size, c_ident_prefix);
    144     q = buf + strlen(buf);
    145     for(i = 0; i < len; i++) {
    146         c = p[i];
    147         if (!((c >= '0' && c <= '9') ||
    148               (c >= 'A' && c <= 'Z') ||
    149               (c >= 'a' && c <= 'z'))) {
    150             c = '_';
    151         }
    152         if ((q - buf) < buf_size - 1)
    153             *q++ = c;
    154     }
    155     *q = '\0';
    156 }
    157 
    158 static void dump_hex(FILE *f, const uint8_t *buf, size_t len)
    159 {
    160     size_t i, col;
    161     col = 0;
    162     for(i = 0; i < len; i++) {
    163         fprintf(f, " 0x%02x,", buf[i]);
    164         if (++col == 8) {
    165             fprintf(f, "\n");
    166             col = 0;
    167         }
    168     }
    169     if (col != 0)
    170         fprintf(f, "\n");
    171 }
    172 
    173 static void output_object_code(JSContext *ctx,
    174                                FILE *fo, JSValueConst obj, const char *c_name,
    175                                BOOL load_only)
    176 {
    177     uint8_t *out_buf;
    178     size_t out_buf_len;
    179     int flags;
    180     flags = JS_WRITE_OBJ_BYTECODE;
    181     if (byte_swap)
    182         flags |= JS_WRITE_OBJ_BSWAP;
    183     out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
    184     if (!out_buf) {
    185         js_std_dump_error(ctx);
    186         exit(1);
    187     }
    188 
    189     namelist_add(&cname_list, c_name, NULL, load_only);
    190 
    191     fprintf(fo, "const uint32_t %s_size = %u;\n\n",
    192             c_name, (unsigned int)out_buf_len);
    193     fprintf(fo, "const uint8_t %s[%u] = {\n",
    194             c_name, (unsigned int)out_buf_len);
    195     dump_hex(fo, out_buf, out_buf_len);
    196     fprintf(fo, "};\n\n");
    197 
    198     js_free(ctx, out_buf);
    199 }
    200 
    201 static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m)
    202 {
    203     /* should never be called when compiling JS code */
    204     abort();
    205 }
    206 
    207 static void find_unique_cname(char *cname, size_t cname_size)
    208 {
    209     char cname1[1024];
    210     int suffix_num;
    211     size_t len, max_len;
    212     assert(cname_size >= 32);
    213     /* find a C name not matching an existing module C name by
    214        adding a numeric suffix */
    215     len = strlen(cname);
    216     max_len = cname_size - 16;
    217     if (len > max_len)
    218         cname[max_len] = '\0';
    219     suffix_num = 1;
    220     for(;;) {
    221         snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num);
    222         if (!namelist_find(&cname_list, cname1))
    223             break;
    224         suffix_num++;
    225     }
    226     pstrcpy(cname, cname_size, cname1);
    227 }
    228 
    229 JSModuleDef *jsc_module_loader(JSContext *ctx,
    230                               const char *module_name, void *opaque)
    231 {
    232     JSModuleDef *m;
    233     namelist_entry_t *e;
    234 
    235     /* check if it is a declared C or system module */
    236     e = namelist_find(&cmodule_list, module_name);
    237     if (e) {
    238         /* add in the static init module list */
    239         namelist_add(&init_module_list, e->name, e->short_name, 0);
    240         /* create a dummy module */
    241         m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
    242     } else if (has_suffix(module_name, ".so")) {
    243         fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name);
    244         /* create a dummy module */
    245         m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
    246         /* the resulting executable will export its symbols for the
    247            dynamic library */
    248         dynamic_export = TRUE;
    249     } else {
    250         size_t buf_len;
    251         uint8_t *buf;
    252         JSValue func_val;
    253         char cname[1024];
    254 
    255         buf = js_load_file(ctx, &buf_len, module_name);
    256         if (!buf) {
    257             JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
    258                                    module_name);
    259             return NULL;
    260         }
    261 
    262         /* compile the module */
    263         func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
    264                            JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
    265         js_free(ctx, buf);
    266         if (JS_IsException(func_val))
    267             return NULL;
    268         get_c_name(cname, sizeof(cname), module_name);
    269         if (namelist_find(&cname_list, cname)) {
    270             find_unique_cname(cname, sizeof(cname));
    271         }
    272         output_object_code(ctx, outfile, func_val, cname, TRUE);
    273 
    274         /* the module is already referenced, so we must free it */
    275         m = JS_VALUE_GET_PTR(func_val);
    276         JS_FreeValue(ctx, func_val);
    277     }
    278     return m;
    279 }
    280 
    281 static void compile_file(JSContext *ctx, FILE *fo,
    282                          const char *filename,
    283                          const char *c_name1,
    284                          int module)
    285 {
    286     uint8_t *buf;
    287     char c_name[1024];
    288     int eval_flags;
    289     JSValue obj;
    290     size_t buf_len;
    291 
    292     buf = js_load_file(ctx, &buf_len, filename);
    293     if (!buf) {
    294         fprintf(stderr, "Could not load '%s'\n", filename);
    295         exit(1);
    296     }
    297     eval_flags = JS_EVAL_FLAG_COMPILE_ONLY;
    298     if (module < 0) {
    299         module = (has_suffix(filename, ".mjs") ||
    300                   JS_DetectModule((const char *)buf, buf_len));
    301     }
    302     if (module)
    303         eval_flags |= JS_EVAL_TYPE_MODULE;
    304     else
    305         eval_flags |= JS_EVAL_TYPE_GLOBAL;
    306 //    obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags);         // filename contains full path
    307     obj = JS_Eval(ctx, (const char *)buf, buf_len, "<compiled_js>", eval_flags);    // which we don't want to expose
    308     // TODO: In the future we should to make this behavior configurable with a flag to qjsc
    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_std_free_handlers(rt);\n"
    336     "  JS_FreeContext(ctx);\n"
    337     "  JS_FreeRuntime(rt);\n"
    338     "  return 0;\n"
    339     "}\n";
    340 
    341 #define PROG_NAME "qjsc"
    342 
    343 void help(void)
    344 {
    345     printf("QuickJS Compiler version " CONFIG_VERSION "\n"
    346            "usage: " PROG_NAME " [options] [files]\n"
    347            "\n"
    348            "options are:\n"
    349            "-c          only output bytecode to a C file\n"
    350            "-e          output main() and bytecode to a C file (default = executable output)\n"
    351            "-o output   set the output filename\n"
    352            "-N cname    set the C name of the generated data\n"
    353            "-m          compile as Javascript module (default=autodetect)\n"
    354            "-D module_name         compile a dynamically loaded module or worker\n"
    355            "-M module_name[,cname] add initialization code for an external C module\n"
    356            "-x          byte swapped output\n"
    357            "-p prefix   set the prefix of the generated C names\n"
    358            "-S n        set the maximum stack size to 'n' bytes (default=%d)\n",
    359            JS_DEFAULT_STACK_SIZE);
    360 #ifdef CONFIG_LTO
    361     {
    362         int i;
    363         printf("-flto       use link time optimization\n");
    364         printf("-fbignum    enable bignum extensions\n");
    365         printf("-fno-[");
    366         for(i = 0; i < countof(feature_list); i++) {
    367             if (i != 0)
    368                 printf("|");
    369             printf("%s", feature_list[i].option_name);
    370         }
    371         printf("]\n"
    372                "            disable selected language features (smaller code size)\n");
    373     }
    374 #endif
    375     exit(1);
    376 }
    377 
    378 #if defined(CONFIG_CC) && !defined(_WIN32)
    379 
    380 int exec_cmd(char **argv)
    381 {
    382     int pid, status, ret;
    383 
    384     pid = fork();
    385     if (pid == 0) {
    386         execvp(argv[0], argv);
    387         exit(1);
    388     }
    389 
    390     for(;;) {
    391         ret = waitpid(pid, &status, 0);
    392         if (ret == pid && WIFEXITED(status))
    393             break;
    394     }
    395     return WEXITSTATUS(status);
    396 }
    397 
    398 static int output_executable(const char *out_filename, const char *cfilename,
    399                              BOOL use_lto, BOOL verbose, const char *exename)
    400 {
    401     const char *argv[64];
    402     const char **arg, *bn_suffix, *lto_suffix;
    403     char libjsname[1024];
    404     char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p;
    405     int ret;
    406 
    407     /* get the directory of the executable */
    408     pstrcpy(exe_dir, sizeof(exe_dir), exename);
    409     p = strrchr(exe_dir, '/');
    410     if (p) {
    411         *p = '\0';
    412     } else {
    413         pstrcpy(exe_dir, sizeof(exe_dir), ".");
    414     }
    415 
    416     /* if 'quickjs.h' is present at the same path as the executable, we
    417        use it as include and lib directory */
    418     snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir);
    419     if (access(buf, R_OK) == 0) {
    420         pstrcpy(inc_dir, sizeof(inc_dir), exe_dir);
    421         pstrcpy(lib_dir, sizeof(lib_dir), exe_dir);
    422     } else {
    423         snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX);
    424         snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX);
    425     }
    426 
    427     lto_suffix = "";
    428     bn_suffix = "";
    429 
    430     arg = argv;
    431     *arg++ = CONFIG_CC;
    432     *arg++ = "-O2";
    433 #ifdef CONFIG_LTO
    434     if (use_lto) {
    435         *arg++ = "-flto";
    436         lto_suffix = ".lto";
    437     }
    438 #endif
    439     /* XXX: use the executable path to find the includes files and
    440        libraries */
    441     *arg++ = "-D";
    442     *arg++ = "_GNU_SOURCE";
    443     *arg++ = "-I";
    444     *arg++ = inc_dir;
    445     *arg++ = "-o";
    446     *arg++ = out_filename;
    447     if (dynamic_export)
    448         *arg++ = "-rdynamic";
    449     *arg++ = cfilename;
    450     snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a",
    451              lib_dir, bn_suffix, lto_suffix);
    452     *arg++ = libjsname;
    453     *arg++ = "-lm";
    454     *arg++ = "-ldl";
    455     *arg++ = "-lpthread";
    456     // FIXME: Make conditional
    457     *arg++ = "-lcurl";
    458     *arg++ = "-lsodium";
    459     *arg++ = "-lmbedcrypto";
    460     *arg = NULL;
    461 
    462     if (verbose) {
    463         for(arg = argv; *arg != NULL; arg++)
    464             printf("%s ", *arg);
    465         printf("\n");
    466     }
    467 
    468     ret = exec_cmd((char **)argv);
    469     unlink(cfilename);
    470     return ret;
    471 }
    472 #else
    473 static int output_executable(const char *out_filename, const char *cfilename,
    474                              BOOL use_lto, BOOL verbose, const char *exename)
    475 {
    476     fprintf(stderr, "Executable output is not supported for this target\n");
    477     exit(1);
    478     return 0;
    479 }
    480 #endif
    481 
    482 
    483 typedef enum {
    484     OUTPUT_C,
    485     OUTPUT_C_MAIN,
    486     OUTPUT_EXECUTABLE,
    487 } OutputTypeEnum;
    488 
    489 int main(int argc, char **argv)
    490 {
    491     int c, i, verbose;
    492     const char *out_filename, *cname;
    493     char cfilename[1024];
    494     FILE *fo;
    495     JSRuntime *rt;
    496     JSContext *ctx;
    497     BOOL use_lto;
    498     int module;
    499     OutputTypeEnum output_type;
    500     size_t stack_size;
    501 #ifdef CONFIG_BIGNUM
    502     BOOL bignum_ext = FALSE;
    503 #endif
    504     namelist_t dynamic_module_list;
    505 
    506     out_filename = NULL;
    507     output_type = OUTPUT_EXECUTABLE;
    508     cname = NULL;
    509     feature_bitmap = FE_ALL;
    510     module = -1;
    511     byte_swap = FALSE;
    512     verbose = 0;
    513     use_lto = FALSE;
    514     stack_size = 0;
    515     memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
    516 
    517     /* add system modules */
    518     namelist_add(&cmodule_list, "std", "std", 0);
    519     namelist_add(&cmodule_list, "os", "os", 0);
    520 
    521     for(;;) {
    522         c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:");
    523         if (c == -1)
    524             break;
    525         switch(c) {
    526         case 'h':
    527             help();
    528         case 'o':
    529             out_filename = optarg;
    530             break;
    531         case 'c':
    532             output_type = OUTPUT_C;
    533             break;
    534         case 'e':
    535             output_type = OUTPUT_C_MAIN;
    536             break;
    537         case 'N':
    538             cname = optarg;
    539             break;
    540         case 'f':
    541             {
    542                 const char *p;
    543                 p = optarg;
    544                 if (!strcmp(optarg, "lto")) {
    545                     use_lto = TRUE;
    546                 } else if (strstart(p, "no-", &p)) {
    547                     use_lto = TRUE;
    548                     for(i = 0; i < countof(feature_list); i++) {
    549                         if (!strcmp(p, feature_list[i].option_name)) {
    550                             feature_bitmap &= ~((uint64_t)1 << i);
    551                             break;
    552                         }
    553                     }
    554                     if (i == countof(feature_list))
    555                         goto bad_feature;
    556                 } else
    557 #ifdef CONFIG_BIGNUM
    558                 if (!strcmp(optarg, "bignum")) {
    559                     bignum_ext = TRUE;
    560                 } else
    561 #endif
    562                 {
    563                 bad_feature:
    564                     fprintf(stderr, "unsupported feature: %s\n", optarg);
    565                     exit(1);
    566                 }
    567             }
    568             break;
    569         case 'm':
    570             module = 1;
    571             break;
    572         case 'M':
    573             {
    574                 char *p;
    575                 char path[1024];
    576                 char cname[1024];
    577                 pstrcpy(path, sizeof(path), optarg);
    578                 p = strchr(path, ',');
    579                 if (p) {
    580                     *p = '\0';
    581                     pstrcpy(cname, sizeof(cname), p + 1);
    582                 } else {
    583                     get_c_name(cname, sizeof(cname), path);
    584                 }
    585                 namelist_add(&cmodule_list, path, cname, 0);
    586             }
    587             break;
    588         case 'D':
    589             namelist_add(&dynamic_module_list, optarg, NULL, 0);
    590             break;
    591         case 'x':
    592             byte_swap = TRUE;
    593             break;
    594         case 'v':
    595             verbose++;
    596             break;
    597         case 'p':
    598             c_ident_prefix = optarg;
    599             break;
    600         case 'S':
    601             stack_size = (size_t)strtod(optarg, NULL);
    602             break;
    603         default:
    604             break;
    605         }
    606     }
    607 
    608     if (optind >= argc)
    609         help();
    610 
    611     if (!out_filename) {
    612         if (output_type == OUTPUT_EXECUTABLE) {
    613             out_filename = "a.out";
    614         } else {
    615             out_filename = "out.c";
    616         }
    617     }
    618 
    619     if (output_type == OUTPUT_EXECUTABLE) {
    620 #if defined(_WIN32) || defined(__ANDROID__)
    621         /* XXX: find a /tmp directory ? */
    622         snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid());
    623 #else
    624         snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid());
    625 #endif
    626     } else {
    627         pstrcpy(cfilename, sizeof(cfilename), out_filename);
    628     }
    629 
    630     fo = fopen(cfilename, "w");
    631     if (!fo) {
    632         perror(cfilename);
    633         exit(1);
    634     }
    635     outfile = fo;
    636 
    637     rt = JS_NewRuntime();
    638     ctx = JS_NewContext(rt);
    639 #ifdef CONFIG_BIGNUM
    640     if (bignum_ext) {
    641         JS_AddIntrinsicBigFloat(ctx);
    642         JS_AddIntrinsicBigDecimal(ctx);
    643         JS_AddIntrinsicOperators(ctx);
    644         JS_EnableBignumExt(ctx, TRUE);
    645     }
    646 #endif
    647 
    648     /* loader for ES6 modules */
    649     JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
    650 
    651     fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n"
    652             "\n"
    653             );
    654 
    655     if (output_type != OUTPUT_C) {
    656         fprintf(fo, "#include \"quickjs-libc.h\"\n"
    657                 "\n"
    658                 );
    659     } else {
    660         fprintf(fo, "#include <inttypes.h>\n"
    661                 "\n"
    662                 );
    663     }
    664 
    665     for(i = optind; i < argc; i++) {
    666         const char *filename = argv[i];
    667         compile_file(ctx, fo, filename, cname, module);
    668         cname = NULL;
    669     }
    670 
    671     for(i = 0; i < dynamic_module_list.count; i++) {
    672         if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
    673             fprintf(stderr, "Could not load dynamic module '%s'\n",
    674                     dynamic_module_list.array[i].name);
    675             exit(1);
    676         }
    677     }
    678 
    679     if (output_type != OUTPUT_C) {
    680         fprintf(fo,
    681                 "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
    682                 "{\n"
    683                 "  JSContext *ctx = JS_NewContextRaw(rt);\n"
    684                 "  if (!ctx)\n"
    685                 "    return NULL;\n");
    686         /* add the basic objects */
    687         fprintf(fo, "  JS_AddIntrinsicBaseObjects(ctx);\n");
    688         for(i = 0; i < countof(feature_list); i++) {
    689             if ((feature_bitmap & ((uint64_t)1 << i)) &&
    690                 feature_list[i].init_name) {
    691                 fprintf(fo, "  JS_AddIntrinsic%s(ctx);\n",
    692                         feature_list[i].init_name);
    693             }
    694         }
    695 #ifdef CONFIG_BIGNUM
    696         if (bignum_ext) {
    697             fprintf(fo,
    698                     "  JS_AddIntrinsicBigFloat(ctx);\n"
    699                     "  JS_AddIntrinsicBigDecimal(ctx);\n"
    700                     "  JS_AddIntrinsicOperators(ctx);\n"
    701                     "  JS_EnableBignumExt(ctx, 1);\n");
    702         }
    703 #endif
    704         /* add the precompiled modules (XXX: could modify the module
    705            loader instead) */
    706         for(i = 0; i < init_module_list.count; i++) {
    707             namelist_entry_t *e = &init_module_list.array[i];
    708             /* initialize the static C modules */
    709 
    710             fprintf(fo,
    711                     "  {\n"
    712                     "    extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n"
    713                     "    js_init_module_%s(ctx, \"%s\");\n"
    714                     "  }\n",
    715                     e->short_name, e->short_name, e->name);
    716         }
    717         for(i = 0; i < cname_list.count; i++) {
    718             namelist_entry_t *e = &cname_list.array[i];
    719             if (e->flags) {
    720                 fprintf(fo, "  js_std_eval_binary(ctx, %s, %s_size, 1);\n",
    721                         e->name, e->name);
    722             }
    723         }
    724         fprintf(fo,
    725                 "  return ctx;\n"
    726                 "}\n\n");
    727 
    728         fputs(main_c_template1, fo);
    729 
    730         if (stack_size != 0) {
    731             fprintf(fo, "  JS_SetMaxStackSize(rt, %u);\n",
    732                     (unsigned int)stack_size);
    733         }
    734 
    735         /* add the module loader if necessary */
    736         if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
    737             fprintf(fo, "  JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
    738         }
    739 
    740         fprintf(fo,
    741                 "  ctx = JS_NewCustomContext(rt);\n"
    742                 "  js_std_add_helpers(ctx, argc, argv);\n");
    743 
    744         for(i = 0; i < cname_list.count; i++) {
    745             namelist_entry_t *e = &cname_list.array[i];
    746             if (!e->flags) {
    747                 fprintf(fo, "  js_std_eval_binary(ctx, %s, %s_size, 0);\n",
    748                         e->name, e->name);
    749             }
    750         }
    751         fputs(main_c_template2, fo);
    752     }
    753 
    754     JS_FreeContext(ctx);
    755     JS_FreeRuntime(rt);
    756 
    757     fclose(fo);
    758 
    759     if (output_type == OUTPUT_EXECUTABLE) {
    760         return output_executable(out_filename, cfilename, use_lto, verbose,
    761                                  argv[0]);
    762     }
    763     namelist_free(&cname_list);
    764     namelist_free(&cmodule_list);
    765     namelist_free(&init_module_list);
    766     return 0;
    767 }