1+ import { freemem } from "node:os" ;
12import wizer from '@bytecodealliance/wizer' ;
23import getWeval from '@bytecodealliance/weval' ;
34import {
@@ -19,7 +20,7 @@ import { fileURLToPath } from 'node:url';
1920import { stdout , stderr , exit , platform } from 'node:process' ;
2021import { init as lexerInit , parse } from 'es-module-lexer' ;
2122export const { version } = JSON . parse (
22- await readFile ( new URL ( '../package.json' , import . meta. url ) , 'utf8' )
23+ await readFile ( new URL ( '../package.json' , import . meta. url ) , 'utf8' ) ,
2324) ;
2425const isWindows = platform === 'win32' ;
2526const DEBUG_BINDINGS = false ;
@@ -32,6 +33,24 @@ function maybeWindowsPath(path) {
3233 return '//?/' + resolve ( path ) . replace ( / \\ / g, '/' ) ;
3334}
3435
36+ /**
37+ * Check whether a value is numeric (including BigInt)
38+ *
39+ * @param {any } n
40+ * @returns {boolean } whether the value is numeric
41+ */
42+ function isNumeric ( n ) {
43+ switch ( typeof n ) {
44+ case 'bigint' :
45+ case 'number' :
46+ return true ;
47+ case 'object' :
48+ return n . constructor == BigInt || n . constructor == Number ;
49+ default :
50+ return false ;
51+ }
52+ }
53+
3554export async function componentize ( jsSource , witWorld , opts ) {
3655 if ( typeof witWorld === 'object' ) {
3756 opts = witWorld ;
@@ -48,7 +67,7 @@ export async function componentize(jsSource, witWorld, opts) {
4867 debugBuild = false ,
4968 runtimeArgs,
5069 aotCache = fileURLToPath (
51- new URL ( `../lib/starlingmonkey_ics.wevalcache` , import . meta. url )
70+ new URL ( `../lib/starlingmonkey_ics.wevalcache` , import . meta. url ) ,
5271 ) ,
5372 } = opts ;
5473
@@ -58,11 +77,9 @@ export async function componentize(jsSource, witWorld, opts) {
5877 new URL (
5978 opts . enableAot
6079 ? `../lib/starlingmonkey_embedding_weval.wasm`
61- : `../lib/starlingmonkey_embedding${
62- debugBuild ? '.debug' : ''
63- } .wasm`,
64- import . meta. url
65- )
80+ : `../lib/starlingmonkey_embedding${ debugBuild ? '.debug' : '' } .wasm` ,
81+ import . meta. url ,
82+ ) ,
6683 ) ;
6784
6885 await lexerInit ;
@@ -108,7 +125,7 @@ export async function componentize(jsSource, witWorld, opts) {
108125 guestImports ,
109126 guestExports ,
110127 features ,
111- false
128+ false ,
112129 ) ;
113130
114131 if ( DEBUG_BINDINGS ) {
@@ -119,7 +136,7 @@ export async function componentize(jsSource, witWorld, opts) {
119136 jsBindings
120137 . split ( '\n' )
121138 . map ( ( ln , idx ) => `${ ( idx + 1 ) . toString ( ) . padStart ( 4 , ' ' ) } | ${ ln } ` )
122- . join ( '\n' )
139+ . join ( '\n' ) ,
123140 ) ;
124141 console . log ( '--- JS Imports ---' ) ;
125142 console . log ( imports ) ;
@@ -133,7 +150,7 @@ export async function componentize(jsSource, witWorld, opts) {
133150 createHash ( 'sha256' )
134151 . update ( Math . random ( ) . toString ( ) )
135152 . digest ( 'hex' )
136- . slice ( 0 , 12 )
153+ . slice ( 0 , 12 ) ,
137154 ) ;
138155 await mkdir ( tmpDir ) ;
139156
@@ -158,8 +175,8 @@ export async function componentize(jsSource, witWorld, opts) {
158175 ]
159176 . map ( ( impt ) => `'${ impt } '` )
160177 . join (
161- ', '
162- ) } .\nMake sure to use a bundler for JS dependencies such as esbuild or RollupJS.`
178+ ', ' ,
179+ ) } .\nMake sure to use a bundler for JS dependencies such as esbuild or RollupJS.`,
163180 ) ;
164181 }
165182 const specifier = jsSource . slice ( jsImpt . s , jsImpt . e ) ;
@@ -186,8 +203,8 @@ export async function componentize(jsSource, witWorld, opts) {
186203 source ,
187204 ] ) ,
188205 ] . map ( async ( [ sourceName , source ] ) =>
189- writeFile ( join ( sourceDir , sourceName ) , source )
190- )
206+ writeFile ( join ( sourceDir , sourceName ) , source ) ,
207+ ) ,
191208 ) ;
192209
193210 let hostenv = { } ;
@@ -224,7 +241,9 @@ export async function componentize(jsSource, witWorld, opts) {
224241 console . log ( env ) ;
225242 }
226243
227- let sourcePath = maybeWindowsPath ( join ( sourceDir , sourceName . slice ( 0 , - 3 ) + '.bindings.js' ) ) ;
244+ let sourcePath = maybeWindowsPath (
245+ join ( sourceDir , sourceName . slice ( 0 , - 3 ) + '.bindings.js' ) ,
246+ ) ;
228247 runtimeArgs = runtimeArgs ? `${ runtimeArgs } ${ sourcePath } ` : sourcePath ;
229248
230249 if ( opts . enableAot ) {
@@ -236,6 +255,18 @@ export async function componentize(jsSource, witWorld, opts) {
236255 wevalBin = await getWeval ( ) ;
237256 }
238257
258+ // Set the min stack size, if one was provided
259+ if ( opts . aotMinStackSizeBytes ) {
260+ if ( ! isNumeric ( opts . aotMinStackSizeBytes ) ) {
261+ throw new TypeError (
262+ `aotMinStackSizeBytes must be a numeric value, received [${ opts . aotMinStackSizeBytes } ] (type ${ typeof opts . aotMinStackSizeBytes } )` ,
263+ ) ;
264+ }
265+ env . RUST_MIN_STACK = opts . aotMinStackSizeBytes ;
266+ } else {
267+ env . RUST_MIN_STACK = defaultMinStackSize ( ) ;
268+ }
269+
239270 try {
240271 let wevalProcess = spawnSync (
241272 wevalBin ,
@@ -255,7 +286,7 @@ export async function componentize(jsSource, witWorld, opts) {
255286 input : runtimeArgs ,
256287 shell : true ,
257288 encoding : 'utf-8' ,
258- }
289+ } ,
259290 ) ;
260291 if ( wevalProcess . status !== 0 )
261292 throw new Error ( 'Wevaling failed to complete' ) ;
@@ -290,7 +321,7 @@ export async function componentize(jsSource, witWorld, opts) {
290321 input : runtimeArgs ,
291322 shell : true ,
292323 encoding : 'utf-8' ,
293- }
324+ } ,
294325 ) ;
295326 if ( wizerProcess . status !== 0 )
296327 throw new Error ( 'Wizering failed to complete' ) ;
@@ -326,7 +357,7 @@ export async function componentize(jsSource, witWorld, opts) {
326357 async function initWasm ( bin ) {
327358 const eep = ( name ) => ( ) => {
328359 throw new Error (
329- `Internal error: unexpected call to "${ name } " during Wasm verification`
360+ `Internal error: unexpected call to "${ name } " during Wasm verification` ,
330361 ) ;
331362 } ;
332363
@@ -346,7 +377,7 @@ export async function componentize(jsSource, witWorld, opts) {
346377 const bufPtr = mem . getUint32 ( iovs + i * 8 , true ) ;
347378 const bufLen = mem . getUint32 ( iovs + 4 + i * 8 , true ) ;
348379 stderr += new TextDecoder ( ) . decode (
349- new Uint8Array ( exports . memory . buffer , bufPtr , bufLen )
380+ new Uint8Array ( exports . memory . buffer , bufPtr , bufLen ) ,
350381 ) ;
351382 written += bufLen ;
352383 }
@@ -372,7 +403,7 @@ export async function componentize(jsSource, witWorld, opts) {
372403
373404 // convert CABI import conventiosn to ESM import conventions
374405 imports = imports . map ( ( [ specifier , impt ] ) =>
375- specifier === '$root' ? [ impt , 'default' ] : [ specifier , impt ]
406+ specifier === '$root' ? [ impt , 'default' ] : [ specifier , impt ] ,
376407 ) ;
377408
378409 const INIT_OK = 0 ;
@@ -409,7 +440,7 @@ export async function componentize(jsSource, witWorld, opts) {
409440 features ,
410441 witWorld ,
411442 maybeWindowsPath ( witPath ) ,
412- worldName
443+ worldName ,
413444 ) ;
414445
415446 if ( DEBUG_BINARY ) {
@@ -422,16 +453,27 @@ export async function componentize(jsSource, witWorld, opts) {
422453 Object . entries ( {
423454 wasi_snapshot_preview1 : await readFile ( preview2Adapter ) ,
424455 } ) ,
425- false
456+ false ,
426457 ) ,
427458 Object . entries ( {
428459 language : [ [ 'JavaScript' , '' ] ] ,
429460 'processed-by' : [ [ 'ComponentizeJS' , version ] ] ,
430- } )
461+ } ) ,
431462 ) ;
432463
433464 return {
434465 component,
435466 imports,
436467 } ;
437468}
469+
470+ /**
471+ * Calculate the min stack size depending on free memory
472+ *
473+ * @param {number } freeMemoryBytes - Amount of free memory in the system, in bytes (if not provided, os.freemem() is used)
474+ * @returns {number } The minimum stack size that should be used as a default.
475+ */
476+ function defaultMinStackSize ( freeMemoryBytes ) {
477+ freeMemoryBytes = freeMemoryBytes ?? freemem ( ) ;
478+ return Math . max ( 8 * 1024 * 1024 , Math . floor ( freeMemoryBytes * 0.1 ) ) ;
479+ }
0 commit comments