mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
A few fixes related to CommonJS module loading (#9540)
* Ensure we always deref the source code * Move more work to concurrent transpiler * Update NodeModuleModule.h * Update string.zig * Make `Bun.gc()` more effective * Update text-loader-fixture-dynamic-import-stress.ts * Update ZigSourceProvider.cpp * Fixes #6946 * Update ModuleLoader.cpp * Update ModuleLoader.cpp * Fixes #8965 * Fixups * Update ModuleLoader.cpp * Update ModuleLoader.cpp * Load it * Update module_loader.zig * Update module_loader.zig --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include "JSDOMOperation.h"
|
||||
|
||||
#include "GCDefferalContext.h"
|
||||
#include "wtf/text/StringImpl.h"
|
||||
|
||||
extern "C" void mi_free(void* ptr);
|
||||
|
||||
@@ -559,4 +560,9 @@ extern "C" bool WTFStringImpl__isThreadSafe(
|
||||
// return wtf->characters8() == reinterpret_cast_ptr<const LChar*>(reinterpret_cast<const uint8_t*>(wtf) + tailOffset<const LChar*>());
|
||||
|
||||
// return wtf->characters16() == reinterpret_cast_ptr<const UChar*>(reinterpret_cast<const uint16_t*>(wtf) + tailOffset<const UChar*>());
|
||||
}
|
||||
|
||||
extern "C" void Bun__WTFStringImpl__ensureHash(WTF::StringImpl* str)
|
||||
{
|
||||
str->hash();
|
||||
}
|
||||
@@ -30,7 +30,10 @@
|
||||
*/
|
||||
|
||||
#include "headers.h"
|
||||
#include "JavaScriptCore/JSCast.h"
|
||||
#include <JavaScriptCore/JSMapInlines.h>
|
||||
#include "root.h"
|
||||
#include "JavaScriptCore/SourceCode.h"
|
||||
#include "headers-handwritten.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
#include <JavaScriptCore/JSSourceCode.h>
|
||||
@@ -67,6 +70,8 @@
|
||||
#include <JavaScriptCore/LazyPropertyInlines.h>
|
||||
#include <JavaScriptCore/HeapAnalyzer.h>
|
||||
#include "PathInlines.h"
|
||||
#include "wtf/NakedPtr.h"
|
||||
#include "wtf/URL.h"
|
||||
|
||||
extern "C" bool Bun__isBunMain(JSC::JSGlobalObject* global, const BunString*);
|
||||
|
||||
@@ -97,10 +102,10 @@ extern "C" void Bun__VM__setEntryPointEvalResultCJS(void*, EncodedJSValue);
|
||||
|
||||
static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObject, JSCommonJSModule* moduleObject, JSString* dirname, JSValue filename, WTF::NakedPtr<Exception>& exception)
|
||||
{
|
||||
JSSourceCode* code = moduleObject->sourceCode.get();
|
||||
SourceCode code = std::move(moduleObject->sourceCode);
|
||||
|
||||
// If an exception occurred somewhere else, we might have cleared the source code.
|
||||
if (UNLIKELY(code == nullptr)) {
|
||||
if (UNLIKELY(code.isNull())) {
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
throwException(globalObject, throwScope, createError(globalObject, "Failed to evaluate module"_s));
|
||||
exception = throwScope.exception();
|
||||
@@ -132,25 +137,22 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj
|
||||
globalObject->putDirect(vm, Identifier::fromLatin1(vm, "__filename"_s), filename, 0);
|
||||
globalObject->putDirect(vm, Identifier::fromLatin1(vm, "__dirname"_s), dirname, 0);
|
||||
|
||||
JSValue result = JSC::evaluate(globalObject, code->sourceCode(), jsUndefined(), exception);
|
||||
JSValue result = JSC::evaluate(globalObject, code, jsUndefined(), exception);
|
||||
|
||||
if (UNLIKELY(exception.get() || result.isEmpty())) {
|
||||
moduleObject->sourceCode.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
Bun__VM__setEntryPointEvalResultCJS(globalObject->bunVM(), JSValue::encode(result));
|
||||
|
||||
moduleObject->sourceCode.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This will return 0 if there was a syntax error or an allocation failure
|
||||
JSValue fnValue = JSC::evaluate(globalObject, code->sourceCode(), jsUndefined(), exception);
|
||||
JSValue fnValue = JSC::evaluate(globalObject, code, jsUndefined(), exception);
|
||||
|
||||
if (UNLIKELY(exception.get() || fnValue.isEmpty())) {
|
||||
moduleObject->sourceCode.clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -171,39 +173,47 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj
|
||||
|
||||
JSC::call(globalObject, fn, callData, moduleObject, args, exception);
|
||||
|
||||
moduleObject->sourceCode.clear();
|
||||
|
||||
return exception.get() == nullptr;
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsFunctionLoadModule, (JSGlobalObject * lexicalGlobalObject, CallFrame* callframe))
|
||||
bool JSCommonJSModule::load(JSC::VM& vm, Zig::GlobalObject* globalObject, WTF::NakedPtr<JSC::Exception>& exception)
|
||||
{
|
||||
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
|
||||
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
|
||||
JSCommonJSModule* moduleObject = jsDynamicCast<JSCommonJSModule*>(callframe->argument(0));
|
||||
if (!moduleObject) {
|
||||
RELEASE_AND_RETURN(throwScope, JSValue::encode(jsBoolean(true)));
|
||||
if (this->hasEvaluated || this->sourceCode.isNull()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (moduleObject->hasEvaluated || !moduleObject->sourceCode) {
|
||||
RELEASE_AND_RETURN(throwScope, JSValue::encode(jsBoolean(true)));
|
||||
}
|
||||
|
||||
WTF::NakedPtr<Exception> exception;
|
||||
|
||||
evaluateCommonJSModuleOnce(
|
||||
globalObject->vm(),
|
||||
jsCast<Zig::GlobalObject*>(globalObject),
|
||||
moduleObject,
|
||||
moduleObject->m_dirname.get(),
|
||||
moduleObject->m_filename.get(),
|
||||
this,
|
||||
this->m_dirname.get(),
|
||||
this->m_filename.get(),
|
||||
exception);
|
||||
|
||||
if (exception.get()) {
|
||||
// On error, remove the module from the require map/
|
||||
// so that it can be re-evaluated on the next require.
|
||||
globalObject->requireMap()->remove(globalObject, moduleObject->id());
|
||||
globalObject->requireMap()->remove(globalObject, this->id());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsFunctionLoadModule, (JSGlobalObject * lexicalGlobalObject, CallFrame* callframe))
|
||||
{
|
||||
auto& vm = lexicalGlobalObject->vm();
|
||||
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
|
||||
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
||||
JSCommonJSModule* moduleObject = jsDynamicCast<JSCommonJSModule*>(callframe->argument(0));
|
||||
if (!moduleObject) {
|
||||
RELEASE_AND_RETURN(throwScope, JSValue::encode(jsBoolean(true)));
|
||||
}
|
||||
|
||||
WTF::NakedPtr<Exception> exception;
|
||||
|
||||
if (!moduleObject->load(vm, globalObject, exception)) {
|
||||
throwException(globalObject, throwScope, exception.get());
|
||||
exception.clear();
|
||||
return JSValue::encode({});
|
||||
@@ -487,15 +497,13 @@ JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject *
|
||||
sourceString,
|
||||
"\n})"_s);
|
||||
|
||||
SourceCode sourceCode = makeSource(
|
||||
moduleObject->sourceCode = makeSource(
|
||||
WTFMove(wrappedString),
|
||||
SourceOrigin(URL::fileURLWithFileSystemPath(filenameString)),
|
||||
JSC::SourceTaintedOrigin::Untainted,
|
||||
filenameString,
|
||||
WTF::TextPosition(),
|
||||
JSC::SourceProviderSourceType::Program);
|
||||
JSSourceCode* jsSourceCode = JSSourceCode::create(vm, WTFMove(sourceCode));
|
||||
moduleObject->sourceCode.set(vm, moduleObject, jsSourceCode);
|
||||
|
||||
auto index = filenameString.reverseFind(PLATFORM_SEP, filenameString.length());
|
||||
// filenameString is coming from js, any separator could be used
|
||||
@@ -593,15 +601,14 @@ public:
|
||||
|
||||
const JSC::ClassInfo JSCommonJSModulePrototype::s_info = { "ModulePrototype"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCommonJSModulePrototype) };
|
||||
|
||||
void JSCommonJSModule::finishCreation(JSC::VM& vm, JSC::JSString* id, JSValue filename, JSC::JSString* dirname, JSC::JSSourceCode* sourceCode)
|
||||
void JSCommonJSModule::finishCreation(JSC::VM& vm, JSC::JSString* id, JSValue filename, JSC::JSString* dirname, const JSC::SourceCode& sourceCode)
|
||||
{
|
||||
Base::finishCreation(vm);
|
||||
ASSERT(inherits(info()));
|
||||
m_id.set(vm, this, id);
|
||||
m_filename.set(vm, this, filename);
|
||||
m_dirname.set(vm, this, dirname);
|
||||
if (sourceCode)
|
||||
this->sourceCode.set(vm, this, sourceCode);
|
||||
this->sourceCode = sourceCode;
|
||||
}
|
||||
|
||||
JSC::Structure* JSCommonJSModule::createStructure(
|
||||
@@ -622,7 +629,7 @@ JSCommonJSModule* JSCommonJSModule::create(
|
||||
JSC::JSString* id,
|
||||
JSValue filename,
|
||||
JSC::JSString* dirname,
|
||||
JSC::JSSourceCode* sourceCode)
|
||||
const JSC::SourceCode& sourceCode)
|
||||
{
|
||||
JSCommonJSModule* cell = new (NotNull, JSC::allocateCell<JSCommonJSModule>(vm)) JSCommonJSModule(vm, structure);
|
||||
cell->finishCreation(vm, id, filename, dirname, sourceCode);
|
||||
@@ -664,7 +671,7 @@ JSCommonJSModule* JSCommonJSModule::create(
|
||||
auto* out = JSCommonJSModule::create(
|
||||
vm,
|
||||
globalObject->CommonJSModuleObjectStructure(),
|
||||
requireMapKey, requireMapKey, dirname, nullptr);
|
||||
requireMapKey, requireMapKey, dirname, SourceCode());
|
||||
|
||||
out->putDirect(
|
||||
vm,
|
||||
@@ -898,7 +905,6 @@ void JSCommonJSModule::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
|
||||
Base::visitChildren(thisObject, visitor);
|
||||
visitor.append(thisObject->m_id);
|
||||
visitor.append(thisObject->sourceCode);
|
||||
visitor.append(thisObject->m_filename);
|
||||
visitor.append(thisObject->m_dirname);
|
||||
visitor.append(thisObject->m_paths);
|
||||
@@ -996,19 +1002,16 @@ void RequireResolveFunctionPrototype::finishCreation(JSC::VM& vm)
|
||||
bool JSCommonJSModule::evaluate(
|
||||
Zig::GlobalObject* globalObject,
|
||||
const WTF::String& key,
|
||||
ResolvedSource source,
|
||||
ResolvedSource& source,
|
||||
bool isBuiltIn)
|
||||
{
|
||||
auto& vm = globalObject->vm();
|
||||
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program, isBuiltIn);
|
||||
this->ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
|
||||
JSC::SourceCode rawInputSource(
|
||||
WTFMove(sourceProvider));
|
||||
|
||||
if (this->hasEvaluated)
|
||||
return true;
|
||||
|
||||
this->sourceCode.set(vm, this, JSC::JSSourceCode::create(vm, WTFMove(rawInputSource)));
|
||||
this->sourceCode = WTFMove(JSC::SourceCode(WTFMove(sourceProvider)));
|
||||
|
||||
WTF::NakedPtr<JSC::Exception> exception;
|
||||
|
||||
@@ -1031,18 +1034,16 @@ bool JSCommonJSModule::evaluate(
|
||||
|
||||
std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
ResolvedSource source,
|
||||
JSValue specifierValue,
|
||||
ResolvedSource& source,
|
||||
bool isBuiltIn)
|
||||
{
|
||||
JSCommonJSModule* moduleObject = nullptr;
|
||||
WTF::String sourceURL = source.source_url.toWTFString();
|
||||
|
||||
JSValue specifierValue = Bun::toJS(globalObject, source.specifier);
|
||||
JSValue entry = globalObject->requireMap()->get(globalObject, specifierValue);
|
||||
|
||||
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program, isBuiltIn);
|
||||
bool ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
|
||||
SourceOrigin sourceOrigin = sourceProvider->sourceOrigin();
|
||||
SourceOrigin sourceOrigin;
|
||||
|
||||
if (entry) {
|
||||
moduleObject = jsDynamicCast<JSCommonJSModule*>(entry);
|
||||
@@ -1050,7 +1051,7 @@ std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
|
||||
if (!moduleObject) {
|
||||
auto& vm = globalObject->vm();
|
||||
auto* requireMapKey = jsStringWithCache(vm, sourceURL);
|
||||
auto* requireMapKey = specifierValue.toString(globalObject);
|
||||
auto index = sourceURL.reverseFind(PLATFORM_SEP, sourceURL.length());
|
||||
JSString* dirname;
|
||||
JSString* filename = requireMapKey;
|
||||
@@ -1060,16 +1061,20 @@ std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
dirname = jsEmptyString(vm);
|
||||
}
|
||||
|
||||
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, JSC::JSSourceCode::create(vm, SourceCode(WTFMove(sourceProvider))));
|
||||
requireMapKey, filename, dirname, WTFMove(JSC::SourceCode(WTFMove(sourceProvider))));
|
||||
|
||||
moduleObject->putDirect(vm,
|
||||
WebCore::clientData(vm)->builtinNames().exportsPublicName(),
|
||||
JSC::constructEmptyObject(globalObject, globalObject->objectPrototype()), 0);
|
||||
|
||||
globalObject->requireMap()->set(globalObject, requireMapKey, moduleObject);
|
||||
} else {
|
||||
sourceOrigin = Zig::toSourceOrigin(sourceURL, isBuiltIn);
|
||||
}
|
||||
|
||||
moduleObject->ignoreESModuleAnnotation = ignoreESModuleAnnotation;
|
||||
@@ -1110,6 +1115,8 @@ std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
|
||||
moduleObject->toSyntheticSource(globalObject, moduleKey, exportNames, exportValues);
|
||||
}
|
||||
} else {
|
||||
// require map was cleared of the entry
|
||||
}
|
||||
},
|
||||
sourceOrigin,
|
||||
@@ -1134,7 +1141,7 @@ JSObject* JSCommonJSModule::createBoundRequireFunction(VM& vm, JSGlobalObject* l
|
||||
auto moduleObject = Bun::JSCommonJSModule::create(
|
||||
vm,
|
||||
globalObject->CommonJSModuleObjectStructure(),
|
||||
filename, filename, dirname, nullptr);
|
||||
filename, filename, dirname, SourceCode());
|
||||
|
||||
JSFunction* requireFunction = JSC::JSBoundFunction::create(vm,
|
||||
globalObject,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "JavaScriptCore/JSGlobalObject.h"
|
||||
#include "root.h"
|
||||
#include "headers-handwritten.h"
|
||||
#include "wtf/NakedPtr.h"
|
||||
|
||||
namespace Zig {
|
||||
class GlobalObject;
|
||||
@@ -34,30 +36,34 @@ public:
|
||||
mutable JSC::WriteBarrier<JSString> m_dirname;
|
||||
mutable JSC::WriteBarrier<Unknown> m_paths;
|
||||
mutable JSC::WriteBarrier<Unknown> m_parent;
|
||||
mutable JSC::WriteBarrier<JSSourceCode> sourceCode;
|
||||
bool ignoreESModuleAnnotation { false };
|
||||
JSC::SourceCode sourceCode = JSC::SourceCode();
|
||||
|
||||
void setSourceCode(JSC::SourceCode&& sourceCode);
|
||||
|
||||
static void destroy(JSC::JSCell*);
|
||||
~JSCommonJSModule();
|
||||
|
||||
void clearSourceCode() { sourceCode = JSC::SourceCode(); }
|
||||
|
||||
void finishCreation(JSC::VM& vm,
|
||||
JSC::JSString* id, JSValue filename,
|
||||
JSC::JSString* dirname, JSC::JSSourceCode* sourceCode);
|
||||
JSC::JSString* dirname, const JSC::SourceCode& sourceCode);
|
||||
|
||||
static JSC::Structure* createStructure(JSC::JSGlobalObject* globalObject);
|
||||
|
||||
bool evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, ResolvedSource resolvedSource, bool isBuiltIn);
|
||||
inline bool evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, ResolvedSource resolvedSource)
|
||||
bool evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, ResolvedSource& resolvedSource, bool isBuiltIn);
|
||||
inline bool evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, ResolvedSource& resolvedSource)
|
||||
{
|
||||
return evaluate(globalObject, sourceURL, resolvedSource, false);
|
||||
}
|
||||
bool evaluate(Zig::GlobalObject* globalObject, const WTF::String& key, const SyntheticSourceProvider::SyntheticSourceGenerator& generator);
|
||||
bool evaluate(Zig::GlobalObject* globalObject, const WTF::String& key, JSSourceCode* sourceCode);
|
||||
bool evaluate(Zig::GlobalObject* globalObject, const WTF::String& key, const JSC::SourceCode& sourceCode);
|
||||
|
||||
static JSCommonJSModule* create(JSC::VM& vm, JSC::Structure* structure,
|
||||
JSC::JSString* id,
|
||||
JSValue filename,
|
||||
JSC::JSString* dirname, JSC::JSSourceCode* sourceCode);
|
||||
JSC::JSString* dirname, const JSC::SourceCode& sourceCode);
|
||||
|
||||
static JSCommonJSModule* create(
|
||||
Zig::GlobalObject* globalObject,
|
||||
@@ -79,10 +85,11 @@ public:
|
||||
JSValue exportsObject();
|
||||
JSValue id();
|
||||
|
||||
bool load(JSC::VM& vm, Zig::GlobalObject* globalObject, WTF::NakedPtr<JSC::Exception>&);
|
||||
|
||||
DECLARE_INFO;
|
||||
DECLARE_VISIT_CHILDREN;
|
||||
|
||||
|
||||
static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
|
||||
|
||||
template<typename, SubspaceAccess mode>
|
||||
@@ -106,25 +113,21 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
JSCommonJSModule* createCommonJSModuleWithoutRunning(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<Zig::SourceProvider> sourceProvider,
|
||||
const WTF::String& sourceURL,
|
||||
ResolvedSource source);
|
||||
|
||||
JSC::Structure* createCommonJSModuleStructure(
|
||||
Zig::GlobalObject* globalObject);
|
||||
|
||||
std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
ResolvedSource source,
|
||||
JSC::JSValue specifierValue,
|
||||
ResolvedSource& source,
|
||||
bool isBuiltIn);
|
||||
|
||||
inline std::optional<JSC::SourceCode> createCommonJSModule(
|
||||
Zig::GlobalObject* globalObject,
|
||||
ResolvedSource source)
|
||||
JSC::JSValue specifierValue,
|
||||
ResolvedSource& source)
|
||||
{
|
||||
return createCommonJSModule(globalObject, source, false);
|
||||
return createCommonJSModule(globalObject, specifierValue, source, false);
|
||||
}
|
||||
|
||||
class RequireResolveFunctionPrototype final : public JSC::JSNonFinalObject {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "root.h"
|
||||
#include "headers-handwritten.h"
|
||||
|
||||
#include "JavaScriptCore/JSGlobalObject.h"
|
||||
#include "ModuleLoader.h"
|
||||
|
||||
#include "JavaScriptCore/Identifier.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
#include <JavaScriptCore/JSCInlines.h>
|
||||
#include <JavaScriptCore/JSNativeStdFunction.h>
|
||||
@@ -290,8 +290,15 @@ static JSValue handleVirtualModuleResult(
|
||||
auto onLoadResult = handleOnLoadResult(globalObject, virtualModuleResult, specifier, wasModuleMock);
|
||||
JSC::VM& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
WTF::String sourceCodeStringForDeref;
|
||||
const auto getSourceCodeStringForDeref = [&]() {
|
||||
if (res->success && res->result.value.needsDeref && res->result.value.source_code.tag == BunStringTag::WTFStringImpl) {
|
||||
res->result.value.needsDeref = false;
|
||||
sourceCodeStringForDeref = String(res->result.value.source_code.impl.wtf);
|
||||
}
|
||||
};
|
||||
|
||||
auto reject = [&](JSC::JSValue exception) -> JSValue {
|
||||
const auto reject = [&](JSC::JSValue exception) -> JSValue {
|
||||
if constexpr (allowPromise) {
|
||||
return rejectedInternalPromise(globalObject, exception);
|
||||
} else {
|
||||
@@ -300,7 +307,7 @@ static JSValue handleVirtualModuleResult(
|
||||
}
|
||||
};
|
||||
|
||||
auto resolve = [&](JSValue code) -> JSValue {
|
||||
const auto resolve = [&](JSValue code) -> JSValue {
|
||||
res->success = true;
|
||||
if constexpr (allowPromise) {
|
||||
scope.release();
|
||||
@@ -310,7 +317,7 @@ static JSValue handleVirtualModuleResult(
|
||||
}
|
||||
};
|
||||
|
||||
auto rejectOrResolve = [&](JSValue code) -> JSValue {
|
||||
const auto rejectOrResolve = [&](JSValue code) -> JSValue {
|
||||
if (auto* exception = scope.exception()) {
|
||||
if constexpr (allowPromise) {
|
||||
scope.clearException();
|
||||
@@ -336,6 +343,7 @@ static JSValue handleVirtualModuleResult(
|
||||
if (!res->success) {
|
||||
return reject(JSValue::decode(reinterpret_cast<EncodedJSValue>(res->result.err.ptr)));
|
||||
}
|
||||
getSourceCodeStringForDeref();
|
||||
|
||||
auto provider = Zig::SourceProvider::create(globalObject, res->result.value);
|
||||
return resolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
|
||||
@@ -383,38 +391,62 @@ static JSValue handleVirtualModuleResult(
|
||||
}
|
||||
|
||||
extern "C" void Bun__onFulfillAsyncModule(
|
||||
JSC::EncodedJSValue promiseValue,
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::EncodedJSValue encodedPromiseValue,
|
||||
ErrorableResolvedSource* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer)
|
||||
{
|
||||
JSC::JSValue value = JSValue::decode(promiseValue);
|
||||
JSC::JSInternalPromise* promise = jsCast<JSC::JSInternalPromise*>(value);
|
||||
auto* globalObject = promise->globalObject();
|
||||
WTF::String sourceCodeStringForDeref;
|
||||
const auto getSourceCodeStringForDeref = [&]() {
|
||||
if (res->result.value.needsDeref && res->result.value.source_code.tag == BunStringTag::WTFStringImpl) {
|
||||
res->result.value.needsDeref = false;
|
||||
sourceCodeStringForDeref = String(res->result.value.source_code.impl.wtf);
|
||||
}
|
||||
};
|
||||
auto& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
JSC::JSInternalPromise* promise = jsCast<JSC::JSInternalPromise*>(JSC::JSValue::decode(encodedPromiseValue));
|
||||
|
||||
if (!res->success) {
|
||||
throwException(scope, res->result.err, globalObject);
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
return promise->reject(promise->globalObject(), exception);
|
||||
return promise->reject(globalObject, exception);
|
||||
}
|
||||
|
||||
if (res->result.value.commonJSExportsLen) {
|
||||
auto created = Bun::createCommonJSModule(jsCast<Zig::GlobalObject*>(globalObject), res->result.value);
|
||||
getSourceCodeStringForDeref();
|
||||
auto specifierValue = Bun::toJS(globalObject, *specifier);
|
||||
|
||||
if (created.has_value()) {
|
||||
return promise->resolve(promise->globalObject(), JSSourceCode::create(vm, WTFMove(created.value())));
|
||||
if (auto entry = globalObject->esmRegistryMap()->get(globalObject, specifierValue)) {
|
||||
if (res->result.value.commonJSExportsLen) {
|
||||
if (entry.isObject()) {
|
||||
if (auto isEvaluated = entry.getObject()->getIfPropertyExists(globalObject, Bun::builtinNames(vm).evaluatedPublicName())) {
|
||||
if (isEvaluated.isTrue()) {
|
||||
// it's a race! we lost.
|
||||
// https://github.com/oven-sh/bun/issues/6946
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto created = Bun::createCommonJSModule(jsCast<Zig::GlobalObject*>(globalObject), specifierValue, res->result.value);
|
||||
if (created.has_value()) {
|
||||
JSSourceCode* code = JSSourceCode::create(vm, WTFMove(created.value()));
|
||||
promise->resolve(globalObject, code);
|
||||
} else {
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
promise->reject(globalObject, exception);
|
||||
}
|
||||
} else {
|
||||
auto* exception = scope.exception();
|
||||
scope.clearException();
|
||||
return promise->reject(promise->globalObject(), exception);
|
||||
auto&& provider = Zig::SourceProvider::create(jsDynamicCast<Zig::GlobalObject*>(globalObject), res->result.value);
|
||||
promise->resolve(globalObject, JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
|
||||
}
|
||||
} else {
|
||||
// the module has since been deleted from the registry.
|
||||
// let's not keep it forever for no reason.
|
||||
}
|
||||
|
||||
auto provider = Zig::SourceProvider::create(jsDynamicCast<Zig::GlobalObject*>(globalObject), res->result.value);
|
||||
promise->resolve(promise->globalObject(), JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
|
||||
}
|
||||
|
||||
extern "C" bool isBunTest;
|
||||
@@ -432,7 +464,13 @@ JSValue fetchCommonJSModule(
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
ErrorableResolvedSource resValue;
|
||||
ErrorableResolvedSource* res = &resValue;
|
||||
|
||||
WTF::String sourceCodeStringForDeref;
|
||||
const auto getSourceCodeStringForDeref = [&]() {
|
||||
if (res->success && res->result.value.needsDeref && res->result.value.source_code.tag == BunStringTag::WTFStringImpl) {
|
||||
res->result.value.needsDeref = false;
|
||||
sourceCodeStringForDeref = String(res->result.value.source_code.impl.wtf);
|
||||
}
|
||||
};
|
||||
auto& builtinNames = WebCore::clientData(vm)->builtinNames();
|
||||
|
||||
bool wasModuleMock = false;
|
||||
@@ -543,7 +581,7 @@ JSValue fetchCommonJSModule(
|
||||
|
||||
JSMap* registry = globalObject->esmRegistryMap();
|
||||
|
||||
auto hasAlreadyLoadedESMVersionSoWeShouldntTranspileItTwice = [&]() -> bool {
|
||||
const auto hasAlreadyLoadedESMVersionSoWeShouldntTranspileItTwice = [&]() -> bool {
|
||||
JSValue entry = registry->get(globalObject, specifierValue);
|
||||
|
||||
if (!entry || !entry.isObject()) {
|
||||
@@ -559,6 +597,7 @@ JSValue fetchCommonJSModule(
|
||||
}
|
||||
|
||||
Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, false);
|
||||
getSourceCodeStringForDeref();
|
||||
|
||||
if (res->success && res->result.value.commonJSExportsLen) {
|
||||
target->evaluate(globalObject, specifier->toWTFString(BunString::ZeroCopy), res->result.value);
|
||||
@@ -605,6 +644,7 @@ extern "C" bool isBunTest;
|
||||
template<bool allowPromise>
|
||||
static JSValue fetchESMSourceCode(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSValue specifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
@@ -614,16 +654,16 @@ static JSValue fetchESMSourceCode(
|
||||
auto& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
auto reject = [&](JSC::JSValue exception) -> JSValue {
|
||||
const auto reject = [&](JSC::JSValue exception) -> JSValue {
|
||||
if constexpr (allowPromise) {
|
||||
return rejectedInternalPromise(globalObject, exception);
|
||||
} else {
|
||||
throwException(globalObject, scope, exception);
|
||||
return JSC::jsUndefined();
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
auto resolve = [&](JSValue code) -> JSValue {
|
||||
const auto resolve = [&](JSValue code) -> JSValue {
|
||||
if constexpr (allowPromise) {
|
||||
auto* ret = resolvedInternalPromise(globalObject, code);
|
||||
scope.release();
|
||||
@@ -633,7 +673,7 @@ static JSValue fetchESMSourceCode(
|
||||
}
|
||||
};
|
||||
|
||||
auto rejectOrResolve = [&](JSValue code) -> JSValue {
|
||||
const auto rejectOrResolve = [&](JSValue code) -> JSValue {
|
||||
if (auto* exception = scope.exception()) {
|
||||
if constexpr (!allowPromise) {
|
||||
scope.release();
|
||||
@@ -709,17 +749,27 @@ static JSValue fetchESMSourceCode(
|
||||
}
|
||||
}
|
||||
|
||||
WTF::String sourceCodeStringForDeref;
|
||||
const auto getSourceCodeStringForDeref = [&]() {
|
||||
if (res->success && res->result.value.needsDeref && res->result.value.source_code.tag == BunStringTag::WTFStringImpl) {
|
||||
res->result.value.needsDeref = false;
|
||||
sourceCodeStringForDeref = String(res->result.value.source_code.impl.wtf);
|
||||
}
|
||||
};
|
||||
|
||||
if constexpr (allowPromise) {
|
||||
void* pendingCtx = Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, true);
|
||||
auto* pendingCtx = Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, true);
|
||||
getSourceCodeStringForDeref();
|
||||
if (pendingCtx) {
|
||||
return reinterpret_cast<JSC::JSInternalPromise*>(pendingCtx);
|
||||
return pendingCtx;
|
||||
}
|
||||
} else {
|
||||
Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, false);
|
||||
getSourceCodeStringForDeref();
|
||||
}
|
||||
|
||||
if (res->success && res->result.value.commonJSExportsLen) {
|
||||
auto created = Bun::createCommonJSModule(globalObject, res->result.value);
|
||||
auto created = Bun::createCommonJSModule(globalObject, specifierJS, res->result.value);
|
||||
|
||||
if (created.has_value()) {
|
||||
return rejectOrResolve(JSSourceCode::create(vm, WTFMove(created.value())));
|
||||
@@ -730,7 +780,7 @@ static JSValue fetchESMSourceCode(
|
||||
scope.clearException();
|
||||
return rejectedInternalPromise(globalObject, exception);
|
||||
} else {
|
||||
return JSC::jsUndefined();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,8 +819,8 @@ static JSValue fetchESMSourceCode(
|
||||
return rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source)));
|
||||
}
|
||||
|
||||
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value);
|
||||
return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
|
||||
return rejectOrResolve(JSC::JSSourceCode::create(vm,
|
||||
JSC::SourceCode(Zig::SourceProvider::create(globalObject, res->result.value))));
|
||||
}
|
||||
|
||||
extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
|
||||
@@ -828,21 +878,23 @@ extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultReject(JSC::JSGlobalO
|
||||
|
||||
JSValue fetchESMSourceCodeSync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSValue specifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute)
|
||||
{
|
||||
return fetchESMSourceCode<false>(globalObject, res, specifier, referrer, typeAttribute);
|
||||
return fetchESMSourceCode<false>(globalObject, specifierJS, res, specifier, referrer, typeAttribute);
|
||||
}
|
||||
|
||||
JSValue fetchESMSourceCodeAsync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSC::JSValue specifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
BunString* typeAttribute)
|
||||
{
|
||||
return fetchESMSourceCode<true>(globalObject, res, specifier, referrer, typeAttribute);
|
||||
return fetchESMSourceCode<true>(globalObject, specifierJS, res, specifier, referrer, typeAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
|
||||
JSValue fetchESMSourceCodeSync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSValue spceifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
@@ -95,6 +96,7 @@ JSValue fetchESMSourceCodeSync(
|
||||
|
||||
JSValue fetchESMSourceCodeAsync(
|
||||
Zig::GlobalObject* globalObject,
|
||||
JSValue spceifierJS,
|
||||
ErrorableResolvedSource* res,
|
||||
BunString* specifier,
|
||||
BunString* referrer,
|
||||
|
||||
@@ -814,8 +814,9 @@ extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client,
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(functionFulfillModuleSync,
|
||||
(JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
(JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
|
||||
{
|
||||
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
|
||||
|
||||
auto& vm = globalObject->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
@@ -836,7 +837,8 @@ JSC_DEFINE_HOST_FUNCTION(functionFulfillModuleSync,
|
||||
res.result.err.ptr = nullptr;
|
||||
|
||||
JSValue result = Bun::fetchESMSourceCodeSync(
|
||||
reinterpret_cast<Zig::GlobalObject*>(globalObject),
|
||||
globalObject,
|
||||
key,
|
||||
&res,
|
||||
&specifier,
|
||||
&specifier,
|
||||
@@ -4480,6 +4482,7 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
|
||||
|
||||
JSValue result = Bun::fetchESMSourceCodeAsync(
|
||||
reinterpret_cast<Zig::GlobalObject*>(globalObject),
|
||||
key,
|
||||
&res,
|
||||
&moduleKeyBun,
|
||||
&source,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <JavaScriptCore/BytecodeCacheError.h>
|
||||
#include "ZigGlobalObject.h"
|
||||
#include "wtf/Assertions.h"
|
||||
|
||||
#include <JavaScriptCore/Completion.h>
|
||||
#include <wtf/Scope.h>
|
||||
@@ -43,7 +44,7 @@ static uintptr_t getSourceProviderMapKey(ResolvedSource& resolvedSource)
|
||||
}
|
||||
}
|
||||
|
||||
static SourceOrigin toSourceOrigin(const String& sourceURL, bool isBuiltin)
|
||||
SourceOrigin toSourceOrigin(const String& sourceURL, bool isBuiltin)
|
||||
{
|
||||
if (isBuiltin) {
|
||||
if (sourceURL.startsWith("node:"_s)) {
|
||||
@@ -55,6 +56,7 @@ static SourceOrigin toSourceOrigin(const String& sourceURL, bool isBuiltin)
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_WITH_MESSAGE(!sourceURL.startsWith("file://"_s), "sourceURL should not already be a file URL");
|
||||
return SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL));
|
||||
}
|
||||
|
||||
@@ -92,7 +94,7 @@ JSC::SourceID sourceIDForSourceURL(const WTF::String& sourceURL)
|
||||
|
||||
extern "C" bool BunTest__shouldGenerateCodeCoverage(BunString sourceURL);
|
||||
|
||||
Ref<SourceProvider> SourceProvider::create(Zig::GlobalObject* globalObject, ResolvedSource resolvedSource, JSC::SourceProviderSourceType sourceType, bool isBuiltin)
|
||||
Ref<SourceProvider> SourceProvider::create(Zig::GlobalObject* globalObject, ResolvedSource& resolvedSource, JSC::SourceProviderSourceType sourceType, bool isBuiltin)
|
||||
{
|
||||
|
||||
auto string = resolvedSource.source_code.toWTFString(BunString::ZeroCopy);
|
||||
@@ -103,8 +105,8 @@ Ref<SourceProvider> SourceProvider::create(Zig::GlobalObject* globalObject, Reso
|
||||
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
|
||||
|
||||
@@ -23,7 +23,7 @@ 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_MAKE_FAST_ALLOCATED;
|
||||
using Base = JSC::SourceProvider;
|
||||
@@ -36,7 +36,7 @@ class SourceProvider final : public JSC::SourceProvider {
|
||||
using SourceOrigin = JSC::SourceOrigin;
|
||||
|
||||
public:
|
||||
static Ref<SourceProvider> create(Zig::GlobalObject*, ResolvedSource resolvedSource, JSC::SourceProviderSourceType sourceType = JSC::SourceProviderSourceType::Module, bool isBuiltIn = false);
|
||||
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 { return StringView(m_source.get()); }
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
#include "root.h"
|
||||
|
||||
#include "JavaScriptCore/DeleteAllCodeEffort.h"
|
||||
#include "headers.h"
|
||||
|
||||
#include "BunClientData.h"
|
||||
@@ -3060,7 +3062,7 @@ void JSC__JSInternalPromise__rejectAsHandledException(JSC__JSInternalPromise* ar
|
||||
JSC__JSInternalPromise* JSC__JSInternalPromise__rejectedPromise(JSC__JSGlobalObject* arg0,
|
||||
JSC__JSValue JSValue1)
|
||||
{
|
||||
return reinterpret_cast<JSC::JSInternalPromise*>(
|
||||
return jsCast<JSC::JSInternalPromise*>(
|
||||
JSC::JSInternalPromise::rejectedPromise(arg0, JSC::JSValue::decode(JSValue1)));
|
||||
}
|
||||
|
||||
@@ -4587,8 +4589,11 @@ JSC__JSValue JSC__VM__runGC(JSC__VM* vm, bool sync)
|
||||
WTF::releaseFastMallocFreeMemory();
|
||||
|
||||
if (sync) {
|
||||
vm->clearSourceProviderCaches();
|
||||
vm->heap.deleteAllUnlinkedCodeBlocks(JSC::PreventCollectionAndDeleteAllCode);
|
||||
vm->heap.collectNow(JSC::Sync, JSC::CollectionScope::Full);
|
||||
} else {
|
||||
vm->heap.deleteAllUnlinkedCodeBlocks(JSC::DeleteAllCodeIfNotCollecting);
|
||||
vm->heap.collectSync(JSC::CollectionScope::Full);
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ extern "C" JSC::EncodedJSValue Bun__runVirtualModule(
|
||||
JSC::JSGlobalObject* global,
|
||||
const BunString* specifier);
|
||||
|
||||
extern "C" void* Bun__transpileFile(
|
||||
extern "C" JSC::JSInternalPromise* Bun__transpileFile(
|
||||
void* bunVM,
|
||||
JSC::JSGlobalObject* global,
|
||||
const BunString* specifier,
|
||||
|
||||
@@ -363,6 +363,7 @@ const ShellIOWriterAsyncDeinit = bun.shell.Interpreter.AsyncDeinitWriter;
|
||||
const TimerReference = JSC.BunTimer.Timeout.TimerReference;
|
||||
const ProcessWaiterThreadTask = if (Environment.isPosix) bun.spawn.WaiterThread.ProcessQueue.ResultTask else opaque {};
|
||||
const ProcessMiniEventLoopWaiterThreadTask = if (Environment.isPosix) bun.spawn.WaiterThread.ProcessMiniEventLoopQueue.ResultTask else opaque {};
|
||||
const RuntimeTranspilerStore = JSC.RuntimeTranspilerStore;
|
||||
// Task.get(ReadFileTask) -> ?ReadFileTask
|
||||
pub const Task = TaggedPointerUnion(.{
|
||||
FetchTasklet,
|
||||
@@ -434,6 +435,7 @@ pub const Task = TaggedPointerUnion(.{
|
||||
TimerReference,
|
||||
|
||||
ProcessWaiterThreadTask,
|
||||
RuntimeTranspilerStore,
|
||||
});
|
||||
const UnboundedQueue = @import("./unbounded_queue.zig").UnboundedQueue;
|
||||
pub const ConcurrentTask = struct {
|
||||
@@ -773,8 +775,7 @@ pub const EventLoop = struct {
|
||||
defer this.debug.exit();
|
||||
|
||||
if (count == 1) {
|
||||
this.global.vm().releaseWeakRefs();
|
||||
this.drainMicrotasksWithGlobal(this.global);
|
||||
this.drainMicrotasksWithGlobal(this.global, this.virtual_machine.jsc);
|
||||
}
|
||||
|
||||
this.entered_event_loop_count -= 1;
|
||||
@@ -807,9 +808,10 @@ pub const EventLoop = struct {
|
||||
}
|
||||
|
||||
extern fn JSC__JSGlobalObject__drainMicrotasks(*JSC.JSGlobalObject) void;
|
||||
fn drainMicrotasksWithGlobal(this: *EventLoop, globalObject: *JSC.JSGlobalObject) void {
|
||||
pub fn drainMicrotasksWithGlobal(this: *EventLoop, globalObject: *JSC.JSGlobalObject, jsc_vm: *JSC.VM) void {
|
||||
JSC.markBinding(@src());
|
||||
|
||||
jsc_vm.releaseWeakRefs();
|
||||
JSC__JSGlobalObject__drainMicrotasks(globalObject);
|
||||
this.deferred_tasks.run();
|
||||
|
||||
@@ -819,8 +821,7 @@ pub const EventLoop = struct {
|
||||
}
|
||||
|
||||
pub fn drainMicrotasks(this: *EventLoop) void {
|
||||
this.virtual_machine.jsc.releaseWeakRefs();
|
||||
this.drainMicrotasksWithGlobal(this.global);
|
||||
this.drainMicrotasksWithGlobal(this.global, this.virtual_machine.jsc);
|
||||
}
|
||||
|
||||
/// When you call a JavaScript function from outside the event loop task
|
||||
@@ -845,7 +846,7 @@ pub const EventLoop = struct {
|
||||
|
||||
pub fn tickQueueWithCount(this: *EventLoop, comptime queue_name: []const u8) u32 {
|
||||
var global = this.global;
|
||||
var global_vm = global.vm();
|
||||
const global_vm = global.vm();
|
||||
var counter: usize = 0;
|
||||
|
||||
if (comptime Environment.isDebug) {
|
||||
@@ -1171,6 +1172,10 @@ pub const EventLoop = struct {
|
||||
var any: *ProcessWaiterThreadTask = task.get(ProcessWaiterThreadTask).?;
|
||||
any.runFromJSThread();
|
||||
},
|
||||
@field(Task.Tag, typeBaseName(@typeName(RuntimeTranspilerStore))) => {
|
||||
var any: *RuntimeTranspilerStore = task.get(RuntimeTranspilerStore).?;
|
||||
any.drain();
|
||||
},
|
||||
@field(Task.Tag, typeBaseName(@typeName(TimerReference))) => {
|
||||
bun.markPosixOnly();
|
||||
var any: *TimerReference = task.get(TimerReference).?;
|
||||
@@ -1185,8 +1190,7 @@ pub const EventLoop = struct {
|
||||
},
|
||||
}
|
||||
|
||||
global_vm.releaseWeakRefs();
|
||||
this.drainMicrotasksWithGlobal(global);
|
||||
this.drainMicrotasksWithGlobal(global, global_vm);
|
||||
}
|
||||
|
||||
@field(this, queue_name).head = if (@field(this, queue_name).count == 0) 0 else @field(this, queue_name).head;
|
||||
@@ -1424,8 +1428,7 @@ pub const EventLoop = struct {
|
||||
while (this.tickWithCount() > 0) : (this.global.handleRejectedPromises()) {
|
||||
this.tickConcurrent();
|
||||
} else {
|
||||
global_vm.releaseWeakRefs();
|
||||
this.drainMicrotasksWithGlobal(global);
|
||||
this.drainMicrotasksWithGlobal(global, global_vm);
|
||||
this.tickConcurrent();
|
||||
if (this.tasks.count > 0) continue;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ const Dependency = @import("../install/dependency.zig");
|
||||
const Async = bun.Async;
|
||||
const String = bun.String;
|
||||
|
||||
const debug = Output.scoped(.ModuleLoader, true);
|
||||
|
||||
// Setting BUN_OVERRIDE_MODULE_PATH to the path to the bun repo will make it so modules are loaded
|
||||
// from there instead of the ones embedded into the binary.
|
||||
// In debug mode, this is set automatically for you, using the path relative to this file.
|
||||
@@ -217,11 +219,12 @@ fn setBreakPointOnFirstLine() bool {
|
||||
}
|
||||
|
||||
pub const RuntimeTranspilerStore = struct {
|
||||
const debug = Output.scoped(.compile, false);
|
||||
|
||||
generation_number: std.atomic.Value(u32) = std.atomic.Value(u32).init(0),
|
||||
store: TranspilerJob.Store,
|
||||
enabled: bool = true,
|
||||
queue: Queue = Queue{},
|
||||
|
||||
pub const Queue = bun.UnboundedQueue(TranspilerJob, .next);
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) RuntimeTranspilerStore {
|
||||
return RuntimeTranspilerStore{
|
||||
@@ -229,6 +232,29 @@ pub const RuntimeTranspilerStore = struct {
|
||||
};
|
||||
}
|
||||
|
||||
// Thsi is run at the top of the event loop on the JS thread.
|
||||
pub fn drain(this: *RuntimeTranspilerStore) void {
|
||||
var batch = this.queue.popBatch();
|
||||
var iter = batch.iterator();
|
||||
if (iter.next()) |job| {
|
||||
// we run just one job first to see if there are more
|
||||
job.runFromJSThread();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
var vm = @fieldParentPtr(JSC.VirtualMachine, "transpiler_store", this);
|
||||
const event_loop = vm.eventLoop();
|
||||
const global = vm.global;
|
||||
const jsc_vm = vm.jsc;
|
||||
while (iter.next()) |job| {
|
||||
// if there are more, we need to drain the microtasks from the previous run
|
||||
event_loop.drainMicrotasksWithGlobal(global, jsc_vm);
|
||||
job.runFromJSThread();
|
||||
}
|
||||
|
||||
// immediately after this is called, the microtasks will be drained again.
|
||||
}
|
||||
|
||||
pub fn transpile(
|
||||
this: *RuntimeTranspilerStore,
|
||||
vm: *JSC.VirtualMachine,
|
||||
@@ -236,7 +262,6 @@ pub const RuntimeTranspilerStore = struct {
|
||||
path: Fs.Path,
|
||||
referrer: []const u8,
|
||||
) *anyopaque {
|
||||
debug("transpile({s})", .{path.text});
|
||||
var job: *TranspilerJob = this.store.get();
|
||||
const owned_path = Fs.Path.init(bun.default_allocator.dupe(u8, path.text) catch unreachable);
|
||||
const promise = JSC.JSInternalPromise.create(globalObject);
|
||||
@@ -253,6 +278,8 @@ pub const RuntimeTranspilerStore = struct {
|
||||
.file = {},
|
||||
},
|
||||
};
|
||||
if (comptime Environment.allow_assert)
|
||||
debug("transpile({s}, {s}, async)", .{ path.text, @tagName(job.loader) });
|
||||
job.schedule();
|
||||
return promise;
|
||||
}
|
||||
@@ -271,6 +298,7 @@ pub const RuntimeTranspilerStore = struct {
|
||||
parse_error: ?anyerror = null,
|
||||
resolved_source: ResolvedSource = ResolvedSource{},
|
||||
work_task: JSC.WorkPoolTask = .{ .callback = runFromWorkerThread },
|
||||
next: ?*TranspilerJob = null,
|
||||
|
||||
pub const Store = bun.HiveArray(TranspilerJob, 64).Fallback;
|
||||
|
||||
@@ -302,9 +330,8 @@ pub const RuntimeTranspilerStore = struct {
|
||||
threadlocal var source_code_printer: ?*js_printer.BufferPrinter = null;
|
||||
|
||||
pub fn dispatchToMainThread(this: *TranspilerJob) void {
|
||||
this.vm.eventLoop().enqueueTaskConcurrent(
|
||||
JSC.ConcurrentTask.fromCallback(this, runFromJSThread),
|
||||
);
|
||||
this.vm.transpiler_store.queue.push(this);
|
||||
this.vm.eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.createFrom(&this.vm.transpiler_store));
|
||||
}
|
||||
|
||||
pub fn runFromJSThread(this: *TranspilerJob) void {
|
||||
@@ -413,7 +440,7 @@ pub const RuntimeTranspilerStore = struct {
|
||||
.hot, .watch => {
|
||||
if (vm.bun_watcher.indexOf(hash)) |index| {
|
||||
const _fd = vm.bun_watcher.watchlist().items(.fd)[index];
|
||||
fd = if (_fd.int() > 0) _fd else null;
|
||||
fd = if (!_fd.isStdio()) _fd else null;
|
||||
package_json = vm.bun_watcher.watchlist().items(.package_json)[index];
|
||||
}
|
||||
},
|
||||
@@ -567,6 +594,7 @@ pub const RuntimeTranspilerStore = struct {
|
||||
.source_url = duped.createIfDifferent(path.text),
|
||||
.hash = 0,
|
||||
};
|
||||
this.resolved_source.source_code.value.WTFStringImpl.ensureHash();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -637,20 +665,31 @@ pub const RuntimeTranspilerStore = struct {
|
||||
}
|
||||
|
||||
const duped = String.createUTF8(specifier);
|
||||
const source_code = brk: {
|
||||
const written = printer.ctx.getWritten();
|
||||
|
||||
const result = cache.output_code orelse bun.String.createLatin1(written);
|
||||
|
||||
if (written.len > 1024 * 1024 * 2 or vm.smol) {
|
||||
printer.ctx.buffer.deinit();
|
||||
source_code_printer.?.* = printer;
|
||||
}
|
||||
|
||||
// In a benchmarking loading @babel/standalone 100 times:
|
||||
//
|
||||
// After ensureHash:
|
||||
// 354.00 ms 4.2% 354.00 ms WTF::StringImpl::hashSlowCase() const
|
||||
//
|
||||
// Before ensureHash:
|
||||
// 506.00 ms 6.1% 506.00 ms WTF::StringImpl::hashSlowCase() const
|
||||
//
|
||||
result.value.WTFStringImpl.ensureHash();
|
||||
|
||||
break :brk result;
|
||||
};
|
||||
this.resolved_source = ResolvedSource{
|
||||
.allocator = null,
|
||||
.source_code = brk: {
|
||||
const written = printer.ctx.getWritten();
|
||||
|
||||
const result = cache.output_code orelse bun.String.createLatin1(written);
|
||||
|
||||
if (written.len > 1024 * 1024 * 2 or vm.smol) {
|
||||
printer.ctx.buffer.deinit();
|
||||
source_code_printer.?.* = printer;
|
||||
}
|
||||
|
||||
break :brk result;
|
||||
},
|
||||
.source_code = source_code,
|
||||
.specifier = duped,
|
||||
.source_url = duped.createIfDifferent(path.text),
|
||||
.commonjs_exports = null,
|
||||
@@ -668,8 +707,6 @@ pub const ModuleLoader = struct {
|
||||
transpile_source_code_arena: ?*bun.ArenaAllocator = null,
|
||||
eval_source: ?*logger.Source = null,
|
||||
|
||||
const debug = Output.scoped(.ModuleLoader, true);
|
||||
|
||||
/// This must be called after calling transpileSourceCode
|
||||
pub fn resetArena(this: *ModuleLoader, jsc_vm: *VirtualMachine) void {
|
||||
std.debug.assert(&jsc_vm.module_loader == this);
|
||||
@@ -1065,6 +1102,7 @@ pub const ModuleLoader = struct {
|
||||
var spec = bun.String.init(ZigString.init(this.specifier).withEncoding());
|
||||
var ref = bun.String.init(ZigString.init(this.referrer).withEncoding());
|
||||
Bun__onFulfillAsyncModule(
|
||||
this.globalThis,
|
||||
this.promise.get().?,
|
||||
&errorable,
|
||||
&spec,
|
||||
@@ -1107,6 +1145,7 @@ pub const ModuleLoader = struct {
|
||||
log.deinit();
|
||||
|
||||
Bun__onFulfillAsyncModule(
|
||||
globalThis,
|
||||
promise,
|
||||
&errorable,
|
||||
&specifier,
|
||||
@@ -1419,6 +1458,7 @@ pub const ModuleLoader = struct {
|
||||
}
|
||||
|
||||
extern "C" fn Bun__onFulfillAsyncModule(
|
||||
globalObject: *JSC.JSGlobalObject,
|
||||
promiseValue: JSC.JSValue,
|
||||
res: *JSC.ErrorableResolvedSource,
|
||||
specifier: *bun.String,
|
||||
@@ -2135,7 +2175,6 @@ pub const ModuleLoader = struct {
|
||||
JSC.markBinding(@src());
|
||||
var log = logger.Log.init(jsc_vm.bundler.allocator);
|
||||
defer log.deinit();
|
||||
debug("transpileFile: {any}", .{specifier_ptr.*});
|
||||
|
||||
var _specifier = specifier_ptr.toUTF8(jsc_vm.allocator);
|
||||
var referrer_slice = referrer.toUTF8(jsc_vm.allocator);
|
||||
@@ -2212,6 +2251,9 @@ pub const ModuleLoader = struct {
|
||||
}
|
||||
};
|
||||
|
||||
if (comptime Environment.allow_assert)
|
||||
debug("transpile({s}, {s}, sync)", .{ specifier, @tagName(synchronous_loader) });
|
||||
|
||||
defer jsc_vm.module_loader.resetArena(jsc_vm);
|
||||
|
||||
var promise: ?*JSC.JSInternalPromise = null;
|
||||
|
||||
@@ -124,7 +124,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleModuleConstructor,
|
||||
}
|
||||
|
||||
auto *out = Bun::JSCommonJSModule::create(vm, structure, idString, jsNull(),
|
||||
dirname, nullptr);
|
||||
dirname, SourceCode());
|
||||
|
||||
if (!parentValue.isUndefined())
|
||||
out->putDirect(vm, JSC::Identifier::fromString(vm, "parent"_s), parentValue,
|
||||
|
||||
@@ -20,24 +20,10 @@ namespace WebCore {
|
||||
using namespace JSC;
|
||||
|
||||
#define BUN_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
|
||||
macro(AbortSignal) \
|
||||
macro(Buffer) \
|
||||
macro(Bun) \
|
||||
macro(Loader) \
|
||||
macro(ReadableByteStreamController) \
|
||||
macro(ReadableStream) \
|
||||
macro(ReadableStreamBYOBReader) \
|
||||
macro(ReadableStreamBYOBRequest) \
|
||||
macro(ReadableStreamDefaultController) \
|
||||
macro(ReadableStreamDefaultReader) \
|
||||
macro(TransformStream) \
|
||||
macro(TransformStreamDefaultController) \
|
||||
macro(WritableStream) \
|
||||
macro(WritableStreamDefaultController) \
|
||||
macro(WritableStreamDefaultWriter) \
|
||||
macro(__esModule) \
|
||||
macro(_events) \
|
||||
macro(abortAlgorithm) \
|
||||
macro(AbortSignal) \
|
||||
macro(abortSteps) \
|
||||
macro(addEventListener) \
|
||||
macro(appendFromJS) \
|
||||
@@ -49,6 +35,8 @@ using namespace JSC;
|
||||
macro(backpressureChangePromise) \
|
||||
macro(basename) \
|
||||
macro(body) \
|
||||
macro(Buffer) \
|
||||
macro(Bun) \
|
||||
macro(bunNativePtr) \
|
||||
macro(bunNativeType) \
|
||||
macro(byobRequest) \
|
||||
@@ -58,11 +46,11 @@ using namespace JSC;
|
||||
macro(cloneArrayBuffer) \
|
||||
macro(close) \
|
||||
macro(closeAlgorithm) \
|
||||
macro(closeRequest) \
|
||||
macro(closeRequested) \
|
||||
macro(closed) \
|
||||
macro(closedPromise) \
|
||||
macro(closedPromiseCapability) \
|
||||
macro(closeRequest) \
|
||||
macro(closeRequested) \
|
||||
macro(code) \
|
||||
macro(connect) \
|
||||
macro(consumeReadableStream) \
|
||||
@@ -75,8 +63,8 @@ using namespace JSC;
|
||||
macro(createInternalModuleById) \
|
||||
macro(createNativeReadableStream) \
|
||||
macro(createReadableStream) \
|
||||
macro(createUsedReadableStream) \
|
||||
macro(createUninitializedArrayBuffer) \
|
||||
macro(createUsedReadableStream) \
|
||||
macro(createWritableStreamFromInternal) \
|
||||
macro(cwd) \
|
||||
macro(data) \
|
||||
@@ -95,6 +83,7 @@ using namespace JSC;
|
||||
macro(errno) \
|
||||
macro(errorSteps) \
|
||||
macro(evaluateCommonJSModule) \
|
||||
macro(evaluated) \
|
||||
macro(execArgv) \
|
||||
macro(exports) \
|
||||
macro(extname) \
|
||||
@@ -138,13 +127,14 @@ using namespace JSC;
|
||||
macro(lazy) \
|
||||
macro(lazyStreamPrototypeMap) \
|
||||
macro(loadCJS2ESM) \
|
||||
macro(Loader) \
|
||||
macro(localStreams) \
|
||||
macro(main) \
|
||||
macro(makeDOMException) \
|
||||
macro(makeGetterTypeError) \
|
||||
macro(makeThisTypeError) \
|
||||
macro(mockedFunction) \
|
||||
macro(method) \
|
||||
macro(mockedFunction) \
|
||||
macro(nextTick) \
|
||||
macro(normalize) \
|
||||
macro(on) \
|
||||
@@ -177,12 +167,18 @@ using namespace JSC;
|
||||
macro(put) \
|
||||
macro(queue) \
|
||||
macro(read) \
|
||||
macro(readIntoRequests) \
|
||||
macro(readRequests) \
|
||||
macro(readable) \
|
||||
macro(ReadableByteStreamController) \
|
||||
macro(ReadableStream) \
|
||||
macro(ReadableStreamBYOBReader) \
|
||||
macro(ReadableStreamBYOBRequest) \
|
||||
macro(readableStreamController) \
|
||||
macro(ReadableStreamDefaultController) \
|
||||
macro(ReadableStreamDefaultReader) \
|
||||
macro(readableStreamToArray) \
|
||||
macro(reader) \
|
||||
macro(readIntoRequests) \
|
||||
macro(readRequests) \
|
||||
macro(readyPromise) \
|
||||
macro(readyPromiseCapability) \
|
||||
macro(redirect) \
|
||||
@@ -226,6 +222,8 @@ using namespace JSC;
|
||||
macro(toNamespacedPath) \
|
||||
macro(trace) \
|
||||
macro(transformAlgorithm) \
|
||||
macro(TransformStream) \
|
||||
macro(TransformStreamDefaultController) \
|
||||
macro(uncork) \
|
||||
macro(underlyingByteSource) \
|
||||
macro(underlyingSink) \
|
||||
@@ -239,10 +237,13 @@ using namespace JSC;
|
||||
macro(view) \
|
||||
macro(whenSignalAborted) \
|
||||
macro(writable) \
|
||||
macro(WritableStream) \
|
||||
macro(WritableStreamDefaultController) \
|
||||
macro(WritableStreamDefaultWriter) \
|
||||
macro(write) \
|
||||
macro(writeAlgorithm) \
|
||||
macro(writeRequests) \
|
||||
macro(writer) \
|
||||
macro(writeRequests) \
|
||||
macro(writing) \
|
||||
macro(written) \
|
||||
|
||||
|
||||
@@ -4,32 +4,63 @@ $visibility = "Private";
|
||||
export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) {
|
||||
var loader = Loader;
|
||||
var queue = $createFIFO();
|
||||
var key = resolvedSpecifier;
|
||||
let key = resolvedSpecifier;
|
||||
const registry = loader.registry;
|
||||
|
||||
while (key) {
|
||||
// we need to explicitly check because state could be $ModuleFetch
|
||||
// it will throw this error if we do not:
|
||||
// $throwTypeError("Requested module is already fetched.");
|
||||
var entry = loader.registry.$get(key)!;
|
||||
let entry = registry.$get(key)!,
|
||||
moduleRecordPromise,
|
||||
state = 0,
|
||||
// entry.fetch is a Promise<SourceCode>
|
||||
// SourceCode is not a string, it's a JSC::SourceCode object
|
||||
fetch: Promise<SourceCode> | undefined;
|
||||
|
||||
if ((entry?.state ?? 0) <= $ModuleFetch) {
|
||||
$fulfillModuleSync(key);
|
||||
entry = loader.registry.$get(key)!;
|
||||
if (entry) {
|
||||
({ state, fetch } = entry);
|
||||
}
|
||||
|
||||
// entry.fetch is a Promise<SourceCode>
|
||||
// SourceCode is not a string, it's a JSC::SourceCode object
|
||||
// this pulls it out of the promise without delaying by a tick
|
||||
// the promise is already fullfilled by $fullfillModuleSync
|
||||
var sourceCodeObject = $getPromiseInternalField(entry.fetch, $promiseFieldReactionsOrResult);
|
||||
// parseModule() returns a Promise, but the value is already fulfilled
|
||||
// so we just pull it out of the promise here once again
|
||||
// But, this time we do it a little more carefully because this is a JSC function call and not bun source code
|
||||
var moduleRecordPromise = loader.parseModule(key, sourceCodeObject);
|
||||
var mod = entry.module;
|
||||
if (
|
||||
!entry ||
|
||||
// if we need to fetch it
|
||||
(state <= $ModuleFetch &&
|
||||
// either:
|
||||
// - we've never fetched it
|
||||
// - a fetch is in progress
|
||||
(!$isPromise(fetch) ||
|
||||
($getPromiseInternalField(fetch, $promiseFieldFlags) & $promiseStateMask) === $promiseStatePending))
|
||||
) {
|
||||
// force it to be no longer pending
|
||||
$fulfillModuleSync(key);
|
||||
|
||||
entry = registry.$get(key)!;
|
||||
|
||||
// the state can transition here
|
||||
// https://github.com/oven-sh/bun/issues/8965
|
||||
if (entry) {
|
||||
({ state = 0, fetch } = entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (state < $ModuleLink && $isPromise(fetch)) {
|
||||
// This will probably never happen, but just in case
|
||||
if (($getPromiseInternalField(fetch, $promiseFieldFlags) & $promiseStateMask) === $promiseStatePending) {
|
||||
throw new TypeError(`require() async module "${key}" is unsupported. use "await import()" instead.`);
|
||||
}
|
||||
|
||||
// this pulls it out of the promise without delaying by a tick
|
||||
// the promise is already fullfilled by $fullfillModuleSync
|
||||
const sourceCodeObject = $getPromiseInternalField(fetch, $promiseFieldReactionsOrResult);
|
||||
moduleRecordPromise = loader.parseModule(key, sourceCodeObject);
|
||||
}
|
||||
let mod = entry?.module;
|
||||
|
||||
if (moduleRecordPromise && $isPromise(moduleRecordPromise)) {
|
||||
var reactionsOrResult = $getPromiseInternalField(moduleRecordPromise, $promiseFieldReactionsOrResult);
|
||||
var flags = $getPromiseInternalField(moduleRecordPromise, $promiseFieldFlags);
|
||||
var state = flags & $promiseStateMask;
|
||||
let reactionsOrResult = $getPromiseInternalField(moduleRecordPromise, $promiseFieldReactionsOrResult);
|
||||
let flags = $getPromiseInternalField(moduleRecordPromise, $promiseFieldFlags);
|
||||
let state = flags & $promiseStateMask;
|
||||
// this branch should never happen, but just to be safe
|
||||
if (state === $promiseStatePending || (reactionsOrResult && $isPromise(reactionsOrResult))) {
|
||||
throw new TypeError(`require() async module "${key}" is unsupported. use "await import()" instead.`);
|
||||
@@ -51,15 +82,15 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) {
|
||||
|
||||
// This is very similar to "requestInstantiate" in ModuleLoader.js in JavaScriptCore.
|
||||
$setStateToMax(entry, $ModuleLink);
|
||||
var dependenciesMap = mod.dependenciesMap;
|
||||
var requestedModules = loader.requestedModules(mod);
|
||||
var dependencies = $newArrayWithSize<string>(requestedModules.length);
|
||||
const dependenciesMap = mod.dependenciesMap;
|
||||
const requestedModules = loader.requestedModules(mod);
|
||||
const dependencies = $newArrayWithSize<string>(requestedModules.length);
|
||||
for (var i = 0, length = requestedModules.length; i < length; ++i) {
|
||||
var depName = requestedModules[i];
|
||||
const depName = requestedModules[i];
|
||||
// optimization: if it starts with a slash then it's an absolute path
|
||||
// we don't need to run the resolver a 2nd time
|
||||
var depKey = depName[0] === "/" ? depName : loader.resolve(depName, key);
|
||||
var depEntry = loader.ensureRegistered(depKey);
|
||||
const depKey = depName[0] === "/" ? depName : loader.resolve(depName, key);
|
||||
const depEntry = loader.ensureRegistered(depKey);
|
||||
|
||||
if (depEntry.state < $ModuleLink) {
|
||||
queue.push(depKey);
|
||||
@@ -76,7 +107,7 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) {
|
||||
entry.isSatisfied = true;
|
||||
|
||||
key = queue.shift();
|
||||
while (key && (loader.registry.$get(key)?.state ?? $ModuleFetch) >= $ModuleLink) {
|
||||
while (key && (registry.$get(key)?.state ?? $ModuleFetch) >= $ModuleLink) {
|
||||
key = queue.shift();
|
||||
}
|
||||
}
|
||||
@@ -90,7 +121,7 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) {
|
||||
);
|
||||
}
|
||||
|
||||
return loader.registry.$get(resolvedSpecifier);
|
||||
return registry.$get(resolvedSpecifier);
|
||||
}
|
||||
|
||||
$visibility = "Private";
|
||||
|
||||
@@ -121,6 +121,13 @@ pub const WTFStringImplStruct = extern struct {
|
||||
return ZigString.Slice.init(this.refCountAllocator(), this.latin1Slice());
|
||||
}
|
||||
|
||||
extern fn Bun__WTFStringImpl__ensureHash(this: WTFStringImpl) void;
|
||||
/// Compute the hash() if necessary
|
||||
pub fn ensureHash(this: WTFStringImpl) void {
|
||||
JSC.markBinding(@src());
|
||||
Bun__WTFStringImpl__ensureHash(this);
|
||||
}
|
||||
|
||||
pub fn toUTF8(this: WTFStringImpl, allocator: std.mem.Allocator) ZigString.Slice {
|
||||
if (this.is8Bit()) {
|
||||
if (bun.strings.toUTF8FromLatin1(allocator, this.latin1Slice()) catch bun.outOfMemory()) |utf8| {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const count = process.platform === "win32" ? 10_000 : 100_000;
|
||||
const count = process.platform === "win32" ? 1000 : 10_000;
|
||||
for (let i = 0; i < count; i++) {
|
||||
await import("./text-loader-fixture-text-file.txt?" + i++);
|
||||
}
|
||||
Bun.gc(true);
|
||||
|
||||
const { default: text } = await import("./text-loader-fixture-text-file.txt");
|
||||
|
||||
|
||||
19
test/regression/issue/06946/06946.test.ts
Normal file
19
test/regression/issue/06946/06946.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { test, expect } from "bun:test";
|
||||
import { bunEnv, bunExe } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
test("06946", async () => {
|
||||
const buns = Array.from(
|
||||
{ length: 25 },
|
||||
() =>
|
||||
Bun.spawn({
|
||||
cmd: [bunExe(), join(import.meta.dir, "t.mjs")],
|
||||
cwd: import.meta.dir,
|
||||
stdio: ["inherit", "inherit", "inherit"],
|
||||
env: bunEnv,
|
||||
}).exited,
|
||||
);
|
||||
|
||||
const exited = await Promise.all(buns);
|
||||
expect(exited).toEqual(Array.from({ length: 25 }, () => 0));
|
||||
});
|
||||
3
test/regression/issue/06946/l.js
Normal file
3
test/regression/issue/06946/l.js
Normal file
@@ -0,0 +1,3 @@
|
||||
class Logger {}
|
||||
exports.Logger = Logger;
|
||||
console.log("l.js has loaded");
|
||||
4
test/regression/issue/06946/t.mjs
Normal file
4
test/regression/issue/06946/t.mjs
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Logger } from "./l";
|
||||
import "./t2";
|
||||
Logger.apply;
|
||||
console.log("t1 end");
|
||||
3
test/regression/issue/06946/t2.js
Normal file
3
test/regression/issue/06946/t2.js
Normal file
@@ -0,0 +1,3 @@
|
||||
console.log("t2 begin");
|
||||
require("./t3");
|
||||
console.log("t2 end");
|
||||
5
test/regression/issue/06946/t3.mjs
Normal file
5
test/regression/issue/06946/t3.mjs
Normal file
@@ -0,0 +1,5 @@
|
||||
console.log("t3 begin");
|
||||
import { Logger } from "./l";
|
||||
console.log("t3 end");
|
||||
Logger.apply;
|
||||
console.log("t3 postend");
|
||||
19
test/regression/issue/08965/08965.test.ts
Normal file
19
test/regression/issue/08965/08965.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { test, expect } from "bun:test";
|
||||
import { bunEnv, bunExe } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
test("08965", async () => {
|
||||
const buns = Array.from(
|
||||
{ length: 25 },
|
||||
() =>
|
||||
Bun.spawn({
|
||||
cmd: [bunExe(), join(import.meta.dir, "1.ts")],
|
||||
cwd: import.meta.dir,
|
||||
stdio: ["inherit", "inherit", "inherit"],
|
||||
env: bunEnv,
|
||||
}).exited,
|
||||
);
|
||||
|
||||
const exited = await Promise.all(buns);
|
||||
expect(exited).toEqual(Array.from({ length: 25 }, () => 0));
|
||||
});
|
||||
8
test/regression/issue/08965/1.ts
Normal file
8
test/regression/issue/08965/1.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import SomeClass from "./3";
|
||||
|
||||
import { config } from "./5";
|
||||
|
||||
const client = {};
|
||||
|
||||
console.log(SomeClass);
|
||||
client.config = config;
|
||||
3
test/regression/issue/08965/3.ts
Normal file
3
test/regression/issue/08965/3.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import somedata = require("./4");
|
||||
|
||||
export default class SomeClass {}
|
||||
4
test/regression/issue/08965/4.js
Normal file
4
test/regression/issue/08965/4.js
Normal file
@@ -0,0 +1,4 @@
|
||||
// 4.js
|
||||
const config = require(`./5`);
|
||||
|
||||
module.exports = {};
|
||||
6
test/regression/issue/08965/5.ts
Normal file
6
test/regression/issue/08965/5.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
const config_ = {};
|
||||
|
||||
type GeneratedConfigType = typeof config_;
|
||||
export interface Config extends GeneratedConfigType {}
|
||||
|
||||
export const config = config_ as Config;
|
||||
Reference in New Issue
Block a user