Use one JSC::SourceProvider instead of 322 (#12761)

This commit is contained in:
Jarred Sumner
2024-07-24 01:26:09 -07:00
committed by GitHub
parent f9371e59f2
commit 8ba0791dc8
6 changed files with 183 additions and 78 deletions

View File

@@ -26,6 +26,8 @@
namespace WebCore {
using namespace JSC;
RefPtr<JSC::SourceProvider> createBuiltinsSourceProvider();
JSHeapData::JSHeapData(Heap& heap)
: m_heapCellTypeForJSWorkerGlobalScope(JSC::IsoHeapCellType::Args<Zig::GlobalObject>())
, m_domBuiltinConstructorSpace ISO_SUBSPACE_INIT(heap, heap.cellHeapCellType, JSDOMBuiltinConstructorBase)
@@ -38,15 +40,14 @@ JSHeapData::JSHeapData(Heap& heap)
#define CLIENT_ISO_SUBSPACE_INIT(subspace) subspace(m_heapData->subspace)
JSVMClientData::JSVMClientData(VM& vm)
: m_builtinFunctions(vm)
, m_builtinNames(vm)
JSVMClientData::JSVMClientData(VM& vm, RefPtr<SourceProvider> sourceProvider)
: m_builtinNames(vm)
, m_builtinFunctions(vm, sourceProvider, m_builtinNames)
, m_heapData(JSHeapData::ensureHeapData(vm.heap))
, CLIENT_ISO_SUBSPACE_INIT(m_domBuiltinConstructorSpace)
, CLIENT_ISO_SUBSPACE_INIT(m_domConstructorSpace)
, CLIENT_ISO_SUBSPACE_INIT(m_domNamespaceObjectSpace)
, m_clientSubspaces(makeUnique<ExtendedDOMClientIsoSubspaces>())
{
}
@@ -72,7 +73,8 @@ JSVMClientData::~JSVMClientData()
}
void JSVMClientData::create(VM* vm, void* bunVM)
{
JSVMClientData* clientData = new JSVMClientData(*vm);
auto provider = WebCore::createBuiltinsSourceProvider();
JSVMClientData* clientData = new JSVMClientData(*vm, provider);
clientData->bunVM = bunVM;
vm->deferredWorkTimer->onAddPendingWork = Bun::JSCTaskScheduler::onAddPendingWork;
vm->deferredWorkTimer->onScheduleWorkSoon = Bun::JSCTaskScheduler::onScheduleWorkSoon;
@@ -83,6 +85,7 @@ void JSVMClientData::create(VM* vm, void* bunVM)
vm->heap.addMarkingConstraint(makeUnique<WebCore::DOMGCOutputConstraint>(*vm, clientData->heapData()));
vm->m_typedArrayController = adoptRef(new WebCoreTypedArrayController(true));
clientData->builtinFunctions().exportNames();
}
} // namespace WebCore

View File

