123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- /*
- * 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_shared<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_shared<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
|