JSModuleNamespaceObject.cpp [plain text]
#include "config.h"
#include "JSModuleNamespaceObject.h"
#include "AbstractModuleRecord.h"
#include "Error.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(ExecState* exec, JSGlobalObject*, AbstractModuleRecord* moduleRecord, Vector<std::pair<Identifier, AbstractModuleRecord::Resolution>>&& resolutions)
{
VM& vm = exec->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);
{
unsigned moduleRecordOffset = 0;
m_names.reserveCapacity(resolutions.size());
for (const auto& pair : resolutions) {
moduleRecordAt(moduleRecordOffset).set(vm, this, pair.second.moduleRecord);
m_names.append(pair.first);
m_exports.add(pair.first.impl(), ExportEntry {
pair.second.localName,
moduleRecordOffset
});
++moduleRecordOffset;
}
}
putDirect(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Module"), DontEnum | DontDelete | ReadOnly);
methodTable(vm)->preventExtensions(this, exec);
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);
for (unsigned i = 0; i < thisObject->m_names.size(); ++i)
visitor.appendHidden(thisObject->moduleRecordAt(i));
}
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(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (propertyName.isSymbol())
return JSObject::getOwnPropertySlot(this, exec, 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 = moduleRecordAt(exportEntry.moduleRecordOffset)->moduleEnvironment();
ScopeOffset scopeOffset;
JSValue value = getValue(environment, exportEntry.localName, scopeOffset);
if (!value) {
throwVMError(exec, scope, createTDZError(exec));
return false;
}
slot.setValueModuleNamespace(this, DontDelete, value, environment, scopeOffset);
return true;
}
case PropertySlot::InternalMethodType::HasProperty: {
slot.setValue(this, DontDelete, jsUndefined());
return true;
}
case PropertySlot::InternalMethodType::VMInquiry:
return false;
}
RELEASE_ASSERT_NOT_REACHED();
return false;
}
bool JSModuleNamespaceObject::getOwnPropertySlot(JSObject* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
return thisObject->getOwnPropertySlotCommon(exec, propertyName, slot);
}
bool JSModuleNamespaceObject::getOwnPropertySlotByIndex(JSObject* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
{
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
return thisObject->getOwnPropertySlotCommon(exec, Identifier::from(exec, propertyName), slot);
}
bool JSModuleNamespaceObject::put(JSCell*, ExecState* exec, PropertyName, JSValue, PutPropertySlot& slot)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (slot.isStrictMode())
throwTypeError(exec, scope, ASCIILiteral(ReadonlyPropertyWriteError));
return false;
}
bool JSModuleNamespaceObject::putByIndex(JSCell*, ExecState* exec, unsigned, JSValue, bool shouldThrow)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (shouldThrow)
throwTypeError(exec, scope, ASCIILiteral(ReadonlyPropertyWriteError));
return false;
}
bool JSModuleNamespaceObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
{
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
if (propertyName.isSymbol())
return JSObject::deleteProperty(thisObject, exec, propertyName);
return !thisObject->m_exports.contains(propertyName.uid());
}
void JSModuleNamespaceObject::getOwnPropertyNames(JSObject* cell, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
for (const auto& name : thisObject->m_names)
propertyNames.add(name.impl());
return JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
}
bool JSModuleNamespaceObject::defineOwnProperty(JSObject*, ExecState* exec, PropertyName, const PropertyDescriptor&, bool shouldThrow)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (shouldThrow)
throwTypeError(exec, scope, ASCIILiteral(NonExtensibleObjectPropertyDefineError));
return false;
}
}