Compare commits

...

1 Commits

Author SHA1 Message Date
Jarred Sumner
7a271e48e6 Fix missing module.prototype._compile 2024-10-03 21:45:22 -07:00
4 changed files with 63 additions and 16 deletions

View File

@@ -103,7 +103,7 @@ static bool canPerformFastEnumeration(Structure* s)
extern "C" bool Bun__VM__specifierIsEvalEntryPoint(void*, EncodedJSValue);
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)
static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* functionGlobalObject, JSCommonJSModule* moduleObject, JSString* dirname, JSValue filename, WTF::NakedPtr<Exception>& exception)
{
SourceCode code = std::move(moduleObject->sourceCode);
@@ -152,7 +152,7 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj
}
// This will return 0 if there was a syntax error or an allocation failure
JSValue fnValue = JSC::evaluate(globalObject, code, jsUndefined(), exception);
JSValue fnValue = JSC::evaluate(functionGlobalObject, code, jsUndefined(), exception);
if (UNLIKELY(exception.get() || fnValue.isEmpty())) {
return false;
@@ -180,12 +180,12 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj
//
// fn(exports, require, module, __filename, __dirname) { /* code */ }(exports, require, module, __filename, __dirname)
//
JSC::call(globalObject, fn, callData, moduleObject, args, exception);
JSC::call(functionGlobalObject, fn, callData, moduleObject, args, exception);
return exception.get() == nullptr;
}
bool JSCommonJSModule::load(JSC::VM& vm, Zig::GlobalObject* globalObject, WTF::NakedPtr<JSC::Exception>& exception)
bool JSCommonJSModule::load(JSC::VM& vm, Zig::GlobalObject* globalObject, JSGlobalObject* functionGlobalObject, WTF::NakedPtr<JSC::Exception>& exception)
{
if (this->hasEvaluated || this->sourceCode.isNull()) {
return true;
@@ -193,16 +193,19 @@ bool JSCommonJSModule::load(JSC::VM& vm, Zig::GlobalObject* globalObject, WTF::N
evaluateCommonJSModuleOnce(
globalObject->vm(),
jsCast<Zig::GlobalObject*>(globalObject),
globalObject,
functionGlobalObject,
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, this->id());
if (LIKELY(functionGlobalObject == globalObject)) {
// On error, remove the module from the require map/
// so that it can be re-evaluated on the next require.
globalObject->requireMap()->remove(globalObject, this->id());
}
return false;
}
@@ -213,7 +216,7 @@ bool JSCommonJSModule::load(JSC::VM& vm, Zig::GlobalObject* globalObject, WTF::N
JSC_DEFINE_HOST_FUNCTION(jsFunctionLoadModule, (JSGlobalObject * lexicalGlobalObject, CallFrame* callframe))
{
auto& vm = lexicalGlobalObject->vm();
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
JSCommonJSModule* moduleObject = jsDynamicCast<JSCommonJSModule*>(callframe->argument(0));
if (!moduleObject) {
@@ -222,7 +225,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionLoadModule, (JSGlobalObject * lexicalGlobalOb
WTF::NakedPtr<Exception> exception;
if (!moduleObject->load(vm, globalObject, exception)) {
if (!moduleObject->load(vm, globalObject, lexicalGlobalObject, exception)) {
throwException(globalObject, throwScope, exception.get());
exception.clear();
return {};
@@ -500,7 +503,7 @@ static JSValue createChildren(VM& vm, JSObject* object)
return constructEmptyArray(object->globalObject(), nullptr, 0);
}
JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject * globalObject, CallFrame* callframe))
JSC_DEFINE_HOST_FUNCTION(jsFunctionCommonJSModuleRecord_compile, (JSGlobalObject * globalObject, CallFrame* callframe))
{
auto* moduleObject = jsDynamicCast<JSCommonJSModule*>(callframe->thisValue());
if (!moduleObject) {
@@ -543,7 +546,8 @@ JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject *
WTF::NakedPtr<JSC::Exception> exception;
evaluateCommonJSModuleOnce(
vm,
jsCast<Zig::GlobalObject*>(globalObject),
defaultGlobalObject(globalObject),
globalObject,
moduleObject,
jsString(vm, dirnameString),
jsString(vm, filenameString),
@@ -559,7 +563,7 @@ JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject *
}
static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = {
{ "_compile"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, functionCommonJSModuleRecord_compile, 2 } },
{ "_compile"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionCommonJSModuleRecord_compile, 2 } },
{ "children"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, createChildren } },
{ "filename"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterFilename, setterFilename } },
{ "id"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterId, setterId } },
@@ -1074,7 +1078,7 @@ bool JSCommonJSModule::evaluate(
this->sourceCode = JSC::SourceCode(WTFMove(sourceProvider));
WTF::NakedPtr<JSC::Exception> exception;
evaluateCommonJSModuleOnce(vm, globalObject, this, this->m_dirname.get(), this->m_filename.get(), exception);
evaluateCommonJSModuleOnce(vm, globalObject, globalObject, this, this->m_dirname.get(), this->m_filename.get(), exception);
if (exception.get()) {
// On error, remove the module from the require map/
@@ -1157,6 +1161,7 @@ std::optional<JSC::SourceCode> createCommonJSModule(
if (!evaluateCommonJSModuleOnce(
vm,
globalObject,
globalObject,
moduleObject,
moduleObject->m_dirname.get(),
moduleObject->m_filename.get(), exception)) {

View File

@@ -23,6 +23,7 @@ using namespace JSC;
JSC_DECLARE_HOST_FUNCTION(jsFunctionCreateCommonJSModule);
JSC_DECLARE_HOST_FUNCTION(jsFunctionLoadModule);
JSC_DECLARE_HOST_FUNCTION(jsFunctionCommonJSModuleRecord_compile);
void populateESMExports(
JSC::JSGlobalObject* globalObject,
@@ -108,7 +109,7 @@ public:
void setExportsObject(JSC::JSValue exportsObject);
JSValue id();
bool load(JSC::VM& vm, Zig::GlobalObject* globalObject, WTF::NakedPtr<JSC::Exception>&);
bool load(JSC::VM& vm, Zig::GlobalObject* globalObject, JSGlobalObject* functionGlobalObject, WTF::NakedPtr<JSC::Exception>&);
DECLARE_INFO;
DECLARE_VISIT_CHILDREN;

View File

@@ -15,6 +15,7 @@
#include "NodeModuleModule.h"
#include "CommonJSModuleRecord.h"
#include "ErrorCode.h"
#include <JavaScriptCore/LazyPropertyInlines.h>
#include <JavaScriptCore/VMTrapsInlines.h>
@@ -624,10 +625,30 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionInitPaths, (JSGlobalObject * globalObject,
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_CUSTOM_GETTER(getterModuleConstructor,
(JSGlobalObject * lexicalGlobalObject,
JSC::EncodedJSValue thisValue,
JSC::PropertyName propertyName)) {
auto *globalObject = defaultGlobalObject(lexicalGlobalObject);
return JSValue::encode(
globalObject->m_nodeModuleConstructor.getInitializedOnMainThread(
globalObject));
}
JSC_DEFINE_CUSTOM_SETTER(setterModuleConstructor,
(JSGlobalObject * lexicalGlobalObject,
JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value,
JSC::PropertyName propertyName)) {
return false;
}
static JSValue getModulePrototypeObject(VM &vm, JSObject *moduleObject) {
auto *globalObject = defaultGlobalObject(moduleObject->globalObject());
auto prototype =
constructEmptyObject(globalObject, globalObject->objectPrototype(), 2);
constructEmptyObject(globalObject, globalObject->objectPrototype(), 3);
prototype->structure()->setMayBePrototype(true);
prototype->putDirectCustomAccessor(
vm, WebCore::clientData(vm)->builtinNames().requirePublicName(),
@@ -635,6 +656,18 @@ static JSValue getModulePrototypeObject(VM &vm, JSObject *moduleObject) {
setterRequireFunction),
0);
prototype->putDirectCustomAccessor(
vm, vm.propertyNames->constructor,
JSC::CustomGetterSetter::create(vm, getterModuleConstructor,
setterModuleConstructor),
PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
prototype->putDirectNativeFunction(
vm, globalObject, Identifier::fromString(vm, "_compile"_s), 1,
jsFunctionCommonJSModuleRecord_compile,
JSC::ImplementationVisibility::Public, NoIntrinsic,
JSC::PropertyAttribute::DontEnum | 0);
return prototype;
}

View File

@@ -23,6 +23,14 @@ test("module.globalPaths exists", () => {
expect(Array.isArray(require("module").globalPaths)).toBe(true);
});
test("_compile exists", () => {
const m = new Module("asdf");
Module.prototype._compile.call(m, "exports.foo = 1; return 42", "asdf");
expect(m.exports.foo).toBe(1);
Module.prototype._compile.call(m, "exports.foo = 2; return 42", "asdf");
expect(m.exports.foo).toBe(2);
});
test("createRequire trailing slash", () => {
const req = createRequire(import.meta.dir + "/");
expect(req.resolve("./node-module-module.test.js")).toBe(