mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 02:48:50 +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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user