mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 13:51:47 +00:00
Compare commits
1 Commits
claude/tes
...
claude/sou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c7adda552 |
File diff suppressed because it is too large
Load Diff
@@ -1519,11 +1519,11 @@ pub fn fetchWithoutOnLoadPlugins(
|
||||
referrer: String,
|
||||
log: *logger.Log,
|
||||
comptime flags: FetchFlags,
|
||||
) anyerror!ResolvedSource {
|
||||
) anyerror!ModuleResult {
|
||||
bun.assert(VirtualMachine.isLoaded());
|
||||
|
||||
if (try ModuleLoader.fetchBuiltinModule(jsc_vm, _specifier)) |builtin| {
|
||||
return builtin;
|
||||
if (try ModuleLoader.fetchBuiltinModule(jsc_vm, _specifier)) |module_result| {
|
||||
return module_result;
|
||||
}
|
||||
|
||||
const specifier_clone = _specifier.toUTF8(bun.default_allocator);
|
||||
@@ -1863,7 +1863,7 @@ pub fn drainMicrotasks(this: *VirtualMachine) void {
|
||||
this.eventLoop().drainMicrotasks() catch {}; // TODO: properly propagate exception upwards
|
||||
}
|
||||
|
||||
pub fn processFetchLog(globalThis: *JSGlobalObject, specifier: bun.String, referrer: bun.String, log: *logger.Log, ret: *ErrorableResolvedSource, err: anyerror) void {
|
||||
pub fn processFetchLog(globalThis: *JSGlobalObject, specifier: bun.String, referrer: bun.String, log: *logger.Log, ret: *ErrorableModuleResult, err: anyerror) void {
|
||||
switch (log.msgs.items.len) {
|
||||
0 => {
|
||||
const msg: logger.Msg = brk: {
|
||||
@@ -1882,14 +1882,14 @@ pub fn processFetchLog(globalThis: *JSGlobalObject, specifier: bun.String, refer
|
||||
};
|
||||
};
|
||||
{
|
||||
ret.* = ErrorableResolvedSource.err(err, (bun.api.BuildMessage.create(globalThis, globalThis.allocator(), msg) catch |e| globalThis.takeException(e)));
|
||||
ret.* = ErrorableModuleResult.err(err, (bun.api.BuildMessage.create(globalThis, globalThis.allocator(), msg) catch |e| globalThis.takeException(e)));
|
||||
}
|
||||
return;
|
||||
},
|
||||
|
||||
1 => {
|
||||
const msg = log.msgs.items[0];
|
||||
ret.* = ErrorableResolvedSource.err(err, switch (msg.metadata) {
|
||||
ret.* = ErrorableModuleResult.err(err, switch (msg.metadata) {
|
||||
.build => (bun.api.BuildMessage.create(globalThis, globalThis.allocator(), msg) catch |e| globalThis.takeException(e)),
|
||||
.resolve => (bun.api.ResolveMessage.create(
|
||||
globalThis,
|
||||
@@ -1919,7 +1919,7 @@ pub fn processFetchLog(globalThis: *JSGlobalObject, specifier: bun.String, refer
|
||||
};
|
||||
}
|
||||
|
||||
ret.* = ErrorableResolvedSource.err(
|
||||
ret.* = ErrorableModuleResult.err(
|
||||
err,
|
||||
globalThis.createAggregateError(
|
||||
errors,
|
||||
@@ -2797,9 +2797,12 @@ pub fn remapZigException(
|
||||
var log = logger.Log.init(bun.default_allocator);
|
||||
defer log.deinit();
|
||||
|
||||
var original_source = fetchWithoutOnLoadPlugins(this, this.global, top.source_url, bun.String.empty, &log, .print_source) catch return;
|
||||
var module_result = fetchWithoutOnLoadPlugins(this, this.global, top.source_url, bun.String.empty, &log, .print_source) catch return;
|
||||
must_reset_parser_arena_later.* = true;
|
||||
break :code original_source.source_code.toUTF8(bun.default_allocator);
|
||||
break :code switch (module_result.tag) {
|
||||
.transpiled => module_result.value.transpiled.source_code.toUTF8(bun.default_allocator),
|
||||
else => return, // For builtin/special modules, we can't show source
|
||||
};
|
||||
};
|
||||
|
||||
if (enable_source_code_preview and code.len == 0) {
|
||||
@@ -3729,6 +3732,7 @@ const DNSResolver = bun.api.dns.Resolver;
|
||||
|
||||
const jsc = bun.jsc;
|
||||
const ConsoleObject = jsc.ConsoleObject;
|
||||
const ErrorableModuleResult = jsc.ErrorableModuleResult;
|
||||
const ErrorableResolvedSource = jsc.ErrorableResolvedSource;
|
||||
const ErrorableString = jsc.ErrorableString;
|
||||
const EventLoop = jsc.EventLoop;
|
||||
@@ -3737,6 +3741,7 @@ const JSGlobalObject = jsc.JSGlobalObject;
|
||||
const JSInternalPromise = jsc.JSInternalPromise;
|
||||
const JSModuleLoader = jsc.JSModuleLoader;
|
||||
const JSValue = jsc.JSValue;
|
||||
const ModuleResult = jsc.ModuleResult;
|
||||
const Node = jsc.Node;
|
||||
const ResolvedSource = jsc.ResolvedSource;
|
||||
const SavedSourceMap = jsc.SavedSourceMap;
|
||||
|
||||
313
src/bun.js/bindings/BunSourceProvider.cpp
Normal file
313
src/bun.js/bindings/BunSourceProvider.cpp
Normal file
@@ -0,0 +1,313 @@
|
||||
#include "root.h"
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#include "BunSourceProvider.h"
|
||||
|
||||
#include <JavaScriptCore/BytecodeCacheError.h>
|
||||
#include "ZigGlobalObject.h"
|
||||
#include "wtf/Assertions.h"
|
||||
|
||||
#include <JavaScriptCore/Completion.h>
|
||||
#include <wtf/Scope.h>
|
||||
#include <wtf/text/StringHash.h>
|
||||
#include <sys/stat.h>
|
||||
#include <JavaScriptCore/SourceCodeKey.h>
|
||||
#include <mimalloc.h>
|
||||
#include <JavaScriptCore/CodeCache.h>
|
||||
|
||||
namespace Zig {
|
||||
|
||||
using Base = JSC::SourceProvider;
|
||||
using BytecodeCacheGenerator = JSC::BytecodeCacheGenerator;
|
||||
using UnlinkedFunctionExecutable = JSC::UnlinkedFunctionExecutable;
|
||||
using CachedBytecode = JSC::CachedBytecode;
|
||||
using UnlinkedFunctionCodeBlock = JSC::UnlinkedFunctionCodeBlock;
|
||||
using SourceCode = JSC::SourceCode;
|
||||
using CodeSpecializationKind = JSC::CodeSpecializationKind;
|
||||
using SourceOrigin = JSC::SourceOrigin;
|
||||
using String = WTF::String;
|
||||
using SourceProviderSourceType = JSC::SourceProviderSourceType;
|
||||
|
||||
extern "C" bool BunTest__shouldGenerateCodeCoverage(BunString sourceURL);
|
||||
extern "C" void Bun__addSourceProviderSourceMap(void* bun_vm, JSC::SourceProvider* opaque_source_provider, BunString* specifier);
|
||||
extern "C" void Bun__removeSourceProviderSourceMap(void* bun_vm, JSC::SourceProvider* opaque_source_provider, BunString* specifier);
|
||||
extern "C" void ByteRangeMapping__generate(BunString sourceURL, BunString code, int sourceID);
|
||||
|
||||
// Forward declaration - implementation is at the end of the file
|
||||
JSC::SourceOrigin toSourceOrigin(const WTF::String& sourceURL, bool isBuiltin);
|
||||
|
||||
Ref<BunSourceProvider> BunSourceProvider::create(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<WTF::StringImpl>&& source,
|
||||
const SourceOrigin& origin,
|
||||
WTF::String&& sourceURL,
|
||||
RefPtr<JSC::CachedBytecode>&& bytecode,
|
||||
JSC::SourceProviderSourceType sourceType)
|
||||
{
|
||||
return adoptRef(*new BunSourceProvider(
|
||||
globalObject,
|
||||
WTFMove(source),
|
||||
origin,
|
||||
WTFMove(sourceURL),
|
||||
WTFMove(bytecode),
|
||||
sourceType));
|
||||
}
|
||||
|
||||
BunSourceProvider::BunSourceProvider(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<WTF::StringImpl>&& source,
|
||||
const SourceOrigin& origin,
|
||||
WTF::String&& sourceURL,
|
||||
RefPtr<JSC::CachedBytecode>&& bytecode,
|
||||
JSC::SourceProviderSourceType sourceType)
|
||||
: Base(origin, WTFMove(sourceURL), String(), JSC::SourceTaintedOrigin::Untainted, TextPosition(), sourceType)
|
||||
, m_source(WTFMove(source))
|
||||
, m_cachedBytecode(WTFMove(bytecode))
|
||||
, m_globalObject(globalObject)
|
||||
{
|
||||
}
|
||||
|
||||
StringView BunSourceProvider::source() const
|
||||
{
|
||||
return StringView(m_source.get());
|
||||
}
|
||||
|
||||
BunSourceProvider::~BunSourceProvider()
|
||||
{
|
||||
// Sourcemap cleanup is handled separately via Bun__removeSourceProviderSourceMap
|
||||
// called from the caller when needed
|
||||
}
|
||||
|
||||
unsigned BunSourceProvider::hash() const
|
||||
{
|
||||
if (m_hash) {
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
return m_source->hash();
|
||||
}
|
||||
|
||||
// Helper function for converting source URLs to SourceOrigin (used by Bun__createSourceProvider and JSCommonJSModule.cpp)
|
||||
JSC::SourceOrigin toSourceOrigin(const WTF::String& sourceURL, bool isBuiltin)
|
||||
{
|
||||
using namespace WTF::StringLiterals;
|
||||
|
||||
ASSERT_WITH_MESSAGE(!sourceURL.startsWith("file://"_s), "specifier should not already be a file URL");
|
||||
|
||||
if (isBuiltin) {
|
||||
if (sourceURL.startsWith("node:"_s)) {
|
||||
return JSC::SourceOrigin(WTF::URL(WTF::makeString("builtin://node/"_s, sourceURL.substring(5))));
|
||||
} else if (sourceURL.startsWith("bun:"_s)) {
|
||||
return JSC::SourceOrigin(WTF::URL(WTF::makeString("builtin://bun/"_s, sourceURL.substring(4))));
|
||||
} else {
|
||||
return JSC::SourceOrigin(WTF::URL(WTF::makeString("builtin://"_s, sourceURL)));
|
||||
}
|
||||
}
|
||||
return JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL));
|
||||
}
|
||||
|
||||
}; // namespace Zig
|
||||
|
||||
// C bridge function to create a BunSourceProvider from TranspiledSource
|
||||
extern "C" JSC::SourceProvider* Bun__createSourceProvider(
|
||||
Zig::GlobalObject* globalObject,
|
||||
const TranspiledSource* source,
|
||||
bool isBuiltin)
|
||||
{
|
||||
using namespace Zig;
|
||||
|
||||
auto sourceString = source->source_code.toWTFString(BunString::ZeroCopy);
|
||||
auto sourceURL = source->source_url.toWTFString(BunString::ZeroCopy);
|
||||
|
||||
bool isCommonJS = source->flags.is_commonjs;
|
||||
auto sourceType = isCommonJS ?
|
||||
JSC::SourceProviderSourceType::Program :
|
||||
JSC::SourceProviderSourceType::Module;
|
||||
|
||||
// Handle bytecode if present
|
||||
RefPtr<JSC::CachedBytecode> bytecode;
|
||||
if (source->bytecode_cache) {
|
||||
const auto destructorPtr = [](const void* ptr) {
|
||||
mi_free(const_cast<void*>(ptr));
|
||||
};
|
||||
const auto destructorNoOp = [](const void* ptr) {
|
||||
// no-op, for bun build --compile.
|
||||
};
|
||||
// For already_bundled bytecode, we don't free it (it's embedded)
|
||||
const auto destructor = source->flags.is_already_bundled ? destructorNoOp : destructorPtr;
|
||||
|
||||
bytecode = JSC::CachedBytecode::create(
|
||||
std::span<uint8_t>(source->bytecode_cache, source->bytecode_cache_len),
|
||||
destructor,
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
bool isCodeCoverageEnabled = !!globalObject->vm().controlFlowProfiler();
|
||||
bool shouldGenerateCodeCoverage = isCodeCoverageEnabled && !isBuiltin &&
|
||||
BunTest__shouldGenerateCodeCoverage(source->source_url);
|
||||
|
||||
auto provider = BunSourceProvider::create(
|
||||
globalObject->isThreadLocalDefaultGlobalObject ? globalObject : nullptr,
|
||||
sourceString.isNull() ? *WTF::StringImpl::empty() : *sourceString.impl(),
|
||||
toSourceOrigin(sourceURL, isBuiltin),
|
||||
WTFMove(sourceURL),
|
||||
WTFMove(bytecode),
|
||||
sourceType
|
||||
);
|
||||
|
||||
// Generate code coverage mapping if needed
|
||||
if (shouldGenerateCodeCoverage) {
|
||||
ByteRangeMapping__generate(
|
||||
Bun::toString(provider->sourceURL()),
|
||||
Bun::toString(provider->source().toStringWithoutCopying()),
|
||||
provider->asID()
|
||||
);
|
||||
}
|
||||
|
||||
// Register sourcemap if needed
|
||||
if (source->flags.is_already_bundled) {
|
||||
BunString sourceUrlBun = source->source_url;
|
||||
Bun__addSourceProviderSourceMap(
|
||||
globalObject->bunVM(),
|
||||
provider.ptr(),
|
||||
&sourceUrlBun
|
||||
);
|
||||
}
|
||||
|
||||
// Transfer ownership to caller
|
||||
return &provider.leakRef();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Exported extern "C" utility functions (formerly in ZigSourceProvider.cpp)
|
||||
// =============================================================================
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Decrement reference count for cached bytecode
|
||||
void CachedBytecode__deref(JSC::CachedBytecode* cachedBytecode)
|
||||
{
|
||||
cachedBytecode->deref();
|
||||
}
|
||||
|
||||
// Get source code slice from a SourceProvider
|
||||
BunString ZigSourceProvider__getSourceSlice(JSC::SourceProvider* provider)
|
||||
{
|
||||
return Bun::toStringView(provider->source());
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
// Shared VM for bytecode caching - thread-local to avoid conflicts
|
||||
static JSC::VM& getVMForBytecodeCache()
|
||||
{
|
||||
static thread_local JSC::VM* vmForBytecodeCache = nullptr;
|
||||
if (!vmForBytecodeCache) {
|
||||
const auto heapSize = JSC::HeapType::Small;
|
||||
auto vmPtr = JSC::VM::tryCreate(heapSize);
|
||||
vmPtr->refSuppressingSaferCPPChecking();
|
||||
vmForBytecodeCache = vmPtr.get();
|
||||
vmPtr->heap.acquireAccess();
|
||||
}
|
||||
return *vmForBytecodeCache;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Generate cached bytecode for ES modules
|
||||
bool generateCachedModuleByteCodeFromSourceCode(
|
||||
BunString* sourceProviderURL,
|
||||
const Latin1Character* inputSourceCode,
|
||||
size_t inputSourceCodeSize,
|
||||
const uint8_t** outputByteCode,
|
||||
size_t* outputByteCodeSize,
|
||||
JSC::CachedBytecode** cachedBytecodePtr)
|
||||
{
|
||||
std::span<const Latin1Character> sourceCodeSpan(inputSourceCode, inputSourceCodeSize);
|
||||
JSC::SourceCode sourceCode = JSC::makeSource(
|
||||
WTF::String(sourceCodeSpan),
|
||||
Zig::toSourceOrigin(sourceProviderURL->toWTFString(), false),
|
||||
JSC::SourceTaintedOrigin::Untainted
|
||||
);
|
||||
|
||||
JSC::VM& vm = getVMForBytecodeCache();
|
||||
JSC::JSLockHolder locker(vm);
|
||||
|
||||
JSC::LexicallyScopedFeatures lexicallyScopedFeatures = JSC::StrictModeLexicallyScopedFeature;
|
||||
JSC::JSParserScriptMode scriptMode = JSC::JSParserScriptMode::Module;
|
||||
JSC::EvalContextType evalContextType = JSC::EvalContextType::None;
|
||||
|
||||
JSC::ParserError parserError;
|
||||
JSC::UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = JSC::recursivelyGenerateUnlinkedCodeBlockForModuleProgram(
|
||||
vm, sourceCode, lexicallyScopedFeatures, scriptMode, {}, parserError, evalContextType
|
||||
);
|
||||
|
||||
if (parserError.isValid())
|
||||
return false;
|
||||
if (!unlinkedCodeBlock)
|
||||
return false;
|
||||
|
||||
auto key = JSC::sourceCodeKeyForSerializedModule(vm, sourceCode);
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode = JSC::encodeCodeBlock(vm, key, unlinkedCodeBlock);
|
||||
|
||||
if (!cachedBytecode)
|
||||
return false;
|
||||
|
||||
cachedBytecode->ref();
|
||||
*cachedBytecodePtr = cachedBytecode.get();
|
||||
*outputByteCode = cachedBytecode->span().data();
|
||||
*outputByteCodeSize = cachedBytecode->span().size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate cached bytecode for CommonJS programs
|
||||
bool generateCachedCommonJSProgramByteCodeFromSourceCode(
|
||||
BunString* sourceProviderURL,
|
||||
const Latin1Character* inputSourceCode,
|
||||
size_t inputSourceCodeSize,
|
||||
const uint8_t** outputByteCode,
|
||||
size_t* outputByteCodeSize,
|
||||
JSC::CachedBytecode** cachedBytecodePtr)
|
||||
{
|
||||
std::span<const Latin1Character> sourceCodeSpan(inputSourceCode, inputSourceCodeSize);
|
||||
JSC::SourceCode sourceCode = JSC::makeSource(
|
||||
WTF::String(sourceCodeSpan),
|
||||
Zig::toSourceOrigin(sourceProviderURL->toWTFString(), false),
|
||||
JSC::SourceTaintedOrigin::Untainted
|
||||
);
|
||||
|
||||
JSC::VM& vm = getVMForBytecodeCache();
|
||||
JSC::JSLockHolder locker(vm);
|
||||
|
||||
JSC::LexicallyScopedFeatures lexicallyScopedFeatures = JSC::NoLexicallyScopedFeatures;
|
||||
JSC::JSParserScriptMode scriptMode = JSC::JSParserScriptMode::Classic;
|
||||
JSC::EvalContextType evalContextType = JSC::EvalContextType::None;
|
||||
|
||||
JSC::ParserError parserError;
|
||||
JSC::UnlinkedProgramCodeBlock* unlinkedCodeBlock = JSC::recursivelyGenerateUnlinkedCodeBlockForProgram(
|
||||
vm, sourceCode, lexicallyScopedFeatures, scriptMode, {}, parserError, evalContextType
|
||||
);
|
||||
|
||||
if (parserError.isValid())
|
||||
return false;
|
||||
if (!unlinkedCodeBlock)
|
||||
return false;
|
||||
|
||||
auto key = JSC::sourceCodeKeyForSerializedProgram(vm, sourceCode);
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode = JSC::encodeCodeBlock(vm, key, unlinkedCodeBlock);
|
||||
|
||||
if (!cachedBytecode)
|
||||
return false;
|
||||
|
||||
cachedBytecode->ref();
|
||||
*cachedBytecodePtr = cachedBytecode.get();
|
||||
*outputByteCode = cachedBytecode->span().data();
|
||||
*outputByteCodeSize = cachedBytecode->span().size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
69
src/bun.js/bindings/BunSourceProvider.h
Normal file
69
src/bun.js/bindings/BunSourceProvider.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "headers.h"
|
||||
#include "root.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace JSC {
|
||||
class Structure;
|
||||
class Identifier;
|
||||
class SourceCodeKey;
|
||||
class SourceProvider;
|
||||
} // namespace JSC
|
||||
|
||||
#include <JavaScriptCore/CachedBytecode.h>
|
||||
#include <JavaScriptCore/JSGlobalObject.h>
|
||||
#include <JavaScriptCore/JSTypeInfo.h>
|
||||
#include <JavaScriptCore/SourceProvider.h>
|
||||
#include <JavaScriptCore/Structure.h>
|
||||
|
||||
namespace Zig {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
class BunSourceProvider final : public JSC::SourceProvider {
|
||||
WTF_DEPRECATED_MAKE_FAST_ALLOCATED(BunSourceProvider);
|
||||
using Base = JSC::SourceProvider;
|
||||
using BytecodeCacheGenerator = JSC::BytecodeCacheGenerator;
|
||||
using UnlinkedFunctionExecutable = JSC::UnlinkedFunctionExecutable;
|
||||
using CachedBytecode = JSC::CachedBytecode;
|
||||
using UnlinkedFunctionCodeBlock = JSC::UnlinkedFunctionCodeBlock;
|
||||
using SourceCode = JSC::SourceCode;
|
||||
using CodeSpecializationKind = JSC::CodeSpecializationKind;
|
||||
using SourceOrigin = JSC::SourceOrigin;
|
||||
|
||||
public:
|
||||
static Ref<BunSourceProvider> create(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<WTF::StringImpl>&& source,
|
||||
const SourceOrigin& origin,
|
||||
WTF::String&& sourceURL,
|
||||
RefPtr<JSC::CachedBytecode>&& bytecode,
|
||||
JSC::SourceProviderSourceType sourceType);
|
||||
|
||||
~BunSourceProvider() final;
|
||||
|
||||
unsigned hash() const final;
|
||||
StringView source() const final;
|
||||
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode() const final
|
||||
{
|
||||
return m_cachedBytecode.copyRef();
|
||||
};
|
||||
|
||||
private:
|
||||
BunSourceProvider(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<WTF::StringImpl>&& source,
|
||||
const SourceOrigin& origin,
|
||||
WTF::String&& sourceURL,
|
||||
RefPtr<JSC::CachedBytecode>&& bytecode,
|
||||
JSC::SourceProviderSourceType sourceType);
|
||||
|
||||
// Simplified members (vs ZigSourceProvider)
|
||||
Ref<WTF::StringImpl> m_source;
|
||||
RefPtr<JSC::CachedBytecode> m_cachedBytecode;
|
||||
Zig::GlobalObject* m_globalObject; // For sourcemap cleanup only
|
||||
unsigned m_hash = 0;
|
||||
};
|
||||
|
||||
} // namespace Zig
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "root.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include <JavaScriptCore/ControlFlowProfiler.h>
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
@@ -260,7 +260,7 @@ JSC::EncodedJSValue builtinLoader(JSC::JSGlobalObject* globalObject, JSC::CallFr
|
||||
BunString specifierBunString = Bun::toString(specifierWtfString);
|
||||
BunString empty = BunStringEmpty;
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
ErrorableResolvedSource res;
|
||||
ErrorableModuleResult res;
|
||||
res.success = false;
|
||||
memset(&res.result, 0, sizeof res.result);
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
|
||||
#include <JavaScriptCore/JSMapInlines.h>
|
||||
#include <JavaScriptCore/GetterSetter.h>
|
||||
#include "ZigSourceProvider.h"
|
||||
#include <JavaScriptCore/FunctionPrototype.h>
|
||||
#include "JSCommonJSModule.h"
|
||||
#include <JavaScriptCore/JSModuleNamespaceObject.h>
|
||||
@@ -82,6 +81,14 @@
|
||||
#include "ErrorCode.h"
|
||||
|
||||
extern "C" bool Bun__isBunMain(JSC::JSGlobalObject* global, const BunString*);
|
||||
extern "C" JSC::SourceProvider* Bun__createSourceProvider(
|
||||
Zig::GlobalObject* globalObject,
|
||||
const TranspiledSource* source,
|
||||
bool isBuiltin);
|
||||
|
||||
namespace Zig {
|
||||
JSC::SourceOrigin toSourceOrigin(const WTF::String& sourceURL, bool isBuiltin);
|
||||
}
|
||||
|
||||
namespace Bun {
|
||||
using namespace JSC;
|
||||
@@ -1311,7 +1318,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireNativeModule, (JSGlobalObject * lexica
|
||||
JSValue specifierValue = callframe->argument(0);
|
||||
WTF::String specifier = specifierValue.toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
ErrorableResolvedSource res;
|
||||
ErrorableModuleResult res;
|
||||
res.success = false;
|
||||
memset(&res.result, 0, sizeof res.result);
|
||||
BunString specifierStr = Bun::toString(specifier);
|
||||
@@ -1360,12 +1367,21 @@ void JSCommonJSModule::evaluate(
|
||||
}
|
||||
}
|
||||
|
||||
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program, isBuiltIn);
|
||||
// Convert ResolvedSource to TranspiledSource for Bun__createSourceProvider
|
||||
TranspiledSource transpiledSource;
|
||||
transpiledSource.source_code = source.source_code;
|
||||
transpiledSource.source_url = source.source_url;
|
||||
transpiledSource.bytecode_cache = source.bytecode_cache;
|
||||
transpiledSource.bytecode_cache_len = source.bytecode_cache_size;
|
||||
transpiledSource.flags.is_commonjs = source.isCommonJSModule;
|
||||
transpiledSource.flags.is_already_bundled = source.already_bundled;
|
||||
|
||||
auto* sourceProvider = Bun__createSourceProvider(globalObject, &transpiledSource, isBuiltIn);
|
||||
this->ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
|
||||
if (this->hasEvaluated)
|
||||
return;
|
||||
|
||||
this->sourceCode = JSC::SourceCode(WTFMove(sourceProvider));
|
||||
this->sourceCode = JSC::SourceCode(adoptRef(*sourceProvider));
|
||||
|
||||
evaluateCommonJSModuleOnce(vm, globalObject, this, this->m_dirname.get(), this->m_filename.get());
|
||||
}
|
||||
@@ -1461,12 +1477,21 @@ std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
source.source_code = Bun::toStringRef(concat);
|
||||
}
|
||||
|
||||
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program, isBuiltIn);
|
||||
// Convert ResolvedSource to TranspiledSource for Bun__createSourceProvider
|
||||
TranspiledSource transpiledSource;
|
||||
transpiledSource.source_code = source.source_code;
|
||||
transpiledSource.source_url = source.source_url;
|
||||
transpiledSource.bytecode_cache = source.bytecode_cache;
|
||||
transpiledSource.bytecode_cache_len = source.bytecode_cache_size;
|
||||
transpiledSource.flags.is_commonjs = source.isCommonJSModule;
|
||||
transpiledSource.flags.is_already_bundled = source.already_bundled;
|
||||
|
||||
auto* sourceProvider = Bun__createSourceProvider(globalObject, &transpiledSource, isBuiltIn);
|
||||
sourceOrigin = sourceProvider->sourceOrigin();
|
||||
moduleObject = JSCommonJSModule::create(
|
||||
vm,
|
||||
globalObject->CommonJSModuleObjectStructure(),
|
||||
requireMapKey, filename, dirname, WTFMove(JSC::SourceCode(WTFMove(sourceProvider))));
|
||||
requireMapKey, filename, dirname, WTFMove(JSC::SourceCode(adoptRef(*sourceProvider))));
|
||||
|
||||
moduleObject->putDirect(vm,
|
||||
WebCore::clientData(vm)->builtinNames().exportsPublicName(),
|
||||
@@ -1527,6 +1552,118 @@ std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
sourceURL));
|
||||
}
|
||||
|
||||
// New overload for TranspiledSource
|
||||
std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSString* requireMapKey,
|
||||
const TranspiledSource& source,
|
||||
bool isBuiltIn)
|
||||
{
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
JSCommonJSModule* moduleObject = nullptr;
|
||||
WTF::String sourceURL = source.source_url.toWTFString();
|
||||
|
||||
JSValue entry = globalObject->requireMap()->get(globalObject, requireMapKey);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
SourceOrigin sourceOrigin;
|
||||
|
||||
if (entry) {
|
||||
moduleObject = jsDynamicCast<JSCommonJSModule*>(entry);
|
||||
}
|
||||
|
||||
if (!moduleObject) {
|
||||
size_t index = sourceURL.reverseFind(PLATFORM_SEP, sourceURL.length());
|
||||
JSString* dirname;
|
||||
JSString* filename = requireMapKey;
|
||||
if (index != WTF::notFound) {
|
||||
dirname = JSC::jsSubstring(globalObject, requireMapKey, 0, index);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
} else {
|
||||
dirname = jsEmptyString(vm);
|
||||
}
|
||||
auto requireMap = globalObject->requireMap();
|
||||
if (requireMap->size() == 0) {
|
||||
requireMapKey = JSC::jsString(vm, WTF::String("."_s));
|
||||
}
|
||||
|
||||
// Handle module wrapper if needed
|
||||
auto sourceString = source.source_code.toWTFString(BunString::ZeroCopy);
|
||||
if (globalObject->hasOverriddenModuleWrapper) [[unlikely]] {
|
||||
sourceString = makeString(
|
||||
globalObject->m_moduleWrapperStart,
|
||||
sourceString,
|
||||
globalObject->m_moduleWrapperEnd);
|
||||
}
|
||||
|
||||
// Create source provider using Bun__createSourceProvider
|
||||
auto* provider = Bun__createSourceProvider(globalObject, &source, isBuiltIn);
|
||||
sourceOrigin = provider->sourceOrigin();
|
||||
|
||||
moduleObject = JSCommonJSModule::create(
|
||||
vm,
|
||||
globalObject->CommonJSModuleObjectStructure(),
|
||||
requireMapKey, filename, dirname, WTFMove(JSC::SourceCode(adoptRef(*provider))));
|
||||
|
||||
moduleObject->putDirect(vm,
|
||||
WebCore::clientData(vm)->builtinNames().exportsPublicName(),
|
||||
JSC::constructEmptyObject(globalObject, globalObject->objectPrototype()), 0);
|
||||
|
||||
requireMap->set(globalObject, filename, moduleObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
} else {
|
||||
sourceOrigin = Zig::toSourceOrigin(sourceURL, isBuiltIn);
|
||||
}
|
||||
|
||||
moduleObject->ignoreESModuleAnnotation = false; // TranspiledSource doesn't have package.json type flag
|
||||
|
||||
return JSC::SourceCode(
|
||||
JSC::SyntheticSourceProvider::create(
|
||||
[](JSC::JSGlobalObject* lexicalGlobalObject,
|
||||
const JSC::Identifier& moduleKey,
|
||||
Vector<JSC::Identifier, 4>& exportNames,
|
||||
JSC::MarkedArgumentBuffer& exportValues) -> void {
|
||||
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
JSValue keyValue = identifierToJSValue(vm, moduleKey);
|
||||
JSValue entry = globalObject->requireMap()->get(globalObject, keyValue);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
if (entry) {
|
||||
if (auto* moduleObject = jsDynamicCast<JSCommonJSModule*>(entry)) {
|
||||
if (!moduleObject->hasEvaluated) {
|
||||
evaluateCommonJSModuleOnce(
|
||||
vm,
|
||||
globalObject,
|
||||
moduleObject,
|
||||
moduleObject->m_dirname.get(),
|
||||
moduleObject->m_filename.get());
|
||||
if (auto exception = scope.exception()) {
|
||||
scope.clearException();
|
||||
|
||||
// On error, remove the module from the require map
|
||||
// so that it can be re-evaluated on the next require.
|
||||
globalObject->requireMap()->remove(globalObject, moduleObject->filename());
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
scope.throwException(globalObject, exception);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
moduleObject->toSyntheticSource(globalObject, moduleKey, exportNames, exportValues);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
}
|
||||
} else {
|
||||
// require map was cleared of the entry
|
||||
}
|
||||
},
|
||||
sourceOrigin,
|
||||
sourceURL));
|
||||
}
|
||||
|
||||
JSObject* JSCommonJSModule::createBoundRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString)
|
||||
{
|
||||
ASSERT(!pathString.startsWith("file://"_s));
|
||||
|
||||
@@ -177,6 +177,21 @@ inline std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
return createCommonJSModule(globalObject, specifierValue, source, false);
|
||||
}
|
||||
|
||||
// New overload for TranspiledSource
|
||||
std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSString* specifierValue,
|
||||
const TranspiledSource& source,
|
||||
bool isBuiltIn);
|
||||
|
||||
inline std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSString* specifierValue,
|
||||
const TranspiledSource& source)
|
||||
{
|
||||
return createCommonJSModule(globalObject, specifierValue, source, false);
|
||||
}
|
||||
|
||||
class RequireResolveFunctionPrototype final : public JSC::JSNonFinalObject {
|
||||
public:
|
||||
using Base = JSC::JSNonFinalObject;
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#include <JavaScriptCore/JSInternalPromise.h>
|
||||
#include <JavaScriptCore/JSInternalFieldObjectImpl.h>
|
||||
|
||||
#include "ZigSourceProvider.h"
|
||||
|
||||
#include <JavaScriptCore/JSSourceCode.h>
|
||||
#include <JavaScriptCore/JSString.h>
|
||||
#include <JavaScriptCore/ObjectConstructor.h>
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
JSValue fetchESMSourceCodeSync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSString* spceifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
ErrorableModuleResult* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute);
|
||||
@@ -101,7 +101,7 @@ JSValue fetchESMSourceCodeSync(
|
||||
JSValue fetchESMSourceCodeAsync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSString* spceifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
ErrorableModuleResult* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute);
|
||||
@@ -123,7 +123,7 @@ JSValue fetchCommonJSModuleNonBuiltin(
|
||||
JSC::JSValue specifierValue,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute,
|
||||
ErrorableResolvedSource* res,
|
||||
ErrorableModuleResult* res,
|
||||
JSCommonJSModule* target,
|
||||
String specifierWtfString,
|
||||
BunLoaderType forceLoaderType,
|
||||
@@ -136,6 +136,6 @@ JSValue resolveAndFetchBuiltinModule(
|
||||
JSValue fetchBuiltinModuleWithoutResolution(
|
||||
Zig::GlobalObject* globalObject,
|
||||
BunString* specifier,
|
||||
ErrorableResolvedSource* res);
|
||||
ErrorableModuleResult* res);
|
||||
|
||||
} // namespace Bun
|
||||
|
||||
19
src/bun.js/bindings/ModuleResult.zig
Normal file
19
src/bun.js/bindings/ModuleResult.zig
Normal file
@@ -0,0 +1,19 @@
|
||||
/// Tagged union return type from transpiler
|
||||
pub const ModuleResult = extern struct {
|
||||
tag: Tag,
|
||||
value: extern union {
|
||||
transpiled: TranspiledSource,
|
||||
special: SpecialModule,
|
||||
builtin_id: u32,
|
||||
},
|
||||
|
||||
pub const Tag = enum(u8) {
|
||||
transpiled,
|
||||
special,
|
||||
builtin,
|
||||
};
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
const TranspiledSource = @import("./TranspiledSource.zig").TranspiledSource;
|
||||
const SpecialModule = @import("./SpecialModule.zig").SpecialModule;
|
||||
18
src/bun.js/bindings/SpecialModule.zig
Normal file
18
src/bun.js/bindings/SpecialModule.zig
Normal file
@@ -0,0 +1,18 @@
|
||||
/// For special cases that need JSValue handling
|
||||
pub const SpecialModule = extern struct {
|
||||
tag: Tag,
|
||||
jsvalue: JSValue,
|
||||
|
||||
pub const Tag = enum(u8) {
|
||||
/// Return exports object directly
|
||||
exports_object,
|
||||
/// Return default export only
|
||||
export_default_object,
|
||||
/// Call custom require.extensions handler
|
||||
custom_extension,
|
||||
};
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
const jsc = bun.jsc;
|
||||
const JSValue = jsc.JSValue;
|
||||
25
src/bun.js/bindings/TranspiledSource.zig
Normal file
25
src/bun.js/bindings/TranspiledSource.zig
Normal file
@@ -0,0 +1,25 @@
|
||||
/// Minimal POD struct for transpiled source code
|
||||
/// Can be safely created on worker threads
|
||||
pub const TranspiledSource = extern struct {
|
||||
/// Transpiled source code (Latin1 or UTF16)
|
||||
/// Ownership transfers to C++ on return
|
||||
source_code: bun.String,
|
||||
|
||||
/// Module specifier for debugging/sourcemaps
|
||||
source_url: bun.String,
|
||||
|
||||
/// Optional bytecode cache (for bun build --compile)
|
||||
bytecode_cache: ?[*]u8 = null,
|
||||
bytecode_cache_len: usize = 0,
|
||||
|
||||
/// Packed flags
|
||||
flags: Flags = .{},
|
||||
|
||||
pub const Flags = packed struct(u32) {
|
||||
is_commonjs: bool = false,
|
||||
is_already_bundled: bool = false,
|
||||
_padding: u30 = 0,
|
||||
};
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
@@ -153,7 +153,6 @@
|
||||
#include "webcrypto/JSCryptoKey.h"
|
||||
#include "webcrypto/JSSubtleCrypto.h"
|
||||
#include "ZigGeneratedClasses.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "UtilInspect.h"
|
||||
#include "Base64Helpers.h"
|
||||
#include "wtf/text/OrdinalNumber.h"
|
||||
@@ -577,7 +576,7 @@ JSC_DEFINE_HOST_FUNCTION(functionFulfillModuleSync,
|
||||
}
|
||||
|
||||
auto specifier = Bun::toString(moduleKey);
|
||||
ErrorableResolvedSource res;
|
||||
ErrorableModuleResult res;
|
||||
res.success = false;
|
||||
// zero-initialize entire result union. zeroed BunString has BunStringTag::Dead, and zeroed
|
||||
// EncodedJSValues are empty, which our code should be handling
|
||||
@@ -3309,7 +3308,7 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
|
||||
|
||||
auto source = Bun::toString(sourceString);
|
||||
auto typeAttribute = Bun::toString(typeAttributeString);
|
||||
ErrorableResolvedSource res;
|
||||
ErrorableModuleResult res;
|
||||
res.success = false;
|
||||
// zero-initialize entire result union. zeroed BunString has BunStringTag::Dead, and zeroed
|
||||
// EncodedJSValues are empty, which our code should be handling
|
||||
|
||||
@@ -1,368 +0,0 @@
|
||||
#include "root.h"
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#include "ZigSourceProvider.h"
|
||||
|
||||
#include <JavaScriptCore/BytecodeCacheError.h>
|
||||
#include "ZigGlobalObject.h"
|
||||
#include "wtf/Assertions.h"
|
||||
|
||||
#include <JavaScriptCore/Completion.h>
|
||||
#include <wtf/Scope.h>
|
||||
#include <wtf/text/StringHash.h>
|
||||
#include <sys/stat.h>
|
||||
#include <JavaScriptCore/SourceCodeKey.h>
|
||||
#include <mimalloc.h>
|
||||
#include <JavaScriptCore/CodeCache.h>
|
||||
|
||||
namespace Zig {
|
||||
|
||||
using Base = JSC::SourceProvider;
|
||||
using BytecodeCacheGenerator = JSC::BytecodeCacheGenerator;
|
||||
using UnlinkedFunctionExecutable = JSC::UnlinkedFunctionExecutable;
|
||||
using CachedBytecode = JSC::CachedBytecode;
|
||||
using UnlinkedFunctionCodeBlock = JSC::UnlinkedFunctionCodeBlock;
|
||||
using SourceCode = JSC::SourceCode;
|
||||
using CodeSpecializationKind = JSC::CodeSpecializationKind;
|
||||
using SourceOrigin = JSC::SourceOrigin;
|
||||
using String = WTF::String;
|
||||
using SourceProviderSourceType = JSC::SourceProviderSourceType;
|
||||
|
||||
SourceOrigin toSourceOrigin(const String& sourceURL, bool isBuiltin)
|
||||
{
|
||||
|
||||
ASSERT_WITH_MESSAGE(!sourceURL.startsWith("file://"_s), "specifier should not already be a file URL");
|
||||
|
||||
if (isBuiltin) {
|
||||
if (sourceURL.startsWith("node:"_s)) {
|
||||
return SourceOrigin(WTF::URL(makeString("builtin://node/"_s, sourceURL.substring(5))));
|
||||
} else if (sourceURL.startsWith("bun:"_s)) {
|
||||
return SourceOrigin(WTF::URL(makeString("builtin://bun/"_s, sourceURL.substring(4))));
|
||||
} else {
|
||||
return SourceOrigin(WTF::URL(makeString("builtin://"_s, sourceURL)));
|
||||
}
|
||||
}
|
||||
return SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL));
|
||||
}
|
||||
|
||||
extern "C" int ByteRangeMapping__getSourceID(void* mappings, BunString sourceURL);
|
||||
extern "C" void* ByteRangeMapping__find(BunString sourceURL);
|
||||
void* sourceMappingForSourceURL(const WTF::String& sourceURL)
|
||||
{
|
||||
return ByteRangeMapping__find(Bun::toString(sourceURL));
|
||||
}
|
||||
|
||||
extern "C" void ByteRangeMapping__generate(BunString sourceURL, BunString code, int sourceID);
|
||||
|
||||
JSC::SourceID sourceIDForSourceURL(const WTF::String& sourceURL)
|
||||
{
|
||||
void* mappings = ByteRangeMapping__find(Bun::toString(sourceURL));
|
||||
if (!mappings) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ByteRangeMapping__getSourceID(mappings, Bun::toString(sourceURL));
|
||||
}
|
||||
|
||||
extern "C" bool BunTest__shouldGenerateCodeCoverage(BunString sourceURL);
|
||||
extern "C" void Bun__addSourceProviderSourceMap(void* bun_vm, SourceProvider* opaque_source_provider, BunString* specifier);
|
||||
extern "C" void Bun__removeSourceProviderSourceMap(void* bun_vm, SourceProvider* opaque_source_provider, BunString* specifier);
|
||||
|
||||
Ref<SourceProvider> SourceProvider::create(
|
||||
Zig::GlobalObject* globalObject,
|
||||
ResolvedSource& resolvedSource,
|
||||
JSC::SourceProviderSourceType sourceType,
|
||||
bool isBuiltin)
|
||||
{
|
||||
auto string = resolvedSource.source_code.toWTFString(BunString::ZeroCopy);
|
||||
auto sourceURLString = resolvedSource.source_url.toWTFString(BunString::ZeroCopy);
|
||||
|
||||
bool isCodeCoverageEnabled = !!globalObject->vm().controlFlowProfiler();
|
||||
|
||||
bool shouldGenerateCodeCoverage = isCodeCoverageEnabled && !isBuiltin && BunTest__shouldGenerateCodeCoverage(resolvedSource.source_url);
|
||||
|
||||
if (resolvedSource.needsDeref && !isBuiltin) {
|
||||
resolvedSource.needsDeref = false;
|
||||
resolvedSource.source_code.deref();
|
||||
// Do not deref either source_url or specifier
|
||||
// Specifier's lifetime is the JSValue, mostly
|
||||
// source_url is owned by the string above
|
||||
// https://github.com/oven-sh/bun/issues/9521
|
||||
}
|
||||
|
||||
const auto getProvider = [&]() -> Ref<SourceProvider> {
|
||||
if (resolvedSource.bytecode_cache != nullptr) {
|
||||
const auto destructorPtr = [](const void* ptr) {
|
||||
mi_free(const_cast<void*>(ptr));
|
||||
};
|
||||
const auto destructorNoOp = [](const void* ptr) {
|
||||
// no-op, for bun build --compile.
|
||||
};
|
||||
const auto destructor = resolvedSource.needsDeref ? destructorPtr : destructorNoOp;
|
||||
|
||||
Ref<JSC::CachedBytecode> bytecode = JSC::CachedBytecode::create(std::span<uint8_t>(resolvedSource.bytecode_cache, resolvedSource.bytecode_cache_size), destructor, {});
|
||||
auto provider = adoptRef(*new SourceProvider(
|
||||
globalObject->isThreadLocalDefaultGlobalObject ? globalObject : nullptr,
|
||||
resolvedSource,
|
||||
string.isNull() ? *StringImpl::empty() : *string.impl(),
|
||||
JSC::SourceTaintedOrigin::Untainted,
|
||||
toSourceOrigin(sourceURLString, isBuiltin),
|
||||
sourceURLString.impl(), TextPosition(),
|
||||
sourceType));
|
||||
provider->m_cachedBytecode = WTFMove(bytecode);
|
||||
return provider;
|
||||
}
|
||||
|
||||
return adoptRef(*new SourceProvider(
|
||||
globalObject->isThreadLocalDefaultGlobalObject ? globalObject : nullptr,
|
||||
resolvedSource,
|
||||
string.isNull() ? *StringImpl::empty() : *string.impl(),
|
||||
JSC::SourceTaintedOrigin::Untainted,
|
||||
toSourceOrigin(sourceURLString, isBuiltin),
|
||||
sourceURLString.impl(), TextPosition(),
|
||||
sourceType));
|
||||
};
|
||||
|
||||
auto provider = getProvider();
|
||||
|
||||
if (shouldGenerateCodeCoverage) {
|
||||
ByteRangeMapping__generate(Bun::toString(provider->sourceURL()), Bun::toString(provider->source().toStringWithoutCopying()), provider->asID());
|
||||
}
|
||||
|
||||
if (resolvedSource.already_bundled) {
|
||||
Bun__addSourceProviderSourceMap(globalObject->bunVM(), provider.ptr(), &resolvedSource.source_url);
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
StringView SourceProvider::source() const
|
||||
{
|
||||
return StringView(m_source.get());
|
||||
}
|
||||
|
||||
SourceProvider::~SourceProvider()
|
||||
{
|
||||
if (m_resolvedSource.already_bundled) {
|
||||
BunString str = Bun::toString(sourceURL());
|
||||
Bun__removeSourceProviderSourceMap(m_globalObject->bunVM(), this, &str);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void CachedBytecode__deref(JSC::CachedBytecode* cachedBytecode)
|
||||
{
|
||||
cachedBytecode->deref();
|
||||
}
|
||||
|
||||
static JSC::VM& getVMForBytecodeCache()
|
||||
{
|
||||
static thread_local JSC::VM* vmForBytecodeCache = nullptr;
|
||||
if (!vmForBytecodeCache) {
|
||||
const auto heapSize = JSC::HeapType::Small;
|
||||
auto vmPtr = JSC::VM::tryCreate(heapSize);
|
||||
vmPtr->refSuppressingSaferCPPChecking();
|
||||
vmForBytecodeCache = vmPtr.get();
|
||||
vmPtr->heap.acquireAccess();
|
||||
}
|
||||
return *vmForBytecodeCache;
|
||||
}
|
||||
|
||||
extern "C" bool generateCachedModuleByteCodeFromSourceCode(BunString* sourceProviderURL, const Latin1Character* inputSourceCode, size_t inputSourceCodeSize, const uint8_t** outputByteCode, size_t* outputByteCodeSize, JSC::CachedBytecode** cachedBytecodePtr)
|
||||
{
|
||||
std::span<const Latin1Character> sourceCodeSpan(inputSourceCode, inputSourceCodeSize);
|
||||
JSC::SourceCode sourceCode = JSC::makeSource(WTF::String(sourceCodeSpan), toSourceOrigin(sourceProviderURL->toWTFString(), false), JSC::SourceTaintedOrigin::Untainted);
|
||||
|
||||
JSC::VM& vm = getVMForBytecodeCache();
|
||||
|
||||
JSC::JSLockHolder locker(vm);
|
||||
LexicallyScopedFeatures lexicallyScopedFeatures = StrictModeLexicallyScopedFeature;
|
||||
JSParserScriptMode scriptMode = JSParserScriptMode::Module;
|
||||
EvalContextType evalContextType = EvalContextType::None;
|
||||
|
||||
ParserError parserError;
|
||||
UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = JSC::recursivelyGenerateUnlinkedCodeBlockForModuleProgram(vm, sourceCode, lexicallyScopedFeatures, scriptMode, {}, parserError, evalContextType);
|
||||
if (parserError.isValid())
|
||||
return false;
|
||||
if (!unlinkedCodeBlock)
|
||||
return false;
|
||||
|
||||
auto key = JSC::sourceCodeKeyForSerializedModule(vm, sourceCode);
|
||||
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode = JSC::encodeCodeBlock(vm, key, unlinkedCodeBlock);
|
||||
if (!cachedBytecode)
|
||||
return false;
|
||||
|
||||
cachedBytecode->ref();
|
||||
*cachedBytecodePtr = cachedBytecode.get();
|
||||
*outputByteCode = cachedBytecode->span().data();
|
||||
*outputByteCodeSize = cachedBytecode->span().size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool generateCachedCommonJSProgramByteCodeFromSourceCode(BunString* sourceProviderURL, const Latin1Character* inputSourceCode, size_t inputSourceCodeSize, const uint8_t** outputByteCode, size_t* outputByteCodeSize, JSC::CachedBytecode** cachedBytecodePtr)
|
||||
{
|
||||
std::span<const Latin1Character> sourceCodeSpan(inputSourceCode, inputSourceCodeSize);
|
||||
|
||||
JSC::SourceCode sourceCode = JSC::makeSource(WTF::String(sourceCodeSpan), toSourceOrigin(sourceProviderURL->toWTFString(), false), JSC::SourceTaintedOrigin::Untainted);
|
||||
JSC::VM& vm = getVMForBytecodeCache();
|
||||
|
||||
JSC::JSLockHolder locker(vm);
|
||||
LexicallyScopedFeatures lexicallyScopedFeatures = NoLexicallyScopedFeatures;
|
||||
JSParserScriptMode scriptMode = JSParserScriptMode::Classic;
|
||||
EvalContextType evalContextType = EvalContextType::None;
|
||||
|
||||
ParserError parserError;
|
||||
UnlinkedProgramCodeBlock* unlinkedCodeBlock = JSC::recursivelyGenerateUnlinkedCodeBlockForProgram(vm, sourceCode, lexicallyScopedFeatures, scriptMode, {}, parserError, evalContextType);
|
||||
if (parserError.isValid())
|
||||
return false;
|
||||
if (!unlinkedCodeBlock)
|
||||
return false;
|
||||
|
||||
auto key = JSC::sourceCodeKeyForSerializedProgram(vm, sourceCode);
|
||||
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode = JSC::encodeCodeBlock(vm, key, unlinkedCodeBlock);
|
||||
if (!cachedBytecode)
|
||||
return false;
|
||||
|
||||
cachedBytecode->ref();
|
||||
*cachedBytecodePtr = cachedBytecode.get();
|
||||
*outputByteCode = cachedBytecode->span().data();
|
||||
*outputByteCodeSize = cachedBytecode->span().size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned SourceProvider::hash() const
|
||||
{
|
||||
if (m_hash) {
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
return m_source->hash();
|
||||
}
|
||||
|
||||
void SourceProvider::freeSourceCode()
|
||||
{
|
||||
}
|
||||
|
||||
void SourceProvider::updateCache(const UnlinkedFunctionExecutable* executable, const SourceCode&,
|
||||
CodeSpecializationKind kind,
|
||||
const UnlinkedFunctionCodeBlock* codeBlock)
|
||||
{
|
||||
// if (!m_resolvedSource.bytecodecache_fd || !m_cachedBytecode)
|
||||
return;
|
||||
|
||||
JSC::BytecodeCacheError error;
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode = JSC::encodeFunctionCodeBlock(executable->vm(), codeBlock, error);
|
||||
if (cachedBytecode && !error.isValid())
|
||||
m_cachedBytecode->addFunctionUpdate(executable, kind, *cachedBytecode);
|
||||
}
|
||||
|
||||
void SourceProvider::cacheBytecode(const BytecodeCacheGenerator& generator)
|
||||
{
|
||||
// if (!m_resolvedSource.bytecodecache_fd)
|
||||
return;
|
||||
|
||||
if (!m_cachedBytecode)
|
||||
m_cachedBytecode = JSC::CachedBytecode::create();
|
||||
auto update = generator();
|
||||
if (update)
|
||||
m_cachedBytecode->addGlobalUpdate(*update);
|
||||
}
|
||||
|
||||
void SourceProvider::commitCachedBytecode()
|
||||
{
|
||||
// if (!m_resolvedSource.bytecodecache_fd || !m_cachedBytecode || !m_cachedBytecode->hasUpdates())
|
||||
return;
|
||||
|
||||
// auto clearBytecode = WTF::makeScopeExit([&] { m_cachedBytecode = nullptr; });
|
||||
// const auto fd = m_resolvedSource.bytecodecache_fd;
|
||||
|
||||
// auto fileSize = FileSystem::fileSize(fd);
|
||||
// if (!fileSize)
|
||||
// return;
|
||||
|
||||
// size_t cacheFileSize;
|
||||
// if (!WTF::convertSafely(*fileSize, cacheFileSize) || cacheFileSize != m_cachedBytecode->size()) {
|
||||
// // The bytecode cache has already been updated
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (!FileSystem::truncateFile(fd, m_cachedBytecode->sizeForUpdate()))
|
||||
// return;
|
||||
|
||||
// m_cachedBytecode->commitUpdates([&](off_t offset, const void* data, size_t size) {
|
||||
// long long result = FileSystem::seekFile(fd, offset, FileSystem::FileSeekOrigin::Beginning);
|
||||
// ASSERT_UNUSED(result, result != -1);
|
||||
// size_t bytesWritten = static_cast<size_t>(FileSystem::writeToFile(fd, data, size));
|
||||
// ASSERT_UNUSED(bytesWritten, bytesWritten == size);
|
||||
// });
|
||||
}
|
||||
|
||||
bool SourceProvider::isBytecodeCacheEnabled() const
|
||||
{
|
||||
// return m_resolvedSource.bytecodecache_fd > 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SourceProvider::readOrGenerateByteCodeCache(JSC::VM& vm, const JSC::SourceCode& sourceCode)
|
||||
{
|
||||
// auto status = this->readCache(vm, sourceCode);
|
||||
// switch (status) {
|
||||
// case -1: {
|
||||
// m_resolvedSource.bytecodecache_fd = 0;
|
||||
// break;
|
||||
// }
|
||||
// case 0: {
|
||||
// JSC::BytecodeCacheError err;
|
||||
// m_cachedBytecode = JSC::generateModuleBytecode(vm, sourceCode, m_resolvedSource.bytecodecache_fd, err);
|
||||
|
||||
// if (err.isValid()) {
|
||||
// m_resolvedSource.bytecodecache_fd = 0;
|
||||
// m_cachedBytecode = JSC::CachedBytecode::create();
|
||||
// }
|
||||
// }
|
||||
// // TODO: read the bytecode into a JSC::SourceCode object here
|
||||
// case 1: {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
int SourceProvider::readCache(JSC::VM& vm, const JSC::SourceCode& sourceCode)
|
||||
{
|
||||
return -1;
|
||||
// if (m_resolvedSource.bytecodecache_fd == 0)
|
||||
// return -1;
|
||||
// if (!FileSystem::isHandleValid(m_resolvedSource.bytecodecache_fd))
|
||||
// return -1;
|
||||
// const auto fd = m_resolvedSource.bytecodecache_fd;
|
||||
|
||||
// bool success;
|
||||
// FileSystem::MappedFileData mappedFile(fd, FileSystem::MappedFileMode::Shared, success);
|
||||
// if (!success)
|
||||
// return -1;
|
||||
|
||||
// const uint8_t* fileData = reinterpret_cast<const uint8_t*>(mappedFile.data());
|
||||
// unsigned fileTotalSize = mappedFile.size();
|
||||
// if (fileTotalSize == 0)
|
||||
// return 0;
|
||||
|
||||
// Ref<JSC::CachedBytecode> cachedBytecode = JSC::CachedBytecode::create(WTFMove(mappedFile));
|
||||
// // auto key = JSC::sourceCodeKeyForSerializedModule(vm, sourceCode);
|
||||
// // if (isCachedBytecodeStillValid(vm, cachedBytecode.copyRef(), key,
|
||||
// // JSC::SourceCodeType::ModuleType)) {
|
||||
// m_cachedBytecode = WTFMove(cachedBytecode);
|
||||
// return 1;
|
||||
// } else {
|
||||
// FileSystem::truncateFile(fd, 0);
|
||||
// return 0;
|
||||
// }
|
||||
}
|
||||
|
||||
extern "C" BunString ZigSourceProvider__getSourceSlice(SourceProvider* provider)
|
||||
{
|
||||
return Bun::toStringView(provider->source());
|
||||
}
|
||||
|
||||
}; // namespace Zig
|
||||
@@ -1,80 +0,0 @@
|
||||
#include "headers.h"
|
||||
#include "root.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace JSC {
|
||||
class Structure;
|
||||
class Identifier;
|
||||
class SourceCodeKey;
|
||||
class SourceProvider;
|
||||
} // namespace JSC
|
||||
|
||||
#include <JavaScriptCore/CachedBytecode.h>
|
||||
#include <JavaScriptCore/JSGlobalObject.h>
|
||||
#include <JavaScriptCore/JSTypeInfo.h>
|
||||
#include <JavaScriptCore/SourceProvider.h>
|
||||
#include <JavaScriptCore/Structure.h>
|
||||
|
||||
namespace Zig {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
void forEachSourceProvider(WTF::Function<void(JSC::SourceID)>);
|
||||
JSC::SourceID sourceIDForSourceURL(const WTF::String& sourceURL);
|
||||
void* sourceMappingForSourceURL(const WTF::String& sourceURL);
|
||||
JSC::SourceOrigin toSourceOrigin(const String& sourceURL, bool isBuiltin);
|
||||
class SourceProvider final : public JSC::SourceProvider {
|
||||
WTF_DEPRECATED_MAKE_FAST_ALLOCATED(SourceProvider);
|
||||
using Base = JSC::SourceProvider;
|
||||
using BytecodeCacheGenerator = JSC::BytecodeCacheGenerator;
|
||||
using UnlinkedFunctionExecutable = JSC::UnlinkedFunctionExecutable;
|
||||
using CachedBytecode = JSC::CachedBytecode;
|
||||
using UnlinkedFunctionCodeBlock = JSC::UnlinkedFunctionCodeBlock;
|
||||
using SourceCode = JSC::SourceCode;
|
||||
using CodeSpecializationKind = JSC::CodeSpecializationKind;
|
||||
using SourceOrigin = JSC::SourceOrigin;
|
||||
|
||||
public:
|
||||
static Ref<SourceProvider> create(
|
||||
Zig::GlobalObject*,
|
||||
ResolvedSource& resolvedSource,
|
||||
JSC::SourceProviderSourceType sourceType = JSC::SourceProviderSourceType::Module,
|
||||
bool isBuiltIn = false);
|
||||
~SourceProvider();
|
||||
unsigned hash() const override;
|
||||
StringView source() const override;
|
||||
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode() const final
|
||||
{
|
||||
return m_cachedBytecode.copyRef();
|
||||
};
|
||||
|
||||
void updateCache(const UnlinkedFunctionExecutable* executable, const SourceCode&, CodeSpecializationKind kind, const UnlinkedFunctionCodeBlock* codeBlock);
|
||||
void cacheBytecode(const BytecodeCacheGenerator& generator);
|
||||
void commitCachedBytecode();
|
||||
bool isBytecodeCacheEnabled() const;
|
||||
void readOrGenerateByteCodeCache(JSC::VM& vm, const JSC::SourceCode& sourceCode);
|
||||
ResolvedSource m_resolvedSource;
|
||||
int readCache(JSC::VM& vm, const JSC::SourceCode& sourceCode);
|
||||
void freeSourceCode();
|
||||
|
||||
private:
|
||||
SourceProvider(Zig::GlobalObject* globalObject, ResolvedSource resolvedSource, Ref<WTF::StringImpl>&& sourceImpl,
|
||||
JSC::SourceTaintedOrigin taintedness,
|
||||
const SourceOrigin& sourceOrigin, WTF::String&& sourceURL,
|
||||
const TextPosition& startPosition, JSC::SourceProviderSourceType sourceType)
|
||||
: Base(sourceOrigin, WTFMove(sourceURL), String(), taintedness, startPosition, sourceType)
|
||||
, m_globalObject(globalObject)
|
||||
, m_source(sourceImpl)
|
||||
{
|
||||
m_resolvedSource = resolvedSource;
|
||||
}
|
||||
|
||||
Zig::GlobalObject* m_globalObject;
|
||||
RefPtr<JSC::CachedBytecode> m_cachedBytecode;
|
||||
Ref<WTF::StringImpl> m_source;
|
||||
unsigned m_hash = 0;
|
||||
};
|
||||
|
||||
} // namespace Zig
|
||||
@@ -129,6 +129,67 @@ typedef struct ErrorableResolvedSource {
|
||||
bool success;
|
||||
} ErrorableResolvedSource;
|
||||
|
||||
// New module result types for Phase 2 refactoring
|
||||
typedef struct TranspiledSourceFlags {
|
||||
bool is_commonjs;
|
||||
bool is_already_bundled;
|
||||
uint32_t _padding : 30;
|
||||
} TranspiledSourceFlags;
|
||||
|
||||
typedef struct TranspiledSource {
|
||||
BunString source_code;
|
||||
BunString source_url;
|
||||
uint8_t* bytecode_cache;
|
||||
size_t bytecode_cache_len;
|
||||
TranspiledSourceFlags flags;
|
||||
} TranspiledSource;
|
||||
|
||||
#ifdef __cplusplus
|
||||
enum class SpecialModuleTag : uint8_t {
|
||||
exports_object = 0,
|
||||
export_default_object = 1,
|
||||
custom_extension = 2,
|
||||
};
|
||||
#else
|
||||
typedef uint8_t SpecialModuleTag;
|
||||
#endif
|
||||
|
||||
typedef struct SpecialModule {
|
||||
SpecialModuleTag tag;
|
||||
JSC::EncodedJSValue jsvalue;
|
||||
} SpecialModule;
|
||||
|
||||
#ifdef __cplusplus
|
||||
enum class ModuleResultTag : uint8_t {
|
||||
transpiled = 0,
|
||||
special = 1,
|
||||
builtin = 2,
|
||||
};
|
||||
#else
|
||||
typedef uint8_t ModuleResultTag;
|
||||
#endif
|
||||
|
||||
typedef union ModuleResultValue {
|
||||
TranspiledSource transpiled;
|
||||
SpecialModule special;
|
||||
uint32_t builtin_id;
|
||||
} ModuleResultValue;
|
||||
|
||||
typedef struct ModuleResult {
|
||||
ModuleResultTag tag;
|
||||
ModuleResultValue value;
|
||||
} ModuleResult;
|
||||
|
||||
typedef union ErrorableModuleResultResult {
|
||||
ModuleResult value;
|
||||
ZigErrorType err;
|
||||
} ErrorableModuleResultResult;
|
||||
|
||||
typedef struct ErrorableModuleResult {
|
||||
ErrorableModuleResultResult result;
|
||||
bool success;
|
||||
} ErrorableModuleResult;
|
||||
|
||||
typedef struct SystemError {
|
||||
int errno_;
|
||||
BunString code;
|
||||
@@ -354,7 +415,7 @@ extern "C" bool Bun__transpileVirtualModule(
|
||||
const BunString* referrer,
|
||||
ZigString* sourceCode,
|
||||
BunLoaderType loader,
|
||||
ErrorableResolvedSource* result);
|
||||
ErrorableModuleResult* result);
|
||||
|
||||
extern "C" JSC::EncodedJSValue Bun__runVirtualModule(
|
||||
JSC::JSGlobalObject* global,
|
||||
@@ -366,7 +427,7 @@ extern "C" JSC::JSInternalPromise* Bun__transpileFile(
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
const BunString* typeAttribute,
|
||||
ErrorableResolvedSource* result,
|
||||
ErrorableModuleResult* result,
|
||||
bool allowPromise,
|
||||
bool isCommonJSRequire,
|
||||
BunLoaderType forceLoaderType);
|
||||
@@ -376,11 +437,11 @@ extern "C" bool Bun__fetchBuiltinModule(
|
||||
JSC::JSGlobalObject* global,
|
||||
const BunString* specifier,
|
||||
const BunString* referrer,
|
||||
ErrorableResolvedSource* result);
|
||||
ErrorableModuleResult* result);
|
||||
extern "C" bool Bun__resolveAndFetchBuiltinModule(
|
||||
void* bunVM,
|
||||
const BunString* specifier,
|
||||
ErrorableResolvedSource* result);
|
||||
ErrorableModuleResult* result);
|
||||
|
||||
// Used in process.version
|
||||
extern "C" const char* Bun__version;
|
||||
|
||||
@@ -90,6 +90,7 @@ pub const RegularExpression = @import("./bindings/RegularExpression.zig").Regula
|
||||
// JavaScript-related
|
||||
pub const Errorable = @import("./bindings/Errorable.zig").Errorable;
|
||||
pub const ResolvedSource = @import("./bindings/ResolvedSource.zig").ResolvedSource;
|
||||
pub const ModuleResult = @import("./bindings/ModuleResult.zig").ModuleResult;
|
||||
pub const ErrorCode = @import("./bindings/ErrorCode.zig").ErrorCode;
|
||||
pub const JSErrorCode = @import("./bindings/JSErrorCode.zig").JSErrorCode;
|
||||
pub const ZigErrorType = @import("./bindings/ZigErrorType.zig").ZigErrorType;
|
||||
@@ -103,6 +104,7 @@ pub const JSRuntimeType = @import("./bindings/JSRuntimeType.zig").JSRuntimeType;
|
||||
pub const ZigStackFrameCode = @import("./bindings/ZigStackFrameCode.zig").ZigStackFrameCode;
|
||||
|
||||
pub const ErrorableResolvedSource = Errorable(ResolvedSource);
|
||||
pub const ErrorableModuleResult = Errorable(ModuleResult);
|
||||
pub const ErrorableZigString = Errorable(ZigString);
|
||||
pub const ErrorableJSValue = Errorable(JSValue);
|
||||
pub const ErrorableString = Errorable(bun.String);
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#endif
|
||||
|
||||
#include "JSDOMConvertBase.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "mimalloc.h"
|
||||
|
||||
#include <JavaScriptCore/ControlFlowProfiler.h>
|
||||
@@ -62,6 +61,22 @@ using namespace JSC;
|
||||
using namespace WTF;
|
||||
using namespace WebCore;
|
||||
|
||||
// Extern declarations for code coverage support functions from Zig
|
||||
extern "C" void* ByteRangeMapping__find(BunString sourceURL);
|
||||
extern "C" JSC::SourceID ByteRangeMapping__getSourceID(void* mappings, BunString sourceURL);
|
||||
|
||||
namespace Zig {
|
||||
// Helper function to find source ID for a given source URL (used for code coverage)
|
||||
inline JSC::SourceID sourceIDForSourceURL(const WTF::String& sourceURL)
|
||||
{
|
||||
void* mappings = ByteRangeMapping__find(Bun::toString(sourceURL));
|
||||
if (!mappings) {
|
||||
return 0;
|
||||
}
|
||||
return ByteRangeMapping__getSourceID(mappings, Bun::toString(sourceURL));
|
||||
}
|
||||
} // namespace Zig
|
||||
|
||||
JSC_DECLARE_HOST_FUNCTION(functionStartRemoteDebugger);
|
||||
JSC_DEFINE_HOST_FUNCTION(functionStartRemoteDebugger,
|
||||
(JSGlobalObject * globalObject,
|
||||
|
||||
Reference in New Issue
Block a user