Skip to content

Commit aa950c0

Browse files
committed
Refactor reactor to reuse shared initialization from qjs.c
Extract common initialization logic from qjs.c into reusable functions that can be shared with the WASI reactor build. This eliminates code duplication between main() and qjs_init_argv(), reducing the reactor file by 45%. Add qjs-common.h with public API: - QJSConfig struct for initialization options - qjs_config_init() / qjs_config_parse_args() for CLI parsing - qjs_setup_runtime() for module loader and promise tracker setup - qjs_apply_config() for loading std modules, includes, and eval - qjs_new_context() (formerly static JS_NewCustomContext) - qjs_eval_buf() / qjs_eval_file() / qjs_parse_limit() Changes to qjs.c: - Make eval_buf, eval_file, parse_limit, JS_NewCustomContext non-static - Add shared helper functions for runtime/context initialization - Guard main() with #ifndef QJS_NO_MAIN for reactor builds The reactor now uses these shared functions instead of duplicating the argument parsing and initialization code. This also removes the #include "qjs.c" hack that was used to access static functions. Signed-off-by: Christian Stewart <christian@aperture.us>
1 parent 6045513 commit aa950c0

File tree

4 files changed

+398
-332
lines changed

4 files changed

+398
-332
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,13 +344,14 @@ if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
344344
if(QJS_WASI_REACTOR)
345345
add_executable(qjs_wasi
346346
quickjs-libc.c
347+
qjs.c
347348
qjs-wasi-reactor.c
348349
)
349350
set_target_properties(qjs_wasi PROPERTIES
350351
OUTPUT_NAME "qjs"
351352
SUFFIX ".wasm"
352353
)
353-
target_compile_definitions(qjs_wasi PRIVATE ${qjs_defines})
354+
target_compile_definitions(qjs_wasi PRIVATE ${qjs_defines} QJS_NO_MAIN)
354355
target_link_libraries(qjs_wasi qjs)
355356
target_link_options(qjs_wasi PRIVATE
356357
-mexec-model=reactor

qjs-common.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* QuickJS shared initialization types and functions
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+
26+
#ifndef QJS_COMMON_H
27+
#define QJS_COMMON_H
28+
29+
#include "quickjs.h"
30+
31+
#define QJS_INCLUDE_MAX 32
32+
33+
/* Return values for qjs_config_parse_args() */
34+
#define QJS_PARSE_OK 0
35+
#define QJS_PARSE_ERROR -1
36+
#define QJS_PARSE_HELP -2 /* Help requested, caller should display help and exit */
37+
38+
/* Configuration for QJS initialization */
39+
typedef struct {
40+
char *expr;
41+
int module; /* -1 = auto, 0 = script, 1 = module */
42+
int load_std;
43+
char *include_list[QJS_INCLUDE_MAX];
44+
int include_count;
45+
int64_t memory_limit; /* -1 = default */
46+
int64_t stack_size; /* -1 = default */
47+
#ifndef QJS_NO_MAIN
48+
/* Main-specific options (not used in reactor builds) */
49+
int interactive;
50+
int dump_memory;
51+
int dump_flags;
52+
int trace_memory;
53+
int empty_run;
54+
char *compile_file;
55+
char *out;
56+
char *exe;
57+
#endif
58+
} QJSConfig;
59+
60+
/* Initialize config with defaults */
61+
void qjs_config_init(QJSConfig *cfg);
62+
63+
/* Parse command line arguments into config. Updates *poptind.
64+
* Returns 0 on success, -1 on error. */
65+
int qjs_config_parse_args(QJSConfig *cfg, int argc, char **argv, int *poptind);
66+
67+
/* Parse a size limit string (e.g., "256m", "1g"). Returns -1 on error. */
68+
int64_t qjs_parse_limit(const char *arg);
69+
70+
/* Create a new custom context with std/os/bjson modules */
71+
JSContext *qjs_new_context(JSRuntime *rt);
72+
73+
/* Set argc/argv for use by qjs_new_context (for execArgv global) */
74+
void qjs_set_argv(int argc, char **argv);
75+
76+
/* Set up runtime with config (memory limit, stack size, module loader, etc.) */
77+
void qjs_setup_runtime(JSRuntime *rt);
78+
79+
/* Apply config to context: load std modules, includes, eval expr/file.
80+
* Returns 0 on success, -1 on error. */
81+
int qjs_apply_config(JSContext *ctx, const QJSConfig *cfg, int argc, char **argv);
82+
83+
/* Evaluate a buffer */
84+
int qjs_eval_buf(JSContext *ctx, const void *buf, int buf_len,
85+
const char *filename, int eval_flags);
86+
87+
/* Evaluate a file */
88+
int qjs_eval_file(JSContext *ctx, const char *filename, int module);
89+
90+
#endif /* QJS_COMMON_H */

qjs-wasi-reactor.c

Lines changed: 26 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
* THE SOFTWARE.
2727
*/
2828

29-
/* Include qjs.c to get access to static functions like eval_buf, eval_file,
30-
* parse_limit, and JS_NewCustomContext */
31-
#include "qjs.c"
29+
#include "quickjs.h"
30+
#include "quickjs-libc.h"
31+
#include "qjs-common.h"
3232

3333
static JSRuntime *reactor_rt = NULL;
3434
static JSContext *reactor_ctx = NULL;
@@ -45,145 +45,52 @@ int qjs_init(void)
4545
__attribute__((export_name("qjs_init_argv")))
4646
int qjs_init_argv(int argc, char **argv)
4747
{
48+
QJSConfig cfg;
4849
int optind = 1;
49-
char *expr = NULL;
50-
int module = -1;
51-
int load_std = 0;
52-
char *include_list[32];
53-
int i, include_count = 0;
54-
int64_t memory_limit = -1;
55-
int64_t stack_size = -1;
5650

5751
if (reactor_rt)
5852
return -1; /* already initialized */
5953

60-
/* Parse options (subset of main()) */
61-
while (optind < argc && *argv[optind] == '-') {
62-
char *arg = argv[optind] + 1;
63-
const char *longopt = "";
64-
char *optarg = NULL;
65-
if (!*arg)
66-
break;
67-
optind++;
68-
if (*arg == '-') {
69-
longopt = arg + 1;
70-
optarg = strchr(longopt, '=');
71-
if (optarg)
72-
*optarg++ = '\0';
73-
arg += strlen(arg);
74-
if (!*longopt)
75-
break;
76-
}
77-
for (; *arg || *longopt; longopt = "") {
78-
char opt = *arg;
79-
if (opt) {
80-
arg++;
81-
if (!optarg && *arg)
82-
optarg = arg;
83-
}
84-
if (opt == 'e' || !strcmp(longopt, "eval")) {
85-
if (!optarg) {
86-
if (optind >= argc)
87-
return -1;
88-
optarg = argv[optind++];
89-
}
90-
expr = optarg;
91-
break;
92-
}
93-
if (opt == 'I' || !strcmp(longopt, "include")) {
94-
if (optind >= argc || include_count >= countof(include_list))
95-
return -1;
96-
include_list[include_count++] = argv[optind++];
97-
continue;
98-
}
99-
if (opt == 'm' || !strcmp(longopt, "module")) {
100-
module = 1;
101-
continue;
102-
}
103-
if (!strcmp(longopt, "std")) {
104-
load_std = 1;
105-
continue;
106-
}
107-
if (!strcmp(longopt, "memory-limit")) {
108-
if (!optarg) {
109-
if (optind >= argc)
110-
return -1;
111-
optarg = argv[optind++];
112-
}
113-
memory_limit = parse_limit(optarg);
114-
break;
115-
}
116-
if (!strcmp(longopt, "stack-size")) {
117-
if (!optarg) {
118-
if (optind >= argc)
119-
return -1;
120-
optarg = argv[optind++];
121-
}
122-
stack_size = parse_limit(optarg);
123-
break;
124-
}
125-
break; /* ignore unknown options */
126-
}
127-
}
54+
qjs_config_init(&cfg);
55+
if (qjs_config_parse_args(&cfg, argc, argv, &optind) < 0)
56+
return -1;
57+
58+
qjs_set_argv(argc, argv);
12859

12960
reactor_rt = JS_NewRuntime();
13061
if (!reactor_rt)
13162
return -1;
132-
if (memory_limit >= 0)
133-
JS_SetMemoryLimit(reactor_rt, (size_t)memory_limit);
134-
if (stack_size >= 0)
135-
JS_SetMaxStackSize(reactor_rt, (size_t)stack_size);
13663

137-
js_std_set_worker_new_context_func(JS_NewCustomContext);
138-
js_std_init_handlers(reactor_rt);
64+
if (cfg.memory_limit >= 0)
65+
JS_SetMemoryLimit(reactor_rt, (size_t)cfg.memory_limit);
66+
if (cfg.stack_size >= 0)
67+
JS_SetMaxStackSize(reactor_rt, (size_t)cfg.stack_size);
13968

140-
reactor_ctx = JS_NewCustomContext(reactor_rt);
141-
if (!reactor_ctx) {
142-
js_std_free_handlers(reactor_rt);
143-
JS_FreeRuntime(reactor_rt);
144-
reactor_rt = NULL;
145-
return -1;
146-
}
69+
qjs_setup_runtime(reactor_rt);
14770

148-
JS_SetModuleLoaderFunc2(reactor_rt, NULL, js_module_loader,
149-
js_module_check_attributes, NULL);
150-
JS_SetHostPromiseRejectionTracker(reactor_rt, js_std_promise_rejection_tracker, NULL);
151-
js_std_add_helpers(reactor_ctx, argc - optind, argv + optind);
152-
153-
if (load_std) {
154-
const char *str =
155-
"import * as bjson from 'qjs:bjson';\n"
156-
"import * as std from 'qjs:std';\n"
157-
"import * as os from 'qjs:os';\n"
158-
"globalThis.bjson = bjson;\n"
159-
"globalThis.std = std;\n"
160-
"globalThis.os = os;\n";
161-
if (eval_buf(reactor_ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE))
162-
goto fail;
163-
}
71+
reactor_ctx = qjs_new_context(reactor_rt);
72+
if (!reactor_ctx)
73+
goto fail;
16474

165-
for (i = 0; i < include_count; i++) {
166-
if (eval_file(reactor_ctx, include_list[i], 0))
167-
goto fail;
168-
}
75+
if (qjs_apply_config(reactor_ctx, &cfg, argc - optind, argv + optind) < 0)
76+
goto fail;
16977

170-
if (expr) {
171-
if (eval_buf(reactor_ctx, expr, strlen(expr), "<cmdline>",
172-
module == 1 ? JS_EVAL_TYPE_MODULE : 0))
173-
goto fail;
174-
} else if (optind < argc) {
175-
if (eval_file(reactor_ctx, argv[optind], module))
78+
/* Evaluate file argument if present */
79+
if (optind < argc) {
80+
if (qjs_eval_file(reactor_ctx, argv[optind], cfg.module))
17681
goto fail;
17782
}
17883

17984
return 0;
18085

18186
fail:
18287
js_std_free_handlers(reactor_rt);
183-
JS_FreeContext(reactor_ctx);
88+
if (reactor_ctx) {
89+
JS_FreeContext(reactor_ctx);
90+
reactor_ctx = NULL;
91+
}
18492
JS_FreeRuntime(reactor_rt);
18593
reactor_rt = NULL;
186-
reactor_ctx = NULL;
18794
return -1;
18895
}
18996

0 commit comments

Comments
 (0)