diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fa0a9a9..7eeb0059 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,6 +135,10 @@ jobs: run: | make stats + - name: cxxtest + run: | + make cxxtest + - name: test if: ${{ matrix.config.configType != 'examples' && matrix.config.configType != 'tcc' }} run: | @@ -211,6 +215,14 @@ jobs: build\${{matrix.buildType}}\qjs.exe examples\test_point.js build\${{matrix.buildType}}\run-test262.exe -c tests.conf build\${{matrix.buildType}}\function_source.exe + - name: Set up Visual Studio shell + uses: egor-tensin/vs-shell@v2 + with: + arch: ${{ matrix.arch == 'x64' && 'x64' || 'x86' }} + - name: cxxtest + run: | + cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc + cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc windows-msvc-vs2019: runs-on: windows-2019 @@ -228,6 +240,14 @@ jobs: - name: stats run: | build\${{matrix.buildType}}\qjs.exe -qd + - name: Set up Visual Studio shell + uses: egor-tensin/vs-shell@v2 + with: + arch: ${{ matrix.arch == 'x64' && 'x64' || 'x86' }} + - name: cxxtest + run: | + cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc + cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc windows-clang: runs-on: windows-latest @@ -244,6 +264,10 @@ jobs: - name: stats run: | build\${{matrix.buildType}}\qjs.exe -qd + - name: cxxtest + run: | + clang-cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc + clang-cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc - name: test run: | cp build\${{matrix.buildType}}\fib.dll examples\ @@ -315,6 +339,14 @@ jobs: run: | make stats ldd build/qjs + - name: cxxtest + if: ${{ matrix.sys != 'clang64' }} + run: | + make cxxtest + - name: cxxtest + if: ${{ matrix.sys == 'clang64' }} + run: | + make cxxtest CXX=clang++ - name: test run: | make test @@ -395,6 +427,10 @@ jobs: - name: stats run: make stats + - name: cxxtest + run: | + make cxxtest + - name: test run: make test @@ -467,6 +503,9 @@ jobs: - name: build run: | make + - name: cxxtest + run: | + make cxxtest - name: test run: | make test @@ -484,6 +523,9 @@ jobs: - name: build run: | make + - name: cxxtest + run: | + make cxxtest - name: test run: | make test diff --git a/Makefile b/Makefile index dda3af07..7b3ec75b 100644 --- a/Makefile +++ b/Makefile @@ -83,6 +83,12 @@ distclean: stats: $(QJS) $(QJS) -qd +# implicitly .PHONY because it doesn't generate output +cxxtest: CXXFLAGS+=-std=c++11 -fsyntax-only -Wall -Wextra -Werror -Wno-unused-parameter +cxxtest: cxxtest.cc quickjs.h + $(CXX) $(CXXFLAGS) -DJS_NAN_BOXING=0 $< + $(CXX) $(CXXFLAGS) -DJS_NAN_BOXING=1 $< + test: $(QJS) $(RUN262) -c tests.conf @@ -110,4 +116,4 @@ unicode_gen: $(BUILD_DIR) libunicode-table.h: unicode_gen $(BUILD_DIR)/unicode_gen unicode $@ -.PHONY: all debug fuzz install clean codegen distclean stats test test262 test262-update test262-check microbench unicode_gen $(QJS) $(QJSC) +.PHONY: all cxxtest debug fuzz install clean codegen distclean stats test test262 test262-update test262-check microbench unicode_gen $(QJS) $(QJSC) diff --git a/cxxtest.cc b/cxxtest.cc new file mode 100644 index 00000000..6488533d --- /dev/null +++ b/cxxtest.cc @@ -0,0 +1,17 @@ +// note: file is not actually compiled, only checked for C++ syntax errors +#include "quickjs.h" + +int main(void) +{ + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + JS_FreeValue(ctx, JS_NAN); + JS_FreeValue(ctx, JS_UNDEFINED); + JS_FreeValue(ctx, JS_NewFloat64(ctx, 42)); + // not a legal way of using JS_MKPTR but this is here + // to have the compiler syntax-check its definition + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_UNINITIALIZED, 0)); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return 0; +} diff --git a/quickjs.h b/quickjs.h index 1e331504..12111f80 100644 --- a/quickjs.h +++ b/quickjs.h @@ -61,9 +61,11 @@ typedef uint32_t JSAtom; - string contents is either pure ASCII or is UTF-8 encoded. */ +/* Overridable purely for testing purposes; don't touch. */ +#ifndef JS_NAN_BOXING #if INTPTR_MAX < INT64_MAX -/* Use NAN boxing for 32bit builds. */ -#define JS_NAN_BOXING +#define JS_NAN_BOXING 1 /* Use NAN boxing for 32bit builds. */ +#endif #endif enum { @@ -90,7 +92,7 @@ enum { #define JS_FLOAT64_NAN NAN #define JSValueConst JSValue /* For backwards compatibility. */ -#if defined(JS_NAN_BOXING) +#if defined(JS_NAN_BOXING) && JS_NAN_BOXING typedef uint64_t JSValue; @@ -174,13 +176,41 @@ typedef struct JSValue { #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64) #define JS_VALUE_GET_PTR(v) ((v).u.ptr) +/* msvc doesn't understand designated initializers without /std:c++20 */ +#ifdef __cplusplus +static inline JSValue JS_MKPTR(int64_t tag, void *ptr) +{ + JSValue v; + v.u.ptr = ptr; + v.tag = tag; + return v; +} +static inline JSValue JS_MKVAL(int64_t tag, int32_t int32) +{ + JSValue v; + v.u.int32 = int32; + v.tag = tag; + return v; +} +static inline JSValue JS_MKNAN(void) +{ + JSValue v; + v.u.float64 = JS_FLOAT64_NAN; + v.tag = JS_TAG_FLOAT64; + return v; +} +/* provide as macros for consistency and backward compat reasons */ +#define JS_MKPTR(tag, ptr) JS_MKPTR(tag, ptr) +#define JS_MKVAL(tag, val) JS_MKVAL(tag, val) +#define JS_NAN JS_MKNAN() /* alas, not a constant expression */ +#else +#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag } #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag } -#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag } +#define JS_NAN (JSValue){ (JSValueUnion){ .float64 = JS_FLOAT64_NAN }, JS_TAG_FLOAT64 } +#endif #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) -#define JS_NAN (JSValue){ (JSValueUnion){ .float64 = JS_FLOAT64_NAN }, JS_TAG_FLOAT64 } - static inline JSValue __JS_NewFloat64(double d) { JSValue v; @@ -900,7 +930,8 @@ static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *fun int length, JSCFunctionEnum cproto, int magic) { /* Used to squelch a -Wcast-function-type warning. */ - JSCFunctionType ft = { .generic_magic = func }; + JSCFunctionType ft; + ft.generic_magic = func; return JS_NewCFunction2(ctx, ft.generic, name, length, cproto, magic); } JS_EXTERN void JS_SetConstructor(JSContext *ctx, JSValue func_obj,