Skip to content

Justjake main #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4d27f74
0.23.0
justjake Dec 13, 2022
93c0260
update changelog for 0.21.1
justjake Dec 13, 2022
8c6f839
Bump qs from 6.5.2 to 6.5.3 (#89)
dependabot[bot] Dec 14, 2022
e43b888
Bump decode-uri-component from 0.2.0 to 0.2.2 (#83)
dependabot[bot] Dec 14, 2022
abc75a2
Fix for func_id rollover (#94)
Jan 3, 2023
a5b3cf7
Bump http-cache-semantics from 4.1.0 to 4.1.1 (#97)
dependabot[bot] Feb 18, 2023
9b8748a
0.21.2
justjake Feb 18, 2023
1dbc82b
scripts/emcc.sh: cache lto .a files in build/emsdk-cache
justjake Feb 18, 2023
4d1505d
unknown change to .map file
justjake Feb 18, 2023
42a06b8
Emit async imports for variants (#100)
justjake Feb 19, 2023
b3fd13e
BigInt (-DCONFIG_BIGNUM) support (#104)
justjake Feb 19, 2023
cb72070
Extended Symbol support (#105)
justjake Feb 19, 2023
7694b73
update changelog
justjake Feb 19, 2023
a992448
0.22.0
justjake Feb 19, 2023
c6bcdf9
Increase ASYNCIFY_STACK_SIZE (#114)
yar2001 Apr 22, 2023
47ebbe2
update docs & changelog
justjake Apr 23, 2023
b8c6417
rebuild docs
justjake Apr 23, 2023
bd30525
0.23.0
justjake Apr 23, 2023
84f25ac
Makefile: use emscripten/emsdk:3.1.35 from docker
justjake Apr 23, 2023
e9e6112
rebuild
justjake Apr 23, 2023
cc038e6
update smoketest
justjake Apr 23, 2023
d5cdaa6
feat: BigNum (#3)
leanmendoza Dec 12, 2022
8a03008
feat: add opcode instructions counter (#1)
leanmendoza Dec 12, 2022
73c6cdd
feat: move opcode counters to uint64 (#4)
leanmendoza Dec 12, 2022
6746334
rebuild
menduz May 3, 2023
a2551b8
fix lock
menduz May 3, 2023
5e65370
fix package.json
menduz May 3, 2023
de8f13b
prettier
menduz May 3, 2023
a3a368a
ignore emsdk-cache in prettier
menduz May 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-20",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker": {}
},
"customizations": {
"vscode": {
"extensions": ["ms-vscode.makefile-tools"]
}
}
}
17 changes: 11 additions & 6 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,15 @@ jobs:
if: matrix.platform == 'macos-latest'

- name: Setup Node.js environment
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
# Version Spec of the version to use. Examples: 10.x, 10.15.1, >=10.15.0
node-version: 12.x
node-version: 16

# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Cache dependencies
uses: actions/cache@v2
- name: Yarn cache
uses: actions/cache@v3
with:
path: "**/.yarn/cache"
key: ${{ hashFiles('**/yarn.lock') }}
Expand All @@ -52,6 +51,12 @@ jobs:
env:
YARN_ENABLE_SCRIPTS: 0

- name: EMSDK cache
uses: actions/cache@v3
with:
path: "emsdk-cache"
key: ${{ hashFiles('scripts/emcc.sh') }}

- name: Build
run: yarn build

Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ npm-error.log

/build
/dist
/emsdk-cache

# QuickJS build stuff
/quickjs/test_fib.c
Expand All @@ -25,6 +26,5 @@ npm-error.log
/quickjs/repl.c
/quickjs/run-test262


**/.yarn/*
!/.yarn/releases
22 changes: 22 additions & 0 deletions .mocharc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use strict"

// https://mochajs.org/#configuring-mocha-nodejs

module.exports = {
// https://typestrong.org/ts-node/docs/recipes/mocha/
require: [
// Specify "require" for CommonJS
// "ts-node/register",
"source-map-support/register",
],
// Specify "loader" for native ESM
loader: "ts-node/esm",
extensions: ["js", "ts", "tsx"],
timeout: 5000,

"watch-files": [
"ts/**/*",
"build/**/*.js",
// "build/**/*.ts",
],
}
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ dist
examples/imports
examples/typescript-smoketest/*.js
build
emsdk-cache
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# Changelog

## v0.23.0

- [#114](https://github.com/justjake/quickjs-emscripten/pull/114) (thanks to @yar2001) improve stack size for ASYNCIFY build variants:
- Change the default ASYNCIFY_STACK_SIZE from 4096 bytes to 81920 bytes. This equates to an increase from approximately 12 to 297 function frames. See the PR for more details.
- `QuickJSAsyncRuntime.setMaxStackSize(stackSizeBytes)` now also adjusts the ASYNCIFY_STACK_SIZE for the entire module.

## v0.22.0

- [#78](https://github.com/justjake/quickjs-emscripten/pull/78), [#105](https://github.com/justjake/quickjs-emscripten/pull/105) (thanks to @ayaboy) add Symbol helpers `context.newUniqueSymbol`, `context.newSymbolFor`, as well as support for symbols in `context.dump`.
- [#104](https://github.com/justjake/quickjs-emscripten/pull/104) BigInt support.
- [#100](https://github.com/justjake/quickjs-emscripten/pull/100) **Breaking change** upgrade Emscripten version and switch to `async import(...)` for loading variants.
We also drop support for older browsers and Node versions:

- Node >= 16 is required
- Safari >= 14.1 is required
- Typescript >= 4.7 is recommended, but not required.

## v0.21.2

- [#94](https://github.com/justjake/quickjs-emscripten/pull/94) (thanks to @swimmadude66) allows QuickJS to create many more functions before overflowing.

## v0.21.1

- [#66](https://github.com/justjake/quickjs-emscripten/pull/66) (thanks to @BickelLukas) fixes `ReferenceError` when running in browser due to `global.process`

## v0.21.0

- [#61](https://github.com/justjake/quickjs-emscripten/pull/61) (thanks to @torywheelwright):
Expand Down
48 changes: 36 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Tools
CC=clang
EMSDK_VERSION=3.1.7
EMSDK_DOCKER_IMAGE=emscripten/emsdk:$(EMSDK_VERSION)
EMCC=EMSDK_VERSION=$(EMSDK_VERSION) EMSDK_DOCKER_IMAGE=$(EMSDK_DOCKER_IMAGE) scripts/emcc.sh
EMSDK_VERSION=3.1.35
EMSDK_DOCKER_IMAGE=emscripten/emsdk:3.1.35
EMCC=EMSDK_VERSION=$(EMSDK_VERSION) EMSDK_DOCKER_IMAGE=$(EMSDK_DOCKER_IMAGE) EMSDK_DOCKER_CACHE=$(THIS_DIR)/emsdk-cache/$(EMSDK_VERSION) scripts/emcc.sh
GENERATE_TS=$(VARIANT_GENERATE_TS_ENV) npx ts-node generate.ts
PRETTIER=npx prettier
THIS_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))

DEBUG_MAKE=1

Expand Down Expand Up @@ -45,31 +46,52 @@ BUILD_TS=ts/generated
# QuickJS
QUICKJS_OBJS=quickjs.o libregexp.o libunicode.o cutils.o quickjs-libc.o libbf.o
QUICKJS_CONFIG_VERSION=$(shell cat $(QUICKJS_ROOT)/VERSION)
QUICKJS_DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(QUICKJS_CONFIG_VERSION)\" -DCONFIG_BIGNUM -DCONFIG_STACK_CHECK
QUICKJS_DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(QUICKJS_CONFIG_VERSION)\" -DCONFIG_STACK_CHECK -DCONFIG_BIGNUM
VARIANT_QUICKJS_OBJS=$(patsubst %.o, $(BUILD_QUICKJS)/%.$(VARIANT).o, $(QUICKJS_OBJS))

# quickjs-emscripten
WRAPPER_DEFINES+=-Wcast-function-type # Likewise, warns about some quickjs casts we don't control.
EMCC_EXPORTED_FUNCS+=-s EXPORTED_FUNCTIONS=@$(BUILD_WRAPPER)/symbols.json
EMCC_EXPORTED_FUNCS_ASYNCIFY+=-s EXPORTED_FUNCTIONS=@$(BUILD_WRAPPER)/symbols.asyncify.json

# Emscripten options
CFLAGS_WASM+=-s WASM=1
CFLAGS_WASM+=-s EXPORTED_RUNTIME_METHODS=@exportedRuntimeMethods.json
CFLAGS_WASM+=-s NODEJS_CATCH_EXIT=0
CFLAGS_WASM+=-s MODULARIZE=1
CFLAGS_WASM+=-s EXPORT_NAME=QuickJSRaw
CFLAGS_WASM+=-s INVOKE_RUN=0
CFLAGS_WASM+=-s ALLOW_MEMORY_GROWTH=1
CFLAGS_WASM+=-s ALLOW_TABLE_GROWTH=1
# CFLAGS_WASM+=-s ENVIRONMENT=web
CFLAGS_WASM+=-s STACK_SIZE=5MB
# CFLAGS_WASM+=-s MINIMAL_RUNTIME=1 # Appears to break MODULARIZE
CFLAGS_WASM+=-s SUPPORT_ERRNO=0

# Emscripten options - like STRICT
# https://github.com/emscripten-core/emscripten/blob/fa339b76424ca9fbe5cf15faea0295d2ac8d58cc/src/settings.js#L1095-L1109
# CFLAGS_WASM+=-s STRICT_JS=1 # Doesn't work with MODULARIZE
CFLAGS_WASM+=-s IGNORE_MISSING_MAIN=0 --no-entry
CFLAGS_WASM+=-s AUTO_JS_LIBRARIES=0
CFLAGS_WASM+=-s -lccall.js
CFLAGS_WASM+=-s AUTO_NATIVE_LIBRARIES=0
CFLAGS_WASM+=-s AUTO_ARCHIVE_INDEXES=0
CFLAGS_WASM+=-s DEFAULT_TO_CXX=0
CFLAGS_WASM+=-s ALLOW_UNIMPLEMENTED_SYSCALLS=0

# Emscripten options - NodeJS
CFLAGS_WASM+=-s MIN_NODE_VERSION=160000
CFLAGS_WASM+=-s NODEJS_CATCH_EXIT=0

# Empscripten options for asyncify variant
# https://emscripten.org/docs/porting/asyncify.html
CFLAGS_WASM_ASYNCIFY+=-s ASYNCIFY=1
CFLAGS_WASM_ASYNCIFY+=-DQTS_ASYNCIFY=1
CFLAGS_WASM_ASYNCIFY+=-s ASYNCIFY_STACK_SIZE=81920
CFLAGS_WASM_ASYNCIFY+=-s ASYNCIFY_REMOVE=@$(BUILD_WRAPPER)/asyncify-remove.json
CFLAGS_WASM_ASYNCIFY+=-s ASYNCIFY_IMPORTS=@$(BUILD_WRAPPER)/asyncify-imports.json
# CFLAGS_WASM_ASYNCIFY+=-s ENVIRONMENT=web
CFLAGS_WASM_ASYNCIFY+=-lasync.js
# CFLAGS_WASM_ASYNCIFY+=-s ENVIRONMENT=web
GENERATE_TS_ENV_ASYNCIFY+=ASYNCIFY=true

# Release options
Expand All @@ -82,8 +104,10 @@ CFLAGS_WASM_RELEASE+=-s FILESYSTEM=0

# Debug options
GENERATE_TS_ENV_DEBUG+=DEBUG=true

CFLAGS_DEBUG+=-O0
CFLAGS_DEBUG+=-DQTS_DEBUG_MODE

CFLAGS_WASM_DEBUG+=-gsource-map
CFLAGS_WASM_DEBUG+=-s ASSERTIONS=1

Expand Down Expand Up @@ -176,15 +200,15 @@ NATIVE: $(BUILD_WRAPPER)/test.$(VARIANT).exe

$(BUILD_WRAPPER)/test.$(VARIANT).exe: $(BUILD_WRAPPER)/test.$(VARIANT).o $(BUILD_WRAPPER)/interface.$(VARIANT).o $(VARIANT_QUICKJS_OBJS)
$(MKDIRP)
$(CC) $(VARIANT_CFLAGS) -o $@ $<
$(CC) $(VARIANT_CFLAGS) -o $@ $<

$(BUILD_WRAPPER)/test.$(VARIANT).o: $(WRAPPER_ROOT)/test.c $(WRAPPER_ROOT)/interface.h
$(MKDIRP)
$(CC) $(VARIANT_CFLAGS) -o $@ $<
$(CC) $(VARIANT_CFLAGS) -o $@ $<

$(BUILD_WRAPPER)/%.NATIVE_$(RELEASE)_$(SYNC).o: $(WRAPPER_ROOT)/%.c
$(MKDIRP)
$(CC) $(VARIANT_CFLAGS) -o $@ $<
$(CC) $(VARIANT_CFLAGS) -o $@ $<

$(BUILD_QUICKJS)/%.NATIVE_$(RELEASE)_$(SYNC).o: $(QUICKJS_ROOT)/%.c
$(MKDIRP)
Expand All @@ -197,20 +221,20 @@ $(WRAPPER_ROOT)/interface.h: $(WRAPPER_ROOT)/interface.c generate.ts
###############################################################################
# WASM variants
WASM: $(BUILD_TS)/emscripten-module.$(VARIANT).js $(BUILD_TS)/emscripten-module.$(VARIANT).d.ts GENERATE
GENERATE: $(BUILD_TS)/ffi.$(VARIANT).ts
GENERATE: $(BUILD_TS)/ffi.$(VARIANT).ts
WASM_SYMBOLS=$(BUILD_WRAPPER)/symbols.json $(BUILD_WRAPPER)/asyncify-remove.json $(BUILD_WRAPPER)/asyncify-imports.json

$(BUILD_TS)/emscripten-module.$(VARIANT).js: $(BUILD_WRAPPER)/interface.$(VARIANT).o $(VARIANT_QUICKJS_OBJS) $(WASM_SYMBOLS) | scripts/emcc.sh
$(MKDIRP)
$(EMCC) $(VARIANT_CFLAGS) $(EMCC_EXPORTED_FUNCS) -o $@ $< $(VARIANT_QUICKJS_OBJS)
$(EMCC) $(VARIANT_CFLAGS) $(WRAPPER_DEFINES) $(EMCC_EXPORTED_FUNCS) -o $@ $< $(VARIANT_QUICKJS_OBJS)

$(BUILD_TS)/emscripten-module.$(VARIANT).d.ts: ts/types-generated/emscripten-module.$(SYNC).d.ts
echo '// Generated from $<' > $@
cat $< >> $@

$(BUILD_WRAPPER)/%.WASM_$(RELEASE)_$(SYNC).o: $(WRAPPER_ROOT)/%.c $(WASM_SYMBOLS) | scripts/emcc.sh
$(MKDIRP)
$(EMCC) $(VARIANT_CFLAGS) $(CFLAGS_SORTED_FUNCS) -c -o $@ $<
$(EMCC) $(VARIANT_CFLAGS) $(CFLAGS_SORTED_FUNCS) $(WRAPPER_DEFINES) -c -o $@ $<

$(BUILD_QUICKJS)/%.WASM_$(RELEASE)_$(SYNC).o: $(QUICKJS_ROOT)/%.c $(WASM_SYMBOLS) | scripts/emcc.sh
$(MKDIRP)
Expand All @@ -230,4 +254,4 @@ $(BUILD_WRAPPER)/asyncify-remove.json:

$(BUILD_WRAPPER)/asyncify-imports.json:
$(MKDIRP)
$(GENERATE_TS) async-callback-symbols $@
$(GENERATE_TS) async-callback-symbols $@
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -567,8 +567,11 @@ the Javascript parts of the library without setting up the Emscripten toolchain.

Intermediate object files from QuickJS end up in ./build/quickjs/.

This project uses `emscripten 3.1.7` via Docker. You will need a working `docker`
install to build the Emscripten artifacts.
This project uses `emscripten 3.1.32`.

- On ARM64, you should install `emscripten` on your machine. For example on macOS, `brew install emscripten`.
- If _the correct version of emcc_ is not in your PATH, compilation falls back to using Docker.
On ARM64, this is 10-50x slower than native compilation, but it's just fine on x64.

Related NPM scripts:

Expand All @@ -583,8 +586,7 @@ Related NPM scripts:
The ./ts directory contains Typescript types and wraps the generated Emscripten
FFI in a more usable interface.

You'll need `node` and `npm` or `yarn`. Install dependencies with `npm install`
or `yarn install`.
You'll need `node` and `yarn`. Install dependencies with `yarn install`.

- `yarn build` produces ./dist.
- `yarn test` runs the tests.
Expand Down
78 changes: 75 additions & 3 deletions c/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,19 @@ int QTS_BuildIsSanitizeLeak() {
#endif
}

#ifdef QTS_ASYNCIFY
EM_JS(void, set_asyncify_stack_size, (size_t size), {
Asyncify.StackSize = size || 81920;
});
#endif

/**
* Set the stack size limit, in bytes. Set to 0 to disable.
*/
void QTS_RuntimeSetMaxStackSize(JSRuntime *rt, size_t stack_size) {
#ifdef QTS_ASYNCIFY
set_asyncify_stack_size(stack_size);
#endif
JS_SetMaxStackSize(rt, stack_size);
}

Expand Down Expand Up @@ -334,6 +343,69 @@ JSBorrowedChar *QTS_GetString(JSContext *ctx, JSValueConst *value) {
return JS_ToCString(ctx, *value);
}

JSValue qts_get_symbol_key(JSContext *ctx, JSValueConst *value) {
JSValue global = JS_GetGlobalObject(ctx);
JSValue Symbol = JS_GetPropertyStr(ctx, global, "Symbol");
JS_FreeValue(ctx, global);

JSValue Symbol_keyFor = JS_GetPropertyStr(ctx, Symbol, "keyFor");
JSValue key = JS_Call(ctx, Symbol_keyFor, Symbol, 1, value);
JS_FreeValue(ctx, Symbol_keyFor);
JS_FreeValue(ctx, Symbol);
return key;
}

JSValue *QTS_NewSymbol(JSContext *ctx, BorrowedHeapChar *description, int isGlobal) {
JSValue global = JS_GetGlobalObject(ctx);
JSValue Symbol = JS_GetPropertyStr(ctx, global, "Symbol");
JS_FreeValue(ctx, global);
JSValue descriptionValue = JS_NewString(ctx, description);
JSValue symbol;

if (isGlobal != 0) {
JSValue Symbol_for = JS_GetPropertyStr(ctx, Symbol, "for");
symbol = JS_Call(ctx, Symbol_for, Symbol, 1, &descriptionValue);
JS_FreeValue(ctx, descriptionValue);
JS_FreeValue(ctx, Symbol_for);
JS_FreeValue(ctx, Symbol);
return jsvalue_to_heap(symbol);
}

symbol = JS_Call(ctx, Symbol, JS_UNDEFINED, 1, &descriptionValue);
JS_FreeValue(ctx, descriptionValue);
JS_FreeValue(ctx, Symbol);

return jsvalue_to_heap(symbol);
}

MaybeAsync(JSBorrowedChar *) QTS_GetSymbolDescriptionOrKey(JSContext *ctx, JSValueConst *value) {
JSBorrowedChar *result;

JSValue key = qts_get_symbol_key(ctx, value);
if (!JS_IsUndefined(key)) {
result = JS_ToCString(ctx, key);
JS_FreeValue(ctx, key);
return result;
}

JSValue description = JS_GetPropertyStr(ctx, *value, "description");
result = JS_ToCString(ctx, description);
JS_FreeValue(ctx, description);
return result;
}

int QTS_IsGlobalSymbol(JSContext *ctx, JSValueConst *value) {
JSValue key = qts_get_symbol_key(ctx, value);
int undefined = JS_IsUndefined(key);
JS_FreeValue(ctx, key);

if (undefined) {
return 0;
} else {
return 1;
}
}

int QTS_IsJobPending(JSRuntime *rt) {
return JS_IsJobPending(rt);
}
Expand Down Expand Up @@ -495,7 +567,7 @@ OwnedHeapChar *QTS_Typeof(JSContext *ctx, JSValueConst *value) {

if (JS_IsNumber(*value)) {
result = "number";
} else if (tag == JS_TAG_BIG_INT) {
} else if (JS_IsBigInt(ctx, *value)) {
result = "bigint";
} else if (JS_IsBigFloat(*value)) {
result = "bigfloat";
Expand Down Expand Up @@ -567,7 +639,7 @@ int QTS_BuildIsAsyncify() {
// -------------------
// function: C -> Host
#ifdef __EMSCRIPTEN__
EM_JS(MaybeAsync(JSValue *), qts_host_call_function, (JSContext * ctx, JSValueConst *this_ptr, int argc, JSValueConst *argv, int magic_func_id), {
EM_JS(MaybeAsync(JSValue *), qts_host_call_function, (JSContext * ctx, JSValueConst *this_ptr, int argc, JSValueConst *argv, uint32_t magic_func_id), {
#ifdef QTS_ASYNCIFY
const asyncify = {['handleSleep'] : Asyncify.handleSleep};
#else
Expand All @@ -589,7 +661,7 @@ JSValue qts_call_function(JSContext *ctx, JSValueConst this_val, int argc, JSVal
}

// Function: Host -> QuickJS
JSValue *QTS_NewFunction(JSContext *ctx, int func_id, const char *name) {
JSValue *QTS_NewFunction(JSContext *ctx, uint32_t func_id, const char *name) {
#ifdef QTS_DEBUG_MODE
char msg[500];
sprintf(msg, "new_function(name: %s, magic: %d)", name, func_id);
Expand Down
Loading