tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 442c00c57481e2175d7b5cedcab280624739b2c8
parent 0ab5fc76883d63d41db23ae49916382fe81f1313
Author: Cornelius Emase <corneliuslochipi@gmail.com>
Date:   Wed, 19 Nov 2025 13:53:01 +0000

Bug 1999787 - Support `bytes` modules in parseModule r=bthrall,arai

Add support for `bytes` modules in the JS shell. We're now also checking
the ArrayBuffer and wrap with CreateDefaultExportSyntheticModule.
Module type now uses JS::ModuleType.

Differential Revision: https://phabricator.services.mozilla.com/D272694

Diffstat:
Ajs/src/jit-test/tests/modules/bytes-module.js | 25+++++++++++++++++++++++++
Mjs/src/shell/js.cpp | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
2 files changed, 86 insertions(+), 26 deletions(-)

diff --git a/js/src/jit-test/tests/modules/bytes-module.js b/js/src/jit-test/tests/modules/bytes-module.js @@ -0,0 +1,25 @@ +let buf = new ArrayBuffer(4); +let view = new Uint8Array(buf); +view[0] = 0x41; +view[1] = 0x42; +view[2] = 0x43; +view[3] = 0x44; + +let m = parseModule(buf, "bytes-module.js", "bytes"); +let a = registerModule("bytes-module", m); + +let importer = parseModule(` + import buf from 'bytes-module' with { type: 'bytes' }; + globalThis.importedBuf = buf; +`); + +let b = registerModule("importer", importer); + +moduleLink(b); +moduleEvaluate(b); + +let importedView = new Uint8Array(globalThis.importedBuf); + +for (let i = 0; i < view.length; i++) { + assertEq(importedView[i], view[i]); +} diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp @@ -5712,14 +5712,6 @@ static bool ParseModule(JSContext* cx, unsigned argc, Value* vp) { return false; } - if (!args[0].isString()) { - const char* typeName = InformalValueTypeName(args[0]); - JS_ReportErrorASCII(cx, "expected string to compile, got %s", typeName); - return false; - } - - JSString* scriptContents = args[0].toString(); - UniqueChars filename; CompileOptions options(cx); JS::ModuleType moduleType = JS::ModuleType::JavaScript; @@ -5738,7 +5730,8 @@ static bool ParseModule(JSContext* cx, unsigned argc, Value* vp) { options.setFileAndLine(filename.get(), 1); - // The 2nd argument is the module type string. "js" or "json" is expected. + // The 2nd argument is the module type string. "js", "json" or "bytes" is + // expected. if (args.length() == 3) { if (!args[2].isString()) { const char* typeName = InformalValueTypeName(args[2]); @@ -5753,8 +5746,11 @@ static bool ParseModule(JSContext* cx, unsigned argc, Value* vp) { } if (JS_LinearStringEqualsLiteral(linearStr, "json")) { moduleType = JS::ModuleType::JSON; + } else if (JS_LinearStringEqualsLiteral(linearStr, "bytes")) { + moduleType = JS::ModuleType::Bytes; } else if (!JS_LinearStringEqualsLiteral(linearStr, "js")) { - JS_ReportErrorASCII(cx, "moduleType string ('js' or 'json') expected"); + JS_ReportErrorASCII( + cx, "moduleType string ('js' or 'json' or 'bytes') expected"); return false; } } @@ -5762,23 +5758,62 @@ static bool ParseModule(JSContext* cx, unsigned argc, Value* vp) { options.setFileAndLine("<string>", 1); } - AutoStableStringChars linearChars(cx); - if (!linearChars.initTwoByte(cx, scriptContents)) { - return false; - } + RootedObject module(cx); + switch (moduleType) { + case JS::ModuleType::JavaScript: + case JS::ModuleType::JSON: { + if (!args[0].isString()) { + const char* typeName = InformalValueTypeName(args[0]); + JS_ReportErrorASCII(cx, "expected string to compile, got %s", typeName); + return false; + } - JS::SourceText<char16_t> srcBuf; - if (!srcBuf.initMaybeBorrowed(cx, linearChars)) { - return false; - } + JSString* scriptContents = args[0].toString(); - RootedObject module(cx); - if (moduleType == JS::ModuleType::JSON) { - module = JS::CompileJsonModule(cx, options, srcBuf); - } else { - options.setModule(); - module = JS::CompileModule(cx, options, srcBuf); + AutoStableStringChars linearChars(cx); + if (!linearChars.initTwoByte(cx, scriptContents)) { + return false; + } + + JS::SourceText<char16_t> srcBuf; + if (!srcBuf.initMaybeBorrowed(cx, linearChars)) { + return false; + } + + if (moduleType == JS::ModuleType::JSON) { + module = JS::CompileJsonModule(cx, options, srcBuf); + } else { + options.setModule(); + module = JS::CompileModule(cx, options, srcBuf); + } + + break; + } + + case JS::ModuleType::Bytes: { + if (!args[0].isObject() || + !JS::IsArrayBufferObject(&args[0].toObject())) { + const char* typeName = InformalValueTypeName(args[0]); + JS_ReportErrorASCII(cx, "expected ArrayBuffer for bytes module, got %s", + typeName); + return false; + } + + /* + * NOTE: The spec requires checking that the ArrayBuffer is immutable. + * Immutable ArrayBuffers (see bug 1952253) are still only a Stage 2.7 + * proposal. This check will be added in a future update. + */ + module = JS::CreateDefaultExportSyntheticModule(cx, args[0]); + break; + } + + case JS::ModuleType::CSS: + case JS::ModuleType::Unknown: + JS_ReportErrorASCII(cx, "Unsupported module type in parseModule"); + return false; } + if (!module) { return false; } @@ -10200,9 +10235,9 @@ static const JSFunctionSpecWithHelp shell_functions[] = { " Sleep for dt seconds."), JS_FN_HELP("parseModule", ParseModule, 3, 0, -"parseModule(code, 'filename', 'js' | 'json')", +"parseModule(code, 'filename', 'js' | 'json' | 'bytes')", " Parses source text as a JS module ('js', this is the default) or a JSON" -" module ('json') and returns a ModuleObject wrapper object."), +" module ('json') or bytes module ('bytes') and returns a ModuleObject wrapper object."), JS_FN_HELP("instantiateModuleStencil", InstantiateModuleStencil, 1, 0, "instantiateModuleStencil(stencil, [options])",