Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions Source/JavaScriptCore/runtime/CachedTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2688,6 +2688,56 @@ RefPtr<CachedBytecode> 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<CachedBytecode> encodeBuiltinFunctionExecutable(VM& vm, UnlinkedFunctionExecutable* executable)
{
BytecodeCacheError error;
FileSystem::FileHandle invalidFileHandle;
Encoder encoder(vm, invalidFileHandle);
encoder.malloc<BuiltinFunctionCacheEntry>()->encode(encoder, *executable);
return encoder.release(error);
}

UnlinkedFunctionExecutable* decodeBuiltinFunctionExecutable(VM& vm, Ref<CachedBytecode> cachedBytecode)
{
auto span = cachedBytecode->span();
if (span.empty())
return nullptr;
const auto* entry = std::bit_cast<const BuiltinFunctionCacheEntry*>(span.data());
Ref decoder = Decoder::create(vm, WTF::move(cachedBytecode));
DeferGC deferGC(vm);
return entry->decode(decoder.get());
}
#endif

std::optional<SourceCodeKey> decodeSourceCodeKey(VM& vm, Ref<CachedBytecode> cachedBytecode)
{
const auto* cachedEntry = std::bit_cast<const GenericCacheEntry*>(cachedBytecode->span().data());
Expand Down
8 changes: 8 additions & 0 deletions Source/JavaScriptCore/runtime/CachedTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,12 @@ JS_EXPORT_PRIVATE void decodeFunctionCodeBlock(Decoder&, int32_t cachedFunctionC

bool isCachedBytecodeStillValid(VM&, Ref<CachedBytecode>, 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<CachedBytecode> encodeBuiltinFunctionExecutable(VM&, UnlinkedFunctionExecutable*);
JS_EXPORT_PRIVATE UnlinkedFunctionExecutable* decodeBuiltinFunctionExecutable(VM&, Ref<CachedBytecode>);
#endif

} // namespace JSC
29 changes: 29 additions & 0 deletions Source/JavaScriptCore/runtime/CodeCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include "IndirectEvalExecutable.h"
#include <wtf/TZoneMallocInlines.h>

#if USE(BUN_JSC_ADDITIONS)
#include "BuiltinExecutables.h"
#endif

namespace JSC {

WTF_MAKE_TZONE_ALLOCATED_IMPL(CodeCache);
Expand Down Expand Up @@ -168,6 +172,31 @@ UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModulePro
return recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(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<class UnlinkedCodeBlockType, class ExecutableType>
UnlinkedCodeBlockType* CodeCache::getUnlinkedGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType)
{
Expand Down
7 changes: 7 additions & 0 deletions Source/JavaScriptCore/runtime/CodeCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,13 @@ UnlinkedEvalCodeBlock* generateUnlinkedCodeBlockForDirectEval(VM&, DirectEvalExe
UnlinkedProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForProgram(VM&, const SourceCode&, LexicallyScopedFeatures, JSParserScriptMode, OptionSet<CodeGenerationMode>, ParserError&, EvalContextType);
UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModuleProgram(VM&, const SourceCode&, LexicallyScopedFeatures, JSParserScriptMode, OptionSet<CodeGenerationMode>, 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<CachedBytecode> serializeBytecode(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, LexicallyScopedFeatures, JSParserScriptMode, FileSystem::FileHandle&, BytecodeCacheError&, OptionSet<CodeGenerationMode>);
SourceCodeKey sourceCodeKeyForSerializedProgram(VM&, const SourceCode&);
Expand Down
Loading