/src/qt/qtwebkit/Source/JavaScriptCore/runtime/JSScope.cpp
C++ | 635 lines | 532 code | 69 blank | 34 comment | 124 complexity | e86029016e0289dfed5dfd3466e99bcf MD5 | raw file
- /*
- * Copyright (C) 2012 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "config.h"
- #include "JSScope.h"
- #include "JSActivation.h"
- #include "JSGlobalObject.h"
- #include "JSNameScope.h"
- #include "JSWithScope.h"
- #include "Operations.h"
- namespace JSC {
- ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSScope);
- void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
- {
- JSScope* thisObject = jsCast<JSScope*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
- Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_next);
- }
- bool JSScope::isDynamicScope(bool& requiresDynamicChecks) const
- {
- switch (structure()->typeInfo().type()) {
- case GlobalObjectType:
- return static_cast<const JSGlobalObject*>(this)->isDynamicScope(requiresDynamicChecks);
- case ActivationObjectType:
- return static_cast<const JSActivation*>(this)->isDynamicScope(requiresDynamicChecks);
- case NameScopeObjectType:
- return static_cast<const JSNameScope*>(this)->isDynamicScope(requiresDynamicChecks);
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
- return false;
- }
- JSObject* JSScope::objectAtScope(JSScope* scope)
- {
- JSObject* object = scope;
- if (object->structure()->typeInfo().type() == WithScopeType)
- return jsCast<JSWithScope*>(object)->object();
- return object;
- }
- int JSScope::localDepth()
- {
- int scopeDepth = 0;
- ScopeChainIterator iter = this->begin();
- ScopeChainIterator end = this->end();
- while (!iter->inherits(&JSActivation::s_info)) {
- ++iter;
- if (iter == end)
- break;
- ++scopeDepth;
- }
- return scopeDepth;
- }
- struct LookupResult {
- JSValue base() const { return m_base; }
- JSValue value() const { return m_value; }
- void setBase(JSValue base) { ASSERT(base); m_base = base; }
- void setValue(JSValue value) { ASSERT(value); m_value = value; }
- private:
- JSValue m_base;
- JSValue m_value;
- };
- static void setPutPropertyAccessOffset(PutToBaseOperation* operation, PropertyOffset offset)
- {
- ASSERT(isOutOfLineOffset(offset));
- operation->m_offset = offset;
- operation->m_offsetInButterfly = offsetInButterfly(offset);
- }
- static bool executeResolveOperations(CallFrame* callFrame, JSScope* scope, const Identifier& propertyName, ResolveOperation* pc, LookupResult& result)
- {
- while (true) {
- switch (pc->m_operation) {
- case ResolveOperation::Fail:
- return false;
- case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope: {
- while (JSScope* nextScope = scope->next()) {
- if (scope->isActivationObject() && scope->structure() != scope->globalObject()->activationStructure())
- return false;
- ASSERT(scope->isNameScopeObject() || scope->isVariableObject() || scope->isGlobalObject());
- scope = nextScope;
- }
- pc++;
- break;
- }
- case ResolveOperation::SetBaseToUndefined:
- result.setBase(jsUndefined());
- pc++;
- continue;
- case ResolveOperation::SetBaseToScope:
- result.setBase(scope);
- pc++;
- continue;
- case ResolveOperation::ReturnScopeAsBase:
- result.setBase(scope);
- return true;
- case ResolveOperation::SetBaseToGlobal:
- result.setBase(scope->globalObject());
- pc++;
- continue;
- case ResolveOperation::SkipScopes: {
- int count = pc->m_scopesToSkip;
- while (count--)
- scope = scope->next();
- ASSERT(scope);
- pc++;
- continue;
- }
- case ResolveOperation::SkipTopScopeNode:
- if (callFrame->r(pc->m_activationRegister).jsValue())
- scope = scope->next();
- ASSERT(scope);
- pc++;
- continue;
- case ResolveOperation::GetAndReturnScopedVar:
- ASSERT(jsCast<JSVariableObject*>(scope)->registerAt(pc->m_offset).get());
- result.setValue(jsCast<JSVariableObject*>(scope)->registerAt(pc->m_offset).get());
- return true;
- case ResolveOperation::GetAndReturnGlobalVar:
- result.setValue(pc->m_registerAddress->get());
- return true;
- case ResolveOperation::GetAndReturnGlobalVarWatchable:
- result.setValue(pc->m_registerAddress->get());
- return true;
- case ResolveOperation::ReturnGlobalObjectAsBase:
- result.setBase(callFrame->lexicalGlobalObject());
- return true;
- case ResolveOperation::GetAndReturnGlobalProperty: {
- JSGlobalObject* globalObject = scope->globalObject();
- if (globalObject->structure() == pc->m_structure.get()) {
- result.setValue(globalObject->getDirect(pc->m_offset));
- return true;
- }
- PropertySlot slot(globalObject);
- if (!globalObject->getPropertySlot(callFrame, propertyName, slot))
- return false;
- JSValue value = slot.getValue(callFrame, propertyName);
- if (callFrame->hadException())
- return false;
- Structure* structure = globalObject->structure();
- // Don't try to cache prototype lookups
- if (globalObject != slot.slotBase() || !slot.isCacheableValue() || !structure->propertyAccessesAreCacheable()) {
- result.setValue(value);
- return true;
- }
- pc->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), structure);
- pc->m_offset = slot.cachedOffset();
- result.setValue(value);
- return true;
- }
- }
- }
- }
- template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScopeInternal(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool )
- {
- JSScope* scope = callFrame->scope();
- ASSERT(scope);
- int scopeCount = 0;
- bool seenGenericObjectScope = false;
- bool requiresDynamicChecks = false;
- bool skipTopScopeNode = false;
- int activationRegister = 0;
- CodeBlock* codeBlock = callFrame->codeBlock();
- if (mode == UnknownResolve) {
- ASSERT(operations->isEmpty());
- if (codeBlock->codeType() == FunctionCode && codeBlock->needsActivation()) {
- activationRegister = codeBlock->activationRegister();
- JSValue activation = callFrame->r(activationRegister).jsValue();
-
- // If the activation register doesn't match our actual scope, a dynamic
- // scope has been inserted so we shouldn't skip the top scope node.
- if (activation == scope) {
- jsCast<JSActivation*>(activation.asCell())->isDynamicScope(requiresDynamicChecks);
- if (!requiresDynamicChecks) {
- ASSERT(jsCast<JSActivation*>(activation.asCell())->symbolTable()->get(identifier.impl()).isNull());
- scope = scope->next();
- ASSERT(scope);
- skipTopScopeNode = true;
- }
- } else if (!activation)
- skipTopScopeNode = true;
- }
- } else
- ASSERT(operations->size());
- if (codeBlock->codeType() == EvalCode && scope->next())
- requiresDynamicChecks = true;
- if (mode == UnknownResolve && putToBaseOperation)
- putToBaseOperation->m_kind = PutToBaseOperation::Generic;
- do {
- JSObject* object = JSScope::objectAtScope(scope);
- slot = PropertySlot(object);
- bool currentScopeNeedsDynamicChecks = false;
- if (!(scope->isVariableObject() || scope->isNameScopeObject()) || (scope->next() && scope->isDynamicScope(currentScopeNeedsDynamicChecks)))
- seenGenericObjectScope = true;
- requiresDynamicChecks = requiresDynamicChecks || currentScopeNeedsDynamicChecks;
- if (object->getPropertySlot(callFrame, identifier, slot)) {
- if (mode == UnknownResolve) {
- if (seenGenericObjectScope)
- goto fail;
- if (putToBaseOperation)
- putToBaseOperation->m_isDynamic = requiresDynamicChecks;
- if (!scope->next()) {
- // Global lookup of some kind
- JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(scope);
- SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl());
- if (!entry.isNull()) {
- if (requiresDynamicChecks)
- operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
- if (putToBaseOperation) {
- putToBaseOperation->m_isDynamic = requiresDynamicChecks;
- if (entry.isReadOnly())
- putToBaseOperation->m_kind = PutToBaseOperation::Readonly;
- else if (entry.couldBeWatched()) {
- putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePutChecked;
- putToBaseOperation->m_predicatePointer = entry.addressOfIsWatched();
- } else
- putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePut;
- putToBaseOperation->m_registerAddress = &globalObject->registerAt(entry.getIndex());
- }
- // Override custom accessor behaviour that the DOM introduces for some
- // event handlers declared on function declarations.
- if (!requiresDynamicChecks)
- slot.setValue(globalObject, globalObject->registerAt(entry.getIndex()).get());
- switch (returnValues) {
- case ReturnValue:
- ASSERT(!putToBaseOperation);
- operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
- break;
- case ReturnBase:
- ASSERT(putToBaseOperation);
- operations->append(ResolveOperation::returnGlobalObjectAsBase());
- break;
- case ReturnBaseAndValue:
- ASSERT(putToBaseOperation);
- operations->append(ResolveOperation::setBaseToGlobal());
- operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
- break;
- case ReturnThisAndValue:
- ASSERT(!putToBaseOperation);
- operations->append(ResolveOperation::setBaseToUndefined());
- operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
- break;
- }
- } else {
- if (!slot.isCacheableValue() || slot.slotBase() != globalObject)
- goto fail;
- if (requiresDynamicChecks)
- operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
- if (putToBaseOperation) {
- putToBaseOperation->m_isDynamic = requiresDynamicChecks;
- putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut;
- putToBaseOperation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure());
- setPutPropertyAccessOffset(putToBaseOperation, slot.cachedOffset());
- }
- switch (returnValues) {
- case ReturnValue:
- ASSERT(!putToBaseOperation);
- operations->append(ResolveOperation::getAndReturnGlobalProperty());
- break;
- case ReturnBase:
- ASSERT(putToBaseOperation);
- operations->append(ResolveOperation::returnGlobalObjectAsBase());
- break;
- case ReturnBaseAndValue:
- ASSERT(putToBaseOperation);
- operations->append(ResolveOperation::setBaseToGlobal());
- operations->append(ResolveOperation::getAndReturnGlobalProperty());
- break;
- case ReturnThisAndValue:
- ASSERT(!putToBaseOperation);
- operations->append(ResolveOperation::setBaseToUndefined());
- operations->append(ResolveOperation::getAndReturnGlobalProperty());
- break;
- }
- }
- return object;
- }
- if (!requiresDynamicChecks) {
- // Normal lexical lookup
- JSVariableObject* variableObject = jsCast<JSVariableObject*>(scope);
- ASSERT(variableObject);
- ASSERT(variableObject->symbolTable());
- SymbolTableEntry entry = variableObject->symbolTable()->get(identifier.impl());
- // Defend against the variable being actually inserted by eval.
- if (entry.isNull()) {
- ASSERT(!jsDynamicCast<JSNameScope*>(variableObject));
- goto fail;
- }
- // If we're getting the 'arguments' then give up on life.
- if (identifier == callFrame->propertyNames().arguments)
- goto fail;
- if (putToBaseOperation) {
- putToBaseOperation->m_kind = entry.isReadOnly() ? PutToBaseOperation::Readonly : PutToBaseOperation::VariablePut;
- putToBaseOperation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), callFrame->lexicalGlobalObject()->activationStructure());
- putToBaseOperation->m_offset = entry.getIndex();
- putToBaseOperation->m_scopeDepth = (skipTopScopeNode ? 1 : 0) + scopeCount;
- }
- if (skipTopScopeNode)
- operations->append(ResolveOperation::skipTopScopeNode(activationRegister));
- operations->append(ResolveOperation::skipScopes(scopeCount));
- switch (returnValues) {
- case ReturnBaseAndValue:
- operations->append(ResolveOperation::setBaseToScope());
- operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex()));
- break;
- case ReturnBase:
- operations->append(ResolveOperation::returnScopeAsBase());
- break;
- case ReturnThisAndValue:
- operations->append(ResolveOperation::setBaseToUndefined());
- // fallthrough
- case ReturnValue:
- operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex()));
- break;
- }
- return object;
- }
- fail:
- if (!operations->size())
- operations->append(ResolveOperation::resolveFail());
- }
- return object;
- }
- scopeCount++;
- } while ((scope = scope->next()));
-
- if (mode == UnknownResolve) {
- ASSERT(operations->isEmpty());
- if (seenGenericObjectScope) {
- operations->append(ResolveOperation::resolveFail());
- return 0;
- }
- if (putToBaseOperation) {
- putToBaseOperation->m_isDynamic = requiresDynamicChecks;
- putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut;
- putToBaseOperation->m_structure.clear();
- putToBaseOperation->m_offset = -1;
- }
- if (requiresDynamicChecks)
- operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
- switch (returnValues) {
- case ReturnValue:
- ASSERT(!putToBaseOperation);
- operations->append(ResolveOperation::getAndReturnGlobalProperty());
- break;
- case ReturnBase:
- ASSERT(putToBaseOperation);
- operations->append(ResolveOperation::returnGlobalObjectAsBase());
- break;
- case ReturnBaseAndValue:
- ASSERT(putToBaseOperation);
- operations->append(ResolveOperation::setBaseToGlobal());
- operations->append(ResolveOperation::getAndReturnGlobalProperty());
- break;
- case ReturnThisAndValue:
- ASSERT(!putToBaseOperation);
- operations->append(ResolveOperation::setBaseToUndefined());
- operations->append(ResolveOperation::getAndReturnGlobalProperty());
- break;
- }
- }
- return 0;
- }
- template <JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScope(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool isStrict)
- {
- if (operations->size())
- return resolveContainingScopeInternal<KnownResolve, returnValues>(callFrame, identifier, slot, operations, putToBaseOperation, isStrict);
- JSObject* result = resolveContainingScopeInternal<UnknownResolve, returnValues>(callFrame, identifier, slot, operations, putToBaseOperation, isStrict);
- operations->shrinkToFit();
- return result;
- }
- JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier, ResolveOperations* operations)
- {
- ASSERT(operations);
- LookupResult fastResult;
- if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
- ASSERT(fastResult.value());
- ASSERT(!callFrame->hadException());
- return fastResult.value();
- }
- if (callFrame->hadException())
- return JSValue();
- PropertySlot slot;
- if (JSScope::resolveContainingScope<ReturnValue>(callFrame, identifier, slot, operations, 0, false)) {
- ASSERT(operations->size());
- return slot.getValue(callFrame, identifier);
- }
- ASSERT(operations->size());
- return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
- }
- JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
- {
- ASSERT(operations);
- ASSERT_UNUSED(putToBaseOperations, putToBaseOperations);
- LookupResult fastResult;
- if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
- ASSERT(fastResult.base());
- ASSERT(!callFrame->hadException());
- return fastResult.base();
- }
- if (callFrame->hadException())
- return JSValue();
- PropertySlot slot;
- if (JSObject* base = JSScope::resolveContainingScope<ReturnBase>(callFrame, identifier, slot, operations, putToBaseOperations, isStrict)) {
- ASSERT(operations->size());
- return base;
- }
- if (!isStrict)
- return callFrame->lexicalGlobalObject();
- return throwError(callFrame, createErrorForInvalidGlobalAssignment(callFrame, identifier.string()));
- }
- JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
- {
- ASSERT(operations);
- ASSERT_UNUSED(putToBaseOperations, putToBaseOperations);
- LookupResult fastResult;
- if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
- ASSERT(fastResult.base());
- ASSERT(fastResult.value());
- ASSERT(!callFrame->hadException());
- *base = fastResult.base();
- return fastResult.value();
- }
- if (callFrame->hadException())
- return JSValue();
- PropertySlot slot;
- if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnBaseAndValue>(callFrame, identifier, slot, operations, putToBaseOperations, false)) {
- ASSERT(operations->size());
- JSValue value = slot.getValue(callFrame, identifier);
- if (callFrame->vm().exception)
- return JSValue();
- *base = propertyBase;
- return value;
- }
- ASSERT(operations->size());
- return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
- }
- JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations)
- {
- ASSERT(operations);
- LookupResult fastResult;
- if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
- ASSERT(fastResult.base());
- ASSERT(fastResult.value());
- ASSERT(!callFrame->hadException());
- *base = fastResult.base();
- return fastResult.value();
- }
- if (callFrame->hadException())
- return JSValue();
- PropertySlot slot;
- if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnThisAndValue>(callFrame, identifier, slot, operations, 0, false)) {
- ASSERT(operations->size());
- JSValue value = slot.getValue(callFrame, identifier);
- if (callFrame->vm().exception)
- return JSValue();
- ASSERT(value);
- *base = propertyBase->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(propertyBase);
- return value;
- }
- ASSERT(operations->size());
- return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
- }
- void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& property, JSValue value, PutToBaseOperation* operation)
- {
- ASSERT_UNUSED(operation, operation);
- ASSERT(base);
- ASSERT(value);
- switch (operation->m_kind) {
- case PutToBaseOperation::Uninitialised:
- CRASH();
- case PutToBaseOperation::Readonly:
- return;
- case PutToBaseOperation::GlobalVariablePutChecked:
- if (*operation->m_predicatePointer)
- goto genericHandler;
- case PutToBaseOperation::GlobalVariablePut:
- if (operation->m_isDynamic) {
- JSObject* baseObject = jsCast<JSObject*>(base);
- if (baseObject != callFrame->lexicalGlobalObject()) {
- if (baseObject->isGlobalObject())
- ASSERT(!jsCast<JSGlobalObject*>(baseObject)->assertRegisterIsInThisObject(operation->m_registerAddress));
- goto genericHandler;
- }
- }
- operation->m_registerAddress->set(callFrame->vm(), base.asCell(), value);
- return;
- case PutToBaseOperation::VariablePut: {
- if (operation->m_isDynamic) {
- JSObject* baseObject = jsCast<JSObject*>(base);
- if (baseObject->structure() != operation->m_structure.get())
- goto genericHandler;
- }
- JSVariableObject* variableObject = jsCast<JSVariableObject*>(base);
- variableObject->registerAt(operation->m_offset).set(callFrame->vm(), variableObject, value);
- return;
- }
- case PutToBaseOperation::GlobalPropertyPut: {
- JSObject* object = jsCast<JSObject*>(base);
- if (operation->m_structure.get() != object->structure())
- break;
- object->putDirect(callFrame->vm(), operation->m_offset, value);
- return;
- }
- genericHandler:
- case PutToBaseOperation::Generic:
- PutPropertySlot slot(operation->m_isStrict);
- base.put(callFrame, property, value, slot);
- return;
- }
- ASSERT(operation->m_kind == PutToBaseOperation::GlobalPropertyPut);
- PutPropertySlot slot(operation->m_isStrict);
- base.put(callFrame, property, value, slot);
- if (!slot.isCacheable())
- return;
- if (callFrame->hadException())
- return;
- JSObject* baseObject = jsCast<JSObject*>(base);
- if (!baseObject->structure()->propertyAccessesAreCacheable())
- return;
- if (slot.base() != callFrame->lexicalGlobalObject())
- return;
- if (slot.base() != baseObject)
- return;
- ASSERT(!baseObject->hasInlineStorage());
- operation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), baseObject->structure());
- setPutPropertyAccessOffset(operation, slot.cachedOffset());
- return;
- }
- JSValue JSScope::resolveGlobal(CallFrame* callFrame, const Identifier& identifier, JSGlobalObject* globalObject, ResolveOperation* resolveOperation)
- {
- ASSERT(resolveOperation);
- ASSERT(resolveOperation->m_operation == ResolveOperation::GetAndReturnGlobalProperty);
- ASSERT_UNUSED(globalObject, callFrame->lexicalGlobalObject() == globalObject);
- LookupResult fastResult;
- if (executeResolveOperations(callFrame, callFrame->scope(), identifier, resolveOperation, fastResult)) {
- ASSERT(fastResult.value());
- ASSERT(!callFrame->hadException());
- return fastResult.value();
- }
- if (callFrame->hadException())
- return JSValue();
- return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
- }
- } // namespace JSC