diff options
Diffstat (limited to 'src/js/builtins')
-rw-r--r-- | src/js/builtins/BunBuiltinNames.h | 22 | ||||
-rw-r--r-- | src/js/builtins/ImportMetaObject.ts | 214 | ||||
-rw-r--r-- | src/js/builtins/JSBufferConstructor.ts | 4 | ||||
-rw-r--r-- | src/js/builtins/JSBufferPrototype.ts | 32 | ||||
-rw-r--r-- | src/js/builtins/Module.ts | 100 | ||||
-rw-r--r-- | src/js/builtins/ProcessObjectInternals.ts | 22 | ||||
-rw-r--r-- | src/js/builtins/ReadableStreamDefaultReader.ts | 4 | ||||
-rw-r--r-- | src/js/builtins/ReadableStreamInternals.ts | 1 | ||||
-rw-r--r-- | src/js/builtins/StreamInternals.ts | 2 | ||||
-rw-r--r-- | src/js/builtins/TransformStream.ts | 1 | ||||
-rw-r--r-- | src/js/builtins/TransformStreamInternals.ts | 1 | ||||
-rw-r--r-- | src/js/builtins/WritableStreamDefaultWriter.ts | 1 | ||||
-rw-r--r-- | src/js/builtins/WritableStreamInternals.ts | 9 | ||||
-rw-r--r-- | src/js/builtins/builtins.d.ts | 18 | ||||
-rw-r--r-- | src/js/builtins/codegen/index.ts | 30 | ||||
-rw-r--r-- | src/js/builtins/tsconfig.json | 8 |
16 files changed, 302 insertions, 167 deletions
diff --git a/src/js/builtins/BunBuiltinNames.h b/src/js/builtins/BunBuiltinNames.h index 640d122ca..1897f939e 100644 --- a/src/js/builtins/BunBuiltinNames.h +++ b/src/js/builtins/BunBuiltinNames.h @@ -1,5 +1,15 @@ #pragma once + +#ifdef ASSERT_ENABLED +#if ASSERT_ENABLED +#define ORIGINAL_ASSERT_ENABLED 1 +#undef ASSERT_ENABLED +#define ASSERT_ENABLED 0 +#endif +#endif + + #include "JavaScriptCore/BuiltinUtils.h" #include "root.h" @@ -27,6 +37,7 @@ using namespace JSC; macro(WritableStream) \ macro(WritableStreamDefaultController) \ macro(WritableStreamDefaultWriter) \ + macro(__esModule) \ macro(_events) \ macro(abortAlgorithm) \ macro(abortSteps) \ @@ -61,6 +72,7 @@ using namespace JSC; macro(controlledReadableStream) \ macro(controller) \ macro(cork) \ + macro(createCommonJSModule) \ macro(createEmptyReadableStream) \ macro(createFIFO) \ macro(createNativeReadableStream) \ @@ -83,6 +95,7 @@ using namespace JSC; macro(end) \ macro(errno) \ macro(errorSteps) \ + macro(evaluateCommonJSModule) \ macro(execArgv) \ macro(exports) \ macro(extname) \ @@ -93,13 +106,11 @@ using namespace JSC; macro(file) \ macro(filePath) \ macro(fillFromJS) \ - macro(filter) \ macro(finishConsumingStream) \ macro(flush) \ macro(flushAlgorithm) \ macro(format) \ macro(fulfillModuleSync) \ - macro(get) \ macro(getInternalWritableStream) \ macro(handleEvent) \ macro(hash) \ @@ -128,7 +139,6 @@ using namespace JSC; macro(lazyLoad) \ macro(lazyStreamPrototypeMap) \ macro(loadCJS2ESM) \ - macro(loadModule) \ macro(localStreams) \ macro(main) \ macro(makeDOMException) \ @@ -265,3 +275,9 @@ private: }; } // namespace WebCore + +#ifdef ORIGINAL_ASSERT_ENABLED +#undef ASSERT_ENABLED +#define ASSERT_ENABLED 1 +#undef ORIGINAL_ASSERT_ENABLED +#endif diff --git a/src/js/builtins/ImportMetaObject.ts b/src/js/builtins/ImportMetaObject.ts index 7fc8b5fe8..934a37881 100644 --- a/src/js/builtins/ImportMetaObject.ts +++ b/src/js/builtins/ImportMetaObject.ts @@ -8,9 +8,9 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { // we need to explicitly check because state could be $ModuleFetch // it will throw this error if we do not: // $throwTypeError("Requested module is already fetched."); - var entry = loader.registry.$get(key); + var entry = loader.registry.$get(key)!; - if (!entry || !entry.state || entry.state <= $ModuleFetch) { + if ((entry?.state ?? 0) <= $ModuleFetch) { $fulfillModuleSync(key); entry = loader.registry.$get(key)!; } @@ -24,14 +24,14 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { // so we just pull it out of the promise here once again // But, this time we do it a little more carefully because this is a JSC function call and not bun source code var moduleRecordPromise = loader.parseModule(key, sourceCodeObject); - var module = entry.module; - if (!module && moduleRecordPromise && $isPromise(moduleRecordPromise)) { + var mod = entry.module; + if (moduleRecordPromise && $isPromise(moduleRecordPromise)) { var reactionsOrResult = $getPromiseInternalField(moduleRecordPromise, $promiseFieldReactionsOrResult); var flags = $getPromiseInternalField(moduleRecordPromise, $promiseFieldFlags); var state = flags & $promiseStateMask; // this branch should never happen, but just to be safe if (state === $promiseStatePending || (reactionsOrResult && $isPromise(reactionsOrResult))) { - throw new TypeError(`require() async module "${key}" is unsupported`); + throw new TypeError(`require() async module "${key}" is unsupported. use "await import()" instead.`); } else if (state === $promiseStateRejected) { if (!reactionsOrResult?.message) { throw new TypeError( @@ -43,15 +43,15 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { throw reactionsOrResult; } - entry.module = module = reactionsOrResult; - } else if (moduleRecordPromise && !module) { - entry.module = module = moduleRecordPromise as LoaderModule; + entry.module = mod = reactionsOrResult; + } else if (moduleRecordPromise && !mod) { + entry.module = mod = moduleRecordPromise as LoaderModule; } // This is very similar to "requestInstantiate" in ModuleLoader.js in JavaScriptCore. $setStateToMax(entry, $ModuleLink); - var dependenciesMap = module.dependenciesMap; - var requestedModules = loader.requestedModules(module); + var dependenciesMap = mod.dependenciesMap; + var requestedModules = loader.requestedModules(mod); var dependencies = $newArrayWithSize<string>(requestedModules.length); for (var i = 0, length = requestedModules.length; i < length; ++i) { var depName = requestedModules[i]; @@ -59,6 +59,7 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { // we don't need to run the resolver a 2nd time var depKey = depName[0] === "/" ? depName : loader.resolve(depName, key); var depEntry = loader.ensureRegistered(depKey); + if (depEntry.state < $ModuleLink) { queue.push(depKey); } @@ -81,7 +82,9 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { if (linkAndEvaluateResult && $isPromise(linkAndEvaluateResult)) { // if you use top-level await, or any dependencies use top-level await, then we throw here // this means the module will still actually load eventually, but that's okay. - throw new TypeError(`require() async module \"${resolvedSpecifier}\" is unsupported`); + throw new TypeError( + `require() async module \"${resolvedSpecifier}\" is unsupported. use "await import()" instead.`, + ); } return loader.registry.$get(resolvedSpecifier); @@ -104,158 +107,113 @@ export function requireESM(this: ImportMetaObject, resolved) { return; } - var commonJS = exports.default; - var cjs = commonJS?.[$commonJSSymbol]; - if (cjs === 0) { - return commonJS; - } else if (cjs && $isCallable(commonJS)) { - return commonJS(); - } - return exports; } -export function internalRequire(this: ImportMetaObject, resolved) { - var cached = $requireMap.$get(resolved); - const last5 = resolved.substring(resolved.length - 5); +export function internalRequire(this: ImportMetaObject, id) { + var cached = $requireMap.$get(id); + const last5 = id.substring(id.length - 5); if (cached) { - if (last5 === ".node") { - return cached.exports; - } - return cached; + return cached.exports; } // TODO: remove this hardcoding if (last5 === ".json") { var fs = (globalThis[Symbol.for("_fs")] ||= Bun.fs()); - var exports = JSON.parse(fs.readFileSync(resolved, "utf8")); - $requireMap.$set(resolved, exports); + var exports = JSON.parse(fs.readFileSync(id, "utf8")); + $requireMap.$set(id, $createCommonJSModule(id, exports, true)); return exports; } else if (last5 === ".node") { - var module = { exports: {} }; - process.dlopen(module, resolved); - $requireMap.$set(resolved, module); + const module = $createCommonJSModule(id, {}, true); + process.dlopen(module, id); + $requireMap.$set(id, module); return module.exports; } else if (last5 === ".toml") { var fs = (globalThis[Symbol.for("_fs")] ||= Bun.fs()); - var exports = Bun.TOML.parse(fs.readFileSync(resolved, "utf8")); - $requireMap.$set(resolved, exports); + var exports = Bun.TOML.parse(fs.readFileSync(id, "utf8")); + $requireMap.$set(id, $createCommonJSModule(id, exports, true)); return exports; } else { - var exports = $requireESM(resolved); - const cachedExports = $requireMap.$get(resolved); - if (cachedExports) { - return cachedExports; + var exports = $requireESM(id); + const cachedModule = $requireMap.$get(id); + if (cachedModule) { + return cachedModule.exports; } - - $requireMap.$set(resolved, exports); + var defaultExport = exports?.default; + if (defaultExport?.[$commonJSSymbol] === 0) { + exports = defaultExport; + } + $requireMap.$set(id, $createCommonJSModule(id, exports, true)); return exports; } } export function createRequireCache() { - class Module { - id; - parent; - filename; - children = []; - paths = []; - - constructor(filename) { - this.id = filename; - // TODO: windows - const lastSlash = filename.lastIndexOf("/"); - if (lastSlash !== -1 && filename.length > lastSlash + 1) { - this.filename = filename.substring(lastSlash + 1); - } else { - this.filename = filename; + var moduleMap = new Map(); + var inner = {}; + return new Proxy(inner, { + get(target, key: string) { + const entry = $requireMap.$get(key); + if (entry) return entry; + + const esm = Loader.registry.$get(key); + if (esm?.evaluated) { + const namespace = Loader.getModuleNamespaceObject(esm.module); + const exports = + namespace[$commonJSSymbol] === 0 || namespace.default?.[$commonJSSymbol] ? namespace.default : namespace; + const mod = $createCommonJSModule(key, exports, true); + $requireMap.$set(key, mod); + return mod; } - } - get loaded() { + return inner[key]; + }, + set(target, key: string, value) { + $requireMap.$set(key, value); return true; - } - - require(path) { - return $internalRequire($resolveSync(path, this.id)); - } - - get exports() { - return $requireMap.$get(this.id) ?? {}; - } + }, - set exports(value) { - $requireMap.$set(this.id, value); - } - } + has(target, key: string) { + return $requireMap.$has(key) || Loader.registry.$has(key); + }, - var moduleMap = new Map(); + deleteProperty(target, key: string) { + moduleMap.$delete(key); + $requireMap.$delete(key); + Loader.registry.$delete(key); + return true; + }, - return new Proxy( - {}, - { - get(target, key: string) { - const entry = $requireMap.$get(key); - if (entry) { - var mod = moduleMap.$get(key); - if (!mod) { - mod = new Module(key); - moduleMap.$set(key, mod); - } - return mod; - } - }, - set(target, key: string, value) { - if (!moduleMap.$has(key)) { - moduleMap.$set(key, new Module(key)); + ownKeys(target) { + var array = [...$requireMap.$keys()]; + const registryKeys = [...Loader.registry.$keys()]; + for (const key of registryKeys) { + if (!array.includes(key)) { + $arrayPush(array, key); } + } - $requireMap.$set(key, value?.exports); - - return true; - }, - - has(target, key: string) { - return $requireMap.$has(key); - }, - - deleteProperty(target, key: string) { - moduleMap.$delete(key); - $requireMap.$delete(key); - Loader.registry.$delete(key); - return true; - }, - - ownKeys(target) { - return [...$requireMap.$keys()]; - }, + return array; + }, - // In Node, require.cache has a null prototype - getPrototypeOf(target) { - return null; - }, + // In Node, require.cache has a null prototype + getPrototypeOf(target) { + return null; + }, - getOwnPropertyDescriptor(target, key: string) { - if ($requireMap.$has(key)) { - return { - configurable: true, - enumerable: true, - }; - } - }, + getOwnPropertyDescriptor(target, key: string) { + if ($requireMap.$has(key) || Loader.registry.$has(key)) { + return { + configurable: true, + enumerable: true, + }; + } }, - ); + }); } -$sloppy; -export function require(this: ImportMetaObject, name) { - var from = this?.path ?? arguments.callee.path; - - if (typeof name !== "string") { - throw new TypeError("require(name) must be a string"); - } - - return $internalRequire($resolveSync(name, from)); +export function require(this: string, name) { + return $internalRequire($resolveSync(name, $toString(this), false)); } $getter; diff --git a/src/js/builtins/JSBufferConstructor.ts b/src/js/builtins/JSBufferConstructor.ts index debc62d51..a1072ea10 100644 --- a/src/js/builtins/JSBufferConstructor.ts +++ b/src/js/builtins/JSBufferConstructor.ts @@ -65,3 +65,7 @@ export function from(items) { // That means we cannot use $tailCallFowrardArguments here, sadly return new $Buffer(Uint8Array.from(arrayLike).buffer); } + +export function isBuffer(bufferlike) { + return bufferlike instanceof $Buffer; +} diff --git a/src/js/builtins/JSBufferPrototype.ts b/src/js/builtins/JSBufferPrototype.ts index 97b25b9b2..f5d6a7bfb 100644 --- a/src/js/builtins/JSBufferPrototype.ts +++ b/src/js/builtins/JSBufferPrototype.ts @@ -427,29 +427,29 @@ export function hexWrite(this: BufferExt, text, offset, length) { return this.write(text, offset, length, "hex"); } -export function utf8Slice(this: BufferExt, offset, length) { - return this.toString(offset, length, "utf8"); +export function utf8Slice(this: BufferExt, start, end) { + return this.toString("utf8", start, end); } -export function ucs2Slice(this: BufferExt, offset, length) { - return this.toString(offset, length, "ucs2"); +export function ucs2Slice(this: BufferExt, start, end) { + return this.toString("ucs2", start, end); } -export function utf16leSlice(this: BufferExt, offset, length) { - return this.toString(offset, length, "utf16le"); +export function utf16leSlice(this: BufferExt, start, end) { + return this.toString("utf16le", start, end); } -export function latin1Slice(this: BufferExt, offset, length) { - return this.toString(offset, length, "latin1"); +export function latin1Slice(this: BufferExt, start, end) { + return this.toString("latin1", start, end); } -export function asciiSlice(this: BufferExt, offset, length) { - return this.toString(offset, length, "ascii"); +export function asciiSlice(this: BufferExt, start, end) { + return this.toString("ascii", start, end); } -export function base64Slice(this: BufferExt, offset, length) { - return this.toString(offset, length, "base64"); +export function base64Slice(this: BufferExt, start, end) { + return this.toString("base64", start, end); } -export function base64urlSlice(this: BufferExt, offset, length) { - return this.toString(offset, length, "base64url"); +export function base64urlSlice(this: BufferExt, start, end) { + return this.toString("base64url", start, end); } -export function hexSlice(this: BufferExt, offset, length) { - return this.toString(offset, length, "hex"); +export function hexSlice(this: BufferExt, start, end) { + return this.toString("hex", start, end); } export function toJSON(this: BufferExt) { diff --git a/src/js/builtins/Module.ts b/src/js/builtins/Module.ts new file mode 100644 index 000000000..0b5fcafe8 --- /dev/null +++ b/src/js/builtins/Module.ts @@ -0,0 +1,100 @@ +interface Module { + id: string; + path: string; + + $require(id: string, mod: any): any; + children: Module[]; +} + +$getter; +export function main() { + return $requireMap.$get(Bun.main); +} + +export function require(this: Module, id: string) { + const existing = $requireMap.$get(id) || $requireMap.$get((id = $resolveSync(id, this.path, false))); + if (existing) { + // Scenario where this is necessary: + // + // In an ES Module, we have: + // + // import "react-dom/server" + // import "react" + // + // Synchronously, the "react" import is created first, and then the + // "react-dom/server" import is created. Then, at ES Module link time, they + // are evaluated. The "react-dom/server" import is evaluated first, and + // require("react") was previously created as an ESM module, so we wait + // for the ESM module to load + // + // ...and then when this code is reached, unless + // we evaluate it "early", we'll get an empty object instead of the module + // exports. + // + $evaluateCommonJSModule(existing); + return existing.exports; + } + + if (id.endsWith(".json") || id.endsWith(".toml") || id.endsWith(".node")) { + return $internalRequire(id); + } + + let esm = Loader.registry.$get(id); + if (esm?.evaluated && (esm.state ?? 0) >= $ModuleReady) { + const mod = esm.module; + const namespace = Loader.getModuleNamespaceObject(mod); + const exports = + namespace?.[$commonJSSymbol] === 0 || namespace?.default?.[$commonJSSymbol] === 0 + ? namespace.default + : namespace.__esModule + ? namespace + : Object.create(namespace, { __esModule: { value: true } }); + $requireMap.$set(id, $createCommonJSModule(id, exports, true)); + return exports; + } + + // To handle import/export cycles, we need to create a module object and put + // it into the map before we import it. + const mod = $createCommonJSModule(id, {}, false); + $requireMap.$set(id, mod); + + // This is where we load the module. We will see if Module._load and + // Module._compile are actually important for compatibility. + // + // Note: we do not need to wrap this in a try/catch, if it throws the C++ code will + // clear the module from the map. + // + var out = this.$require(id, mod); + + // -1 means we need to lookup the module from the ESM registry. + if (out === -1) { + try { + out = $requireESM(id); + } catch (exception) { + // Since the ESM code is mostly JS, we need to handle exceptions here. + $requireMap.$delete(id); + throw exception; + } + + esm = Loader.registry.$get(id); + + // If we can pull out a ModuleNamespaceObject, let's do it. + if (esm?.evaluated && (esm.state ?? 0) >= $ModuleReady) { + const namespace = Loader.getModuleNamespaceObject(esm!.module); + return (mod.exports = + // if they choose a module + namespace?.[$commonJSSymbol] === 0 || namespace?.default?.[$commonJSSymbol] === 0 + ? namespace.default + : namespace.__esModule + ? namespace + : Object.create(namespace, { __esModule: { value: true } })); + } + } + + $evaluateCommonJSModule(mod); + return mod.exports; +} + +export function requireResolve(this: Module, id: string) { + return $resolveSync(id, this.path, false); +} diff --git a/src/js/builtins/ProcessObjectInternals.ts b/src/js/builtins/ProcessObjectInternals.ts index 8b24e68ba..8e2449a43 100644 --- a/src/js/builtins/ProcessObjectInternals.ts +++ b/src/js/builtins/ProcessObjectInternals.ts @@ -49,9 +49,14 @@ export function binding(bindingName) { return constants; } -export function getStdioWriteStream(fd_, rawRequire) { - var module = { path: "node:process", require: rawRequire }; - var require = path => module.require(path); +export function getStdioWriteStream(fd_) { + var require = path => { + var existing = $requireMap.get(path); + if (existing) return existing.exports; + + return $internalRequire(path); + }; + var module = { path: "node:process", require }; function createStdioWriteStream(fd_) { var { Duplex, eos, destroy } = require("node:stream"); @@ -472,10 +477,15 @@ export function getStdioWriteStream(fd_, rawRequire) { return new FastStdioWriteStream(fd_); } -export function getStdinStream(fd_, rawRequire, Bun) { - var module = { path: "node:process", require: rawRequire }; - var require = path => module.require(path); +export function getStdinStream(fd_) { + var require = path => { + var existing = $requireMap.get(path); + if (existing) return existing.exports; + + return $internalRequire(path); + }; + var module = { path: "node:process", require: require }; var { Duplex, eos, destroy } = require("node:stream"); var StdinStream = class StdinStream extends Duplex { diff --git a/src/js/builtins/ReadableStreamDefaultReader.ts b/src/js/builtins/ReadableStreamDefaultReader.ts index ecd553ed5..a5654d834 100644 --- a/src/js/builtins/ReadableStreamDefaultReader.ts +++ b/src/js/builtins/ReadableStreamDefaultReader.ts @@ -43,7 +43,7 @@ export function cancel(this, reason) { return $readableStreamReaderGenericCancel(this, reason); } -export function readMany(this) { +export function readMany(this: ReadableStreamDefaultReader): ReadableStreamDefaultReadManyResult<any> { if (!$isReadableStreamDefaultReader(this)) throw new TypeError("ReadableStreamDefaultReader.readMany() should not be called directly"); @@ -150,7 +150,7 @@ export function readMany(this) { var pullResult = controller.$pull(controller); if (pullResult && $isPromise(pullResult)) { - return pullResult.$then(onPullMany); + return pullResult.$then(onPullMany) as any; } return onPullMany(pullResult); diff --git a/src/js/builtins/ReadableStreamInternals.ts b/src/js/builtins/ReadableStreamInternals.ts index 0c4e816f4..a9d67aa06 100644 --- a/src/js/builtins/ReadableStreamInternals.ts +++ b/src/js/builtins/ReadableStreamInternals.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /* * Copyright (C) 2015 Canon Inc. All rights reserved. * Copyright (C) 2015 Igalia. diff --git a/src/js/builtins/StreamInternals.ts b/src/js/builtins/StreamInternals.ts index b42dc2f57..7bb262951 100644 --- a/src/js/builtins/StreamInternals.ts +++ b/src/js/builtins/StreamInternals.ts @@ -184,7 +184,7 @@ export function createFIFO() { this._capacityMask = (this._capacityMask << 1) | 1; } - shrinkArray() { + _shrinkArray() { this._list.length >>>= 1; this._capacityMask >>>= 1; } diff --git a/src/js/builtins/TransformStream.ts b/src/js/builtins/TransformStream.ts index 54467db39..2a124d4e1 100644 --- a/src/js/builtins/TransformStream.ts +++ b/src/js/builtins/TransformStream.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /* * Copyright (C) 2020 Apple Inc. All rights reserved. * diff --git a/src/js/builtins/TransformStreamInternals.ts b/src/js/builtins/TransformStreamInternals.ts index 9994d1282..9da403e71 100644 --- a/src/js/builtins/TransformStreamInternals.ts +++ b/src/js/builtins/TransformStreamInternals.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /* * Copyright (C) 2020 Apple Inc. All rights reserved. * diff --git a/src/js/builtins/WritableStreamDefaultWriter.ts b/src/js/builtins/WritableStreamDefaultWriter.ts index 795b43892..50b2cd13f 100644 --- a/src/js/builtins/WritableStreamDefaultWriter.ts +++ b/src/js/builtins/WritableStreamDefaultWriter.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /* * Copyright (C) 2020 Apple Inc. All rights reserved. * diff --git a/src/js/builtins/WritableStreamInternals.ts b/src/js/builtins/WritableStreamInternals.ts index f436a285e..2008dab1c 100644 --- a/src/js/builtins/WritableStreamInternals.ts +++ b/src/js/builtins/WritableStreamInternals.ts @@ -610,16 +610,17 @@ export function setUpWritableStreamDefaultControllerFromUnderlyingSink( highWaterMark, sizeAlgorithm, ) { + // @ts-ignore const controller = new $WritableStreamDefaultController(); - let startAlgorithm = () => {}; - let writeAlgorithm = () => { + let startAlgorithm: (...args: any[]) => any = () => {}; + let writeAlgorithm: (...args: any[]) => any = () => { return Promise.$resolve(); }; - let closeAlgorithm = () => { + let closeAlgorithm: (...args: any[]) => any = () => { return Promise.$resolve(); }; - let abortAlgorithm = () => { + let abortAlgorithm: (...args: any[]) => any = () => { return Promise.$resolve(); }; diff --git a/src/js/builtins/builtins.d.ts b/src/js/builtins/builtins.d.ts index d2e7037dc..9b32ea45e 100644 --- a/src/js/builtins/builtins.d.ts +++ b/src/js/builtins/builtins.d.ts @@ -57,6 +57,9 @@ declare function $getPromiseInternalField<K extends PromiseFieldType, V>( promise: Promise<V>, key: K, ): PromiseFieldToValue<K, V>; +declare function $fulfillPromise(...args: any[]): TODO; +declare function $evaluateCommonJSModule(...args: any[]): TODO; +declare function $loadCJS2ESM(...args: any[]): TODO; declare function $getGeneratorInternalField(): TODO; declare function $getAsyncGeneratorInternalField(): TODO; declare function $getAbstractModuleRecordInternalField(): TODO; @@ -229,7 +232,7 @@ declare function $createFIFO(): TODO; declare function $createNativeReadableStream(): TODO; declare function $createReadableStream(): TODO; declare function $createUninitializedArrayBuffer(size: number): ArrayBuffer; -declare function $createWritableStreamFromInternal(): TODO; +declare function $createWritableStreamFromInternal(...args: any[]): TODO; declare function $cwd(): TODO; declare function $data(): TODO; declare function $dataView(): TODO; @@ -330,6 +333,7 @@ declare function $read(): TODO; declare function $readIntoRequests(): TODO; declare function $readRequests(): TODO; declare function $readable(): TODO; +declare function $readableByteStreamControllerGetDesiredSize(...args: any): TODO; declare function $readableStreamController(): TODO; declare function $readableStreamToArray(): TODO; declare function $reader(): TODO; @@ -341,9 +345,9 @@ declare function $releaseLock(): TODO; declare function $removeEventListener(): TODO; declare function $require(): TODO; declare function $requireESM(path: string): any; -declare const $requireMap: Map<string, TODO>; +declare const $requireMap: Map<string, NodeModule>; declare function $resolve(name: string, from: string): Promise<string>; -declare function $resolveSync(name: string, from: string): string; +declare function $resolveSync(name: string, from: string, isESM?: boolean): string; declare function $resume(): TODO; declare function $search(): TODO; declare function $searchParams(): TODO; @@ -402,6 +406,8 @@ declare function $writer(): TODO; declare function $writing(): TODO; declare function $written(): TODO; +declare function $createCommonJSModule(id: string, exports: any, hasEvaluated: boolean): NodeModule; + // The following I cannot find any definitions of, but they are functional. declare function $toLength(length: number): number; declare function $isTypedArrayView(obj: unknown): obj is ArrayBufferView | DataView | Uint8Array; @@ -431,9 +437,9 @@ declare interface ArrayBufferConstructor<T> extends ClassWithIntrinsics<ArrayBuf declare interface PromiseConstructor<T> extends ClassWithIntrinsics<PromiseConstructor<T>> {} declare interface UnderlyingSource { - $lazy: boolean; - $bunNativeType: number; - $bunNativePtr: number; + $lazy?: boolean; + $bunNativeType?: number; + $bunNativePtr?: number; autoAllocateChunkSize?: number; } diff --git a/src/js/builtins/codegen/index.ts b/src/js/builtins/codegen/index.ts index e20601a15..a5d3c2dc8 100644 --- a/src/js/builtins/codegen/index.ts +++ b/src/js/builtins/codegen/index.ts @@ -3,7 +3,35 @@ import path from "path"; import { sliceSourceCode } from "./builtin-parser"; import { applyGlobalReplacements, enums, globalsToPrefix } from "./replacements"; import { cap, fmtCPPString, low } from "./helpers"; +import { spawn, spawnSync } from "bun"; + +async function createStaticHashtables() { + const STATIC_HASH_TABLES = ["src/bun.js/bindings/Process.cpp"]; + console.time("Creating static hash tables..."); + const create_hash_table = path.join( + import.meta.dir, + "../../../../bun-webkit/Source/JavaScriptCore/create_hash_table", + ); + for (let cpp of STATIC_HASH_TABLES) { + cpp = path.join(import.meta.dir, "../../../../", cpp); + const { stdout, exited } = spawn({ + cmd: [create_hash_table, cpp], + stdout: "pipe", + stderr: "inherit", + }); + await exited; + let str = await new Response(stdout).text(); + str = str.replaceAll(/^\/\/.*$/gm, ""); + str = str.replaceAll(/^#include.*$/gm, ""); + str = str.replaceAll(`namespace JSC {`, ""); + str = str.replaceAll(`} // namespace JSC`, ""); + str = "// File generated via `make generate-builtins`\n" + str.trim() + "\n"; + await Bun.write(cpp.replace(/\.cpp$/, ".lut.h"), str); + } + console.timeEnd("Creating static hash tables..."); +} +const staticHashTablePromise = createStaticHashtables(); console.log("Bundling Bun builtins..."); const MINIFY = process.argv.includes("--minify") || process.argv.includes("-m"); @@ -618,6 +646,8 @@ if (!KEEP_TMP) { await rmSync(TMP_DIR, { recursive: true }); } +await staticHashTablePromise; + console.log( `Embedded JS size: %s bytes (across %s functions, %s files)`, totalJSSize, diff --git a/src/js/builtins/tsconfig.json b/src/js/builtins/tsconfig.json index f8b12c5c3..6cdbe0eef 100644 --- a/src/js/builtins/tsconfig.json +++ b/src/js/builtins/tsconfig.json @@ -3,5 +3,11 @@ "compilerOptions": { "noEmit": true }, - "include": [".", "../private.d.ts", "builtins.d.ts", "../generated/builtins/WebCoreJSBuiltins.d.ts", "../../../packages/bun-types/index.d.ts"] + "include": [ + ".", + "../private.d.ts", + "builtins.d.ts", + "../out/WebCoreJSBuiltins.d.ts", + "../../../packages/bun-types/index.d.ts" + ] } |