diff --git a/Source/JavaScriptCore/runtime/CachedTypes.cpp b/Source/JavaScriptCore/runtime/CachedTypes.cpp index 8b9f5a668154..51215d6f81a9 100644 --- a/Source/JavaScriptCore/runtime/CachedTypes.cpp +++ b/Source/JavaScriptCore/runtime/CachedTypes.cpp @@ -2688,6 +2688,56 @@ RefPtr encodeFunctionCodeBlock(VM& vm, const UnlinkedFunctionCod return encoder.release(error); } +#if USE(BUN_JSC_ADDITIONS) +// Top-level entry for a builtin UnlinkedFunctionExecutable. +// Simpler than GenericCacheEntry: no SourceCodeKey (source is fixed at build time), +// no bootSessionUUID (Bun fork already neutralizes it). Only version check. +class BuiltinFunctionCacheEntry { +public: + BuiltinFunctionCacheEntry() + : m_cacheVersion(computeJSCBytecodeCacheVersion()) + { + } + + void encode(Encoder& encoder, const UnlinkedFunctionExecutable& executable) + { + m_executable.encode(encoder, executable); + } + + UnlinkedFunctionExecutable* decode(Decoder& decoder) const + { + if (m_cacheVersion != computeJSCBytecodeCacheVersion()) + return nullptr; + return m_executable.decode(decoder); + } + +private: + uint32_t m_cacheVersion; + CachedFunctionExecutable m_executable; +}; +static_assert(alignof(BuiltinFunctionCacheEntry) <= alignof(std::max_align_t)); + +RefPtr encodeBuiltinFunctionExecutable(VM& vm, UnlinkedFunctionExecutable* executable) +{ + BytecodeCacheError error; + FileSystem::FileHandle invalidFileHandle; + Encoder encoder(vm, invalidFileHandle); + encoder.malloc()->encode(encoder, *executable); + return encoder.release(error); +} + +UnlinkedFunctionExecutable* decodeBuiltinFunctionExecutable(VM& vm, Ref cachedBytecode) +{ + auto span = cachedBytecode->span(); + if (span.empty()) + return nullptr; + const auto* entry = std::bit_cast(span.data()); + Ref decoder = Decoder::create(vm, WTF::move(cachedBytecode)); + DeferGC deferGC(vm); + return entry->decode(decoder.get()); +} +#endif + std::optional decodeSourceCodeKey(VM& vm, Ref cachedBytecode) { const auto* cachedEntry = std::bit_cast(cachedBytecode->span().data()); diff --git a/Source/JavaScriptCore/runtime/CachedTypes.h b/Source/JavaScriptCore/runtime/CachedTypes.h index 4fe52e63238f..ad70041558cd 100644 --- a/Source/JavaScriptCore/runtime/CachedTypes.h +++ b/Source/JavaScriptCore/runtime/CachedTypes.h @@ -130,4 +130,12 @@ JS_EXPORT_PRIVATE void decodeFunctionCodeBlock(Decoder&, int32_t cachedFunctionC bool isCachedBytecodeStillValid(VM&, Ref, const SourceCodeKey&, SourceCodeType); +#if USE(BUN_JSC_ADDITIONS) +// Encode/decode a top-level UnlinkedFunctionExecutable (including nested code blocks) +// for Bun's builtin module bytecode cache. Unlike encodeCodeBlock, this skips +// SourceCodeKey validation since builtin sources are fixed at build time. +JS_EXPORT_PRIVATE RefPtr encodeBuiltinFunctionExecutable(VM&, UnlinkedFunctionExecutable*); +JS_EXPORT_PRIVATE UnlinkedFunctionExecutable* decodeBuiltinFunctionExecutable(VM&, Ref); +#endif + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp index d539c7a50833..d53bc09bc500 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.cpp +++ b/Source/JavaScriptCore/runtime/CodeCache.cpp @@ -30,6 +30,10 @@ #include "IndirectEvalExecutable.h" #include +#if USE(BUN_JSC_ADDITIONS) +#include "BuiltinExecutables.h" +#endif + namespace JSC { WTF_MAKE_TZONE_ALLOCATED_IMPL(CodeCache); @@ -168,6 +172,31 @@ UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModulePro return recursivelyGenerateUnlinkedCodeBlock(vm, source, lexicallyScopedFeatures, scriptMode, codeGenerationMode, error, evalContextType); } +#if USE(BUN_JSC_ADDITIONS) +UnlinkedFunctionExecutable* recursivelyGenerateUnlinkedCodeBlockForBuiltinFunction(VM& vm, const SourceCode& source, const Identifier& name, ParserError& error, ImplementationVisibility implementationVisibility, ConstructorKind constructorKind, ConstructAbility constructAbility, InlineAttribute inlineAttribute) +{ + UnlinkedFunctionExecutable* executable = BuiltinExecutables::createExecutable( + vm, source, name, implementationVisibility, + constructorKind, constructAbility, inlineAttribute, + NeedsClassFieldInitializer::No, PrivateBrandRequirement::None); + if (!executable) + return nullptr; + + SourceCode innerSource = executable->linkedSourceCode(source); + UnlinkedFunctionCodeBlock* codeBlock = executable->unlinkedCodeBlockFor( + vm, innerSource, CodeSpecializationKind::CodeForCall, { }, error, + executable->parseMode()); + if (error.isValid() || !codeBlock) + return nullptr; + + generateUnlinkedCodeBlockForFunctions(vm, codeBlock, innerSource, { }, error); + if (error.isValid()) + return nullptr; + + return executable; +} +#endif + template UnlinkedCodeBlockType* CodeCache::getUnlinkedGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserScriptMode scriptMode, OptionSet codeGenerationMode, ParserError& error, EvalContextType evalContextType) { diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h index 2aa836bdb247..d147b0e68b55 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.h +++ b/Source/JavaScriptCore/runtime/CodeCache.h @@ -266,6 +266,13 @@ UnlinkedEvalCodeBlock* generateUnlinkedCodeBlockForDirectEval(VM&, DirectEvalExe UnlinkedProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForProgram(VM&, const SourceCode&, LexicallyScopedFeatures, JSParserScriptMode, OptionSet, ParserError&, EvalContextType); UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModuleProgram(VM&, const SourceCode&, LexicallyScopedFeatures, JSParserScriptMode, OptionSet, ParserError&, EvalContextType); +#if USE(BUN_JSC_ADDITIONS) +// Parse a builtin function source (with @-prefixed private identifiers) and +// recursively generate bytecode for all nested functions. Used by Bun to +// pre-generate bytecode for internal modules at build time. +JS_EXPORT_PRIVATE UnlinkedFunctionExecutable* recursivelyGenerateUnlinkedCodeBlockForBuiltinFunction(VM&, const SourceCode&, const Identifier& name, ParserError&, ImplementationVisibility = ImplementationVisibility::Public, ConstructorKind = ConstructorKind::None, ConstructAbility = ConstructAbility::CannotConstruct, InlineAttribute = InlineAttribute::None); +#endif + void writeCodeBlock(const SourceCodeKey&, const SourceCodeValue&); RefPtr serializeBytecode(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, LexicallyScopedFeatures, JSParserScriptMode, FileSystem::FileHandle&, BytecodeCacheError&, OptionSet); SourceCodeKey sourceCodeKeyForSerializedProgram(VM&, const SourceCode&);