Skip to content

Commit 2ab369d

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 295c47b + 7891004 commit 2ab369d

34 files changed

+4989
-4207
lines changed

CMakeLists.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ if(MSVC)
7070
xcheck_add_c_compiler_flag(/wd5045) # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
7171
endif()
7272

73+
# Set a 8MB default stack size on Windows.
74+
# It defaults to 1MB on MSVC, which is the same as our current JS stack size,
75+
# so it will overflow and crash otherwise.
76+
# On MinGW it defaults to 2MB.
77+
if(WIN32)
78+
if(MSVC)
79+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8388608")
80+
else()
81+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,8388608")
82+
endif()
83+
endif()
84+
7385
# MacOS and GCC 11 or later need -Wno-maybe-uninitialized
7486
# https://github.com/quickjs-ng/quickjs/issues/453
7587
if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11)
@@ -88,7 +100,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
88100
endif()
89101

90102
if(CMAKE_BUILD_TYPE MATCHES "Debug")
91-
add_compile_options(-O0)
103+
xcheck_add_c_compiler_flag(/Od)
104+
xcheck_add_c_compiler_flag(-O0)
92105
xcheck_add_c_compiler_flag(-ggdb)
93106
xcheck_add_c_compiler_flag(-fno-omit-frame-pointer)
94107
endif()

Makefile

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ endif
4545

4646
all: $(QJS)
4747

48+
amalgam: TEMP := $(shell mktemp -d)
49+
amalgam: $(QJS)
50+
$(QJS) amalgam.js $(TEMP)/quickjs-amalgam.c
51+
cp quickjs.h quickjs-libc.h $(TEMP)
52+
cd $(TEMP) && zip -9 quickjs-amalgam.zip quickjs-amalgam.c quickjs.h quickjs-libc.h
53+
cp $(TEMP)/quickjs-amalgam.zip $(BUILD_DIR)
54+
cd $(TEMP) && $(RM) quickjs-amalgam.zip quickjs-amalgam.c quickjs.h quickjs-libc.h
55+
$(RM) -d $(TEMP)
56+
4857
fuzz:
4958
clang -g -O1 -fsanitize=address,undefined,fuzzer -o fuzz fuzz.c
5059
./fuzz
@@ -71,6 +80,7 @@ codegen: $(QJSC)
7180
$(QJSC) -e -o gen/hello.c examples/hello.js
7281
$(QJSC) -e -o gen/hello_module.c -m examples/hello_module.js
7382
$(QJSC) -e -o gen/test_fib.c -M examples/fib.so,fib -m examples/test_fib.js
83+
$(QJSC) -C -ss -o gen/builtin-array-fromasync.h builtin-array-fromasync.js
7484

7585
debug:
7686
BUILD_TYPE=Debug $(MAKE)
@@ -81,6 +91,23 @@ distclean:
8191
stats: $(QJS)
8292
$(QJS) -qd
8393

94+
jscheck: CFLAGS=-I. -D_GNU_SOURCE -DJS_CHECK_JSVALUE -Wall -Werror -fsyntax-only -c -o /dev/null
95+
jscheck:
96+
$(CC) $(CFLAGS) api-test.c
97+
$(CC) $(CFLAGS) ctest.c
98+
$(CC) $(CFLAGS) fuzz.c
99+
$(CC) $(CFLAGS) gen/function_source.c
100+
$(CC) $(CFLAGS) gen/hello.c
101+
$(CC) $(CFLAGS) gen/hello_module.c
102+
$(CC) $(CFLAGS) gen/repl.c
103+
$(CC) $(CFLAGS) gen/standalone.c
104+
$(CC) $(CFLAGS) gen/test_fib.c
105+
$(CC) $(CFLAGS) qjs.c
106+
$(CC) $(CFLAGS) qjsc.c
107+
$(CC) $(CFLAGS) quickjs-libc.c
108+
$(CC) $(CFLAGS) quickjs.c
109+
$(CC) $(CFLAGS) run-test262.c
110+
84111
# effectively .PHONY because it doesn't generate output
85112
ctest: CFLAGS=-std=c11 -fsyntax-only -Wall -Wextra -Werror -pedantic
86113
ctest: ctest.c quickjs.h
@@ -117,4 +144,4 @@ unicode_gen: $(BUILD_DIR)
117144
libunicode-table.h: unicode_gen
118145
$(BUILD_DIR)/unicode_gen unicode $@
119146

