in src/codegen/bundle-functions.ts [303:771]
export async function bundleBuiltinFunctions({ requireTransformer }: BundleBuiltinFunctionsArgs) {
const filesToProcess = readdirSync(SRC_DIR)
.filter(x => x.endsWith(".ts") && !x.endsWith(".d.ts"))
.sort();
// Bun seems to crash if this is parallelized, :(
if (PARALLEL) {
await Promise.all(filesToProcess.map(processFunctionFile));
} else {
for (const x of filesToProcess) {
await processFunctionFile(x);
}
}
let combinedSourceCodeChars = "";
let combinedSourceCodeLength = 0;
// Compute source offsets
{
for (const { basename, functions } of files) {
for (const fn of functions) {
fn.sourceOffset = combinedSourceCodeLength;
combinedSourceCodeLength += fn.source.length;
if (combinedSourceCodeChars && !combinedSourceCodeChars.endsWith(",")) {
combinedSourceCodeChars += ",";
}
combinedSourceCodeChars += addCPPCharArray(fn.source, false);
// If you want to see the individual function sources:
// if (true) {
// Bun.write(CODEGEN_DIR + "/functions/" + low(basename) + cap(fn.name) + ".js", fn.source + "\n");
// }
}
}
}
let additionalPrivateNames = new Set();
function privateName(name) {
additionalPrivateNames.add(name);
return "builtinNames." + name + "PrivateName()";
}
// C++ codegen
let bundledCPP = `// Generated by ${import.meta.path}
namespace Zig { class GlobalObject; }
#include "root.h"
#include "config.h"
#include "JSDOMGlobalObject.h"
#include "WebCoreJSClientData.h"
#include <JavaScriptCore/JSObjectInlines.h>
#include "BunBuiltinNames.h"
namespace WebCore {
static const LChar combinedSourceCodeBuffer[${combinedSourceCodeLength + 1}] = { ${combinedSourceCodeChars}, 0 };
static const std::span<const LChar> internalCombinedSource = { combinedSourceCodeBuffer, ${combinedSourceCodeLength} };
`;
for (const { basename, functions } of files) {
bundledCPP += `
#pragma mark ${basename}
`;
const lowerBasename = low(basename);
for (const fn of functions) {
const name = `${basename}${cap(fn.name)}`;
bundledCPP += `
JSC::FunctionExecutable* ${lowerBasename}${cap(fn.name)}CodeGenerator(JSC::VM& vm)
{
auto &builtins = static_cast<JSVMClientData*>(vm.clientData)->builtinFunctions().${lowerBasename}Builtins();
auto *executable = builtins.${lowerBasename}${cap(fn.name)}CodeExecutable();
return executable->link(vm, nullptr, builtins.${lowerBasename}${cap(fn.name)}CodeSource(), std::nullopt, JSC::NoIntrinsic);
}
`;
}
}
const initializeSourceCodeFn = (fn: BundledBuiltin, basename: string) => {
const name = `${low(basename)}${cap(fn.name)}CodeSource`;
return `m_${name}(SourceCode(sourceProvider.copyRef(), ${fn.sourceOffset}, ${fn.source.length + fn.sourceOffset}, 1, 1))`;
};
for (const { basename, internal, functions } of files) {
bundledCPP += `
#pragma mark ${basename}
${basename}BuiltinsWrapper::${basename}BuiltinsWrapper(JSC::VM& vm, RefPtr<JSC::SourceProvider> sourceProvider, BunBuiltinNames &builtinNames)
: m_vm(vm)`;
if (internal) {
bundledCPP += `, ${functions.map(fn => `m_${fn.name}PrivateName(${privateName(fn.name)})`).join(",\n ")}`;
}
bundledCPP += `, ${functions.map(fn => initializeSourceCodeFn(fn, basename)).join(",\n ")} {}
`;
}
bundledCPP += `
RefPtr<JSC::SourceProvider> createBuiltinsSourceProvider() {
return JSC::StringSourceProvider::create(StringImpl::createWithoutCopying(internalCombinedSource), SourceOrigin(), String(), SourceTaintedOrigin());
}
`;
bundledCPP += `
JSBuiltinFunctions::JSBuiltinFunctions(JSC::VM& vm, RefPtr<JSC::SourceProvider> provider, BunBuiltinNames& builtinNames) : m_vm(vm),
${files.map(({ basename }) => `m_${low(basename)}Builtins(vm, provider, builtinNames)`).join(", ")}
{}
void JSBuiltinFunctions::exportNames() {
`;
for (const { basename, internal } of files) {
if (internal) {
bundledCPP += ` m_${low(basename)}Builtins.exportNames();\n`;
}
}
bundledCPP += `
}
`;
bundledCPP += `
JSBuiltinInternalFunctions::JSBuiltinInternalFunctions(JSC::VM& vm) : m_vm(vm)
`;
for (const { basename, internal } of files) {
if (internal) {
bundledCPP += ` , m_${low(basename)}(vm)\n`;
}
}
bundledCPP += `{
UNUSED_PARAM(vm);
}
template<typename Visitor>
void JSBuiltinInternalFunctions::visit(Visitor& visitor)
{
`;
for (const { basename, internal } of files) {
if (internal) bundledCPP += ` m_${low(basename)}.visit(visitor);\n`;
}
bundledCPP += `
UNUSED_PARAM(visitor);
}
template void JSBuiltinInternalFunctions::visit(AbstractSlotVisitor&);
template void JSBuiltinInternalFunctions::visit(SlotVisitor&);
SUPPRESS_ASAN void JSBuiltinInternalFunctions::initialize(Zig::GlobalObject& globalObject)
{
UNUSED_PARAM(globalObject);
`;
for (const { basename, internal } of files) {
if (internal) {
bundledCPP += ` m_${low(basename)}.init(globalObject);\n`;
}
}
bundledCPP += `
JSVMClientData& clientData = *static_cast<JSVMClientData*>(m_vm.clientData);
Zig::GlobalObject::GlobalPropertyInfo staticGlobals[] = {
`;
for (const { basename, internal } of files) {
if (internal) {
bundledCPP += `#define DECLARE_GLOBAL_STATIC(name) \\
Zig::GlobalObject::GlobalPropertyInfo( \\
clientData.builtinFunctions().${low(basename)}Builtins().name##PrivateName(), ${low(basename)}().m_##name##Function.get() , JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly),
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_FUNCTION_NAME(DECLARE_GLOBAL_STATIC)
#undef DECLARE_GLOBAL_STATIC
`;
}
}
bundledCPP += `
};
globalObject.addStaticGlobals(staticGlobals, std::size(staticGlobals));
UNUSED_PARAM(clientData);
}
} // namespace WebCore
`;
// C++ Header codegen
let bundledHeader = `// Generated by ${import.meta.path}
// Do not edit by hand.
#pragma once
namespace Zig { class GlobalObject; }
#include "root.h"
#include <JavaScriptCore/BuiltinUtils.h>
#include <JavaScriptCore/Identifier.h>
#include <JavaScriptCore/JSFunction.h>
#include <JavaScriptCore/UnlinkedFunctionExecutable.h>
#include <JavaScriptCore/VM.h>
#include <JavaScriptCore/WeakInlines.h>
namespace JSC {
class FunctionExecutable;
}
namespace WebCore {
`;
for (const { basename, functions, internal } of files) {
bundledHeader += `/* ${basename}.ts */
`;
const lowerBasename = low(basename);
for (const fn of functions) {
const name = `${lowerBasename}${cap(fn.name)}Code`;
bundledHeader += `// ${fn.name}
#define WEBCORE_BUILTIN_${basename.toUpperCase()}_${fn.name.toUpperCase()} 1
static constexpr JSC::ConstructAbility s_${name}ConstructAbility = JSC::ConstructAbility::${fn.constructAbility};
static constexpr JSC::InlineAttribute s_${name}InlineAttribute = JSC::InlineAttribute::${fn.directives.alwaysInline ? "Always" : "None"};
static constexpr JSC::ConstructorKind s_${name}ConstructorKind = JSC::ConstructorKind::${fn.constructKind};
static constexpr JSC::ImplementationVisibility s_${name}ImplementationVisibility = JSC::ImplementationVisibility::${fn.visibility};
`;
}
bundledHeader += `#define WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_DATA(macro) \\\n`;
for (const fn of functions) {
bundledHeader += ` macro(${fn.name}, ${lowerBasename}${cap(fn.name)}, ${fn.params.length}) \\\n`;
}
bundledHeader += "\n";
bundledHeader += `#define WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_CODE(macro) \\\n`;
for (const fn of functions) {
const name = `${lowerBasename}${cap(fn.name)}Code`;
bundledHeader += ` macro(${name}, ${fn.name}, ${fn.overriddenName}, s_${name}Length) \\\n`;
}
bundledHeader += "\n";
bundledHeader += `#define WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_FUNCTION_NAME(macro) \\\n`;
for (const fn of functions) {
bundledHeader += ` macro(${fn.name}) \\\n`;
}
bundledHeader += `
#define DECLARE_BUILTIN_GENERATOR(codeName, functionName, overriddenName, argumentCount) \\
JSC::FunctionExecutable* codeName##Generator(JSC::VM&);
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_CODE(DECLARE_BUILTIN_GENERATOR)
#undef DECLARE_BUILTIN_GENERATOR
class ${basename}BuiltinsWrapper : private JSC::WeakHandleOwner {
public:
explicit ${basename}BuiltinsWrapper(JSC::VM& vm, RefPtr<JSC::SourceProvider> sourceProvider, BunBuiltinNames &builtinNames);
#define EXPOSE_BUILTIN_EXECUTABLES(name, functionName, overriddenName, length) \\
JSC::UnlinkedFunctionExecutable* name##Executable(); \\
const JSC::SourceCode& name##Source() const { return m_##name##Source; }
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_CODE(EXPOSE_BUILTIN_EXECUTABLES)
#undef EXPOSE_BUILTIN_EXECUTABLES
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_FUNCTION_NAME(DECLARE_BUILTIN_IDENTIFIER_ACCESSOR)
void exportNames();
private:
JSC::VM& m_vm;
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_FUNCTION_NAME(DECLARE_BUILTIN_NAMES)
#define DECLARE_BUILTIN_SOURCE_MEMBERS(name, functionName, overriddenName, length) \\
JSC::SourceCode m_##name##Source;\\
JSC::Weak<JSC::UnlinkedFunctionExecutable> m_##name##Executable;
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_CODE(DECLARE_BUILTIN_SOURCE_MEMBERS)
#undef DECLARE_BUILTIN_SOURCE_MEMBERS
};
#define DEFINE_BUILTIN_EXECUTABLES(name, functionName, overriddenName, length) \\
inline JSC::UnlinkedFunctionExecutable* ${basename}BuiltinsWrapper::name##Executable() \\
{\\
if (!m_##name##Executable) {\\
JSC::Identifier executableName = functionName##PublicName();\\
if (overriddenName)\\
executableName = JSC::Identifier::fromString(m_vm, overriddenName);\\
m_##name##Executable = JSC::Weak<JSC::UnlinkedFunctionExecutable>(JSC::createBuiltinExecutable(m_vm, m_##name##Source, executableName, s_##name##ImplementationVisibility, s_##name##ConstructorKind, s_##name##ConstructAbility, s_##name##InlineAttribute), this, &m_##name##Executable);\\
}\\
return m_##name##Executable.get();\\
}
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_CODE(DEFINE_BUILTIN_EXECUTABLES)
#undef DEFINE_BUILTIN_EXECUTABLES
inline void ${basename}BuiltinsWrapper::exportNames()
{
#define EXPORT_FUNCTION_NAME(name) m_vm.propertyNames->appendExternalName(name##PublicName(), name##PrivateName());
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_FUNCTION_NAME(EXPORT_FUNCTION_NAME)
#undef EXPORT_FUNCTION_NAME
}
`;
if (internal) {
bundledHeader += `class ${basename}BuiltinFunctions {
public:
explicit ${basename}BuiltinFunctions(JSC::VM& vm) : m_vm(vm) { }
void init(JSC::JSGlobalObject&);
template<typename Visitor> void visit(Visitor&);
public:
JSC::VM& m_vm;
#define DECLARE_BUILTIN_SOURCE_MEMBERS(functionName) \\
JSC::WriteBarrier<JSC::JSFunction> m_##functionName##Function;
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_FUNCTION_NAME(DECLARE_BUILTIN_SOURCE_MEMBERS)
#undef DECLARE_BUILTIN_SOURCE_MEMBERS
};
inline void ${basename}BuiltinFunctions::init(JSC::JSGlobalObject& globalObject)
{
#define EXPORT_FUNCTION(codeName, functionName, overriddenName, length) \\
m_##functionName##Function.set(m_vm, &globalObject, JSC::JSFunction::create(m_vm, &globalObject, codeName##Generator(m_vm), &globalObject));
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_CODE(EXPORT_FUNCTION)
#undef EXPORT_FUNCTION
}
template<typename Visitor>
inline void ${basename}BuiltinFunctions::visit(Visitor& visitor)
{
#define VISIT_FUNCTION(name) visitor.append(m_##name##Function);
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_FUNCTION_NAME(VISIT_FUNCTION)
#undef VISIT_FUNCTION
}
template void ${basename}BuiltinFunctions::visit(JSC::AbstractSlotVisitor&);
template void ${basename}BuiltinFunctions::visit(JSC::SlotVisitor&);
`;
}
}
bundledHeader += `class JSBuiltinFunctions {
public:
explicit JSBuiltinFunctions(JSC::VM& vm, RefPtr<JSC::SourceProvider> provider, BunBuiltinNames &builtinNames);
void exportNames();
`;
for (const { basename } of files) {
bundledHeader += ` ${basename}BuiltinsWrapper& ${low(basename)}Builtins() { return m_${low(
basename,
)}Builtins; }\n`;
}
bundledHeader += `
private:
JSC::VM& m_vm;
`;
for (const { basename } of files) {
bundledHeader += ` ${basename}BuiltinsWrapper m_${low(basename)}Builtins;\n`;
}
bundledHeader += `;
};
class JSBuiltinInternalFunctions {
public:
explicit JSBuiltinInternalFunctions(JSC::VM&);
template<typename Visitor> void visit(Visitor&);
void initialize(Zig::GlobalObject&);
`;
for (const { basename, internal } of files) {
if (internal) {
bundledHeader += ` ${basename}BuiltinFunctions& ${low(basename)}() { return m_${low(basename)}; }\n`;
}
}
bundledHeader += `
private:
JSC::VM& m_vm;
`;
for (const { basename, internal } of files) {
if (internal) {
bundledHeader += ` ${basename}BuiltinFunctions m_${low(basename)};\n`;
}
}
bundledHeader += `
};
} // namespace WebCore
`;
// Handle builtin names
{
const BunBuiltinNamesHeader = require("fs").readFileSync(
path.join(import.meta.dir, "../js/builtins/BunBuiltinNames.h"),
"utf8",
);
let definedBuiltinNamesStartI = BunBuiltinNamesHeader.indexOf(
"#define BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME",
);
let definedBuiltinNamesMacroEndI = BunBuiltinNamesHeader.indexOf(
"--- END of BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME ---",
);
const definedBuiltinNames = BunBuiltinNamesHeader.slice(definedBuiltinNamesStartI, definedBuiltinNamesMacroEndI)
.split("\n")
.map(x => x.trim())
.filter(x => x.startsWith("macro("))
.map(x => x.slice(x.indexOf("(") + 1, x.indexOf(")")))
.map(x => x.trim())
.sort();
const uniqueDefinedBuiltinNames = new Set();
for (let name of definedBuiltinNames) {
const prevSize = uniqueDefinedBuiltinNames.size;
uniqueDefinedBuiltinNames.add(name);
if (uniqueDefinedBuiltinNames.size === prevSize) {
throw new Error(`Duplicate private name "${name}" in BunBuiltinNames.h`);
}
}
for (let additionalPrivateName of additionalPrivateNames) {
if (uniqueDefinedBuiltinNames.has(additionalPrivateName)) {
additionalPrivateNames.delete(additionalPrivateName);
}
}
let additionalPrivateNamesHeader = `// Generated by ${import.meta.path}
#pragma once
#ifndef BUN_ADDITIONAL_BUILTIN_NAMES
#define BUN_ADDITIONAL_BUILTIN_NAMES(macro) \\
${Array.from(additionalPrivateNames)
.map(x => `macro(${x})`)
.join(" \\\n ")}
#endif
`;
writeIfNotChanged(path.join(CODEGEN_DIR, "BunBuiltinNames+extras.h"), additionalPrivateNamesHeader);
}
writeIfNotChanged(path.join(CODEGEN_DIR, "WebCoreJSBuiltins.h"), bundledHeader);
writeIfNotChanged(path.join(CODEGEN_DIR, "WebCoreJSBuiltins.cpp"), bundledCPP);
// Generate TS types
let dts = `// Generated by \`bun src/js/builtins/codegen\`
// Do not edit by hand.
type RemoveThis<F> = F extends (this: infer T, ...args: infer A) => infer R ? (...args: A) => R : F;
`;
for (const { basename, functions, internal } of files) {
if (internal) {
dts += `\n// ${basename}.ts\n`;
for (const fn of functions) {
dts += `declare const \$${fn.name}: RemoveThis<typeof import("${path.relative(
CODEGEN_DIR,
path.join(SRC_DIR, basename),
)}")[${JSON.stringify(fn.name)}]>;\n`;
}
}
}
dts += getJS2NativeDTS();
writeIfNotChanged(path.join(CODEGEN_DIR, "WebCoreJSBuiltins.d.ts"), dts);
const totalJSSize = files.reduce(
(acc, { functions }) => acc + functions.reduce((acc, fn) => acc + fn.source.length, 0),
0,
);
if (!KEEP_TMP) {
await rmSync(TMP_DIR, { recursive: true });
}
globalThis.internalFunctionJSSize = totalJSSize;
globalThis.internalFunctionCount = files.reduce((acc, { functions }) => acc + functions.length, 0);
globalThis.internalFunctionFileCount = files.length;
}