Skip to content

Commit d1c6bac

Browse files
feat: allow setting rust min stack size
Signed-off-by: Victor Adossi <vadossi@cosmonic.com>
1 parent 7f17009 commit d1c6bac

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(
@@ -239,6 +256,18 @@ export async function componentize(opts,
239256
wevalBin = await getWeval();
240257
}
241258

259+
// Set the min stack size, if one was provided
260+
if (opts.aotMinStackSizeBytes) {
261+
if (!isNumeric(opts.aotMinStackSizeBytes)) {
262+
throw new TypeError(
263+
`aotMinStackSizeBytes must be a numeric value, received [${opts.aotMinStackSizeBytes}] (type ${typeof opts.aotMinStackSizeBytes})`,
264+
);
265+
}
266+
env.RUST_MIN_STACK = opts.aotMinStackSizeBytes;
267+
} else {
268+
env.RUST_MIN_STACK = defaultMinStackSize();
269+
}
270+
242271
wizerProcess = spawnSync(
243272
wevalBin,
244273
[
@@ -312,7 +341,7 @@ export async function componentize(opts,
312341
async function initWasm(bin) {
313342
const eep = (name) => () => {
314343
throw new Error(
315-
`Internal error: unexpected call to "${name}" during Wasm verification`
344+
`Internal error: unexpected call to "${name}" during Wasm verification`,
316345
);
317346
};
318347

@@ -332,7 +361,7 @@ export async function componentize(opts,
332361
const bufPtr = mem.getUint32(iovs + i * 8, true);
333362
const bufLen = mem.getUint32(iovs + 4 + i * 8, true);
334363
stderr += new TextDecoder().decode(
335-
new Uint8Array(exports.memory.buffer, bufPtr, bufLen)
364+
new Uint8Array(exports.memory.buffer, bufPtr, bufLen),
336365
);
337366
written += bufLen;
338367
}
@@ -390,7 +419,7 @@ export async function componentize(opts,
390419
features,
391420
witWorld,
392421
maybeWindowsPath(witPath),
393-
worldName
422+
worldName,
394423
);
395424

396425
if (debugBindings) {
@@ -403,12 +432,12 @@ export async function componentize(opts,
403432
Object.entries({
404433
wasi_snapshot_preview1: await readFile(preview2Adapter),
405434
}),
406-
false
435+
false,
407436
),
408437
Object.entries({
409438
language: [['JavaScript', '']],
410439
'processed-by': [['ComponentizeJS', version]],
411-
})
440+
}),
412441
);
413442

414443
// convert CABI import conventions to ESM import conventions
@@ -421,3 +450,14 @@ export async function componentize(opts,
421450
imports,
422451
};
423452
}
453+
454+
/**
455+
* Calculate the min stack size depending on free memory
456+
*
457+
* @param {number} freeMemoryBytes - Amount of free memory in the system, in bytes (if not provided, os.freemem() is used)
458+
* @returns {number} The minimum stack size that should be used as a default.
459+
*/
460+
function defaultMinStackSize(freeMemoryBytes) {
461+
freeMemoryBytes = freeMemoryBytes ?? freemem();
462+
return Math.max(8 * 1024 * 1024, Math.floor(freeMemoryBytes * 0.1));
463+
}

0 commit comments

Comments
 (0)