#include "config.h"
#include "DebuggerScope.h"
#include "JSLexicalEnvironment.h"
#include "JSCInlines.h"
#include "JSWithScope.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DebuggerScope);
const ClassInfo DebuggerScope::s_info = { "DebuggerScope", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DebuggerScope) };
DebuggerScope* DebuggerScope::create(VM& vm, JSScope* scope)
{
Structure* structure = scope->globalObject()->debuggerScopeStructure();
DebuggerScope* debuggerScope = new (NotNull, allocateCell<DebuggerScope>(vm.heap)) DebuggerScope(vm, structure, scope);
debuggerScope->finishCreation(vm);
return debuggerScope;
}
DebuggerScope::DebuggerScope(VM& vm, Structure* structure, JSScope* scope)
: JSNonFinalObject(vm, structure)
{
ASSERT(scope);
m_scope.set(vm, this, scope);
}
void DebuggerScope::finishCreation(VM& vm)
{
Base::finishCreation(vm);
}
void DebuggerScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
JSObject::visitChildren(thisObject, visitor);
visitor.append(thisObject->m_scope);
visitor.append(thisObject->m_next);
}
String DebuggerScope::className(const JSObject* object)
{
const DebuggerScope* scope = jsCast<const DebuggerScope*>(object);
if (!scope->isValid())
return String();
JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
return thisObject->methodTable()->className(thisObject);
}
bool DebuggerScope::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
DebuggerScope* scope = jsCast<DebuggerScope*>(object);
if (!scope->isValid())
return false;
JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
slot.setThisValue(JSValue(thisObject));
bool result = thisObject->getPropertySlot(exec, propertyName, slot);
if (result && slot.isValue() && slot.getValue(exec, propertyName) == jsTDZValue()) {
slot.setValue(slot.slotBase(), static_cast<unsigned>(PropertyAttribute::DontEnum), jsUndefined());
return true;
}
return result;
}
bool DebuggerScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
DebuggerScope* scope = jsCast<DebuggerScope*>(cell);
ASSERT(scope->isValid());
if (!scope->isValid())
return false;
JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
slot.setThisValue(JSValue(thisObject));
return thisObject->methodTable()->put(thisObject, exec, propertyName, value, slot);
}
bool DebuggerScope::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
{
DebuggerScope* scope = jsCast<DebuggerScope*>(cell);
ASSERT(scope->isValid());
if (!scope->isValid())
return false;
JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
return thisObject->methodTable()->deleteProperty(thisObject, exec, propertyName);
}
void DebuggerScope::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
DebuggerScope* scope = jsCast<DebuggerScope*>(object);
ASSERT(scope->isValid());
if (!scope->isValid())
return;
JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
thisObject->methodTable()->getPropertyNames(thisObject, exec, propertyNames, mode);
}
bool DebuggerScope::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
{
DebuggerScope* scope = jsCast<DebuggerScope*>(object);
ASSERT(scope->isValid());
if (!scope->isValid())
return false;
JSObject* thisObject = JSScope::objectAtScope(scope->jsScope());
return thisObject->methodTable()->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
}
DebuggerScope* DebuggerScope::next()
{
ASSERT(isValid());
if (!m_next && m_scope->next()) {
VM& vm = *m_scope->vm();
DebuggerScope* nextScope = create(vm, m_scope->next());
m_next.set(vm, this, nextScope);
}
return m_next.get();
}
void DebuggerScope::invalidateChain()
{
if (!isValid())
return;
DebuggerScope* scope = this;
while (scope) {
DebuggerScope* nextScope = scope->m_next.get();
scope->m_next.clear();
scope->m_scope.clear(); scope = nextScope;
}
}
bool DebuggerScope::isCatchScope() const
{
return m_scope->isCatchScope();
}
bool DebuggerScope::isFunctionNameScope() const
{
return m_scope->isFunctionNameScopeObject();
}
bool DebuggerScope::isWithScope() const
{
return m_scope->isWithScope();
}
bool DebuggerScope::isGlobalScope() const
{
return m_scope->isGlobalObject();
}
bool DebuggerScope::isGlobalLexicalEnvironment() const
{
return m_scope->isGlobalLexicalEnvironment();
}
bool DebuggerScope::isClosureScope() const
{
return m_scope->isVarScope() || m_scope->isLexicalScope();
}
bool DebuggerScope::isNestedLexicalScope() const
{
return m_scope->isNestedLexicalScope();
}
String DebuggerScope::name() const
{
SymbolTable* symbolTable = m_scope->symbolTable(*vm());
if (!symbolTable)
return String();
CodeBlock* codeBlock = symbolTable->rareDataCodeBlock();
if (!codeBlock)
return String();
return String::fromUTF8(codeBlock->inferredName());
}
DebuggerLocation DebuggerScope::location() const
{
SymbolTable* symbolTable = m_scope->symbolTable(*vm());
if (!symbolTable)
return DebuggerLocation();
CodeBlock* codeBlock = symbolTable->rareDataCodeBlock();
if (!codeBlock)
return DebuggerLocation();
ScriptExecutable* executable = codeBlock->ownerScriptExecutable();
return DebuggerLocation(executable);
}
JSValue DebuggerScope::caughtValue(ExecState* exec) const
{
ASSERT(isCatchScope());
JSLexicalEnvironment* catchEnvironment = jsCast<JSLexicalEnvironment*>(m_scope.get());
SymbolTable* catchSymbolTable = catchEnvironment->symbolTable();
RELEASE_ASSERT(catchSymbolTable->size() == 1);
PropertyName errorName(catchSymbolTable->begin(catchSymbolTable->m_lock)->key.get());
PropertySlot slot(m_scope.get(), PropertySlot::InternalMethodType::Get);
bool success = catchEnvironment->getOwnPropertySlot(catchEnvironment, exec, errorName, slot);
RELEASE_ASSERT(success && slot.isValue());
return slot.getValue(exec, errorName);
}
}