diff --git a/packages/bench/CMakeLists.txt b/packages/bench/CMakeLists.txt index e09ab40b..17cdadfa 100644 --- a/packages/bench/CMakeLists.txt +++ b/packages/bench/CMakeLists.txt @@ -19,7 +19,7 @@ add_compile_definitions( "NODE_ADDON_API_ENABLE_MAYBE" ) add_link_options( - "-sMIN_CHROME_VERSION=84" + "-sMIN_CHROME_VERSION=85" "-sALLOW_MEMORY_GROWTH=1" "-sMODULARIZE=1" ) @@ -38,6 +38,7 @@ target_link_libraries(emnapic PRIVATE emnapi-basic fib) target_link_options(emnapic PRIVATE "-sEXPORTED_FUNCTIONS=['_napi_register_wasm_v1','_malloc','_free']" "-sEXPORT_NAME=emnapic" + "-sEXPORTED_RUNTIME_METHODS=['emnapiInit']" ) add_executable(emnapicpp "${CMAKE_CURRENT_SOURCE_DIR}/src/lib.cpp") @@ -45,4 +46,5 @@ target_link_libraries(emnapicpp PRIVATE emnapi-basic fib) target_link_options(emnapicpp PRIVATE "-sEXPORTED_FUNCTIONS=['_napi_register_wasm_v1','_malloc','_free']" "-sEXPORT_NAME=emnapicpp" + "-sEXPORTED_RUNTIME_METHODS=['emnapiInit']" ) diff --git a/packages/emnapi/common.gypi b/packages/emnapi/common.gypi index ebfc6333..03e08a3b 100644 --- a/packages/emnapi/common.gypi +++ b/packages/emnapi/common.gypi @@ -85,7 +85,7 @@ '-sNODEJS_CATCH_EXIT=0', '-sNODEJS_CATCH_REJECTION=0', '-sWASM_BIGINT=1', - '-sMIN_CHROME_VERSION=84', + '-sMIN_CHROME_VERSION=85', '-sMIN_NODE_VERSION=161500', '-sSTACK_SIZE=<(stack_size)', '-sDEFAULT_PTHREAD_STACK_SIZE=<(stack_size)', @@ -102,7 +102,7 @@ '-sNODEJS_CATCH_EXIT=0', '-sNODEJS_CATCH_REJECTION=0', '-sWASM_BIGINT=1', - '-sMIN_CHROME_VERSION=84', + '-sMIN_CHROME_VERSION=85', '-sMIN_NODE_VERSION=161500', '-sSTACK_SIZE=<(stack_size)', '-sDEFAULT_PTHREAD_STACK_SIZE=<(stack_size)', diff --git a/packages/emnapi/src/function.ts b/packages/emnapi/src/function.ts index b67d6ec4..ddd056c0 100644 --- a/packages/emnapi/src/function.ts +++ b/packages/emnapi/src/function.ts @@ -30,7 +30,7 @@ export function napi_get_cb_info (env: napi_env, cbinfo: napi_callback_info, arg $CHECK_ENV!(env) const envObject = emnapiCtx.envStore.get(env)! if (!cbinfo) return envObject.setLastError(napi_status.napi_invalid_arg) - const cbinfoValue = emnapiCtx.cbinfoStack.get(cbinfo)! + const cbinfoValue = emnapiCtx.scopeStore.get(cbinfo)!.callbackInfo from64('argc') from64('argv') @@ -176,8 +176,15 @@ export function napi_get_new_target ( from64('result') - const cbinfoValue = emnapiCtx.cbinfoStack.get(cbinfo)! - const value = cbinfoValue.getNewTarget(envObject) + const cbinfoValue = emnapiCtx.scopeStore.get(cbinfo)!.callbackInfo + const { thiz, fn } = cbinfoValue + + const value = thiz == null || thiz.constructor == null + ? 0 + : thiz instanceof fn + ? envObject.ensureHandleId(thiz.constructor) + : 0 + makeSetValue('result', 0, 'value', '*') return envObject.clearLastError() } diff --git a/packages/emnapi/src/internal.ts b/packages/emnapi/src/internal.ts index b9d22ffb..6e6db1fa 100644 --- a/packages/emnapi/src/internal.ts +++ b/packages/emnapi/src/internal.ts @@ -12,24 +12,32 @@ export function emnapiCreateFunction any> (envObje const functionName = (!utf8name || !length) ? '' : (emnapiString.UTF8ToString(utf8name, length)) let f: F + const napiCallback = makeDynCall('ppp', 'cb') + const callback = (envObject: Env) => { + return napiCallback(envObject.id, envObject.ctx.scopeStore.currentScope.id) + } - const makeFunction = () => function (this: any): any { - 'use strict' - const cbinfo = emnapiCtx.cbinfoStack.push(this, data, arguments, f) - const scope = emnapiCtx.openScope(envObject) + const makeFunction = (envObject: Env, callback: (env: Env) => any) => function (this: any, ...args: any[]): any { + const scope = envObject.ctx.openScope(envObject) + const callbackInfo = scope.callbackInfo + callbackInfo.data = data + callbackInfo.args = args + callbackInfo.thiz = this + callbackInfo.fn = f try { - return envObject.callIntoModule((envObject) => { - const napiValue = makeDynCall('ppp', 'cb')(envObject.id, cbinfo) - return (!napiValue) ? undefined : emnapiCtx.handleStore.get(napiValue)!.value - }) + const napiValue = envObject.callIntoModule(callback) + return (!napiValue) ? undefined : envObject.ctx.handleStore.get(napiValue)!.value } finally { - emnapiCtx.cbinfoStack.pop() - emnapiCtx.closeScope(envObject, scope) + callbackInfo.data = 0 + callbackInfo.args = undefined! + callbackInfo.thiz = undefined + callbackInfo.fn = undefined! + envObject.ctx.closeScope(envObject, scope) } } if (functionName === '') { - f = makeFunction() as F + f = makeFunction(envObject, callback) as F return { status: napi_status.napi_ok, f } } @@ -39,7 +47,7 @@ export function emnapiCreateFunction any> (envObje // #if DYNAMIC_EXECUTION if (emnapiCtx.feature.supportNewFunction) { - const _ = makeFunction() + const _ = makeFunction(envObject, callback) try { f = (new Function('_', 'return function ' + functionName + '(){' + @@ -48,15 +56,15 @@ export function emnapiCreateFunction any> (envObje '};' ))(_) } catch (_err) { - f = makeFunction() as F + f = makeFunction(envObject, callback) as F if (emnapiCtx.feature.canSetFunctionName) Object.defineProperty(f, 'name', { value: functionName }) } } else { - f = makeFunction() as F + f = makeFunction(envObject, callback) as F if (emnapiCtx.feature.canSetFunctionName) Object.defineProperty(f, 'name', { value: functionName }) } // #else - f = makeFunction() as F + f = makeFunction(envObject, callback) as F if (emnapiCtx.feature.canSetFunctionName) Object.defineProperty(f, 'name', { value: functionName }) // #endif return { status: napi_status.napi_ok, f } diff --git a/packages/runtime/src/CallbackInfo.ts b/packages/runtime/src/CallbackInfo.ts deleted file mode 100644 index d0811616..00000000 --- a/packages/runtime/src/CallbackInfo.ts +++ /dev/null @@ -1,76 +0,0 @@ -import type { Env } from './env' - -const EMPTY_ARGS = [] as const - -export class CallbackInfo { - public constructor ( - public id: number, - public parent: CallbackInfo, - public child: CallbackInfo | null, - public thiz: any, - public data: void_p, - public args: ArrayLike, - public fn: Function - ) {} - - public getNewTarget (envObject: Env): number { - const thiz = this.thiz - - if (thiz == null || thiz.constructor == null) return 0 - return thiz instanceof this.fn ? envObject.ensureHandleId(thiz.constructor) : 0 - } - - public dispose (): void { - if (this.thiz !== undefined) this.thiz = undefined - this.args = EMPTY_ARGS - this.fn = null! - } -} - -const ROOT_CBINFO = new CallbackInfo(0, null!, null, null, 0, null!, null!) - -export class CallbackInfoStack { - public current: CallbackInfo = ROOT_CBINFO - - public get (id: number): CallbackInfo | null { - if (id === 1) return ROOT_CBINFO.child! - - let info = ROOT_CBINFO - for (let i = 0; i < id; ++i) { - info = info.child! - if (info === null) return null - } - return info === ROOT_CBINFO ? null : info - } - - public pop (): void { - const current = this.current - if (current === ROOT_CBINFO) return - this.current = current.parent - current.dispose() - } - - public push ( - thiz: any, - data: void_p, - args: ArrayLike, - fn: Function - ): number { - let info = this.current.child - if (info) { - info.thiz = thiz - info.data = data - info.args = args - info.fn = fn - } else { - info = new CallbackInfo(this.current.id + 1, this.current, null, thiz, data, args, fn) - this.current.child = info - } - this.current = info - return info.id - } - - public dispose (): void { - this.current = null! - } -} diff --git a/packages/runtime/src/Context.ts b/packages/runtime/src/Context.ts index 28145d2e..731ac5b9 100644 --- a/packages/runtime/src/Context.ts +++ b/packages/runtime/src/Context.ts @@ -19,7 +19,6 @@ import { NAPI_VERSION_EXPERIMENTAL, NODE_API_DEFAULT_MODULE_API_VERSION } from './util' -import { CallbackInfoStack } from './CallbackInfo' import { NotSupportWeakRefError, NotSupportBufferError } from './errors' import { Reference, ReferenceWithData, ReferenceWithFinalizer, type ReferenceOwnership } from './Reference' import { type IDeferrdValue, Deferred } from './Deferred' @@ -117,7 +116,6 @@ export class Context { public refStore = new Store() public deferredStore = new Store() public handleStore = new HandleStore() - public cbinfoStack = new CallbackInfoStack() private readonly refCounter?: NodejsWaitingRequestCounter private readonly cleanupQueue: CleanupQueue diff --git a/packages/runtime/src/HandleScope.ts b/packages/runtime/src/HandleScope.ts index 8a55d5f5..fc888ff1 100644 --- a/packages/runtime/src/HandleScope.ts +++ b/packages/runtime/src/HandleScope.ts @@ -1,6 +1,13 @@ import type { Handle, HandleStore } from './Handle' import { External } from './External' +export interface ICallbackInfo { + thiz: any + data: void_p + args: ArrayLike + fn: Function +} + export class HandleScope { public handleStore: HandleStore public id: number @@ -8,7 +15,8 @@ export class HandleScope { public child: HandleScope | null public start: number public end: number - public _escapeCalled: boolean + private _escapeCalled: boolean + public callbackInfo: ICallbackInfo public constructor (handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end = start) { this.handleStore = handleStore @@ -19,6 +27,12 @@ export class HandleScope { this.start = start this.end = end this._escapeCalled = false + this.callbackInfo = { + thiz: undefined, + data: 0, + args: undefined!, + fn: undefined! + } } public add (value: V): Handle { @@ -32,6 +46,7 @@ export class HandleScope { } public dispose (): void { + if (this._escapeCalled) this._escapeCalled = false if (this.start === this.end) return this.handleStore.erase(this.start, this.end) } diff --git a/packages/runtime/src/ScopeStore.ts b/packages/runtime/src/ScopeStore.ts index c69c10f1..3d9a49c2 100644 --- a/packages/runtime/src/ScopeStore.ts +++ b/packages/runtime/src/ScopeStore.ts @@ -5,22 +5,16 @@ import { HandleScope } from './HandleScope' export class ScopeStore { private readonly _rootScope: HandleScope public currentScope: HandleScope + private readonly _values: [undefined, ...HandleScope[]] constructor () { this._rootScope = new HandleScope(null!, 0, null, 1, HandleStore.MIN_ID) this.currentScope = this._rootScope + this._values = [undefined] } get (id: number): HandleScope | undefined { - id = Number(id) - let scope = this.currentScope - while (scope !== this._rootScope) { - if (scope.id === id) { - return scope - } - scope = scope.parent! - } - return undefined + return this._values[id] } openScope (envObject: Env): HandleScope { @@ -29,9 +23,10 @@ export class ScopeStore { if (scope !== null) { scope.start = scope.end = currentScope.end - scope._escapeCalled = false } else { - scope = new HandleScope(envObject.ctx.handleStore, currentScope.id + 1, currentScope, currentScope.end) + const id = currentScope.id + 1 + scope = new HandleScope(envObject.ctx.handleStore, id, currentScope, currentScope.end) + this._values[id] = scope } this.currentScope = scope @@ -48,18 +43,7 @@ export class ScopeStore { } dispose (): void { - let scope: HandleScope | null = this.currentScope - while (scope !== null) { - scope.handleStore = null! - scope.id = 0 - scope.parent = null - scope.start = HandleStore.MIN_ID - scope.end = HandleStore.MIN_ID - scope._escapeCalled = false - const child: HandleScope | null = scope.child - scope.child = null - scope = child - } - this.currentScope = null! + this.currentScope = this._rootScope + this._values.length = 1 } } diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 72569517..c4ad49bb 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -1,4 +1,3 @@ -export { CallbackInfo, CallbackInfoStack } from './CallbackInfo' export { createContext, getDefaultContext, Context, type CleanupHookCallbackFunction } from './Context' export { Deferred, type IDeferrdValue } from './Deferred' export { Env, NodeEnv, type IReferenceBinding } from './env' @@ -7,7 +6,7 @@ export { External, isExternal, getExternalValue } from './External' export { Finalizer } from './Finalizer' export { TrackedFinalizer } from './TrackedFinalizer' export { Handle, ConstHandle, HandleStore } from './Handle' -export { HandleScope } from './HandleScope' +export { HandleScope, type ICallbackInfo } from './HandleScope' export { Persistent } from './Persistent' export { Reference, ReferenceWithData, ReferenceWithFinalizer, ReferenceOwnership } from './Reference' export { RefTracker } from './RefTracker' diff --git a/packages/test/CMakeLists.txt b/packages/test/CMakeLists.txt index 77e35905..e2514af8 100644 --- a/packages/test/CMakeLists.txt +++ b/packages/test/CMakeLists.txt @@ -86,7 +86,7 @@ if(IS_EMSCRIPTEN) "-sNODEJS_CATCH_EXIT=0" "-sWASM_BIGINT=1" "-sALLOW_MEMORY_GROWTH=1" - "-sMIN_CHROME_VERSION=84" + "-sMIN_CHROME_VERSION=85" "-sSTACK_SIZE=1048576" "-sDEFAULT_PTHREAD_STACK_SIZE=1048576" "-sINITIAL_MEMORY=16777216"