Skip to content

Commit dddfd66

Browse files
authored
[Backport] fix: allow maximum memory 4GB (#205)
1 parent 12b9cf3 commit dddfd66

24 files changed

Lines changed: 143 additions & 77 deletions

File tree

.github/workflows/main.yml

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ env:
4040

4141
jobs:
4242
build:
43-
timeout-minutes: 15
43+
timeout-minutes: 20
4444
name: Build
4545
runs-on: ubuntu-latest
4646
env:
@@ -126,13 +126,25 @@ jobs:
126126
npm run rebuild:wt -w packages/test
127127
npm run test:wt -w packages/test
128128
129+
- name: Test wasm32-wasi-threads (4GB)
130+
if: ${{ matrix.target == 'wasm32-wasi-threads' }}
131+
env:
132+
EMNAPI_TEST_4GB: '1'
133+
run: npm run test:wt -w packages/test
134+
129135
- name: Test wasm32-unknown-emscripten
130136
if: ${{ matrix.target == 'wasm32-unknown-emscripten' }}
131137
run: |
132138
npm run test:version
133139
npm run rebuild -w packages/test
134140
npm run test -w packages/test
135141
142+
- name: Test wasm32-unknown-emscripten (4GB)
143+
if: ${{ matrix.target == 'wasm32-unknown-emscripten' }}
144+
env:
145+
EMNAPI_TEST_4GB: '1'
146+
run: npm run test -w packages/test
147+
136148
- name: Test wasm64-unknown-emscripten
137149
if: ${{ matrix.target == 'wasm64-unknown-emscripten' }}
138150
env:
@@ -143,18 +155,39 @@ jobs:
143155
node ./packages/test/script/build-emscripten.js Debug
144156
node ./packages/test/script/test.js
145157
158+
- name: Test wasm64-unknown-emscripten (4GB)
159+
if: ${{ matrix.target == 'wasm64-unknown-emscripten' }}
160+
env:
161+
MEMORY64: '1'
162+
EMNAPI_TEST_4GB: '1'
163+
UV_THREADPOOL_SIZE: '2'
164+
NODE_TEST_KNOWN_GLOBALS: '0'
165+
run: node ./packages/test/script/test.js
166+
146167
- name: Test wasm32-wasi
147168
if: ${{ matrix.target == 'wasm32-wasi' }}
148169
run: |
149170
npm run rebuild:w -w packages/test
150171
npm run test:w -w packages/test
151172
173+
- name: Test wasm32-wasi (4GB)
174+
if: ${{ matrix.target == 'wasm32-wasi' }}
175+
env:
176+
EMNAPI_TEST_4GB: '1'
177+
run: npm run test:w -w packages/test
178+
152179
- name: Test wasm32-unknown-unknown
153180
if: ${{ matrix.target == 'wasm32-unknown-unknown' }}
154181
run: |
155182
npm run rebuild:wasm32 -w packages/test
156183
npm run test:wasm32 -w packages/test
157184
185+
- name: Test wasm32-unknown-unknown (4GB)
186+
if: ${{ matrix.target == 'wasm32-unknown-unknown' }}
187+
env:
188+
EMNAPI_TEST_4GB: '1'
189+
run: npm run test:wasm32 -w packages/test
190+
158191
release:
159192
name: Release main packages
160193
env:

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
}
2828
},
2929
"dependencies": {
30-
"@emnapi/wasi-threads": "1.2.0",
30+
"@emnapi/wasi-threads": "1.2.1",
3131
"tslib": "^2.4.0"
3232
},
3333
"scripts": {

packages/emnapi/src/core/async-work.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ var emnapiAWMT = {
9191
emnapiAWMT.globalAddress = _malloc(to64('emnapiAWMT.globalOffset.end') as number)
9292
// Ensure the shared state is zero-initialized before use so that
9393
// idle_threads/mutex/cond and related fields start from a known state.
94+
from64('emnapiAWMT.globalAddress')
9495
const size = emnapiAWMT.globalOffset.end
9596
const addr = emnapiAWMT.globalAddress
9697
new Uint8Array(wasmMemory.buffer, addr, size).fill(0)
97-
from64('emnapiAWMT.globalAddress')
9898
emnapiAWMT.queueInit(emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.q)
9999
emnapiAWMT.queueInit(emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.exit_message)
100100
}
@@ -126,16 +126,18 @@ var emnapiAWMT = {
126126
if (index === 0) {
127127
return Promise.reject(new Error('Failed to create async worker'))
128128
}
129-
if (index > 0) {
130-
const view = new DataView(wasmMemory.buffer)
131-
const tidOffset = 20
132-
const tid = view.getInt32(index + tidOffset, true)
133-
const worker = PThread.pthreads[tid]
134-
return worker.whenLoaded!
135-
} else {
136-
const worker = emnapiAWMT.pool[-index - 1]
137-
return worker.whenLoaded!
129+
let worker: any
130+
if (index < 0) {
131+
worker = emnapiAWMT.pool[-index - 1]
132+
if (worker) return worker.whenLoaded
138133
}
134+
from64('index')
135+
136+
const view = new DataView(wasmMemory.buffer)
137+
const tidOffset = 20
138+
const tid = view.getInt32(index + tidOffset, true)
139+
worker = PThread.pthreads[tid]
140+
return worker.whenLoaded!
139141
})
140142
emnapiAWMT.workerReady = Promise.all(promises) as any
141143
return emnapiAWMT.workerReady as Promise<any>
@@ -351,6 +353,7 @@ export var napi_create_async_work = singleThreadAsyncWork
351353

352354
// eslint-disable-next-line @typescript-eslint/no-unused-vars
353355
const id = emnapiAWST.create(env, resourceObject, resourceName, execute, complete, data)
356+
from64('result')
354357
makeSetValue('result', 0, 'id', '*')
355358
return envObject.clearLastError()
356359
}
@@ -371,6 +374,7 @@ export var napi_create_async_work = singleThreadAsyncWork
371374
const sizeofAW = emnapiAWMT.offset.end
372375
const aw = _malloc(to64('sizeofAW'))
373376
if (!aw) return envObject.setLastError(napi_status.napi_generic_failure)
377+
from64('aw')
374378
new Uint8Array(wasmMemory.buffer).subarray(aw, aw + sizeofAW).fill(0)
375379
const s = envObject.ensureHandleId(resourceObject)
376380
const resourceRef = emnapiCtx.createReference(envObject, s, 1, ReferenceOwnership.kUserland as any)
@@ -393,14 +397,14 @@ export var napi_delete_async_work = singleThreadAsyncWork
393397
? function (env: napi_env, work: number): napi_status {
394398
const envObject: Env = $CHECK_ENV_NOT_IN_GC!(env)
395399
$CHECK_ARG!(envObject, work)
396-
400+
from64('work')
397401
emnapiAWST.remove(work)
398402
return envObject.clearLastError()
399403
}
400404
: function (env: napi_env, work: number): napi_status {
401405
const envObject: Env = $CHECK_ENV_NOT_IN_GC!(env)
402406
$CHECK_ARG!(envObject, work)
403-
407+
from64('work')
404408
const resource = emnapiAWMT.getResource(work)
405409
emnapiCtx.refStore.get(resource)!.dispose()
406410

@@ -421,15 +425,15 @@ export var napi_queue_async_work = singleThreadAsyncWork
421425
$CHECK_ENV!(env)
422426
const envObject = emnapiCtx.envStore.get(env)!
423427
$CHECK_ARG!(envObject, work)
424-
428+
from64('work')
425429
emnapiAWST.queue(work)
426430
return envObject.clearLastError()
427431
}
428432
: function (env: napi_env, work: number): napi_status {
429433
$CHECK_ENV!(env)
430434
const envObject = emnapiCtx.envStore.get(env)!
431435
$CHECK_ARG!(envObject, work)
432-
436+
from64('work')
433437
emnapiAWMT.scheduleWork(work)
434438
return envObject.clearLastError()
435439
}
@@ -440,7 +444,7 @@ export var napi_cancel_async_work = singleThreadAsyncWork
440444
$CHECK_ENV!(env)
441445
const envObject = emnapiCtx.envStore.get(env)!
442446
$CHECK_ARG!(envObject, work)
443-
447+
from64('work')
444448
const status = emnapiAWST.cancel(work)
445449
if (status === napi_status.napi_ok) return envObject.clearLastError()
446450
return envObject.setLastError(status)
@@ -449,14 +453,15 @@ export var napi_cancel_async_work = singleThreadAsyncWork
449453
$CHECK_ENV!(env)
450454
const envObject = emnapiCtx.envStore.get(env)!
451455
$CHECK_ARG!(envObject, work)
452-
456+
from64('work')
453457
const status = emnapiAWMT.cancelWork(work)
454458
if (status === napi_status.napi_ok) return envObject.clearLastError()
455459
return envObject.setLastError(status)
456460
}
457461

