JSModuleNamespaceObject.cpp [plain text]
#include "config.h"
#include "JSModuleNamespaceObject.h"
#include "AbstractModuleRecord.h"
#include "JSCInlines.h"
#include "JSModuleEnvironment.h"
namespace JSC {
const ClassInfo JSModuleNamespaceObject::s_info = { "ModuleNamespaceObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSModuleNamespaceObject) };
JSModuleNamespaceObject::JSModuleNamespaceObject(VM& vm, Structure* structure)
: Base(vm, structure)
, m_exports()
{
}
void JSModuleNamespaceObject::finishCreation(JSGlobalObject* globalObject, AbstractModuleRecord* moduleRecord, Vector<std::pair<Identifier, AbstractModuleRecord::Resolution>>&& resolutions)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
Base::finishCreation(vm);
ASSERT(inherits(vm, info()));
std::sort(resolutions.begin(), resolutions.end(), [] (const auto& lhs, const auto& rhs) {
return codePointCompare(lhs.first.impl(), rhs.first.impl()) < 0;
});
m_moduleRecord.set(vm, this, moduleRecord);
m_names.reserveCapacity(resolutions.size());
{
auto locker = holdLock(cellLock());
for (const auto& pair : resolutions) {
m_names.append(pair.first);
auto addResult = m_exports.add(pair.first.impl(), ExportEntry());
addResult.iterator->value.localName = pair.second.localName;
addResult.iterator->value.moduleRecord.set(vm, this, pair.second.moduleRecord);
}
}
putDirect(vm, vm.propertyNames->toStringTagSymbol, jsNontrivialString(vm, "Module"_s), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
methodTable(vm)->preventExtensions(this, globalObject);
scope.assertNoException();
}
void JSModuleNamespaceObject::destroy(JSCell* cell)
{
JSModuleNamespaceObject* thisObject = static_cast<JSModuleNamespaceObject*>(cell);
thisObject->JSModuleNamespaceObject::~JSModuleNamespaceObject();
}
void JSModuleNamespaceObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
visitor.append(thisObject->m_moduleRecord);
{
auto locker = holdLock(thisObject->cellLock());
for (auto& pair : thisObject->m_exports)
visitor.appendHidden(pair.value.moduleRecord);
}
}
static JSValue getValue(JSModuleEnvironment* environment, PropertyName localName, ScopeOffset& scopeOffset)
{
SymbolTable* symbolTable = environment->symbolTable();
{
ConcurrentJSLocker locker(symbolTable->m_lock);
auto iter = symbolTable->find(locker, localName.uid());
ASSERT(iter != symbolTable->end(locker));
SymbolTableEntry& entry = iter->value;
ASSERT(!entry.isNull());
scopeOffset = entry.scopeOffset();
}
return environment->variableAt(scopeOffset).get();
}
bool JSModuleNamespaceObject::getOwnPropertySlotCommon(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (propertyName.isSymbol())
return JSObject::getOwnPropertySlot(this, globalObject, propertyName, slot);
slot.setIsTaintedByOpaqueObject();
auto iterator = m_exports.find(propertyName.uid());
if (iterator == m_exports.end())
return false;
ExportEntry& exportEntry = iterator->value;
switch (slot.internalMethodType()) {
case PropertySlot::InternalMethodType::GetOwnProperty:
case PropertySlot::InternalMethodType::Get: {
JSModuleEnvironment* environment = exportEntry.moduleRecord->moduleEnvironment();
ScopeOffset scopeOffset;
JSValue value = getValue(environment, exportEntry.localName, scopeOffset);
if (!value) {
throwVMError(globalObject, scope, createTDZError(globalObject));
return false;
}
slot.setValueModuleNamespace(this, static_cast<unsigned>(PropertyAttribute::DontDelete), value, environment, scopeOffset);
return true;
}
case PropertySlot::InternalMethodType::HasProperty: {
slot.setValue(this, static_cast<unsigned>(PropertyAttribute::DontDelete), jsUndefined());
return true;
}
case PropertySlot::InternalMethodType::VMInquiry:
slot.setValue(this, static_cast<unsigned>(JSC::PropertyAttribute::None), jsUndefined());
return false;
}
RELEASE_ASSERT_NOT_REACHED();
return false;
}
bool JSModuleNamespaceObject::getOwnPropertySlot(JSObject* cell, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
{
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
return thisObject->getOwnPropertySlotCommon(globalObject, propertyName, slot);
}
bool JSModuleNamespaceObject::getOwnPropertySlotByIndex(JSObject* cell, JSGlobalObject* globalObject, unsigned propertyName, PropertySlot& slot)
{
VM& vm = globalObject->vm();
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
return thisObject->getOwnPropertySlotCommon(globalObject, Identifier::from(vm, propertyName), slot);
}
bool JSModuleNamespaceObject::put(JSCell*, JSGlobalObject* globalObject, PropertyName, JSValue, PutPropertySlot& slot)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (slot.isStrictMode())
throwTypeError(globalObject, scope, ReadonlyPropertyWriteError);
return false;
}
bool JSModuleNamespaceObject::putByIndex(JSCell*, JSGlobalObject* globalObject, unsigned, JSValue, bool shouldThrow)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (shouldThrow)
throwTypeError(globalObject, scope, ReadonlyPropertyWriteError);
return false;
}
bool JSModuleNamespaceObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, DeletePropertySlot& slot)
{
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
if (propertyName.isSymbol())
return JSObject::deleteProperty(thisObject, globalObject, propertyName, slot);
return !thisObject->m_exports.contains(propertyName.uid());
}
void JSModuleNamespaceObject::getOwnPropertyNames(JSObject* cell, JSGlobalObject* globalObject, PropertyNameArray& propertyNames, EnumerationMode mode)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
for (const auto& name : thisObject->m_names) {
if (!mode.includeDontEnumProperties()) {
PropertySlot slot(cell, PropertySlot::InternalMethodType::GetOwnProperty);
thisObject->getOwnPropertySlotCommon(globalObject, name.impl(), slot);
RETURN_IF_EXCEPTION(scope, void());
}
propertyNames.add(name.impl());
}
JSObject::getOwnPropertyNames(thisObject, globalObject, propertyNames, mode);
}
bool JSModuleNamespaceObject::defineOwnProperty(JSObject*, JSGlobalObject* globalObject, PropertyName, const PropertyDescriptor&, bool shouldThrow)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (shouldThrow)
throwTypeError(globalObject, scope, NonExtensibleObjectPropertyDefineError);
return false;
}
}