mirror of
https://github.com/oven-sh/bun
synced 2026-02-08 09:58:55 +00:00
Compare commits
4 Commits
dylan/pyth
...
claude/sou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
825beb24a7 | ||
|
|
41b73f48f2 | ||
|
|
24e3903475 | ||
|
|
cbeda2155e |
File diff suppressed because it is too large
Load Diff
@@ -1446,15 +1446,12 @@ pub fn clearRefString(_: *anyopaque, ref_string: *jsc.RefString) void {
|
||||
_ = VirtualMachine.get().ref_strings.remove(ref_string.hash);
|
||||
}
|
||||
|
||||
pub fn refCountedResolvedSource(this: *VirtualMachine, code: []const u8, specifier: bun.String, source_url: []const u8, hash_: ?u32, comptime add_double_ref: bool) ResolvedSource {
|
||||
pub fn refCountedTranspiledSource(this: *VirtualMachine, code: []const u8, specifier: bun.String, source_url: []const u8, hash_: ?u32, comptime add_double_ref: bool) jsc.TranspiledSource {
|
||||
// refCountedString will panic if the code is empty
|
||||
if (code.len == 0) {
|
||||
return ResolvedSource{
|
||||
return jsc.TranspiledSource{
|
||||
.source_code = bun.String.init(""),
|
||||
.specifier = specifier,
|
||||
.source_url = specifier.createIfDifferent(source_url),
|
||||
.allocator = null,
|
||||
.source_code_needs_deref = false,
|
||||
};
|
||||
}
|
||||
var source = this.refCountedString(code, hash_, !add_double_ref);
|
||||
@@ -1463,12 +1460,9 @@ pub fn refCountedResolvedSource(this: *VirtualMachine, code: []const u8, specifi
|
||||
source.ref();
|
||||
}
|
||||
|
||||
return ResolvedSource{
|
||||
return jsc.TranspiledSource{
|
||||
.source_code = bun.String.init(source.impl),
|
||||
.specifier = specifier,
|
||||
.source_url = specifier.createIfDifferent(source_url),
|
||||
.allocator = source,
|
||||
.source_code_needs_deref = false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1519,7 +1513,7 @@ pub fn fetchWithoutOnLoadPlugins(
|
||||
referrer: String,
|
||||
log: *logger.Log,
|
||||
comptime flags: FetchFlags,
|
||||
) anyerror!ResolvedSource {
|
||||
) anyerror!jsc.ModuleResult {
|
||||
bun.assert(VirtualMachine.isLoaded());
|
||||
|
||||
if (try ModuleLoader.fetchBuiltinModule(jsc_vm, _specifier)) |builtin| {
|
||||
@@ -1545,7 +1539,7 @@ pub fn fetchWithoutOnLoadPlugins(
|
||||
defer if (flags != .print_source) jsc_vm.module_loader.resetArena(jsc_vm);
|
||||
errdefer if (flags == .print_source) jsc_vm.module_loader.resetArena(jsc_vm);
|
||||
|
||||
return try ModuleLoader.transpileSourceCode(
|
||||
return ModuleLoader.transpileSourceCode(
|
||||
jsc_vm,
|
||||
lr.specifier,
|
||||
referrer_clone.slice(),
|
||||
@@ -1863,7 +1857,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: *jsc.ErrorableModuleResult, err: anyerror) void {
|
||||
switch (log.msgs.items.len) {
|
||||
0 => {
|
||||
const msg: logger.Msg = brk: {
|
||||
@@ -1882,14 +1876,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.* = jsc.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.* = jsc.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 +1913,7 @@ pub fn processFetchLog(globalThis: *JSGlobalObject, specifier: bun.String, refer
|
||||
};
|
||||
}
|
||||
|
||||
ret.* = ErrorableResolvedSource.err(
|
||||
ret.* = jsc.ErrorableModuleResult.err(
|
||||
err,
|
||||
globalThis.createAggregateError(
|
||||
errors,
|
||||
@@ -2797,9 +2791,14 @@ 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;
|
||||
const 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);
|
||||
// Extract source code from the module result
|
||||
const source_code = if (module_result.tag == @intFromEnum(jsc.ModuleResult.Tag.transpiled))
|
||||
module_result.result.transpiled.source_code
|
||||
else
|
||||
bun.String.empty;
|
||||
break :code source_code.toUTF8(bun.default_allocator);
|
||||
};
|
||||
|
||||
if (enable_source_code_preview and code.len == 0) {
|
||||
@@ -3729,7 +3728,6 @@ const DNSResolver = bun.api.dns.Resolver;
|
||||
|
||||
const jsc = bun.jsc;
|
||||
const ConsoleObject = jsc.ConsoleObject;
|
||||
const ErrorableResolvedSource = jsc.ErrorableResolvedSource;
|
||||
const ErrorableString = jsc.ErrorableString;
|
||||
const EventLoop = jsc.EventLoop;
|
||||
const Exception = jsc.Exception;
|
||||
@@ -3738,7 +3736,6 @@ const JSInternalPromise = jsc.JSInternalPromise;
|
||||
const JSModuleLoader = jsc.JSModuleLoader;
|
||||
const JSValue = jsc.JSValue;
|
||||
const Node = jsc.Node;
|
||||
const ResolvedSource = jsc.ResolvedSource;
|
||||
const SavedSourceMap = jsc.SavedSourceMap;
|
||||
const VM = jsc.VM;
|
||||
const ZigException = jsc.ZigException;
|
||||
|
||||
140
src/bun.js/bindings/BunSourceProvider.cpp
Normal file
140
src/bun.js/bindings/BunSourceProvider.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "BunSourceProvider.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
#include "JavaScriptCore/SourceOrigin.h"
|
||||
#include "wtf/text/WTFString.h"
|
||||
|
||||
namespace Bun {
|
||||
|
||||
SourceProvider::SourceProvider(
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
const String& source,
|
||||
const JSC::SourceOrigin& sourceOrigin,
|
||||
String&& sourceURL,
|
||||
RefPtr<JSC::CachedBytecode>&& cachedBytecode,
|
||||
const TextPosition& startPosition,
|
||||
JSC::SourceProviderSourceType sourceType)
|
||||
: StringSourceProvider(
|
||||
source,
|
||||
sourceOrigin,
|
||||
JSC::SourceTaintedOrigin::Untainted,
|
||||
WTFMove(sourceURL),
|
||||
startPosition,
|
||||
sourceType)
|
||||
, m_cachedBytecode(WTFMove(cachedBytecode))
|
||||
, m_globalObject(globalObject)
|
||||
, m_hash(0)
|
||||
{
|
||||
// Compute hash for the source
|
||||
m_hash = source.impl()->hash();
|
||||
|
||||
// Register the source map with the Bun VM
|
||||
auto* zigGlobalObject = jsCast<Zig::GlobalObject*>(m_globalObject);
|
||||
auto specifier = Bun::toString(this->sourceURL());
|
||||
Bun__addSourceProviderSourceMap(zigGlobalObject->bunVM(), this, &specifier);
|
||||
}
|
||||
|
||||
SourceProvider::~SourceProvider()
|
||||
{
|
||||
// Cleanup is automatic via RefPtr
|
||||
}
|
||||
|
||||
Ref<SourceProvider> SourceProvider::create(
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
const String& source,
|
||||
const JSC::SourceOrigin& sourceOrigin,
|
||||
String&& sourceURL,
|
||||
RefPtr<JSC::CachedBytecode>&& cachedBytecode,
|
||||
const TextPosition& startPosition,
|
||||
JSC::SourceProviderSourceType sourceType)
|
||||
{
|
||||
return adoptRef(*new SourceProvider(
|
||||
globalObject,
|
||||
source,
|
||||
sourceOrigin,
|
||||
WTFMove(sourceURL),
|
||||
WTFMove(cachedBytecode),
|
||||
startPosition,
|
||||
sourceType));
|
||||
}
|
||||
|
||||
} // namespace Bun
|
||||
|
||||
/**
|
||||
* C bridge function to create a SourceProvider from Zig
|
||||
*
|
||||
* This is the main entry point from Zig code to create a C++ SourceProvider.
|
||||
* It takes ownership of the strings in the TranspiledSource struct.
|
||||
*/
|
||||
extern "C" Bun::SourceProvider* Bun__createSourceProvider(
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
TranspiledSource* transpiled)
|
||||
{
|
||||
// Convert Bun strings to WTF strings
|
||||
WTF::String source = transpiled->source_code.toWTFString(BunString::ZeroCopy);
|
||||
WTF::String sourceURL = transpiled->source_url.toWTFString(BunString::ZeroCopy);
|
||||
|
||||
// Handle bytecode cache if present
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode = nullptr;
|
||||
if (transpiled->bytecode_cache != nullptr && transpiled->bytecode_cache_len > 0) {
|
||||
// For now, skip bytecode cache - it requires FileSystem::MappedFileData
|
||||
// TODO: Implement bytecode caching properly
|
||||
cachedBytecode = nullptr;
|
||||
}
|
||||
|
||||
// Create the source origin from the source URL
|
||||
JSC::SourceOrigin sourceOrigin(WTF::URL(WTF::URL(), sourceURL));
|
||||
|
||||
// Determine source type based on flags
|
||||
JSC::SourceProviderSourceType sourceType = transpiled->flags.is_commonjs
|
||||
? JSC::SourceProviderSourceType::Program
|
||||
: JSC::SourceProviderSourceType::Module;
|
||||
|
||||
// Create the SourceProvider
|
||||
auto provider = Bun::SourceProvider::create(
|
||||
globalObject,
|
||||
source,
|
||||
sourceOrigin,
|
||||
WTFMove(sourceURL),
|
||||
WTFMove(cachedBytecode),
|
||||
TextPosition(),
|
||||
sourceType);
|
||||
|
||||
// Leak the ref for C ownership (caller must manage)
|
||||
return &provider.leakRef();
|
||||
}
|
||||
|
||||
// TODO: Bytecode caching stubs - need to reimplement with new SourceProvider
|
||||
extern "C" bool generateCachedModuleByteCodeFromSourceCode(
|
||||
BunString* sourceProviderURL,
|
||||
const uint8_t* input_code,
|
||||
size_t inputSourceCodeSize,
|
||||
uint8_t** outputByteCode,
|
||||
size_t* outputByteCodeSize,
|
||||
void** cached_bytecode)
|
||||
{
|
||||
// Temporarily disabled - TODO: implement bytecode caching
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" bool generateCachedCommonJSProgramByteCodeFromSourceCode(
|
||||
BunString* sourceProviderURL,
|
||||
const uint8_t* input_code,
|
||||
size_t inputSourceCodeSize,
|
||||
uint8_t** outputByteCode,
|
||||
size_t* outputByteCodeSize,
|
||||
void** cached_bytecode)
|
||||
{
|
||||
// Temporarily disabled - TODO: implement bytecode caching
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" void CachedBytecode__deref(void* cached_bytecode)
|
||||
{
|
||||
// Temporarily disabled - TODO: implement bytecode caching
|
||||
}
|
||||
|
||||
extern "C" void ZigSourceProvider__getSourceSlice(void* sourceProvider, BunString* out)
|
||||
{
|
||||
// Temporarily disabled - TODO: implement if needed
|
||||
*out = Bun::toString(WTF::String());
|
||||
}
|
||||
105
src/bun.js/bindings/BunSourceProvider.h
Normal file
105
src/bun.js/bindings/BunSourceProvider.h
Normal file
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include "root.h"
|
||||
#include "headers-handwritten.h"
|
||||
#include "JavaScriptCore/SourceProvider.h"
|
||||
#include "JavaScriptCore/SourceOrigin.h"
|
||||
#include "JavaScriptCore/CachedBytecode.h"
|
||||
#include "wtf/RefPtr.h"
|
||||
|
||||
namespace Bun {
|
||||
|
||||
class SourceProvider;
|
||||
|
||||
/// Registers a source map with the Bun VM for debugging/stack traces
|
||||
extern "C" void Bun__addSourceProviderSourceMap(
|
||||
void* bun_vm,
|
||||
SourceProvider* opaque_source_provider,
|
||||
BunString* specifier);
|
||||
|
||||
/**
|
||||
* BunSourceProvider - JSC SourceProvider implementation for Bun modules
|
||||
*
|
||||
* This is a lightweight SourceProvider that holds transpiled JavaScript source code
|
||||
* without needing the full ResolvedSource struct. It owns:
|
||||
* - The source code string
|
||||
* - Optional bytecode cache
|
||||
* - A reference to the global object for sourcemap registration
|
||||
* - The computed hash
|
||||
*
|
||||
* Notably, it does NOT store the full ResolvedSource, which is the key difference
|
||||
* from the old implementation. This reduces memory usage and simplifies ownership.
|
||||
*/
|
||||
class SourceProvider final : public JSC::StringSourceProvider {
|
||||
public:
|
||||
/**
|
||||
* Create a new BunSourceProvider from transpiled source
|
||||
*
|
||||
* @param globalObject The JSGlobalObject for sourcemap registration
|
||||
* @param source The transpiled JavaScript source code
|
||||
* @param sourceOrigin The origin of the source (URL, etc.)
|
||||
* @param sourceURL The source URL for debugging
|
||||
* @param cachedBytecode Optional cached bytecode
|
||||
* @param startPosition Starting position in source
|
||||
* @param sourceType Type of source (module, script, etc.)
|
||||
* @return A new ref-counted SourceProvider
|
||||
*/
|
||||
static Ref<SourceProvider> create(
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
const String& source,
|
||||
const JSC::SourceOrigin& sourceOrigin,
|
||||
String&& sourceURL,
|
||||
RefPtr<JSC::CachedBytecode>&& cachedBytecode,
|
||||
const TextPosition& startPosition = TextPosition(),
|
||||
JSC::SourceProviderSourceType sourceType = JSC::SourceProviderSourceType::Module);
|
||||
|
||||
/// Get the cached bytecode if available
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode() const { return m_cachedBytecode; }
|
||||
|
||||
/// Destructor
|
||||
virtual ~SourceProvider();
|
||||
|
||||
private:
|
||||
/// Private constructor - use create() instead
|
||||
SourceProvider(
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
const String& source,
|
||||
const JSC::SourceOrigin& sourceOrigin,
|
||||
String&& sourceURL,
|
||||
RefPtr<JSC::CachedBytecode>&& cachedBytecode,
|
||||
const TextPosition& startPosition,
|
||||
JSC::SourceProviderSourceType sourceType);
|
||||
|
||||
/// The source code string (owned by base class)
|
||||
// Inherited: String m_source;
|
||||
|
||||
/// Optional cached bytecode
|
||||
RefPtr<JSC::CachedBytecode> m_cachedBytecode;
|
||||
|
||||
/// Reference to global object (for sourcemap registration)
|
||||
JSC::JSGlobalObject* m_globalObject;
|
||||
|
||||
/// Precomputed hash for the source
|
||||
unsigned m_hash;
|
||||
};
|
||||
|
||||
} // namespace Bun
|
||||
|
||||
namespace Zig {
|
||||
// Helper function to get source ID from URL (for debugging/coverage)
|
||||
std::optional<JSC::SourceID> sourceIDForSourceURL(const WTF::String& sourceURL);
|
||||
}
|
||||
|
||||
/**
|
||||
* C bridge function to create a SourceProvider from Zig
|
||||
*
|
||||
* Takes a TranspiledSource struct from Zig and creates a C++ SourceProvider.
|
||||
* The ownership of strings and bytecode transfers from Zig to C++.
|
||||
*
|
||||
* @param globalObject The global object
|
||||
* @param transpiled The transpiled source from Zig
|
||||
* @return A leaked ref to the SourceProvider (caller takes ownership)
|
||||
*/
|
||||
extern "C" Bun::SourceProvider* Bun__createSourceProvider(
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
TranspiledSource* transpiled);
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "root.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "BunSourceProvider.h"
|
||||
#include <JavaScriptCore/ControlFlowProfiler.h>
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
@@ -2,6 +2,7 @@ pub fn Errorable(comptime Type: type) type {
|
||||
return extern struct {
|
||||
result: Result,
|
||||
success: bool,
|
||||
_padding: [7]u8 = undefined, // Explicit padding to match C alignment
|
||||
|
||||
pub const Result = extern union {
|
||||
value: Type,
|
||||
|
||||
@@ -260,9 +260,8 @@ JSC::EncodedJSValue builtinLoader(JSC::JSGlobalObject* globalObject, JSC::CallFr
|
||||
BunString specifierBunString = Bun::toString(specifierWtfString);
|
||||
BunString empty = BunStringEmpty;
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
ErrorableResolvedSource res;
|
||||
res.success = false;
|
||||
memset(&res.result, 0, sizeof res.result);
|
||||
ModuleResult res;
|
||||
memset(&res, 0, sizeof res);
|
||||
|
||||
JSValue result = fetchCommonJSModuleNonBuiltin<true>(
|
||||
global->bunVM(),
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
#include <JavaScriptCore/JSMapInlines.h>
|
||||
#include <JavaScriptCore/GetterSetter.h>
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "BunSourceProvider.h"
|
||||
#include <JavaScriptCore/FunctionPrototype.h>
|
||||
#include "JSCommonJSModule.h"
|
||||
#include <JavaScriptCore/JSModuleNamespaceObject.h>
|
||||
@@ -1311,14 +1311,13 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireNativeModule, (JSGlobalObject * lexica
|
||||
JSValue specifierValue = callframe->argument(0);
|
||||
WTF::String specifier = specifierValue.toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
ErrorableResolvedSource res;
|
||||
res.success = false;
|
||||
memset(&res.result, 0, sizeof res.result);
|
||||
ModuleResult res;
|
||||
memset(&res, 0, sizeof res);
|
||||
BunString specifierStr = Bun::toString(specifier);
|
||||
auto result = fetchBuiltinModuleWithoutResolution(globalObject, &specifierStr, &res);
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
if (result) {
|
||||
if (res.success)
|
||||
if (res.tag != ModuleResultTag_err)
|
||||
return JSC::JSValue::encode(result);
|
||||
}
|
||||
throwScope.assertNoExceptionExceptTermination();
|
||||
@@ -1337,35 +1336,17 @@ void RequireResolveFunctionPrototype::finishCreation(JSC::VM& vm)
|
||||
void JSCommonJSModule::evaluate(
|
||||
Zig::GlobalObject* globalObject,
|
||||
const WTF::String& key,
|
||||
ResolvedSource& source,
|
||||
bool isBuiltIn)
|
||||
JSC::SourceProvider* provider,
|
||||
bool isBuiltIn,
|
||||
bool fromPackageJSONTypeModule)
|
||||
{
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
|
||||
if (globalObject->hasOverriddenModuleWrapper) [[unlikely]] {
|
||||
auto string = source.source_code.toWTFString(BunString::ZeroCopy);
|
||||
auto trimStart = string.find('\n');
|
||||
if (trimStart != WTF::notFound) {
|
||||
if (source.needsDeref && !isBuiltIn) {
|
||||
source.needsDeref = false;
|
||||
source.source_code.deref();
|
||||
}
|
||||
auto wrapperStart = globalObject->m_moduleWrapperStart;
|
||||
auto wrapperEnd = globalObject->m_moduleWrapperEnd;
|
||||
source.source_code = Bun::toStringRef(makeString(
|
||||
wrapperStart,
|
||||
string.substring(trimStart, string.length() - trimStart - 4),
|
||||
wrapperEnd));
|
||||
source.needsDeref = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program, isBuiltIn);
|
||||
this->ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
|
||||
this->ignoreESModuleAnnotation = fromPackageJSONTypeModule;
|
||||
if (this->hasEvaluated)
|
||||
return;
|
||||
|
||||
this->sourceCode = JSC::SourceCode(WTFMove(sourceProvider));
|
||||
this->sourceCode = JSC::SourceCode(Ref<JSC::SourceProvider>(*provider));
|
||||
|
||||
evaluateCommonJSModuleOnce(vm, globalObject, this, this->m_dirname.get(), this->m_filename.get());
|
||||
}
|
||||
@@ -1374,7 +1355,8 @@ void JSCommonJSModule::evaluateWithPotentiallyOverriddenCompile(
|
||||
Zig::GlobalObject* globalObject,
|
||||
const WTF::String& key,
|
||||
JSValue keyJSString,
|
||||
ResolvedSource& source)
|
||||
JSC::SourceProvider* provider,
|
||||
bool fromPackageJSONTypeModule)
|
||||
{
|
||||
if (JSValue compileFunction = this->m_overriddenCompile.get()) {
|
||||
auto& vm = globalObject->vm();
|
||||
@@ -1388,12 +1370,9 @@ void JSCommonJSModule::evaluateWithPotentiallyOverriddenCompile(
|
||||
throwTypeError(globalObject, scope, "overridden module._compile is not a function (called from overridden Module._extensions)"_s);
|
||||
return;
|
||||
}
|
||||
WTF::String sourceString = source.source_code.toWTFString(BunString::ZeroCopy);
|
||||
// Get source from provider
|
||||
WTF::String sourceString = provider->source().toString();
|
||||
RETURN_IF_EXCEPTION(scope, );
|
||||
if (source.needsDeref) {
|
||||
source.needsDeref = false;
|
||||
source.source_code.deref();
|
||||
}
|
||||
// Remove the wrapper from the source string, since the transpiler has added it.
|
||||
auto trimStart = sourceString.find('\n');
|
||||
WTF::String sourceStringWithoutWrapper;
|
||||
@@ -1414,24 +1393,24 @@ void JSCommonJSModule::evaluateWithPotentiallyOverriddenCompile(
|
||||
RETURN_IF_EXCEPTION(scope, );
|
||||
return;
|
||||
}
|
||||
this->evaluate(globalObject, key, source, false);
|
||||
this->evaluate(globalObject, key, provider, false, fromPackageJSONTypeModule);
|
||||
}
|
||||
|
||||
std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSString* requireMapKey,
|
||||
ResolvedSource& source,
|
||||
bool isBuiltIn)
|
||||
JSC::SourceProvider* provider,
|
||||
bool isBuiltIn,
|
||||
bool fromPackageJSONTypeModule)
|
||||
{
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
JSCommonJSModule* moduleObject = nullptr;
|
||||
WTF::String sourceURL = source.source_url.toWTFString();
|
||||
WTF::String sourceURL = provider->sourceOrigin().url().string();
|
||||
|
||||
JSValue entry = globalObject->requireMap()->get(globalObject, requireMapKey);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
bool ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
|
||||
SourceOrigin sourceOrigin;
|
||||
SourceOrigin sourceOrigin = provider->sourceOrigin();
|
||||
|
||||
if (entry) {
|
||||
moduleObject = jsDynamicCast<JSCommonJSModule*>(entry);
|
||||
@@ -1452,21 +1431,10 @@ std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
requireMapKey = JSC::jsString(vm, WTF::String("."_s));
|
||||
}
|
||||
|
||||
if (globalObject->hasOverriddenModuleWrapper) [[unlikely]] {
|
||||
auto concat = makeString(
|
||||
globalObject->m_moduleWrapperStart,
|
||||
source.source_code.toWTFString(BunString::ZeroCopy),
|
||||
globalObject->m_moduleWrapperEnd);
|
||||
source.source_code.deref();
|
||||
source.source_code = Bun::toStringRef(concat);
|
||||
}
|
||||
|
||||
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program, isBuiltIn);
|
||||
sourceOrigin = sourceProvider->sourceOrigin();
|
||||
moduleObject = JSCommonJSModule::create(
|
||||
vm,
|
||||
globalObject->CommonJSModuleObjectStructure(),
|
||||
requireMapKey, filename, dirname, WTFMove(JSC::SourceCode(WTFMove(sourceProvider))));
|
||||
requireMapKey, filename, dirname, JSC::SourceCode(Ref<JSC::SourceProvider>(*provider)));
|
||||
|
||||
moduleObject->putDirect(vm,
|
||||
WebCore::clientData(vm)->builtinNames().exportsPublicName(),
|
||||
@@ -1474,11 +1442,9 @@ std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
|
||||
requireMap->set(globalObject, filename, moduleObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
} else {
|
||||
sourceOrigin = Zig::toSourceOrigin(sourceURL, isBuiltIn);
|
||||
}
|
||||
|
||||
moduleObject->ignoreESModuleAnnotation = ignoreESModuleAnnotation;
|
||||
moduleObject->ignoreESModuleAnnotation = fromPackageJSONTypeModule;
|
||||
|
||||
return JSC::SourceCode(
|
||||
JSC::SyntheticSourceProvider::create(
|
||||
|
||||
@@ -87,11 +87,11 @@ public:
|
||||
|
||||
static JSC::Structure* createStructure(JSC::JSGlobalObject* globalObject);
|
||||
|
||||
void evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, ResolvedSource& resolvedSource, bool isBuiltIn);
|
||||
void evaluateWithPotentiallyOverriddenCompile(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, JSValue keyJSString, ResolvedSource& resolvedSource);
|
||||
inline void evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, ResolvedSource& resolvedSource)
|
||||
void evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, JSC::SourceProvider* provider, bool isBuiltIn, bool fromPackageJSONTypeModule);
|
||||
void evaluateWithPotentiallyOverriddenCompile(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, JSValue keyJSString, JSC::SourceProvider* provider, bool fromPackageJSONTypeModule);
|
||||
inline void evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, JSC::SourceProvider* provider, bool fromPackageJSONTypeModule)
|
||||
{
|
||||
return evaluate(globalObject, sourceURL, resolvedSource, false);
|
||||
return evaluate(globalObject, sourceURL, provider, false, fromPackageJSONTypeModule);
|
||||
}
|
||||
|
||||
static JSCommonJSModule* create(JSC::VM& vm, JSC::Structure* structure,
|
||||
@@ -112,7 +112,8 @@ public:
|
||||
static JSCommonJSModule* create(
|
||||
Zig::GlobalObject* globalObject,
|
||||
const WTF::String& key,
|
||||
ResolvedSource resolvedSource);
|
||||
JSC::SourceProvider* provider,
|
||||
bool fromPackageJSONTypeModule);
|
||||
|
||||
static JSObject* createBoundRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString);
|
||||
|
||||
@@ -166,15 +167,17 @@ JSC::Structure* createCommonJSModuleStructure(
|
||||
std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSString* specifierValue,
|
||||
ResolvedSource& source,
|
||||
bool isBuiltIn);
|
||||
JSC::SourceProvider* provider,
|
||||
bool isBuiltIn,
|
||||
bool fromPackageJSONTypeModule);
|
||||
|
||||
inline std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSString* specifierValue,
|
||||
ResolvedSource& source)
|
||||
JSC::SourceProvider* provider,
|
||||
bool fromPackageJSONTypeModule)
|
||||
{
|
||||
return createCommonJSModule(globalObject, specifierValue, source, false);
|
||||
return createCommonJSModule(globalObject, specifierValue, provider, false, fromPackageJSONTypeModule);
|
||||
}
|
||||
|
||||
class RequireResolveFunctionPrototype final : public JSC::JSNonFinalObject {
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
#include <JavaScriptCore/JSInternalPromise.h>
|
||||
#include <JavaScriptCore/JSInternalFieldObjectImpl.h>
|
||||
|
||||
#include "ZigSourceProvider.h"
|
||||
// ZigSourceProvider.h removed - now using BunSourceProvider.h
|
||||
#include "BunSourceProvider.h"
|
||||
|
||||
#include <JavaScriptCore/JSSourceCode.h>
|
||||
#include <JavaScriptCore/JSString.h>
|
||||
@@ -41,29 +42,32 @@
|
||||
|
||||
#include "BunProcess.h"
|
||||
|
||||
namespace Zig {
|
||||
|
||||
static inline JSC::SourceOrigin toSourceOrigin(const WTF::String& sourceURL, bool isBuiltIn)
|
||||
{
|
||||
if (isBuiltIn) {
|
||||
return JSC::SourceOrigin(URL(WTF::makeString("builtin://"_s, sourceURL)));
|
||||
}
|
||||
return JSC::SourceOrigin(URL(WTF::URL({ }, sourceURL)));
|
||||
}
|
||||
|
||||
// Helper function to get source ID from URL
|
||||
// Returns nullopt if not found
|
||||
std::optional<JSC::SourceID> sourceIDForSourceURL(const WTF::String& sourceURL)
|
||||
{
|
||||
// TODO: Implement proper source ID lookup if needed
|
||||
// For now, return nullopt to indicate source not found
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Zig
|
||||
|
||||
namespace Bun {
|
||||
using namespace JSC;
|
||||
using namespace Zig;
|
||||
using namespace WebCore;
|
||||
|
||||
class ResolvedSourceCodeHolder {
|
||||
public:
|
||||
ResolvedSourceCodeHolder(ErrorableResolvedSource* res_)
|
||||
: res(res_)
|
||||
{
|
||||
}
|
||||
|
||||
~ResolvedSourceCodeHolder()
|
||||
{
|
||||
if (res->success && res->result.value.source_code.tag == BunStringTag::WTFStringImpl && res->result.value.needsDeref) {
|
||||
res->result.value.needsDeref = false;
|
||||
res->result.value.source_code.impl.wtf->deref();
|
||||
}
|
||||
}
|
||||
|
||||
ErrorableResolvedSource* res;
|
||||
};
|
||||
|
||||
extern "C" BunLoaderType Bun__getDefaultLoader(JSC::JSGlobalObject*, BunString* specifier);
|
||||
|
||||
static JSC::JSInternalPromise* rejectedInternalPromise(JSC::JSGlobalObject* globalObject, JSC::JSValue value)
|
||||
@@ -331,7 +335,7 @@ template<bool allowPromise>
|
||||
static JSValue handleVirtualModuleResult(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSValue virtualModuleResult,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
bool wasModuleMock = false,
|
||||
@@ -341,7 +345,6 @@ static JSValue handleVirtualModuleResult(
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
auto onLoadResult = handleOnLoadResult(globalObject, virtualModuleResult, specifier, wasModuleMock);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
ResolvedSourceCodeHolder sourceCodeHolder(res);
|
||||
|
||||
const auto reject = [&](JSC::JSValue exception) -> JSValue {
|
||||
if constexpr (allowPromise) {
|
||||
@@ -353,7 +356,6 @@ static JSValue handleVirtualModuleResult(
|
||||
};
|
||||
|
||||
const auto resolve = [&](JSValue code) -> JSValue {
|
||||
res->success = true;
|
||||
if constexpr (allowPromise) {
|
||||
scope.release();
|
||||
return resolvedInternalPromise(globalObject, code);
|
||||
@@ -372,8 +374,6 @@ static JSValue handleVirtualModuleResult(
|
||||
}
|
||||
}
|
||||
|
||||
res->success = true;
|
||||
|
||||
if constexpr (allowPromise) {
|
||||
scope.release();
|
||||
return resolvedInternalPromise(globalObject, code);
|
||||
@@ -384,13 +384,13 @@ static JSValue handleVirtualModuleResult(
|
||||
|
||||
switch (onLoadResult.type) {
|
||||
case OnLoadResultTypeCode: {
|
||||
Bun__transpileVirtualModule(globalObject, specifier, referrer, &onLoadResult.value.sourceText.string, onLoadResult.value.sourceText.loader, res);
|
||||
if (!res->success) {
|
||||
RELEASE_AND_RETURN(scope, reject(JSValue::decode(res->result.err.value)));
|
||||
bool success = Bun__transpileVirtualModule(globalObject, specifier, referrer, &onLoadResult.value.sourceText.string, onLoadResult.value.sourceText.loader, res);
|
||||
if (!success || res->tag == ModuleResultTag_err) {
|
||||
RELEASE_AND_RETURN(scope, reject(JSValue::decode(res->result.err.exception)));
|
||||
}
|
||||
|
||||
auto provider = Zig::SourceProvider::create(globalObject, res->result.value);
|
||||
return resolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
|
||||
auto* provider = Bun__createSourceProvider(globalObject, &res->result.transpiled);
|
||||
return resolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(adoptRef(*provider))));
|
||||
}
|
||||
case OnLoadResultTypeError: {
|
||||
RELEASE_AND_RETURN(scope, reject(onLoadResult.value.error));
|
||||
@@ -457,17 +457,16 @@ static JSValue handleVirtualModuleResult(
|
||||
extern "C" void Bun__onFulfillAsyncModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::EncodedJSValue encodedPromiseValue,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* result,
|
||||
BunString* specifier,
|
||||
BunString* referrer)
|
||||
{
|
||||
ResolvedSourceCodeHolder sourceCodeHolder(res);
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
JSC::JSInternalPromise* promise = jsCast<JSC::JSInternalPromise*>(JSC::JSValue::decode(encodedPromiseValue));
|
||||
|
||||
if (!res->success) {
|
||||
RELEASE_AND_RETURN(scope, promise->reject(globalObject, JSValue::decode(res->result.err.value)));
|
||||
if (result->tag == ModuleResultTag_err) {
|
||||
RELEASE_AND_RETURN(scope, promise->reject(globalObject, JSValue::decode(result->result.err.exception)));
|
||||
}
|
||||
|
||||
auto specifierValue = Bun::toJS(globalObject, *specifier);
|
||||
@@ -492,25 +491,43 @@ extern "C" void Bun__onFulfillAsyncModule(
|
||||
}
|
||||
}
|
||||
|
||||
if (res->result.value.isCommonJSModule) {
|
||||
auto created = Bun::createCommonJSModule(jsCast<Zig::GlobalObject*>(globalObject), specifierValue, res->result.value);
|
||||
EXCEPTION_ASSERT(created.has_value() == !scope.exception());
|
||||
if (created.has_value()) {
|
||||
JSSourceCode* code = JSSourceCode::create(vm, WTFMove(created.value()));
|
||||
promise->resolve(globalObject, code);
|
||||
scope.assertNoExceptionExceptTermination();
|
||||
} else {
|
||||
auto* exception = scope.exception();
|
||||
if (!vm.isTerminationException(exception)) {
|
||||
scope.clearException();
|
||||
promise->reject(globalObject, exception);
|
||||
switch (result->tag) {
|
||||
case ModuleResultTag_transpiled: {
|
||||
auto& transpiled = result->result.transpiled;
|
||||
bool isCommonJS = transpiled.flags.is_commonjs;
|
||||
bool fromPackageJSONTypeModule = transpiled.flags.from_package_json_type_module;
|
||||
|
||||
auto* provider = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
|
||||
if (isCommonJS) {
|
||||
auto created = Bun::createCommonJSModule(jsCast<Zig::GlobalObject*>(globalObject), specifierValue, provider, fromPackageJSONTypeModule);
|
||||
EXCEPTION_ASSERT(created.has_value() == !scope.exception());
|
||||
if (created.has_value()) {
|
||||
JSSourceCode* code = JSSourceCode::create(vm, WTFMove(created.value()));
|
||||
promise->resolve(globalObject, code);
|
||||
scope.assertNoExceptionExceptTermination();
|
||||
} else {
|
||||
auto* exception = scope.exception();
|
||||
if (!vm.isTerminationException(exception)) {
|
||||
scope.clearException();
|
||||
promise->reject(globalObject, exception);
|
||||
scope.assertNoExceptionExceptTermination();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
promise->resolve(globalObject, JSC::JSSourceCode::create(vm, JSC::SourceCode(adoptRef(*provider))));
|
||||
scope.assertNoExceptionExceptTermination();
|
||||
}
|
||||
} else {
|
||||
auto&& provider = Zig::SourceProvider::create(jsDynamicCast<Zig::GlobalObject*>(globalObject), res->result.value);
|
||||
promise->resolve(globalObject, JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
|
||||
scope.assertNoExceptionExceptTermination();
|
||||
break;
|
||||
}
|
||||
case ModuleResultTag_special:
|
||||
case ModuleResultTag_builtin:
|
||||
// These shouldn't happen in async module loading
|
||||
ASSERT_NOT_REACHED();
|
||||
break;
|
||||
case ModuleResultTag_err:
|
||||
// Already handled above
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// the module has since been deleted from the registry.
|
||||
@@ -521,47 +538,28 @@ extern "C" void Bun__onFulfillAsyncModule(
|
||||
JSValue fetchBuiltinModuleWithoutResolution(
|
||||
Zig::GlobalObject* globalObject,
|
||||
BunString* specifier,
|
||||
ErrorableResolvedSource* res)
|
||||
ModuleResult* res)
|
||||
{
|
||||
void* bunVM = globalObject->bunVM();
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
BunString referrer = BunStringEmpty;
|
||||
if (Bun__fetchBuiltinModule(bunVM, globalObject, specifier, &referrer, res)) {
|
||||
if (!res->success) {
|
||||
return {};
|
||||
switch (res->tag) {
|
||||
case ModuleResultTag_special: {
|
||||
// Special modules that are JSValues (bun, process, etc)
|
||||
return JSValue::decode(res->result.special.jsvalue);
|
||||
}
|
||||
|
||||
auto tag = res->result.value.tag;
|
||||
switch (tag) {
|
||||
// require("bun")
|
||||
case SyntheticModuleType::BunObject: {
|
||||
return globalObject->bunObject();
|
||||
}
|
||||
// require("module"), require("node:module")
|
||||
case SyntheticModuleType::NodeModule: {
|
||||
return globalObject->m_nodeModuleConstructor.getInitializedOnMainThread(globalObject);
|
||||
}
|
||||
// require("process"), require("node:process")
|
||||
case SyntheticModuleType::NodeProcess: {
|
||||
return globalObject->processObject();
|
||||
}
|
||||
|
||||
case SyntheticModuleType::ESM: {
|
||||
res->success = false;
|
||||
case ModuleResultTag_builtin: {
|
||||
// Builtin ES modules - return sentinel to indicate ESM
|
||||
RELEASE_AND_RETURN(scope, jsNumber(-1));
|
||||
}
|
||||
|
||||
default: {
|
||||
if (tag & SyntheticModuleType::InternalModuleRegistryFlag) {
|
||||
constexpr auto mask = (SyntheticModuleType::InternalModuleRegistryFlag - 1);
|
||||
auto result = globalObject->internalModuleRegistry()->requireId(globalObject, vm, static_cast<InternalModuleRegistry::Field>(tag & mask));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return result;
|
||||
} else {
|
||||
res->success = false;
|
||||
RELEASE_AND_RETURN(scope, jsNumber(-1));
|
||||
}
|
||||
case ModuleResultTag_transpiled: {
|
||||
// Shouldn't happen for builtins typically, but return empty
|
||||
return {};
|
||||
}
|
||||
case ModuleResultTag_err: {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,39 +573,23 @@ JSValue resolveAndFetchBuiltinModule(
|
||||
void* bunVM = globalObject->bunVM();
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
ErrorableResolvedSource res;
|
||||
res.success = false;
|
||||
memset(&res.result, 0, sizeof res.result);
|
||||
ModuleResult res;
|
||||
memset(&res, 0, sizeof res);
|
||||
if (Bun__resolveAndFetchBuiltinModule(bunVM, specifier, &res)) {
|
||||
ASSERT(res.success);
|
||||
|
||||
auto tag = res.result.value.tag;
|
||||
switch (tag) {
|
||||
// require("bun")
|
||||
case SyntheticModuleType::BunObject: {
|
||||
return globalObject->bunObject();
|
||||
switch (res.tag) {
|
||||
case ModuleResultTag_special: {
|
||||
// Special modules that are JSValues (bun, process, etc)
|
||||
return JSValue::decode(res.result.special.jsvalue);
|
||||
}
|
||||
// require("module"), require("node:module")
|
||||
case SyntheticModuleType::NodeModule: {
|
||||
return globalObject->m_nodeModuleConstructor.getInitializedOnMainThread(globalObject);
|
||||
}
|
||||
// require("process"), require("node:process")
|
||||
case SyntheticModuleType::NodeProcess: {
|
||||
return globalObject->processObject();
|
||||
}
|
||||
|
||||
case SyntheticModuleType::ESM: {
|
||||
case ModuleResultTag_builtin: {
|
||||
// Builtin ES modules
|
||||
return {};
|
||||
}
|
||||
|
||||
default: {
|
||||
if (tag & SyntheticModuleType::InternalModuleRegistryFlag) {
|
||||
constexpr auto mask = (SyntheticModuleType::InternalModuleRegistryFlag - 1);
|
||||
auto result = globalObject->internalModuleRegistry()->requireId(globalObject, vm, static_cast<InternalModuleRegistry::Field>(tag & mask));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return result;
|
||||
}
|
||||
|
||||
case ModuleResultTag_transpiled: {
|
||||
// Shouldn't happen typically
|
||||
return {};
|
||||
}
|
||||
case ModuleResultTag_err: {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -651,12 +633,10 @@ JSValue fetchCommonJSModule(
|
||||
void* bunVM = globalObject->bunVM();
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
ErrorableResolvedSource resValue;
|
||||
resValue.success = false;
|
||||
memset(&resValue.result, 0, sizeof resValue.result);
|
||||
ModuleResult resValue;
|
||||
memset(&resValue, 0, sizeof resValue);
|
||||
|
||||
ErrorableResolvedSource* res = &resValue;
|
||||
ResolvedSourceCodeHolder sourceCodeHolder(res);
|
||||
ModuleResult* res = &resValue;
|
||||
|
||||
BunString specifier = Bun::toString(specifierWtfString);
|
||||
|
||||
@@ -688,8 +668,8 @@ JSValue fetchCommonJSModule(
|
||||
RELEASE_AND_RETURN(scope, JSValue {});
|
||||
}
|
||||
case JSPromise::Status::Fulfilled: {
|
||||
if (!res->success) {
|
||||
throwException(scope, res->result.err, globalObject);
|
||||
if (res->tag == ModuleResultTag_err) {
|
||||
throwException(globalObject, scope, JSValue::decode(res->result.err.exception));
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
if (!wasModuleMock) {
|
||||
@@ -706,7 +686,7 @@ JSValue fetchCommonJSModule(
|
||||
auto builtin = fetchBuiltinModuleWithoutResolution(globalObject, &specifier, res);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
if (builtin) {
|
||||
if (!res->success) {
|
||||
if (res->tag == ModuleResultTag_err) {
|
||||
RELEASE_AND_RETURN(scope, builtin);
|
||||
}
|
||||
target->setExportsObject(builtin);
|
||||
@@ -739,8 +719,8 @@ JSValue fetchCommonJSModule(
|
||||
RELEASE_AND_RETURN(scope, JSValue {});
|
||||
}
|
||||
case JSPromise::Status::Fulfilled: {
|
||||
if (!res->success) {
|
||||
throwException(scope, res->result.err, globalObject);
|
||||
if (res->tag == ModuleResultTag_err) {
|
||||
throwException(globalObject, scope, JSValue::decode(res->result.err.exception));
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
if (!wasModuleMock) {
|
||||
@@ -787,75 +767,80 @@ JSValue fetchCommonJSModuleNonBuiltin(
|
||||
JSC::JSValue specifierValue,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
JSCommonJSModule* target,
|
||||
String specifierWtfString,
|
||||
BunLoaderType forceLoaderType,
|
||||
JSC::ThrowScope& scope)
|
||||
{
|
||||
Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, false, !isExtension, forceLoaderType);
|
||||
if (res->success && res->result.value.isCommonJSModule) {
|
||||
if constexpr (isExtension) {
|
||||
target->evaluateWithPotentiallyOverriddenCompile(globalObject, specifierWtfString, specifierValue, res->result.value);
|
||||
} else {
|
||||
target->evaluate(globalObject, specifierWtfString, res->result.value);
|
||||
|
||||
switch (res->tag) {
|
||||
case ModuleResultTag_transpiled: {
|
||||
auto& transpiled = res->result.transpiled;
|
||||
bool isCommonJS = transpiled.flags.is_commonjs;
|
||||
bool fromPackageJSONTypeModule = transpiled.flags.from_package_json_type_module;
|
||||
|
||||
if (isCommonJS) {
|
||||
auto* provider = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
if constexpr (isExtension) {
|
||||
target->evaluateWithPotentiallyOverriddenCompile(globalObject, specifierWtfString, specifierValue, provider, fromPackageJSONTypeModule);
|
||||
} else {
|
||||
target->evaluate(globalObject, specifierWtfString, provider, fromPackageJSONTypeModule);
|
||||
}
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
RELEASE_AND_RETURN(scope, target);
|
||||
}
|
||||
|
||||
// ESM module
|
||||
auto* provider = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
globalObject->moduleLoader()->provideFetch(globalObject, specifierValue, JSC::SourceCode(adoptRef(*provider)));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
RELEASE_AND_RETURN(scope, target);
|
||||
RELEASE_AND_RETURN(scope, jsNumber(-1));
|
||||
}
|
||||
|
||||
if (!res->success) {
|
||||
throwException(scope, res->result.err, globalObject);
|
||||
case ModuleResultTag_special: {
|
||||
auto& special = res->result.special;
|
||||
JSC::JSValue value = JSC::JSValue::decode(special.jsvalue);
|
||||
|
||||
switch (special.tag) {
|
||||
case SpecialModuleTag_exports_object:
|
||||
case SpecialModuleTag_export_default_object: {
|
||||
if (!value) {
|
||||
JSC::throwException(globalObject, scope, JSC::createSyntaxError(globalObject, "Failed to parse Object"_s));
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
target->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), value, 0);
|
||||
target->hasEvaluated = true;
|
||||
RELEASE_AND_RETURN(scope, target);
|
||||
}
|
||||
case SpecialModuleTag_custom_extension: {
|
||||
if constexpr (isExtension) {
|
||||
ASSERT_NOT_REACHED();
|
||||
JSC::throwException(globalObject, scope, JSC::createSyntaxError(globalObject, "Recursive extension. This is a bug in Bun"_s));
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
evaluateCommonJSCustomExtension(globalObject, target, specifierWtfString, specifierValue, value);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
RELEASE_AND_RETURN(scope, target);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ModuleResultTag_builtin: {
|
||||
// Shouldn't happen in this path
|
||||
ASSERT_NOT_REACHED();
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
|
||||
// The JSONForObjectLoader tag is source code returned from Bun that needs
|
||||
// to go through the JSON parser in JSC.
|
||||
//
|
||||
// We don't use JSON.parse directly in JS because we want the top-level keys of the JSON
|
||||
// object to be accessible as named imports.
|
||||
//
|
||||
// We don't use Bun's JSON parser because JSON.parse is faster and
|
||||
// handles stack overflow better.
|
||||
//
|
||||
// When parsing tsconfig.*.json or jsconfig.*.json, we go through Bun's JSON
|
||||
// parser instead to support comments and trailing commas.
|
||||
if (res->result.value.tag == SyntheticModuleType::JSONForObjectLoader) {
|
||||
WTF::String jsonSource = res->result.value.source_code.toWTFString(BunString::NonNull);
|
||||
JSC::JSValue value = JSC::JSONParseWithException(globalObject, jsonSource);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
target->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), value, 0);
|
||||
target->hasEvaluated = true;
|
||||
RELEASE_AND_RETURN(scope, target);
|
||||
|
||||
case ModuleResultTag_err: {
|
||||
throwException(globalObject, scope, JSValue::decode(res->result.err.exception));
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
// TOML and JSONC may go through here
|
||||
else if (res->result.value.tag == SyntheticModuleType::ExportsObject || res->result.value.tag == SyntheticModuleType::ExportDefaultObject) {
|
||||
JSC::JSValue value = JSC::JSValue::decode(res->result.value.jsvalue_for_export);
|
||||
if (!value) {
|
||||
JSC::throwException(globalObject, scope, JSC::createSyntaxError(globalObject, "Failed to parse Object"_s));
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
|
||||
target->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), value, 0);
|
||||
target->hasEvaluated = true;
|
||||
RELEASE_AND_RETURN(scope, target);
|
||||
} else if (res->result.value.tag == SyntheticModuleType::CommonJSCustomExtension) {
|
||||
if constexpr (isExtension) {
|
||||
ASSERT_NOT_REACHED();
|
||||
JSC::throwException(globalObject, scope, JSC::createSyntaxError(globalObject, "Recursive extension. This is a bug in Bun"_s));
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
evaluateCommonJSCustomExtension(globalObject, target, specifierWtfString, specifierValue, JSC::JSValue::decode(res->result.value.cjsCustomExtension));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
RELEASE_AND_RETURN(scope, target);
|
||||
}
|
||||
|
||||
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value);
|
||||
globalObject->moduleLoader()->provideFetch(globalObject, specifierValue, JSC::SourceCode(provider));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
RELEASE_AND_RETURN(scope, jsNumber(-1));
|
||||
RELEASE_AND_RETURN(scope, {});
|
||||
}
|
||||
|
||||
// Explicit instantiations of fetchCommonJSModuleNonBuiltin
|
||||
@@ -867,7 +852,7 @@ template JSValue fetchCommonJSModuleNonBuiltin<true>(
|
||||
JSC::JSValue specifierValue,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
JSCommonJSModule* target,
|
||||
String specifierWtfString,
|
||||
BunLoaderType forceLoaderType,
|
||||
@@ -880,7 +865,7 @@ template JSValue fetchCommonJSModuleNonBuiltin<false>(
|
||||
JSC::JSValue specifierValue,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
JSCommonJSModule* target,
|
||||
String specifierWtfString,
|
||||
BunLoaderType forceLoaderType,
|
||||
@@ -892,7 +877,7 @@ template<bool allowPromise>
|
||||
static JSValue fetchESMSourceCode(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSString* specifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute)
|
||||
@@ -900,7 +885,6 @@ static JSValue fetchESMSourceCode(
|
||||
void* bunVM = globalObject->bunVM();
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
ResolvedSourceCodeHolder sourceCodeHolder(res);
|
||||
|
||||
const auto reject = [&](JSC::JSValue exception) -> JSValue {
|
||||
if constexpr (allowPromise) {
|
||||
@@ -944,59 +928,63 @@ static JSValue fetchESMSourceCode(
|
||||
}
|
||||
|
||||
if (Bun__fetchBuiltinModule(bunVM, globalObject, specifier, referrer, res)) {
|
||||
if (!res->success) {
|
||||
throwException(scope, res->result.err, globalObject);
|
||||
if (res->tag == ModuleResultTag_err) {
|
||||
throwException(globalObject, scope, JSValue::decode(res->result.err.exception));
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
RELEASE_AND_RETURN(scope, reject(exception));
|
||||
}
|
||||
|
||||
// This can happen if it's a `bun build --compile`'d CommonJS file
|
||||
if (res->result.value.isCommonJSModule) {
|
||||
auto created = Bun::createCommonJSModule(globalObject, specifierJS, res->result.value);
|
||||
EXCEPTION_ASSERT(created.has_value() == !scope.exception());
|
||||
if (created.has_value()) {
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(created.value()))));
|
||||
// Handle transpiled builtins (e.g., `bun build --compile`'d CommonJS file)
|
||||
if (res->tag == ModuleResultTag_transpiled) {
|
||||
auto& transpiled = res->result.transpiled;
|
||||
bool isCommonJS = transpiled.flags.is_commonjs;
|
||||
bool fromPackageJSONTypeModule = transpiled.flags.from_package_json_type_module;
|
||||
|
||||
auto* provider = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
|
||||
if (isCommonJS) {
|
||||
auto created = Bun::createCommonJSModule(globalObject, specifierJS, provider, fromPackageJSONTypeModule);
|
||||
EXCEPTION_ASSERT(created.has_value() == !scope.exception());
|
||||
if (created.has_value()) {
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(created.value()))));
|
||||
}
|
||||
|
||||
if constexpr (allowPromise) {
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
RELEASE_AND_RETURN(scope, rejectedInternalPromise(globalObject, exception));
|
||||
} else {
|
||||
scope.release();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (allowPromise) {
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
RELEASE_AND_RETURN(scope, rejectedInternalPromise(globalObject, exception));
|
||||
} else {
|
||||
scope.release();
|
||||
return {};
|
||||
}
|
||||
// ES Module
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, JSC::SourceCode(adoptRef(*provider)))));
|
||||
}
|
||||
|
||||
auto moduleKey = specifier->toWTFString(BunString::ZeroCopy);
|
||||
|
||||
auto tag = res->result.value.tag;
|
||||
switch (tag) {
|
||||
case SyntheticModuleType::ESM: {
|
||||
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value, JSC::SourceProviderSourceType::Module, true);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, JSC::SourceCode(provider))));
|
||||
// Handle special modules (bun, process, etc) - these return JSValues
|
||||
if (res->tag == ModuleResultTag_special) {
|
||||
auto moduleKey = specifier->toWTFString(BunString::ZeroCopy);
|
||||
auto source = JSC::SourceCode(JSC::SyntheticSourceProvider::create(
|
||||
generateInternalModuleSourceCode(globalObject, static_cast<InternalModuleRegistry::Field>(0)),
|
||||
JSC::SourceOrigin(URL(makeString("builtins://"_s, moduleKey))),
|
||||
moduleKey));
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(source))));
|
||||
}
|
||||
|
||||
#define CASE(str, name) \
|
||||
case (SyntheticModuleType::name): { \
|
||||
auto source = JSC::SourceCode(JSC::SyntheticSourceProvider::create(generateNativeModule_##name, JSC::SourceOrigin(), WTFMove(moduleKey))); \
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(source)))); \
|
||||
}
|
||||
BUN_FOREACH_ESM_NATIVE_MODULE(CASE)
|
||||
#undef CASE
|
||||
|
||||
// CommonJS modules from src/js/*
|
||||
default: {
|
||||
if (tag & SyntheticModuleType::InternalModuleRegistryFlag) {
|
||||
constexpr auto mask = (SyntheticModuleType::InternalModuleRegistryFlag - 1);
|
||||
auto source = JSC::SourceCode(JSC::SyntheticSourceProvider::create(generateInternalModuleSourceCode(globalObject, static_cast<InternalModuleRegistry::Field>(tag & mask)), JSC::SourceOrigin(URL(makeString("builtins://"_s, moduleKey))), moduleKey));
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(source))));
|
||||
} else {
|
||||
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value, JSC::SourceProviderSourceType::Module, true);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider))));
|
||||
}
|
||||
}
|
||||
// Handle builtin ES modules
|
||||
if (res->tag == ModuleResultTag_builtin) {
|
||||
// For builtin ES modules, Zig returns the module name in result.builtin
|
||||
// We need to generate the appropriate source code
|
||||
auto moduleKey = specifier->toWTFString(BunString::ZeroCopy);
|
||||
// Return synthetic source for builtin ESM
|
||||
auto source = JSC::SourceCode(JSC::SyntheticSourceProvider::create(
|
||||
generateInternalModuleSourceCode(globalObject, static_cast<InternalModuleRegistry::Field>(0)),
|
||||
JSC::SourceOrigin(URL(makeString("builtin://"_s, moduleKey))),
|
||||
moduleKey));
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(source))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1018,100 +1006,79 @@ static JSValue fetchESMSourceCode(
|
||||
Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, false, false, BunLoaderTypeNone);
|
||||
}
|
||||
|
||||
if (res->success && res->result.value.isCommonJSModule) {
|
||||
auto created = Bun::createCommonJSModule(globalObject, specifierJS, res->result.value);
|
||||
EXCEPTION_ASSERT(created.has_value() == !scope.exception());
|
||||
if (created.has_value()) {
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(created.value()))));
|
||||
switch (res->tag) {
|
||||
case ModuleResultTag_transpiled: {
|
||||
auto& transpiled = res->result.transpiled;
|
||||
bool isCommonJS = transpiled.flags.is_commonjs;
|
||||
bool fromPackageJSONTypeModule = transpiled.flags.from_package_json_type_module;
|
||||
|
||||
auto* provider = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
|
||||
if (isCommonJS) {
|
||||
auto created = Bun::createCommonJSModule(globalObject, specifierJS, provider, fromPackageJSONTypeModule);
|
||||
EXCEPTION_ASSERT(created.has_value() == !scope.exception());
|
||||
if (created.has_value()) {
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(created.value()))));
|
||||
}
|
||||
|
||||
if constexpr (allowPromise) {
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
RELEASE_AND_RETURN(scope, rejectedInternalPromise(globalObject, exception));
|
||||
} else {
|
||||
scope.release();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (allowPromise) {
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
RELEASE_AND_RETURN(scope, rejectedInternalPromise(globalObject, exception));
|
||||
} else {
|
||||
scope.release();
|
||||
return {};
|
||||
}
|
||||
// ES Module
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(adoptRef(*provider)))));
|
||||
}
|
||||
|
||||
if (!res->success) {
|
||||
throwException(scope, res->result.err, globalObject);
|
||||
case ModuleResultTag_special: {
|
||||
auto& special = res->result.special;
|
||||
JSC::JSValue value = JSC::JSValue::decode(special.jsvalue);
|
||||
|
||||
if (!value) {
|
||||
RELEASE_AND_RETURN(scope, reject(JSC::createSyntaxError(globalObject, "Failed to parse Object"_s)));
|
||||
}
|
||||
|
||||
// Use appropriate generator based on special module tag
|
||||
JSC::SyntheticSourceProvider::SyntheticSourceGenerator function;
|
||||
if (special.tag == SpecialModuleTag_export_default_object) {
|
||||
function = generateJSValueExportDefaultObjectSourceCode(globalObject, value);
|
||||
} else {
|
||||
function = generateJSValueModuleSourceCode(globalObject, value);
|
||||
}
|
||||
|
||||
auto source = JSC::SourceCode(
|
||||
JSC::SyntheticSourceProvider::create(WTFMove(function),
|
||||
JSC::SourceOrigin(), specifier->toWTFString(BunString::ZeroCopy)));
|
||||
JSC::ensureStillAliveHere(value);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source))));
|
||||
}
|
||||
|
||||
case ModuleResultTag_builtin: {
|
||||
// Shouldn't typically happen in this path (handled above)
|
||||
ASSERT_NOT_REACHED();
|
||||
return {};
|
||||
}
|
||||
|
||||
case ModuleResultTag_err: {
|
||||
throwException(globalObject, scope, JSValue::decode(res->result.err.exception));
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
RELEASE_AND_RETURN(scope, reject(exception));
|
||||
}
|
||||
|
||||
// The JSONForObjectLoader tag is source code returned from Bun that needs
|
||||
// to go through the JSON parser in JSC.
|
||||
//
|
||||
// We don't use JSON.parse directly in JS because we want the top-level keys of the JSON
|
||||
// object to be accessible as named imports.
|
||||
//
|
||||
// We don't use Bun's JSON parser because JSON.parse is faster and
|
||||
// handles stack overflow better.
|
||||
//
|
||||
// When parsing tsconfig.*.json or jsconfig.*.json, we go through Bun's JSON
|
||||
// parser instead to support comments and trailing commas.
|
||||
if (res->result.value.tag == SyntheticModuleType::JSONForObjectLoader) {
|
||||
WTF::String jsonSource = res->result.value.source_code.toWTFString(BunString::NonNull);
|
||||
JSC::JSValue value = JSC::JSONParseWithException(globalObject, jsonSource);
|
||||
if (scope.exception()) [[unlikely]] {
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
RELEASE_AND_RETURN(scope, reject(exception));
|
||||
}
|
||||
|
||||
// JSON can become strings, null, numbers, booleans so we must handle "export default 123"
|
||||
auto function = generateJSValueModuleSourceCode(
|
||||
globalObject,
|
||||
value);
|
||||
auto source = JSC::SourceCode(
|
||||
JSC::SyntheticSourceProvider::create(WTFMove(function),
|
||||
JSC::SourceOrigin(), specifier->toWTFString(BunString::ZeroCopy)));
|
||||
JSC::ensureStillAliveHere(value);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source))));
|
||||
}
|
||||
// TOML and JSONC may go through here
|
||||
else if (res->result.value.tag == SyntheticModuleType::ExportsObject) {
|
||||
JSC::JSValue value = JSC::JSValue::decode(res->result.value.jsvalue_for_export);
|
||||
if (!value) {
|
||||
RELEASE_AND_RETURN(scope, reject(JSC::createSyntaxError(globalObject, "Failed to parse Object"_s)));
|
||||
}
|
||||
|
||||
// JSON can become strings, null, numbers, booleans so we must handle "export default 123"
|
||||
auto function = generateJSValueModuleSourceCode(
|
||||
globalObject,
|
||||
value);
|
||||
auto source = JSC::SourceCode(
|
||||
JSC::SyntheticSourceProvider::create(WTFMove(function),
|
||||
JSC::SourceOrigin(), specifier->toWTFString(BunString::ZeroCopy)));
|
||||
JSC::ensureStillAliveHere(value);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source))));
|
||||
} else if (res->result.value.tag == SyntheticModuleType::ExportDefaultObject) {
|
||||
JSC::JSValue value = JSC::JSValue::decode(res->result.value.jsvalue_for_export);
|
||||
if (!value) {
|
||||
RELEASE_AND_RETURN(scope, reject(JSC::createSyntaxError(globalObject, "Failed to parse Object"_s)));
|
||||
}
|
||||
|
||||
// JSON can become strings, null, numbers, booleans so we must handle "export default 123"
|
||||
auto function = generateJSValueExportDefaultObjectSourceCode(
|
||||
globalObject,
|
||||
value);
|
||||
auto source = JSC::SourceCode(
|
||||
JSC::SyntheticSourceProvider::create(WTFMove(function),
|
||||
JSC::SourceOrigin(), specifier->toWTFString(BunString::ZeroCopy)));
|
||||
JSC::ensureStillAliveHere(value);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source))));
|
||||
}
|
||||
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(Zig::SourceProvider::create(globalObject, res->result.value)))));
|
||||
return {};
|
||||
}
|
||||
|
||||
JSValue fetchESMSourceCodeSync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSString* specifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute)
|
||||
@@ -1122,7 +1089,7 @@ JSValue fetchESMSourceCodeSync(
|
||||
JSValue fetchESMSourceCodeAsync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSString* specifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute)
|
||||
@@ -1136,9 +1103,8 @@ using namespace Bun;
|
||||
BUN_DEFINE_HOST_FUNCTION(jsFunctionOnLoadObjectResultResolve, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
auto& vm = JSC::getVM(globalObject);
|
||||
ErrorableResolvedSource res;
|
||||
res.success = false;
|
||||
memset(&res.result, 0, sizeof res.result);
|
||||
ModuleResult res;
|
||||
memset(&res, 0, sizeof res);
|
||||
JSC::JSValue objectResult = callFrame->argument(0);
|
||||
PendingVirtualModuleResult* pendingModule = JSC::jsCast<PendingVirtualModuleResult*>(callFrame->argument(1));
|
||||
JSC::JSValue specifierString = pendingModule->internalField(0).get();
|
||||
@@ -1154,7 +1120,7 @@ BUN_DEFINE_HOST_FUNCTION(jsFunctionOnLoadObjectResultResolve, (JSC::JSGlobalObje
|
||||
bool wasModuleMock = pendingModule->wasModuleMock;
|
||||
|
||||
JSC::JSValue result = handleVirtualModuleResult<false>(static_cast<Zig::GlobalObject*>(globalObject), objectResult, &res, &specifier, &referrer, wasModuleMock);
|
||||
if (!scope.exception() && !res.success) [[unlikely]] {
|
||||
if (!scope.exception() && res.tag == ModuleResultTag_err) [[unlikely]] {
|
||||
throwException(globalObject, scope, result);
|
||||
}
|
||||
if (scope.exception()) [[unlikely]] {
|
||||
|
||||
@@ -11,6 +11,9 @@ BUN_DECLARE_HOST_FUNCTION(jsFunctionOnLoadObjectResultReject);
|
||||
|
||||
namespace Zig {
|
||||
class GlobalObject;
|
||||
|
||||
// Helper function to get source ID from URL (for debugging/coverage)
|
||||
std::optional<JSC::SourceID> sourceIDForSourceURL(const WTF::String& sourceURL);
|
||||
}
|
||||
|
||||
namespace JSC {
|
||||
@@ -93,7 +96,7 @@ public:
|
||||
JSValue fetchESMSourceCodeSync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSString* spceifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute);
|
||||
@@ -101,7 +104,7 @@ JSValue fetchESMSourceCodeSync(
|
||||
JSValue fetchESMSourceCodeAsync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSString* spceifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute);
|
||||
@@ -123,7 +126,7 @@ JSValue fetchCommonJSModuleNonBuiltin(
|
||||
JSC::JSValue specifierValue,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute,
|
||||
ErrorableResolvedSource* res,
|
||||
ModuleResult* res,
|
||||
JSCommonJSModule* target,
|
||||
String specifierWtfString,
|
||||
BunLoaderType forceLoaderType,
|
||||
@@ -136,6 +139,6 @@ JSValue resolveAndFetchBuiltinModule(
|
||||
JSValue fetchBuiltinModuleWithoutResolution(
|
||||
Zig::GlobalObject* globalObject,
|
||||
BunString* specifier,
|
||||
ErrorableResolvedSource* res);
|
||||
ModuleResult* res);
|
||||
|
||||
} // namespace Bun
|
||||
|
||||
86
src/bun.js/bindings/ModuleResult.zig
Normal file
86
src/bun.js/bindings/ModuleResult.zig
Normal file
@@ -0,0 +1,86 @@
|
||||
/// Tagged union return type from module loading/transpilation.
|
||||
/// This is the main result type returned by the transpiler to C++.
|
||||
pub const ModuleResult = extern struct {
|
||||
/// Tag indicating which variant is active
|
||||
tag: u8,
|
||||
|
||||
/// Explicit padding to match C struct alignment
|
||||
_padding: [7]u8,
|
||||
|
||||
/// The actual result data (tagged union)
|
||||
result: Result,
|
||||
|
||||
pub const Tag = enum(u8) {
|
||||
/// Normal transpiled source code
|
||||
transpiled = 0,
|
||||
|
||||
/// Special module (synthetic, custom extension, etc.)
|
||||
special = 1,
|
||||
|
||||
/// Built-in module reference
|
||||
builtin = 2,
|
||||
|
||||
/// Error occurred during loading/transpilation
|
||||
err = 3,
|
||||
};
|
||||
|
||||
pub const Result = extern union {
|
||||
/// Transpiled source code (when tag == .transpiled)
|
||||
transpiled: TranspiledSource,
|
||||
|
||||
/// Special module (when tag == .special)
|
||||
special: SpecialModule,
|
||||
|
||||
/// Built-in module specifier (when tag == .builtin)
|
||||
builtin: bun.String,
|
||||
|
||||
/// Error result (when tag == .err)
|
||||
err: ErrorResult,
|
||||
};
|
||||
|
||||
pub const ErrorResult = extern struct {
|
||||
/// The exception JSValue to throw
|
||||
exception: jsc.JSValue,
|
||||
};
|
||||
|
||||
/// Helper to create a transpiled result
|
||||
pub fn transpiled(source: TranspiledSource) ModuleResult {
|
||||
return .{
|
||||
.tag = @intFromEnum(Tag.transpiled),
|
||||
._padding = undefined,
|
||||
.result = .{ .transpiled = source },
|
||||
};
|
||||
}
|
||||
|
||||
/// Helper to create a special module result
|
||||
pub fn special(spec: SpecialModule) ModuleResult {
|
||||
return .{
|
||||
.tag = @intFromEnum(Tag.special),
|
||||
._padding = undefined,
|
||||
.result = .{ .special = spec },
|
||||
};
|
||||
}
|
||||
|
||||
/// Helper to create a builtin module result
|
||||
pub fn builtin(specifier: bun.String) ModuleResult {
|
||||
return .{
|
||||
.tag = @intFromEnum(Tag.builtin),
|
||||
._padding = undefined,
|
||||
.result = .{ .builtin = specifier },
|
||||
};
|
||||
}
|
||||
|
||||
/// Helper to create an error result
|
||||
pub fn err(exception: jsc.JSValue) ModuleResult {
|
||||
return .{
|
||||
.tag = @intFromEnum(Tag.err),
|
||||
._padding = undefined,
|
||||
.result = .{ .err = .{ .exception = exception } },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
const jsc = bun.jsc;
|
||||
const TranspiledSource = @import("./TranspiledSource.zig").TranspiledSource;
|
||||
const SpecialModule = @import("./SpecialModule.zig").SpecialModule;
|
||||
@@ -1,36 +0,0 @@
|
||||
pub const ResolvedSource = extern struct {
|
||||
/// Specifier's lifetime is the caller from C++
|
||||
/// https://github.com/oven-sh/bun/issues/9521
|
||||
specifier: bun.String = bun.String.empty,
|
||||
source_code: bun.String = bun.String.empty,
|
||||
|
||||
/// source_url is eventually deref'd on success
|
||||
source_url: bun.String = bun.String.empty,
|
||||
|
||||
is_commonjs_module: bool = false,
|
||||
|
||||
/// When .tag is .common_js_custom_extension, this is special-cased to hold
|
||||
/// the JSFunction extension. It is kept alive by
|
||||
/// - This structure is stored on the stack
|
||||
/// - There is a JSC::Strong reference to it
|
||||
cjs_custom_extension_index: JSValue = .zero,
|
||||
|
||||
allocator: ?*anyopaque = null,
|
||||
|
||||
jsvalue_for_export: JSValue = .zero,
|
||||
|
||||
tag: Tag = .javascript,
|
||||
|
||||
/// This is for source_code
|
||||
source_code_needs_deref: bool = true,
|
||||
already_bundled: bool = false,
|
||||
bytecode_cache: ?[*]u8 = null,
|
||||
bytecode_cache_size: usize = 0,
|
||||
|
||||
pub const Tag = @import("ResolvedSourceTag").ResolvedSourceTag;
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
|
||||
const jsc = bun.jsc;
|
||||
const JSValue = jsc.JSValue;
|
||||
23
src/bun.js/bindings/SpecialModule.zig
Normal file
23
src/bun.js/bindings/SpecialModule.zig
Normal file
@@ -0,0 +1,23 @@
|
||||
/// Special module cases that need JSValue handling.
|
||||
/// Used for modules that cannot be represented as transpiled source code.
|
||||
pub const SpecialModule = extern struct {
|
||||
/// Tag indicating the type of special module
|
||||
tag: Tag,
|
||||
|
||||
/// The JavaScript value containing the module contents
|
||||
jsvalue: jsc.JSValue,
|
||||
|
||||
pub const Tag = enum(u8) {
|
||||
/// Module exports an object directly (synthetic modules)
|
||||
exports_object = 0,
|
||||
|
||||
/// Module exports a default object
|
||||
export_default_object = 1,
|
||||
|
||||
/// Module with custom extension handling
|
||||
custom_extension = 2,
|
||||
};
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
const jsc = bun.jsc;
|
||||
35
src/bun.js/bindings/TranspiledSource.zig
Normal file
35
src/bun.js/bindings/TranspiledSource.zig
Normal file
@@ -0,0 +1,35 @@
|
||||
/// POD (Plain Old Data) struct for transpiled source code.
|
||||
/// Thread-safe: contains no JSValue fields, only raw data.
|
||||
/// Ownership of all data transfers to C++ when returned.
|
||||
pub const TranspiledSource = extern struct {
|
||||
/// The transpiled JavaScript source code
|
||||
source_code: bun.String,
|
||||
|
||||
/// The source URL (file path or specifier)
|
||||
source_url: bun.String,
|
||||
|
||||
/// Optional bytecode cache data (may be null)
|
||||
bytecode_cache: ?[*]const u8,
|
||||
|
||||
/// Length of bytecode cache (0 if no cache)
|
||||
bytecode_cache_len: usize,
|
||||
|
||||
/// Packed flags for module metadata
|
||||
flags: Flags,
|
||||
|
||||
pub const Flags = packed struct(u8) {
|
||||
/// True if this is a CommonJS module
|
||||
is_commonjs: bool = false,
|
||||
|
||||
/// True if the module was already bundled (skip re-bundling)
|
||||
is_already_bundled: bool = false,
|
||||
|
||||
/// True if the module comes from package.json type: "module"
|
||||
from_package_json_type_module: bool = false,
|
||||
|
||||
/// Reserved bits for future use
|
||||
_padding: u5 = 0,
|
||||
};
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
@@ -153,7 +153,7 @@
|
||||
#include "webcrypto/JSCryptoKey.h"
|
||||
#include "webcrypto/JSSubtleCrypto.h"
|
||||
#include "ZigGeneratedClasses.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "BunSourceProvider.h"
|
||||
#include "UtilInspect.h"
|
||||
#include "Base64Helpers.h"
|
||||
#include "wtf/text/OrdinalNumber.h"
|
||||
@@ -577,11 +577,10 @@ JSC_DEFINE_HOST_FUNCTION(functionFulfillModuleSync,
|
||||
}
|
||||
|
||||
auto specifier = Bun::toString(moduleKey);
|
||||
ErrorableResolvedSource res;
|
||||
res.success = false;
|
||||
ModuleResult res;
|
||||
// zero-initialize entire result union. zeroed BunString has BunStringTag::Dead, and zeroed
|
||||
// EncodedJSValues are empty, which our code should be handling
|
||||
memset(&res.result, 0, sizeof res.result);
|
||||
memset(&res, 0, sizeof res);
|
||||
|
||||
JSValue result = Bun::fetchESMSourceCodeSync(
|
||||
globalObject,
|
||||
@@ -3309,11 +3308,10 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
|
||||
|
||||
auto source = Bun::toString(sourceString);
|
||||
auto typeAttribute = Bun::toString(typeAttributeString);
|
||||
ErrorableResolvedSource res;
|
||||
res.success = false;
|
||||
ModuleResult res;
|
||||
// zero-initialize entire result union. zeroed BunString has BunStringTag::Dead, and zeroed
|
||||
// EncodedJSValues are empty, which our code should be handling
|
||||
memset(&res.result, 0, sizeof res.result);
|
||||
memset(&res, 0, sizeof res);
|
||||
|
||||
JSValue result = Bun::fetchESMSourceCodeAsync(
|
||||
static_cast<Zig::GlobalObject*>(globalObject),
|
||||
|
||||
@@ -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
|
||||
@@ -105,29 +105,6 @@ typedef struct ErrorableString {
|
||||
ErrorableStringResult result;
|
||||
bool success;
|
||||
} ErrorableString;
|
||||
typedef struct ResolvedSource {
|
||||
BunString specifier;
|
||||
BunString source_code;
|
||||
BunString source_url;
|
||||
bool isCommonJSModule;
|
||||
JSC::EncodedJSValue cjsCustomExtension;
|
||||
void* allocator;
|
||||
JSC::EncodedJSValue jsvalue_for_export;
|
||||
uint32_t tag;
|
||||
bool needsDeref;
|
||||
bool already_bundled;
|
||||
uint8_t* bytecode_cache;
|
||||
size_t bytecode_cache_size;
|
||||
} ResolvedSource;
|
||||
static const uint32_t ResolvedSourceTagPackageJSONTypeModule = 1;
|
||||
typedef union ErrorableResolvedSourceResult {
|
||||
ResolvedSource value;
|
||||
ZigErrorType err;
|
||||
} ErrorableResolvedSourceResult;
|
||||
typedef struct ErrorableResolvedSource {
|
||||
ErrorableResolvedSourceResult result;
|
||||
bool success;
|
||||
} ErrorableResolvedSource;
|
||||
|
||||
typedef struct SystemError {
|
||||
int errno_;
|
||||
@@ -252,6 +229,66 @@ const BunLoaderType BunLoaderTypeWASM = 10;
|
||||
const BunLoaderType BunLoaderTypeNAPI = 11;
|
||||
const BunLoaderType BunLoaderTypeYAML = 19;
|
||||
|
||||
#pragma mark - Module Loading
|
||||
|
||||
// Forward declarations for new module loading types
|
||||
typedef struct TranspiledSource TranspiledSource;
|
||||
typedef struct SpecialModule SpecialModule;
|
||||
typedef struct ModuleResult ModuleResult;
|
||||
|
||||
// Flags for TranspiledSource
|
||||
typedef struct TranspiledSourceFlags {
|
||||
uint8_t is_commonjs : 1;
|
||||
uint8_t is_already_bundled : 1;
|
||||
uint8_t from_package_json_type_module : 1;
|
||||
uint8_t _padding : 5;
|
||||
} TranspiledSourceFlags;
|
||||
|
||||
// TranspiledSource - POD struct for transpiled source code
|
||||
typedef struct TranspiledSource {
|
||||
BunString source_code;
|
||||
BunString source_url;
|
||||
const uint8_t* bytecode_cache;
|
||||
size_t bytecode_cache_len;
|
||||
TranspiledSourceFlags flags;
|
||||
} TranspiledSource;
|
||||
|
||||
// SpecialModule tags
|
||||
typedef uint8_t SpecialModuleTag;
|
||||
const SpecialModuleTag SpecialModuleTag_exports_object = 0;
|
||||
const SpecialModuleTag SpecialModuleTag_export_default_object = 1;
|
||||
const SpecialModuleTag SpecialModuleTag_custom_extension = 2;
|
||||
|
||||
// SpecialModule - for special cases that need JSValue handling
|
||||
typedef struct SpecialModule {
|
||||
SpecialModuleTag tag;
|
||||
JSC::EncodedJSValue jsvalue;
|
||||
} SpecialModule;
|
||||
|
||||
// ModuleResult tags
|
||||
typedef uint8_t ModuleResultTag;
|
||||
const ModuleResultTag ModuleResultTag_transpiled = 0;
|
||||
const ModuleResultTag ModuleResultTag_special = 1;
|
||||
const ModuleResultTag ModuleResultTag_builtin = 2;
|
||||
const ModuleResultTag ModuleResultTag_err = 3;
|
||||
|
||||
// ModuleResult error result
|
||||
typedef struct ModuleResultError {
|
||||
JSC::EncodedJSValue exception;
|
||||
} ModuleResultError;
|
||||
|
||||
// ModuleResult - tagged union return type
|
||||
typedef struct ModuleResult {
|
||||
ModuleResultTag tag;
|
||||
uint8_t _padding[7]; // Explicit padding to match Zig struct alignment
|
||||
union {
|
||||
TranspiledSource transpiled;
|
||||
SpecialModule special;
|
||||
BunString builtin;
|
||||
ModuleResultError err;
|
||||
} result;
|
||||
} ModuleResult;
|
||||
|
||||
#pragma mark - Stream
|
||||
|
||||
typedef uint8_t Encoding;
|
||||
@@ -354,7 +391,7 @@ extern "C" bool Bun__transpileVirtualModule(
|
||||
const BunString* referrer,
|
||||
ZigString* sourceCode,
|
||||
BunLoaderType loader,
|
||||
ErrorableResolvedSource* result);
|
||||
ModuleResult* result);
|
||||
|
||||
extern "C" JSC::EncodedJSValue Bun__runVirtualModule(
|
||||
JSC::JSGlobalObject* global,
|
||||
@@ -366,7 +403,7 @@ extern "C" JSC::JSInternalPromise* Bun__transpileFile(
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
const BunString* typeAttribute,
|
||||
ErrorableResolvedSource* result,
|
||||
ModuleResult* result,
|
||||
bool allowPromise,
|
||||
bool isCommonJSRequire,
|
||||
BunLoaderType forceLoaderType);
|
||||
@@ -376,11 +413,11 @@ extern "C" bool Bun__fetchBuiltinModule(
|
||||
JSC::JSGlobalObject* global,
|
||||
const BunString* specifier,
|
||||
const BunString* referrer,
|
||||
ErrorableResolvedSource* result);
|
||||
ModuleResult* result);
|
||||
extern "C" bool Bun__resolveAndFetchBuiltinModule(
|
||||
void* bunVM,
|
||||
const BunString* specifier,
|
||||
ErrorableResolvedSource* result);
|
||||
ModuleResult* result);
|
||||
|
||||
// Used in process.version
|
||||
extern "C" const char* Bun__version;
|
||||
|
||||
2
src/bun.js/bindings/headers.h
generated
2
src/bun.js/bindings/headers.h
generated
@@ -431,7 +431,7 @@ CPP_DECL bool Zig__GlobalObject__resetModuleRegistryMap(JSC::JSGlobalObject* arg
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
ZIG_DECL void Zig__GlobalObject__fetch(ErrorableResolvedSource* arg0, JSC::JSGlobalObject* arg1, BunString* arg2, BunString* arg3);
|
||||
ZIG_DECL void Zig__GlobalObject__fetch(ModuleResult* arg0, JSC::JSGlobalObject* arg1, BunString* arg2, BunString* arg3);
|
||||
ZIG_DECL void Zig__GlobalObject__onCrash();
|
||||
ZIG_DECL JSC::EncodedJSValue Zig__GlobalObject__promiseRejectionTracker(JSC::JSGlobalObject* arg0, JSC::JSPromise* arg1, uint32_t JSPromiseRejectionOperation2);
|
||||
ZIG_DECL JSC::EncodedJSValue Zig__GlobalObject__reportUncaughtException(JSC::JSGlobalObject* arg0, JSC::Exception* arg1);
|
||||
|
||||
@@ -89,7 +89,9 @@ 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 TranspiledSource = @import("./bindings/TranspiledSource.zig").TranspiledSource;
|
||||
pub const SpecialModule = @import("./bindings/SpecialModule.zig").SpecialModule;
|
||||
pub const ErrorCode = @import("./bindings/ErrorCode.zig").ErrorCode;
|
||||
pub const JSErrorCode = @import("./bindings/JSErrorCode.zig").JSErrorCode;
|
||||
pub const ZigErrorType = @import("./bindings/ZigErrorType.zig").ZigErrorType;
|
||||
@@ -102,10 +104,10 @@ pub const EventType = @import("./bindings/EventType.zig").EventType;
|
||||
pub const JSRuntimeType = @import("./bindings/JSRuntimeType.zig").JSRuntimeType;
|
||||
pub const ZigStackFrameCode = @import("./bindings/ZigStackFrameCode.zig").ZigStackFrameCode;
|
||||
|
||||
pub const ErrorableResolvedSource = Errorable(ResolvedSource);
|
||||
pub const ErrorableZigString = Errorable(ZigString);
|
||||
pub const ErrorableJSValue = Errorable(JSValue);
|
||||
pub const ErrorableString = Errorable(bun.String);
|
||||
pub const ErrorableModuleResult = Errorable(ModuleResult);
|
||||
|
||||
pub const ZigStackTrace = @import("./bindings/ZigStackTrace.zig").ZigStackTrace;
|
||||
pub const ZigStackFrame = @import("./bindings/ZigStackFrame.zig").ZigStackFrame;
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#endif
|
||||
|
||||
#include "JSDOMConvertBase.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "BunSourceProvider.h"
|
||||
#include "mimalloc.h"
|
||||
|
||||
#include <JavaScriptCore/ControlFlowProfiler.h>
|
||||
@@ -838,13 +838,15 @@ JSC_DEFINE_HOST_FUNCTION(functionCodeCoverageForFile,
|
||||
RETURN_IF_EXCEPTION(throwScope, {});
|
||||
bool ignoreSourceMap = callFrame->argument(1).toBoolean(globalObject);
|
||||
|
||||
auto sourceID = Zig::sourceIDForSourceURL(fileName);
|
||||
if (!sourceID) {
|
||||
auto sourceIDOpt = Zig::sourceIDForSourceURL(fileName);
|
||||
if (!sourceIDOpt) {
|
||||
throwException(globalObject, throwScope,
|
||||
createError(globalObject, "No source for file"_s));
|
||||
return {};
|
||||
}
|
||||
|
||||
auto sourceID = *sourceIDOpt;
|
||||
|
||||
auto basicBlocks = vm.controlFlowProfiler()->getBasicBlocksForSourceIDWithoutFunctionRange(
|
||||
sourceID, vm);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user