Skip to content

Commit 4919e9d

Browse files
feat: allow setting rust min stack size (#206)
Signed-off-by: Victor Adossi <vadossi@cosmonic.com>
1 parent ec58786 commit 4919e9d

File tree

2 files changed

+58
-12
lines changed

2 files changed

+58
-12
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ The component iself can be executed in any component runtime, see the [example](
111111

112112
To enable AOT compilation, set the `enableAot: true` option to run [Weval][weval] ahead-of-time compilation.
113113

114+
AOT compilation can also be configured with the following options:
115+
116+
| Option | Type | Example | Description |
117+
|------------------------|-------------------------------------|-----------------|--------------------------------------------------------------------------|
118+
| `aotMinStackSizeBytes` | `nubmer | Number | bigint | BigInt` | `2_007_846_092` | The minimum stack size (via `RUST_MIN_STACK` to set when running `weval` |
119+
114120
[weval]: https://github.com/bytecodealliance/weval
115121

116122
### Custom `weval` binary

src/componentize.js

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { freemem } from "node:os";
12
import wizer from '@bytecodealliance/wizer';
23
import getWeval from '@bytecodealliance/weval';
34
import {
@@ -18,7 +19,7 @@ import {
1819
import { fileURLToPath } from 'node:url';
1920
import { cwd, stdout, platform } from 'node:process';
2021
export const { version } = JSON.parse(
21-
await readFile(new URL('../package.json', import.meta.url), 'utf8')
22+
await readFile(new URL('../package.json', import.meta.url), 'utf8'),
2223
);
2324
const isWindows = platform === 'win32';
2425

@@ -56,6 +57,24 @@ function parseWizerStderr(stderr) {
5657
return `${output.substring(0, causeStart)}${output.substring(causeEnd)}`.trim();
5758
}
5859

60+
/**
61+
* Check whether a value is numeric (including BigInt)
62+
*
63+
* @param {any} n
64+
* @returns {boolean} whether the value is numeric
65+
*/
66+
function isNumeric(n) {
67+
switch (typeof n) {
68+
case 'bigint':
69+
case 'number':
70+
return true;
71+
case 'object':
72+
return n.constructor == BigInt || n.constructor == Number;
73+
default:
74+
return false;
75+
}
76+
}
77+
5978
export async function componentize(opts,
6079
_deprecatedWitWorldOrOpts = undefined,
6180
_deprecatedOpts = undefined) {
@@ -106,7 +125,7 @@ export async function componentize(opts,
106125
debugBindings = false,
107126
enableWizerLogging = false,
108127
aotCache = fileURLToPath(
109-
new URL(`../lib/starlingmonkey_ics.wevalcache`, import.meta.url)
128+
new URL(`../lib/starlingmonkey_ics.wevalcache`, import.meta.url),
110129
),
111130
} = opts;
112131

@@ -116,11 +135,9 @@ export async function componentize(opts,
116135
new URL(
117136
opts.enableAot
118137
? `../lib/starlingmonkey_embedding_weval.wasm`
119-
: `../lib/starlingmonkey_embedding${
120-
debugBuild ? '.debug' : ''
121-
}.wasm`,
122-
import.meta.url
123-
)
138+
: `../lib/starlingmonkey_embedding${debugBuild ? '.debug' : ''}.wasm`,
139+
import.meta.url,
140+
),
124141
);
125142

126143
let { wasm, jsBindings, exports, imports } = spliceBindings(
@@ -245,6 +262,18 @@ export async function componentize(opts,
245262
wevalBin = await getWeval();
246263
}
247264

265+
// Set the min stack size, if one was provided
266+
if (opts.aotMinStackSizeBytes) {
267+
if (!isNumeric(opts.aotMinStackSizeBytes)) {
268+
throw new TypeError(
269+
`aotMinStackSizeBytes must be a numeric value, received [${opts.aotMinStackSizeBytes}] (type ${typeof opts.aotMinStackSizeBytes})`,
270+
);
271+
}
272+
env.RUST_MIN_STACK = opts.aotMinStackSizeBytes;
273+
} else {
274+
env.RUST_MIN_STACK = defaultMinStackSize();
275+
}
276+
248277
wizerProcess = spawnSync(
249278
wevalBin,
250279
[
@@ -318,7 +347,7 @@ export async function componentize(opts,
318347
async function initWasm(bin) {
319348
const eep = (name) => () => {
320349
throw new Error(
321-
`Internal error: unexpected call to "${name}" during Wasm verification`
350+
`Internal error: unexpected call to "${name}" during Wasm verification`,
322351
);
323352
};
324353

@@ -338,7 +367,7 @@ export async function componentize(opts,
338367
const bufPtr = mem.getUint32(iovs + i * 8, true);
339368
const bufLen = mem.getUint32(iovs + 4 + i * 8, true);
340369
stderr += new TextDecoder().decode(
341-
new Uint8Array(exports.memory.buffer, bufPtr, bufLen)
370+
new Uint8Array(exports.memory.buffer, bufPtr, bufLen),
342371
);
343372
written += bufLen;
344373
}
@@ -396,7 +425,7 @@ export async function componentize(opts,
396425
features,
397426
witWorld,
398427
maybeWindowsPath(witPath),
399-
worldName
428+
worldName,
400429
);
401430

402431
if (debugBindings) {
@@ -409,12 +438,12 @@ export async function componentize(opts,
409438
Object.entries({
410439
wasi_snapshot_preview1: await readFile(preview2Adapter),
411440
}),
412-
false
441+
false,
413442
),
414443
Object.entries({
415444
language: [['JavaScript', '']],
416445
'processed-by': [['ComponentizeJS', version]],
417-
})
446+
}),
418447
);
419448

420449
// convert CABI import conventions to ESM import conventions
@@ -427,3 +456,14 @@ export async function componentize(opts,
427456
imports,
428457
};
429458
}
459+
460+
/**
461+
* Calculate the min stack size depending on free memory
462+
*
463+
* @param {number} freeMemoryBytes - Amount of free memory in the system, in bytes (if not provided, os.freemem() is used)
464+
* @returns {number} The minimum stack size that should be used as a default.
465+
*/
466+
function defaultMinStackSize(freeMemoryBytes) {
467+
freeMemoryBytes = freeMemoryBytes ?? freemem();
468+
return Math.max(8 * 1024 * 1024, Math.floor(freeMemoryBytes * 0.1));
469+
}

0 commit comments

Comments
 (0)