458462
/** @__sig pp */
459463
export function _emnapi_async_worker (globalAddress: number): number {
464+
from64('globalAddress')
460465
emnapiAWMT.globalAddress = globalAddress
461466
const mutex = emnapiAWMT.getMutex()
462467
const cond = emnapiAWMT.getCond()

packages/emnapi/src/emnapi.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export function $emnapiSyncMemory<T extends ArrayBufferLike | ArrayBufferView> (
150150
if (arrayBufferOrView instanceof ArrayBuffer || emnapiExternalMemory.isSharedArrayBuffer(arrayBufferOrView)) {
151151
const pointer = emnapiExternalMemory.getArrayBufferPointer(arrayBufferOrView, false).address
152152
if (!pointer) throw new Error('Unknown ArrayBuffer address')
153-
if (typeof len !== 'number' || len === -1) {
153+
if (typeof len !== 'number' || len === -1 || len === 4294967295) {
154154
len = arrayBufferOrView.byteLength - offset
155155
}
156156
len = len >>> 0
@@ -172,7 +172,7 @@ export function $emnapiSyncMemory<T extends ArrayBufferLike | ArrayBufferView> (
172172
const latestView = viewPointerInfo.view
173173
const pointer = viewPointerInfo.address
174174
if (!pointer) throw new Error('Unknown ArrayBuffer address')
175-
if (typeof len !== 'number' || len === -1) {
175+
if (typeof len !== 'number' || len === -1 || len === 4294967295) {
176176
len = latestView.byteLength - offset
177177
}
178178
len = len >>> 0

packages/emnapi/src/emscripten/async-work.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { emnapiCtx } from 'emnapi:shared'
2-
import { makeSetValue } from 'emscripten:parse-tools'
2+
import { from64, makeSetValue } from 'emscripten:parse-tools'
33
import { emnapiAWST } from '../async-work'
44
import { $CHECK_ARG, $CHECK_ENV, $CHECK_ENV_NOT_IN_GC } from '../macro'
55

@@ -24,6 +24,7 @@ export function napi_create_async_work (env: napi_env, resource: napi_value, res
2424

2525
// eslint-disable-next-line @typescript-eslint/no-unused-vars
2626
const id = emnapiAWST.create(env, resourceObject, resourceName, execute, complete, data)
27+
from64('result')
2728
makeSetValue('result', 0, 'id', '*')
2829
return envObject.clearLastError()
2930
}

packages/emnapi/src/macro.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export function $CHECK_ENV_NOT_IN_GC (env: napi_env): any {
5151
/** @macro */
5252
export function $CHECK_NEW_STRING_ARGS (env: napi_env, str: const_char_p, length: number, result: Pointer<napi_value>): any {
5353
const envObject: Env = $CHECK_ENV_NOT_IN_GC!(env)
54-
const autoLength = length === -1
54+
const autoLength = length === -1 || length === 4294967295
5555
const sizelength = length >>> 0
5656
if (length !== 0) {
5757
$CHECK_ARG!(envObject, str)

packages/emnapi/src/memory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { _free, wasmMemory, _malloc } from 'emscripten:runtime'
22
import { emnapiCtx } from 'emnapi:shared'
3-
import { to64 } from 'emscripten:parse-tools'
3+
import { from64, to64 } from 'emscripten:parse-tools'
44

55
export type ViewConstuctor =
66
Int8ArrayConstructor |
@@ -113,6 +113,7 @@ export const emnapiExternalMemory: {
113113

114114
const pointer = _malloc(to64('arrayBuffer.byteLength'))
115115
if (!pointer) throw new Error('Out of memory')
116+
from64('pointer')
116117
new Uint8Array(wasmMemory.buffer).set(new Uint8Array(arrayBuffer), pointer)
117118

118119
info.address = pointer

packages/emnapi/src/string.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export var emnapiString = {
134134
ptr >>>= 0
135135
const HEAPU8 = new Uint8Array(wasmMemory.buffer)
136136
let end = ptr
137-
if (length === -1) {
137+
if (length === -1 || length === 4294967295) {
138138
for (; HEAPU8[end];) ++end
139139
} else {
140140
end = ptr + (length >>> 0)
@@ -209,11 +209,11 @@ export var emnapiString = {
209209
if (!ptr || !length) return ''
210210
ptr >>>= 0
211211
let end = ptr
212-
if (length === -1) {
213-
let idx = end >> 1
212+
if (length === -1 || length === 4294967295) {
213+
let idx = end >>> 1
214214
const HEAPU16 = new Uint16Array(wasmMemory.buffer)
215215
while (HEAPU16[idx]) ++idx
216-
end = idx << 1
216+
end = (idx << 1) >>> 0
217217
} else {
218218
end = ptr + (length >>> 0) * 2
219219
}

0 commit comments

Comments
 (0)