@@ -76,7 +76,7 @@ class JSVMClientData : public JSC::VM::ClientData {
WTF_MAKE_FAST_ALLOCATED;
public:
explicit JSVMClientData(JSC::VM&);
explicit JSVMClientData(JSC::VM&, RefPtr<JSC::SourceProvider>);
virtual ~JSVMClientData();

View File

@@ -1,5 +1,4 @@
#include "InternalModuleRegistry.h"
#include "ZigGlobalObject.h"
#include <JavaScriptCore/BuiltinUtils.h>
#include <JavaScriptCore/JSFunction.h>

View File

@@ -8,13 +8,19 @@
// library, instead of RegExp hacks.
//
// For explanation on this, please nag @paperdave to write documentation on how everything works.
//
// The output is intended to be similar to what WebCore does internally with a couple differences:
//
// - We concatenate all the sources into one big string, which then createsa
// single JSC::SourceProvider and pass start/end positions to each function's
// JSC::SourceCode. JSC does this, but WebCore does not seem to.
import { readdirSync, rmSync } from "fs";
import path from "path";
import { sliceSourceCode } from "./builtin-parser";
import { applyGlobalReplacements, define } from "./replacements";
import { cap, fmtCPPCharArray, low, writeIfNotChanged } from "./helpers";
import { createAssertClientJS, createLogClientJS } from "./client-js";
import { getJS2NativeDTS } from "./generate-js2native";
import { addCPPCharArray, cap, low, writeIfNotChanged } from "./helpers";
import { applyGlobalReplacements, define } from "./replacements";
const PARALLEL = false;
const KEEP_TMP = true;
@@ -52,6 +58,7 @@ interface BundledBuiltin {
source: string;
params: string[];
visibility: string;
sourceOffset: number;
}
/**
@@ -228,6 +235,10 @@ $$capture_start$$(${fn.async ? "async " : ""}${
constructKind: fn.directives.ConstructKind ?? "None",
isLinkTimeConstant: !!fn.directives.linkTimeConstant,
intrinsic: fn.directives.intrinsic ?? "NoIntrinsic",
// Not known yet.
sourceOffset: 0,
overriddenName: fn.directives.getter
? `"get ${fn.name}"_s`
: fn.directives.overriddenName
@@ -275,6 +286,34 @@ export async function bundleBuiltinFunctions({ requireTransformer }: BundleBuilt
}
}
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; }
@@ -283,48 +322,78 @@ export async function bundleBuiltinFunctions({ requireTransformer }: BundleBuilt
#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 += `/* ${basename}.ts */\n`;
bundledCPP += `
#pragma mark ${basename}
`;
const lowerBasename = low(basename);
for (const fn of functions) {
const [code, count] = fmtCPPCharArray(fn.source, true);
const name = `${lowerBasename}${cap(fn.name)}Code`;
bundledCPP += `// ${fn.name}
const JSC::ConstructAbility s_${name}ConstructAbility = JSC::ConstructAbility::${fn.constructAbility};
const JSC::InlineAttribute s_${name}InlineAttribute = JSC::InlineAttribute::${
fn.directives.alwaysInline ? "Always" : "None"
};
const JSC::ConstructorKind s_${name}ConstructorKind = JSC::ConstructorKind::${fn.constructKind};
const JSC::ImplementationVisibility s_${name}ImplementationVisibility = JSC::ImplementationVisibility::${
fn.visibility
};
const int s_${name}Length = ${fn.source.length};
const JSC::Intrinsic s_${name}Intrinsic = JSC::NoIntrinsic;
const char s_${name}Bytes[${count}] = ${code};
const char* s_${name} = s_${name}Bytes;
`;
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);
}
`;
}
bundledCPP += `#define DEFINE_BUILTIN_GENERATOR(codeName, functionName, overriddenName, argumentCount) \\
JSC::FunctionExecutable* codeName##Generator(JSC::VM& vm) \\
{\\
JSVMClientData* clientData = static_cast<JSVMClientData*>(vm.clientData); \\
return clientData->builtinFunctions().${lowerBasename}Builtins().codeName##Executable()->link(vm, nullptr, clientData->builtinFunctions().${lowerBasename}Builtins().codeName##Source(), std::nullopt, s_##codeName##Intrinsic); \\
}
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 ")}`;
}
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_CODE(DEFINE_BUILTIN_GENERATOR)
#undef DEFINE_BUILTIN_GENERATOR
`;
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)
JSBuiltinInternalFunctions::JSBuiltinInternalFunctions(JSC::VM& vm) : m_vm(vm)
`;
for (const { basename, internal } of files) {
@@ -333,10 +402,9 @@ export async function bundleBuiltinFunctions({ requireTransformer }: BundleBuilt
}
}
bundledCPP += `
{
UNUSED_PARAM(vm);
}
bundledCPP += `{
UNUSED_PARAM(vm);
}
template<typename Visitor>
void JSBuiltinInternalFunctions::visit(Visitor& visitor)
@@ -417,12 +485,10 @@ export async function bundleBuiltinFunctions({ requireTransformer }: BundleBuilt
const name = `${lowerBasename}${cap(fn.name)}Code`;
bundledHeader += `// ${fn.name}
#define WEBCORE_BUILTIN_${basename.toUpperCase()}_${fn.name.toUpperCase()} 1
extern const char* s_${name};
extern const int s_${name}Length;
extern const JSC::ConstructAbility s_${name}ConstructAbility;
extern const JSC::InlineAttribute s_${name}InlineAttribute;
extern const JSC::ConstructorKind s_${name}ConstructorKind;
extern const JSC::ImplementationVisibility s_${name}ImplementationVisibility;
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};
`;
}
@@ -450,14 +516,7 @@ export async function bundleBuiltinFunctions({ requireTransformer }: BundleBuilt
class ${basename}BuiltinsWrapper : private JSC::WeakHandleOwner {
public:
explicit ${basename}BuiltinsWrapper(JSC::VM& vm)
: m_vm(vm)
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_FUNCTION_NAME(INITIALIZE_BUILTIN_NAMES)
#define INITIALIZE_BUILTIN_SOURCE_MEMBERS(name, functionName, overriddenName, length) , m_##name##Source(JSC::makeSource(StringImpl::createWithoutCopying({reinterpret_cast<const LChar*>(s_##name), static_cast<size_t>(length)}), { }, JSC::SourceTaintedOrigin::Untainted))
WEBCORE_FOREACH_${basename.toUpperCase()}_BUILTIN_CODE(INITIALIZE_BUILTIN_SOURCE_MEMBERS)
#undef INITIALIZE_BUILTIN_SOURCE_MEMBERS
{
}
explicit ${basename}BuiltinsWrapper(JSC::VM& vm, RefPtr<JSC::SourceProvider> sourceProvider, BunBuiltinNames &builtinNames);
#define EXPOSE_BUILTIN_EXECUTABLES(name, functionName, overriddenName, length) \\
JSC::UnlinkedFunctionExecutable* name##Executable(); \\
@@ -544,25 +603,9 @@ export async function bundleBuiltinFunctions({ requireTransformer }: BundleBuilt
}
bundledHeader += `class JSBuiltinFunctions {
public:
explicit JSBuiltinFunctions(JSC::VM& vm)
: m_vm(vm)
`;
for (const { basename } of files) {
bundledHeader += ` , m_${low(basename)}Builtins(m_vm)\n`;
}
bundledHeader += `
{
`;
for (const { basename, internal } of files) {
if (internal) {
bundledHeader += ` m_${low(basename)}Builtins.exportNames();\n`;
}
}
bundledHeader += ` }
explicit JSBuiltinFunctions(JSC::VM& vm, RefPtr<JSC::SourceProvider> provider, BunBuiltinNames &builtinNames);
void exportNames();
`;
for (const { basename } of files) {
@@ -613,7 +656,53 @@ export async function bundleBuiltinFunctions({ requireTransformer }: BundleBuilt
} // 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);

View File

@@ -18,7 +18,17 @@ export function fmtCPPCharArray(str: string, nullTerminated: boolean = true) {
.join(",") +
(nullTerminated ? ",0" : "") +
"}";
return [chars, normalized.length + (nullTerminated ? 1 : 0)];
return [chars, normalized.length + (nullTerminated ? 1 : 0)] as const;
}
export function addCPPCharArray(str: string, nullTerminated: boolean = true) {
const normalized = str.trim() + "\n";
return (
normalized
.split("")
.map(a => a.charCodeAt(0))
.join(",") + (nullTerminated ? ",0" : "")
);
}
export function declareASCIILiteral(name: string, value: string) {

View File

@@ -14,6 +14,7 @@
#include <JavaScriptCore/VM.h>
#include <JavaScriptCore/Identifier.h>
#include <JavaScriptCore/BuiltinUtils.h>
#include "BunBuiltinNames+extras.h"
namespace WebCore {
@@ -194,7 +195,6 @@ using namespace JSC;
macro(requireESM) \
macro(requireMap) \
macro(requireNativeModule) \
macro(resolve) \
macro(resolveSync) \
macro(resume) \
macro(self) \
@@ -250,6 +250,8 @@ using namespace JSC;
macro(writeRequests) \
macro(writing) \
macro(written) \
BUN_ADDITIONAL_BUILTIN_NAMES(macro)
// --- END of BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME ---
class BunBuiltinNames {
public:
@@ -268,6 +270,8 @@ public:
BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_IDENTIFIER_ACCESSOR)
const JSC::Identifier& resolvePublicName() const { return m_vm.propertyNames->resolve;}
private:
JSC::VM& m_vm;
BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_NAMES)