120-
.PHONY: all ctest cxxtest debug fuzz install clean codegen distclean stats test test262 test262-update test262-check microbench unicode_gen $(QJS) $(QJSC)
147+
.PHONY: all amalgam ctest cxxtest debug fuzz jscheck install clean codegen distclean stats test test262 test262-update test262-check microbench unicode_gen $(QJS) $(QJSC)

amalgam.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {loadFile, writeFile} from "qjs:std"
2+
3+
const cutils_c = loadFile("cutils.c")
4+
const cutils_h = loadFile("cutils.h")
5+
const libbf_c = loadFile("libbf.c")
6+
const libbf_h = loadFile("libbf.h")
7+
const libregexp_c = loadFile("libregexp.c")
8+
const libregexp_h = loadFile("libregexp.h")
9+
const libregexp_opcode_h = loadFile("libregexp-opcode.h")
10+
const libunicode_c = loadFile("libunicode.c")
11+
const libunicode_h = loadFile("libunicode.h")
12+
const libunicode_table_h = loadFile("libunicode-table.h")
13+
const list_h = loadFile("list.h")
14+
const quickjs_atom_h = loadFile("quickjs-atom.h")
15+
const quickjs_c = loadFile("quickjs.c")
16+
const quickjs_c_atomics_h = loadFile("quickjs-c-atomics.h")
17+
const quickjs_h = loadFile("quickjs.h")
18+
const quickjs_libc_c = loadFile("quickjs-libc.c")
19+
const quickjs_libc_h = loadFile("quickjs-libc.h")
20+
const quickjs_opcode_h = loadFile("quickjs-opcode.h")
21+
const gen_builtin_array_fromasync_h = loadFile("gen/builtin-array-fromasync.h")
22+
23+
let source = "#if defined(QJS_BUILD_LIBC) && defined(__linux__) && !defined(_GNU_SOURCE)\n"
24+
+ "#define _GNU_SOURCE\n"
25+
+ "#endif\n"
26+
+ quickjs_c_atomics_h
27+
+ cutils_h
28+
+ list_h
29+
+ libbf_h
30+
+ libunicode_h // exports lre_is_id_start, used by libregexp.h
31+
+ libregexp_h
32+
+ libunicode_table_h
33+
+ quickjs_h
34+
+ quickjs_c
35+
+ cutils_c
36+
+ libbf_c
37+
+ libregexp_c
38+
+ libunicode_c
39+
+ "#ifdef QJS_BUILD_LIBC\n"
40+
+ quickjs_libc_h
41+
+ quickjs_libc_c
42+
+ "#endif // QJS_BUILD_LIBC\n"
43+
source = source.replace(/#include "quickjs-atom.h"/g, quickjs_atom_h)
44+
source = source.replace(/#include "quickjs-opcode.h"/g, quickjs_opcode_h)
45+
source = source.replace(/#include "libregexp-opcode.h"/g, libregexp_opcode_h)
46+
source = source.replace(/#include "gen\/builtin-array-fromasync.h"/g,
47+
gen_builtin_array_fromasync_h)
48+
source = source.replace(/#include "[^"]+"/g, "")
49+
writeFile(execArgv[2] ?? "quickjs-amalgam.c", source)

api-test.c

Lines changed: 131 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
#endif
44
#include <assert.h>
55
#include <stdlib.h>
6+
#include <string.h>
67
#include "quickjs.h"
78

89
#define MAX_TIME 10
910

10-
static int timeout_interrupt_handler(JSRuntime *rt, void *opaque)
11+
static int timeout_interrupt_handler(JSRuntime *rt, void *opaque)
1112
{
1213
int *time = (int *)opaque;
1314
if (*time <= MAX_TIME)
@@ -17,7 +18,7 @@ static int timeout_interrupt_handler(JSRuntime *rt, void *opaque)
1718

1819
static void sync_call(void)
1920
{
20-
const char *code =
21+
const char *code =
2122
"(function() { \
2223
try { \
2324
while (true) {} \
@@ -42,7 +43,7 @@ static void sync_call(void)
4243

4344
static void async_call(void)
4445
{
45-
const char *code =
46+
const char *code =
4647
"(async function() { \
4748
const loop = async () => { \
4849
await Promise.resolve(); \
@@ -73,7 +74,8 @@ static void async_call(void)
7374
JS_FreeRuntime(rt);
7475
}
7576

76-
static JSValue save_value(JSContext *ctx, JSValue this_val, int argc, JSValue *argv)
77+
static JSValue save_value(JSContext *ctx, JSValueConst this_val,
78+
int argc, JSValueConst *argv)
7779
{
7880
assert(argc == 1);
7981
JSValue *p = (JSValue *)JS_GetContextOpaque(ctx);
@@ -96,8 +98,6 @@ static void async_call_stack_overflow(void)
9698

9799
JSRuntime *rt = JS_NewRuntime();
98100
JSContext *ctx = JS_NewContext(rt);
99-
JS_SetMaxStackSize(rt, 128 * 1024);
100-
JS_UpdateStackTop(rt);
101101
JSValue value = JS_UNDEFINED;
102102
JS_SetContextOpaque(ctx, &value);
103103
JSValue global = JS_GetGlobalObject(ctx);
@@ -147,11 +147,136 @@ static void raw_context_global_var(void)
147147
JS_FreeRuntime(rt);
148148
}
149149

150+
static void is_array(void)
151+
{
152+
JSRuntime *rt = JS_NewRuntime();
153+
JSContext *ctx = JS_NewContext(rt);
154+
{
155+
static const char code[] = "[]";
156+
JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL);
157+
assert(!JS_IsException(ret));
158+
assert(JS_IsArray(ret));
159+
JS_FreeValue(ctx, ret);
160+
}
161+
{
162+
static const char code[] = "new Proxy([], {})";
163+
JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL);
164+
assert(!JS_IsException(ret));
165+
assert(!JS_IsArray(ret));
166+
assert(JS_IsProxy(ret));
167+
JSValue handler = JS_GetProxyHandler(ctx, ret);
168+
JSValue target = JS_GetProxyTarget(ctx, ret);
169+
assert(!JS_IsException(handler));
170+
assert(!JS_IsException(target));
171+
assert(!JS_IsProxy(handler));
172+
assert(!JS_IsProxy(target));
173+
assert(JS_IsObject(handler));
174+
assert(JS_IsArray(target));
175+
JS_FreeValue(ctx, handler);
176+
JS_FreeValue(ctx, target);
177+
JS_FreeValue(ctx, ret);
178+
}
179+
JS_FreeContext(ctx);
180+
JS_FreeRuntime(rt);
181+
}
182+
183+
static int loader_calls;
184+
185+
static JSModuleDef *loader(JSContext *ctx, const char *name, void *opaque)
186+
{
187+
loader_calls++;
188+
assert(!strcmp(name, "b"));
189+
static const char code[] = "export function f(x){}";
190+
JSValue ret = JS_Eval(ctx, code, strlen(code), "b",
191+
JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY);
192+
assert(!JS_IsException(ret));
193+
JSModuleDef *m = JS_VALUE_GET_PTR(ret);
194+
assert(m);
195+
JS_FreeValue(ctx, ret);
196+
return m;
197+
}
198+
199+
static void module_serde(void)
200+
{
201+
JSRuntime *rt = JS_NewRuntime();
202+
JS_SetDumpFlags(rt, JS_DUMP_MODULE_RESOLVE);
203+
JS_SetModuleLoaderFunc(rt, NULL, loader, NULL);
204+
JSContext *ctx = JS_NewContext(rt);
205+
static const char code[] = "import {f} from 'b'; f()";
206+
assert(loader_calls == 0);
207+
JSValue mod = JS_Eval(ctx, code, strlen(code), "a",
208+
JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY);
209+
assert(loader_calls == 1);
210+
assert(!JS_IsException(mod));
211+
assert(JS_IsModule(mod));
212+
size_t len = 0;
213+
uint8_t *buf = JS_WriteObject(ctx, &len, mod,
214+
JS_WRITE_OBJ_BYTECODE|JS_WRITE_OBJ_REFERENCE);
215+
assert(buf);
216+
assert(len > 0);
217+
JS_FreeValue(ctx, mod);
218+
assert(loader_calls == 1);
219+
mod = JS_ReadObject(ctx, buf, len, JS_READ_OBJ_BYTECODE);
220+
free(buf);
221+
assert(loader_calls == 1); // 'b' is returned from cache
222+
assert(!JS_IsException(mod));
223+
JSValue ret = JS_EvalFunction(ctx, mod);
224+
assert(!JS_IsException(ret));
225+
assert(JS_IsPromise(ret));
226+
JSValue result = JS_PromiseResult(ctx, ret);
227+
assert(!JS_IsException(result));
228+
assert(JS_IsUndefined(result));
229+
JS_FreeValue(ctx, result);
230+
JS_FreeValue(ctx, ret);
231+
JS_FreeValue(ctx, mod);
232+
JS_FreeContext(ctx);
233+
JS_FreeRuntime(rt);
234+
}
235+
236+
static void two_byte_string(void)
237+
{
238+
JSRuntime *rt = JS_NewRuntime();
239+
JSContext *ctx = JS_NewContext(rt);
240+
{
241+
JSValue v = JS_NewTwoByteString(ctx, NULL, 0);
242+
assert(!JS_IsException(v));
243+
const char *s = JS_ToCString(ctx, v);
244+
assert(s);
245+
assert(!strcmp(s, ""));
246+
JS_FreeCString(ctx, s);
247+
JS_FreeValue(ctx, v);
248+
}
249+
{
250+
JSValue v = JS_NewTwoByteString(ctx, (uint16_t[]){'o','k'}, 2);
251+
assert(!JS_IsException(v));
252+
const char *s = JS_ToCString(ctx, v);
253+
assert(s);
254+
assert(!strcmp(s, "ok"));
255+
JS_FreeCString(ctx, s);
256+
JS_FreeValue(ctx, v);
257+
}
258+
{
259+
JSValue v = JS_NewTwoByteString(ctx, (uint16_t[]){0xD800}, 1);
260+
assert(!JS_IsException(v));
261+
const char *s = JS_ToCString(ctx, v);
262+
assert(s);
263+
// questionable but surrogates don't map to UTF-8 without WTF-8
264+
assert(!strcmp(s, "\xED\xA0\x80"));
265+
JS_FreeCString(ctx, s);
266+
JS_FreeValue(ctx, v);
267+
}
268+
JS_FreeContext(ctx);
269+
JS_FreeRuntime(rt);
270+
}
271+
150272
int main(void)
151273
{
152274
sync_call();
153275
async_call();
154276
async_call_stack_overflow();
155277
raw_context_global_var();
278+
is_array();
279+
module_serde();
280+
two_byte_string();
156281
return 0;
157282
}

builtin-array-fromasync.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
;(function(Array, TypeError, asyncIterator, defineProperty, iterator) {
2+
"use strict" // result.length=i should throw if .length is not writable
3+
return async function fromAsync(arrayLike, mapFn=undefined, thisArg=undefined) {
4+
if (mapFn !== undefined && typeof mapFn !== "function") throw new TypeError("not a function")
5+
let result, i = 0, isConstructor = typeof this === "function"
6+
let sync = false, method = arrayLike[asyncIterator]
7+
if (method == null) sync = true, method = arrayLike[iterator]
8+
if (method == null) {
9+
let {length} = arrayLike
10+
length = +length || 0
11+
result = isConstructor ? new this(length) : Array(length)
12+
while (i < length) {
13+
let value = arrayLike[i]
14+
if (sync) value = await value
15+
if (mapFn) value = await mapFn.call(thisArg, value, i)
16+
defineProperty(result, i++, {value, configurable: true, writable: true})
17+
}
18+
} else {
19+
const iter = method.call(arrayLike)
20+
result = isConstructor ? new this() : Array()
21+
try {
22+
for (;;) {
23+
let {value, done} = await iter.next()
24+
if (done) break
25+
if (sync) value = await value
26+
if (mapFn) value = await mapFn.call(thisArg, value, i)
27+
defineProperty(result, i++, {value, configurable: true, writable: true})
28+
}
29+
} finally {
30+
if (iter.return) iter.return()
31+
}
32+
}
33+
result.length = i
34+
return result
35+
}
36+
})

docs/docs/building.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ make
2626
This will build the `qjs` and `qjsc` executables and other test tools. Head over [here](./cli) for
2727
instructions on how to use them.
2828

29+
## Amalgamated builds
30+
31+
The amalgamated build rolls individual source files into a single big file.
32+
It's a good choice for projects that want to use QuickJS without CMake.
33+
34+
Download quickjs-amalgam.zip from https://github.com/quickjs-ng/quickjs/releases
35+
36+
To enable the std, os and bjson modules, compile quickjs-amalgam.c with
37+
`-DQJS_BUILD_LIBC`.
38+
2939
## Debug builds
3040

3141
```bash

docs/docs/projects.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,7 @@ Rust wrapper focus on embedding-ready and no-pain type conversion and interopera
3030
## [GodotJS](https://github.com/godotjs/GodotJS)
3131

3232
This project adds TypeScript/JavaScript support for Godot 4.x. It supports multiple javascript runtimes, including QuickJS-NG.
33+
34+
## [quickjs_es_runtime](https://github.com/HiRoFa/quickjs_es_runtime)
35+
36+
Rust wrapper with typescript, modules, promises, async/await and much more.

0 commit comments

Comments
 (0)