diff options
author | 2023-07-11 19:14:34 -0700 | |
---|---|---|
committer | 2023-07-11 19:14:34 -0700 | |
commit | cbb88672f217a90db1aa1eb29cd92d5d9035b22b (patch) | |
tree | 43a00501f3cde495967e116f0b660777051551f8 /src/bun.js/bindings/ImportMetaObject.cpp | |
parent | 1f900cff453700b19bca2acadfe26da4468c1282 (diff) | |
parent | 34b0e7a2bbd8bf8097341cdb0075d0908283e834 (diff) | |
download | bun-jarred/esm-conditions.tar.gz bun-jarred/esm-conditions.tar.zst bun-jarred/esm-conditions.zip |
Merge branch 'main' into jarred/esm-conditionsjarred/esm-conditions
Diffstat (limited to 'src/bun.js/bindings/ImportMetaObject.cpp')
-rw-r--r-- | src/bun.js/bindings/ImportMetaObject.cpp | 597 |
1 files changed, 402 insertions, 195 deletions
diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp index a53712823..037305c81 100644 --- a/src/bun.js/bindings/ImportMetaObject.cpp +++ b/src/bun.js/bindings/ImportMetaObject.cpp @@ -38,6 +38,9 @@ #include "JSDOMURL.h" #include "JavaScriptCore/JSNativeStdFunction.h" #include "JavaScriptCore/GetterSetter.h" +#include <JavaScriptCore/LazyProperty.h> +#include <JavaScriptCore/LazyPropertyInlines.h> +#include <JavaScriptCore/VMTrapsInlines.h> namespace Zig { using namespace JSC; @@ -56,6 +59,7 @@ static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject, return JSC::JSValue::encode(JSC::JSValue {}); } default: { + JSValue thisValue = callFrame->thisValue(); JSC::JSValue moduleName = callFrame->argument(0); auto doIt = [&](const WTF::String& fromStr) -> JSC::EncodedJSValue { @@ -83,10 +87,12 @@ static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject, // require.resolve also supports a paths array // we only support a single path if (!fromValue.isUndefinedOrNull() && fromValue.isObject()) { - if (JSValue pathsValue = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) { - if (JSC::JSArray* array = JSC::jsDynamicCast<JSC::JSArray*>(pathsValue)) { - if (array->length() > 0) { - fromValue = array->getIndex(globalObject, 0); + if (auto pathsObject = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) { + if (pathsObject.isCell() && pathsObject.asCell()->type() == JSC::JSType::ArrayType) { + auto pathsArray = JSC::jsCast<JSC::JSArray*>(pathsObject); + if (pathsArray->length() > 0) { + fromValue = pathsArray->getIndex(globalObject, 0); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {})); } } } @@ -123,216 +129,265 @@ Zig::ImportMetaObject* Zig::ImportMetaObject::create(JSC::JSGlobalObject* global } JSC_DECLARE_HOST_FUNCTION(jsFunctionRequireResolve); +JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireResolve, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + JSValue thisValue = callFrame->thisValue(); + WTF::String fromStr; -class JSRequireResolveFunctionPrototype final : public JSC::InternalFunction { -public: - using Base = JSC::InternalFunction; - - static JSRequireResolveFunctionPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject) - { - auto* structure = createStructure(vm, globalObject, globalObject->functionPrototype()); - JSRequireResolveFunctionPrototype* function = new (NotNull, JSC::allocateCell<JSRequireResolveFunctionPrototype>(vm)) JSRequireResolveFunctionPrototype(vm, structure); - function->finishCreation(vm); - return function; + if (thisValue.isString()) { + fromStr = thisValue.toWTFString(globalObject); } - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info()); - } + return functionRequireResolve(globalObject, callFrame, fromStr); +} - DECLARE_INFO; +JSC_DEFINE_CUSTOM_GETTER(jsRequireCacheGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + Zig::GlobalObject* thisObject = jsCast<Zig::GlobalObject*>(globalObject); + return JSValue::encode(thisObject->lazyRequireCacheObject()); +} + +JSC_DEFINE_CUSTOM_SETTER(jsRequireCacheSetter, + (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName propertyName)) +{ + JSObject* thisObject = jsDynamicCast<JSObject*>(JSValue::decode(thisValue)); + if (!thisObject) + return false; + + thisObject->putDirect(globalObject->vm(), propertyName, JSValue::decode(value), 0); + return true; +} - static JSC::EncodedJSValue pathsFunction(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +JSC_DEFINE_HOST_FUNCTION(requireResolvePathsFunction, (JSGlobalObject * globalObject, CallFrame* callframe)) +{ + return JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr, 0)); +} + +static const HashTableValue RequireResolveFunctionPrototypeValues[] = { + { "paths"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, requireResolvePathsFunction, 1 } }, +}; + +class RequireResolveFunctionPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + static RequireResolveFunctionPrototype* create( + JSC::JSGlobalObject* globalObject) { - return JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr)); + auto& vm = globalObject->vm(); + + auto* structure = RequireResolveFunctionPrototype::createStructure(vm, globalObject, globalObject->functionPrototype()); + RequireResolveFunctionPrototype* prototype = new (NotNull, JSC::allocateCell<RequireResolveFunctionPrototype>(vm)) RequireResolveFunctionPrototype(vm, structure); + prototype->finishCreation(vm); + return prototype; } -private: - JSRequireResolveFunctionPrototype(JSC::VM& vm, JSC::Structure* structure) - : JSC::InternalFunction(vm, structure, jsFunctionRequireResolve, jsFunctionRequireResolve) + DECLARE_INFO; + RequireResolveFunctionPrototype( + JSC::VM& vm, + JSC::Structure* structure) + : Base(vm, structure) { } - void finishCreation(JSC::VM& vm) + template<typename CellType, JSC::SubspaceAccess> + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { - this->putDirectNativeFunction(vm, globalObject(), Identifier::fromString(vm, "paths"_s), 0, pathsFunction, ImplementationVisibility::Public, NoIntrinsic, 0); - Base::finishCreation(vm, 2, "resolve"_s, PropertyAdditionMode::WithoutStructureTransition); + return &vm.plainObjectSpace(); } }; -const JSC::ClassInfo JSRequireResolveFunctionPrototype::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRequireResolveFunctionPrototype) }; +class ResolveFunction final : public JSC::InternalFunction { -class JSRequireResolveFunction final : public JSC::InternalFunction { public: using Base = JSC::InternalFunction; - - static JSRequireResolveFunction* create(JSC::VM& vm, JSC::Structure* structure, const WTF::String& from) - { - JSRequireResolveFunction* function = new (NotNull, JSC::allocateCell<JSRequireResolveFunction>(vm)) JSRequireResolveFunction(vm, structure, from); - function->finishCreation(vm); - return function; - } - - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + static ResolveFunction* create(JSGlobalObject* globalObject) { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info()); + JSObject* resolvePrototype = RequireResolveFunctionPrototype::create(globalObject); + Structure* structure = Structure::create( + globalObject->vm(), + globalObject, + resolvePrototype, + JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), + ResolveFunction::info()); + auto* resolveFunction = new (NotNull, JSC::allocateCell<ResolveFunction>(globalObject->vm())) ResolveFunction(globalObject->vm(), structure); + resolveFunction->finishCreation(globalObject->vm()); + return resolveFunction; } DECLARE_INFO; - WTF::String from; - - template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - - return WebCore::subspaceForImpl<JSRequireResolveFunction, UseCustomHeapCellType::No>( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForRequireResolveFunction.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForRequireResolveFunction = std::forward<decltype(space)>(space); }, - [](auto& spaces) { return spaces.m_subspaceForRequireResolveFunction.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForRequireResolveFunction = std::forward<decltype(space)>(space); }); - } - -private: - JSRequireResolveFunction(JSC::VM& vm, JSC::Structure* structure, const WTF::String& from_) - : JSC::InternalFunction(vm, structure, jsFunctionRequireResolve, jsFunctionRequireResolve) - , from(from_) + template<typename CellType, JSC::SubspaceAccess> + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + return &vm.internalFunctionSpace(); } - void finishCreation(JSC::VM& vm) + ResolveFunction( + JSC::VM& vm, + JSC::Structure* structure) + : InternalFunction(vm, structure, jsFunctionRequireResolve, nullptr) { - Base::finishCreation(vm); } }; -const JSC::ClassInfo JSRequireResolveFunction::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRequireResolveFunction) }; - -JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireResolve, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +JSObject* Zig::ImportMetaObject::createRequireResolveFunctionUnbound(VM& vm, JSGlobalObject* globalObject) { - JSRequireResolveFunction* thisObject = JSC::jsCast<JSRequireResolveFunction*>(callFrame->jsCallee()); - return functionRequireResolve(globalObject, callFrame, thisObject->from); + return ResolveFunction::create(globalObject); } -JSValue Zig::ImportMetaObject::createResolveFunctionPrototype(JSC::VM& vm, Zig::GlobalObject* globalObject) +JSObject* Zig::ImportMetaObject::createRequireFunctionUnbound(VM& vm, JSGlobalObject* globalObject) { - return JSRequireResolveFunctionPrototype::create(vm, globalObject); -} + auto& builtinNames = WebCore::builtinNames(vm); -JSC::Structure* Zig::ImportMetaObject::createResolveFunctionStructure(JSC::VM& vm, Zig::GlobalObject* globalObject) -{ - JSValue prototype = globalObject->requireResolveFunctionPrototype(); - return JSRequireResolveFunction::createStructure(vm, globalObject, prototype); -} + JSC::JSFunction* requireDotMainFunction = JSFunction::create( + vm, + moduleMainCodeGenerator(vm), + globalObject->globalScope()); -JSC_DEFINE_CUSTOM_GETTER(jsRequireCacheGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) -{ - Zig::GlobalObject* thisObject = jsCast<Zig::GlobalObject*>(globalObject); - return JSValue::encode(thisObject->lazyRequireCacheObject()); + auto* prototype = JSC::constructEmptyObject(globalObject, globalObject->functionPrototype()); + prototype->putDirect( + vm, + JSC::Identifier::fromString(vm, "main"_s), + JSC::GetterSetter::create(vm, globalObject, requireDotMainFunction, JSValue()), + PropertyAttribute::Builtin | PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | 0); + prototype->putDirect(vm, JSC::Identifier::fromString(vm, "extensions"_s), constructEmptyObject(globalObject), 0); + prototype->putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "cache"_s), JSC::CustomGetterSetter::create(vm, Zig::jsRequireCacheGetter, Zig::jsRequireCacheSetter), 0); + return JSFunction::create(vm, importMetaObjectRequireCodeGenerator(vm), globalObject, JSFunction::createStructure(vm, globalObject, prototype)); } -JSC_DEFINE_CUSTOM_SETTER(jsRequireCacheSetter, - (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, - JSC::EncodedJSValue value, JSC::PropertyName propertyName)) +JSObject* Zig::ImportMetaObject::createRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString) { - JSObject* thisObject = jsDynamicCast<JSObject*>(JSValue::decode(thisValue)); - if (!thisObject) - return false; + auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject); + auto& builtinNames = WebCore::builtinNames(vm); - thisObject->putDirect(globalObject->vm(), propertyName, JSValue::decode(value), 0); - return true; -} + JSFunction* resolveFunctionUnbound = jsCast<JSFunction*>(globalObject->importMetaRequireResolveFunctionUnbound()); + JSFunction* requireFunctionUnbound = jsCast<JSFunction*>(globalObject->importMetaRequireFunctionUnbound()); + auto str = jsString(vm, pathString); + + JSFunction* requireFunction = JSC::JSBoundFunction::create(vm, + globalObject, requireFunctionUnbound, + str, ArgList(), 1, jsString(vm, String("require"_s))); + + JSFunction* resolveFunction = JSC::JSBoundFunction::create(vm, + globalObject, resolveFunctionUnbound, + str, ArgList(), 2, jsString(vm, String("resolve"_s))); + + requireFunction->putDirect(vm, builtinNames.resolvePublicName(), resolveFunction, PropertyAttribute::Function | 0); -JSObject* Zig::ImportMetaObject::createRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString) -{ - Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(lexicalGlobalObject); - JSFunction* requireFunction = JSFunction::create(vm, importMetaObjectRequireCodeGenerator(vm), globalObject); - auto* resolveFunction = JSRequireResolveFunction::create(vm, globalObject->requireResolveFunctionStructure(), pathString); - auto clientData = WebCore::clientData(vm); - requireFunction->putDirect(vm, clientData->builtinNames().pathPublicName(), jsString(vm, pathString), PropertyAttribute::DontEnum | 0); - requireFunction->putDirect(vm, clientData->builtinNames().resolvePublicName(), resolveFunction, PropertyAttribute::Function | PropertyAttribute::DontDelete | 0); - requireFunction->putDirectCustomAccessor(vm, Identifier::fromString(vm, "cache"_s), JSC::CustomGetterSetter::create(vm, jsRequireCacheGetter, jsRequireCacheSetter), 0); return requireFunction; } +const JSC::ClassInfo RequireResolveFunctionPrototype::s_info = { "resolve"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RequireResolveFunctionPrototype) }; +const JSC::ClassInfo ResolveFunction::s_info = { "resolve"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ResolveFunction) }; + extern "C" EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) { JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); - switch (callFrame->argumentCount()) { - case 0: { + JSValue thisValue = callFrame->thisValue(); + JSC::JSValue moduleName = callFrame->argument(0); + JSC::JSValue fromValue = callFrame->argument(1); - // not "requires" because "require" could be confusing - JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync needs 1 argument (a string)"_s); + if (moduleName.isUndefinedOrNull()) { + JSC::throwTypeError(globalObject, scope, "expects a string"_s); scope.release(); return JSC::JSValue::encode(JSC::JSValue {}); } - default: { - JSC::JSValue moduleName = callFrame->argument(0); - if (moduleName.isUndefinedOrNull()) { - JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync expects a string"_s); - scope.release(); - return JSC::JSValue::encode(JSC::JSValue {}); - } + JSC__JSValue from; + bool isESM = true; - JSC__JSValue from; - bool isESM = true; + if (callFrame->argumentCount() > 1) { - if (callFrame->argumentCount() > 1) { - JSC::JSValue fromValue = callFrame->argument(1); + if (callFrame->argumentCount() > 2) { + JSC::JSValue isESMValue = callFrame->argument(2); + if (isESMValue.isBoolean()) { + isESM = isESMValue.toBoolean(globalObject); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {})); + } + } - // require.resolve also supports a paths array - // we only support a single path - if (!fromValue.isUndefinedOrNull() && fromValue.isObject()) { - if (JSC::JSArray* array = JSC::jsDynamicCast<JSC::JSArray*>(fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s)))) { - if (array->length() > 0) { - fromValue = array->getIndex(globalObject, 0); - } - } + if (!fromValue.isUndefinedOrNull() && fromValue.isObject()) { - if (callFrame->argumentCount() > 2) { - JSC::JSValue isESMValue = callFrame->argument(2); - if (isESMValue.isBoolean()) { - isESM = isESMValue.toBoolean(globalObject); + if (auto pathsObject = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) { + if (pathsObject.isCell() && pathsObject.asCell()->type() == JSC::JSType::ArrayType) { + auto pathsArray = JSC::jsCast<JSC::JSArray*>(pathsObject); + if (pathsArray->length() > 0) { + fromValue = pathsArray->getIndex(globalObject, 0); RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {})); } } - } else if (fromValue.isBoolean()) { - isESM = fromValue.toBoolean(globalObject); - RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {})); - } - from = JSC::JSValue::encode(fromValue); - - } else { - JSC::JSObject* thisObject = JSC::jsDynamicCast<JSC::JSObject*>(callFrame->thisValue()); - if (UNLIKELY(!thisObject)) { - auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); - JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync must be bound to an import.meta object"_s); - return JSC::JSValue::encode(JSC::JSValue {}); } - auto clientData = WebCore::clientData(vm); - - from = JSC::JSValue::encode(thisObject->get(globalObject, clientData->builtinNames().pathPublicName())); + } else if (fromValue.isBoolean()) { + isESM = fromValue.toBoolean(globalObject); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {})); + fromValue = JSC::jsUndefined(); } - auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, isESM); + if (fromValue.isString()) { + from = JSC::JSValue::encode(fromValue); + } else if (thisValue.isString()) { + from = JSC::JSValue::encode(thisValue); + } - if (!JSC::JSValue::decode(result).isString()) { - JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); + } else if (thisValue.isString()) { + from = JSC::JSValue::encode(thisValue); + } else { + JSC::JSObject* thisObject = JSC::jsDynamicCast<JSC::JSObject*>(thisValue); + if (UNLIKELY(!thisObject)) { + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync must be bound to an import.meta object"_s); return JSC::JSValue::encode(JSC::JSValue {}); } + auto clientData = WebCore::clientData(vm); + JSValue pathProperty = thisObject->getIfPropertyExists(globalObject, clientData->builtinNames().pathPublicName()); + + if (pathProperty && pathProperty.isString()) + from = JSC::JSValue::encode(pathProperty); + } + + auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, isESM); + + if (!JSC::JSValue::decode(result).isString()) { + JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + scope.release(); + return result; +} + +extern "C" EncodedJSValue functionImportMeta__resolveSyncPrivate(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + JSC::VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + + JSC::JSValue moduleName = callFrame->argument(0); + JSValue from = callFrame->argument(1); + bool isESM = callFrame->argument(2).asBoolean(); + + if (moduleName.isUndefinedOrNull()) { + JSC::throwTypeError(globalObject, scope, "expected module name as a string"_s); scope.release(); - return result; + return JSC::JSValue::encode(JSC::JSValue {}); } + + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {})); + + auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), JSValue::encode(from), isESM); + + if (!JSC::JSValue::decode(result).isString()) { + JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); + return JSC::JSValue::encode(JSC::JSValue {}); } + + scope.release(); + return result; } JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolve); @@ -362,7 +417,7 @@ JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve, JSC__JSValue from; - if (callFrame->argumentCount() > 1) { + if (callFrame->argumentCount() > 1 && callFrame->argument(1).isString()) { from = JSC::JSValue::encode(callFrame->argument(1)); } else { JSC::JSObject* thisObject = JSC::jsDynamicCast<JSC::JSObject*>(callFrame->thisValue()); @@ -374,7 +429,7 @@ JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve, auto clientData = WebCore::clientData(vm); - from = JSC::JSValue::encode(thisObject->get(globalObject, clientData->builtinNames().pathPublicName())); + from = JSC::JSValue::encode(thisObject->getIfPropertyExists(globalObject, clientData->builtinNames().pathPublicName())); } return Bun__resolve(globalObject, JSC::JSValue::encode(moduleName), from, true); @@ -382,89 +437,244 @@ JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve, } } +enum class ImportMetaPropertyOffset : uint32_t { + url, + dir, + file, + path, + require, + +}; +static constexpr uint32_t numberOfImportMetaProperties = 5; + +Zig::ImportMetaObject* ImportMetaObject::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, const WTF::String& url) +{ + ImportMetaObject* ptr = new (NotNull, JSC::allocateCell<ImportMetaObject>(vm)) ImportMetaObject(vm, structure, url); + ptr->finishCreation(vm); + return ptr; +} +Zig::ImportMetaObject* ImportMetaObject::create(JSC::JSGlobalObject* jslobalObject, JSC::JSString* keyString) +{ + auto* globalObject = jsCast<Zig::GlobalObject*>(jslobalObject); + auto& vm = globalObject->vm(); + auto view = keyString->value(globalObject); + JSC::Structure* structure = globalObject->ImportMetaObjectStructure(); + return Zig::ImportMetaObject::create(vm, globalObject, structure, view); +} + +JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_url, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName propertyName)) +{ + ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(thisObject->urlProperty.getInitializedOnMainThread(thisObject)); +} +JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_dir, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName propertyName)) +{ + ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(thisObject->dirProperty.getInitializedOnMainThread(thisObject)); +} +JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_file, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName propertyName)) +{ + ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(thisObject->fileProperty.getInitializedOnMainThread(thisObject)); +} +JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_path, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName propertyName)) +{ + ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(thisObject->pathProperty.getInitializedOnMainThread(thisObject)); +} +JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_require, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName propertyName)) +{ + ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(thisObject->requireProperty.getInitializedOnMainThread(thisObject)); +} + +static const HashTableValue ImportMetaObjectPrototypeValues[] = { + { "resolve"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, functionImportMeta__resolve, 0 } }, + { "resolveSync"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, functionImportMeta__resolveSync, 0 } }, + { "url"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_url, 0 } }, + { "dir"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_dir, 0 } }, + { "file"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_file, 0 } }, + { "path"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_path, 0 } }, + { "require"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_require, 0 } }, +}; + class ImportMetaObjectPrototype final : public JSC::JSNonFinalObject { public: + DECLARE_INFO; using Base = JSC::JSNonFinalObject; - static ImportMetaObjectPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) + static Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { - ImportMetaObjectPrototype* ptr = new (NotNull, JSC::allocateCell<ImportMetaObjectPrototype>(vm)) ImportMetaObjectPrototype(vm, globalObject, structure); - ptr->finishCreation(vm, globalObject); - return ptr; + return Structure::create(vm, globalObject, globalObject->objectPrototype(), TypeInfo(ObjectType, StructureFlags), info()); + } + + static ImportMetaObjectPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + { + ImportMetaObjectPrototype* prototype = new (NotNull, JSC::allocateCell<ImportMetaObjectPrototype>(vm)) ImportMetaObjectPrototype(vm, structure); + prototype->finishCreation(vm, globalObject); + return prototype; } - DECLARE_INFO; template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { return &vm.plainObjectSpace(); } - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + + void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + Base::finishCreation(vm); + + auto* clientData = WebCore::clientData(vm); + auto& builtinNames = clientData->builtinNames(); + + reifyStaticProperties(vm, ImportMetaObject::info(), ImportMetaObjectPrototypeValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); + + this->putDirect( + vm, + builtinNames.mainPublicName(), + GetterSetter::create(vm, globalObject, JSFunction::create(vm, importMetaObjectMainCodeGenerator(vm), globalObject), nullptr), + JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin | 0); } -private: - ImportMetaObjectPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + ImportMetaObjectPrototype(JSC::VM& vm, JSC::Structure* structure) : Base(vm, structure) { } +}; + +const ClassInfo ImportMetaObjectPrototype::s_info = { + "ImportMeta"_s, - void finishCreation(JSC::VM&, JSC::JSGlobalObject*); + Base::info(), nullptr, nullptr, CREATE_METHOD_TABLE(ImportMetaObjectPrototype) }; -STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(ImportMetaObjectPrototype, ImportMetaObjectPrototype::Base); -JSObject* ImportMetaObject::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) +JSC::Structure* ImportMetaObject::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { - return ImportMetaObjectPrototype::create(vm, &globalObject, ImportMetaObjectPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype())); -} + ImportMetaObjectPrototype* prototype = ImportMetaObjectPrototype::create(vm, + globalObject, + ImportMetaObjectPrototype::createStructure(vm, globalObject)); -void ImportMetaObjectPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject_) -{ - Base::finishCreation(vm); - auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject_); auto clientData = WebCore::clientData(vm); - auto& builtinNames = clientData->builtinNames(); - this->putDirect(vm, builtinNames.filePublicName(), jsEmptyString(vm), 0); - this->putDirect(vm, builtinNames.dirPublicName(), jsEmptyString(vm), 0); - this->putDirect(vm, builtinNames.pathPublicName(), jsEmptyString(vm), 0); - this->putDirect(vm, builtinNames.urlPublicName(), jsEmptyString(vm), 0); - - this->putDirect( - vm, - builtinNames.mainPublicName(), - GetterSetter::create(vm, globalObject, JSFunction::create(vm, importMetaObjectMainCodeGenerator(vm), globalObject), nullptr), - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin | 0); - - this->putDirect(vm, Identifier::fromString(vm, "primordials"_s), jsUndefined(), JSC::PropertyAttribute::DontEnum | 0); - - String requireString = "[[require]]"_s; - this->putDirect(vm, builtinNames.requirePublicName(), Zig::ImportMetaObject::createRequireFunction(vm, globalObject, requireString), PropertyAttribute::Builtin | PropertyAttribute::Function | 0); - - this->putDirectNativeFunction(vm, globalObject, builtinNames.resolvePublicName(), 1, - functionImportMeta__resolve, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::Function | 0); - this->putDirectNativeFunction( - vm, globalObject, builtinNames.resolveSyncPublicName(), - 1, - functionImportMeta__resolveSync, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::Function | 0); - - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), ImportMetaObject::info()); } void ImportMetaObject::finishCreation(VM& vm) { Base::finishCreation(vm); ASSERT(inherits(info())); + + this->requireProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSFunction>::Initializer& init) { + ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner); + + WTF::URL url = meta->url.startsWith('/') ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url); + WTF::StringView path; + if (url.protocolIs("file"_s)) { + path = url.fileSystemPath(); + } else { + path = url.path(); + } + + JSFunction* value = jsCast<JSFunction*>(ImportMetaObject::createRequireFunction(init.vm, meta->globalObject(), path.toString())); + init.set(value); + }); + this->urlProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSString>::Initializer& init) { + ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner); + WTF::URL url = meta->url.startsWith('/') ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url); + + init.set(jsString(init.vm, url.string())); + }); + this->dirProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSString>::Initializer& init) { + ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner); + + WTF::URL url = meta->url.startsWith('/') ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url); + WTF::StringView dirname; + + if (url.protocolIs("file"_s)) { + dirname = url.fileSystemPath(); + } else { + dirname = url.path(); + } + + if (dirname.endsWith("/"_s)) { + dirname = dirname.substring(0, dirname.length() - 1); + } else if (dirname.contains('/')) { + dirname = dirname.substring(0, dirname.reverseFind('/')); + } + + init.set(jsString(init.vm, dirname.toString())); + }); + this->fileProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSString>::Initializer& init) { + ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner); + + WTF::URL url = meta->url.startsWith('/') ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url); + WTF::StringView path; + if (url.protocolIs("file"_s)) { + path = url.fileSystemPath(); + } else { + path = url.path(); + } + + WTF::StringView filename; + + if (path.endsWith("/"_s)) { + filename = path.substring(path.reverseFind('/', path.length() - 2) + 1); + } else { + filename = path.substring(path.reverseFind('/') + 1); + } + + init.set(jsString(init.vm, filename.toString())); + }); + this->pathProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSString>::Initializer& init) { + ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner); + + WTF::URL url = meta->url.startsWith('/') ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url); + WTF::StringView path; + + if (url.protocolIs("file"_s)) { + path = url.fileSystemPath(); + } else { + path = url.path(); + } + + init.set(jsString(init.vm, path.toString())); + }); +} + +template<typename Visitor> +void ImportMetaObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + ImportMetaObject* fn = jsCast<ImportMetaObject*>(cell); + ASSERT_GC_OBJECT_INHERITS(fn, info()); + Base::visitChildren(fn, visitor); + + fn->requireProperty.visit(visitor); + fn->urlProperty.visit(visitor); + fn->dirProperty.visit(visitor); + fn->fileProperty.visit(visitor); + fn->pathProperty.visit(visitor); } +DEFINE_VISIT_CHILDREN(ImportMetaObject); + void ImportMetaObject::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) { auto* thisObject = jsCast<ImportMetaObject*>(cell); @@ -475,9 +685,6 @@ void ImportMetaObject::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) Base::analyzeHeap(cell, analyzer); } -const JSC::ClassInfo ImportMetaObjectPrototype::s_info = { "ImportMeta"_s, &Base::s_info, nullptr, nullptr, - CREATE_METHOD_TABLE(ImportMetaObjectPrototype) }; - const JSC::ClassInfo ImportMetaObject::s_info = { "ImportMeta"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ImportMetaObject) }; } |