diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-22 15:40:17 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-22 15:40:17 +0200 |
commit | 43a42f108af6bcbd91f2672731c3047c26213af1 (patch) | |
tree | 7fa092e5f5d873c72f2486a70e26be26f7a38bec /Source/JavaScriptCore/runtime/JSScope.cpp | |
parent | d9cf437c840c6eb7417bdd97e6c40979255d3158 (diff) | |
download | qtwebkit-43a42f108af6bcbd91f2672731c3047c26213af1.tar.gz |
Imported WebKit commit 302e7806bff028bd1167a1ec7c86a1ee00ecfb49 (http://svn.webkit.org/repository/webkit/trunk@132067)
New snapshot that fixes build without QtWidgets
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSScope.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSScope.cpp | 597 |
1 files changed, 483 insertions, 114 deletions
diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp index 8fd49b861..508a90540 100644 --- a/Source/JavaScriptCore/runtime/JSScope.cpp +++ b/Source/JavaScriptCore/runtime/JSScope.cpp @@ -86,126 +86,388 @@ int JSScope::localDepth() return scopeDepth; } -JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier) -{ - JSScope* scope = callFrame->scope(); - ASSERT(scope); +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; } - do { - JSObject* object = JSScope::objectAtScope(scope); - PropertySlot slot(object); - if (object->getPropertySlot(callFrame, identifier, slot)) - return slot.getValue(callFrame, identifier); - } while ((scope = scope->next())); +private: + JSValue m_base; + JSValue m_value; +}; - return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); + +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->getDirectOffset(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->globalData(), callFrame->codeBlock()->ownerExecutable(), structure); + pc->m_offset = slot.cachedOffset(); + result.setValue(value); + return true; + } + } + } } -JSValue JSScope::resolveSkip(CallFrame* callFrame, const Identifier& identifier, int skip) +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(); - - bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); - ASSERT(skip || !checkTopLevel); - if (checkTopLevel && skip--) { - if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) - scope = scope->next(); - } - while (skip--) { - scope = scope->next(); - ASSERT(scope); - } + 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); - PropertySlot slot(object); - if (object->getPropertySlot(callFrame, identifier, slot)) - return slot.getValue(callFrame, identifier); + 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->globalData(), 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()); + // Variable was actually inserted by eval + if (entry.isNull()) { + ASSERT(!jsDynamicCast<JSNameScope*>(variableObject)); + goto fail; + } + + if (putToBaseOperation) { + putToBaseOperation->m_kind = entry.isReadOnly() ? PutToBaseOperation::Readonly : PutToBaseOperation::VariablePut; + putToBaseOperation->m_structure.set(callFrame->globalData(), 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())); - - return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); + + 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; } -JSValue JSScope::resolveGlobal( - CallFrame* callFrame, - const Identifier& identifier, - JSGlobalObject* globalObject, - WriteBarrierBase<Structure>* cachedStructure, - PropertyOffset* cachedOffset -) +template <JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScope(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool isStrict) { - if (globalObject->structure() == cachedStructure->get()) - return globalObject->getDirectOffset(*cachedOffset); - - PropertySlot slot(globalObject); - if (!globalObject->getPropertySlot(callFrame, identifier, slot)) - return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); - - JSValue result = slot.getValue(callFrame, identifier); - if (callFrame->globalData().exception) - return JSValue(); - - if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { - cachedStructure->set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure()); - *cachedOffset = slot.cachedOffset(); - } + 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::resolveGlobalDynamic( - CallFrame* callFrame, - const Identifier& identifier, - int skip, - WriteBarrierBase<Structure>* cachedStructure, - PropertyOffset* cachedOffset -) +JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier, ResolveOperations* operations) { - JSScope* scope = callFrame->scope(); - ASSERT(scope); - - CodeBlock* codeBlock = callFrame->codeBlock(); - - bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); - ASSERT(skip || !checkTopLevel); - if (checkTopLevel && skip--) { - if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) - scope = scope->next(); + ASSERT(operations); + LookupResult fastResult; + if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) { + ASSERT(fastResult.value()); + ASSERT(!callFrame->hadException()); + return fastResult.value(); } - while (skip--) { - JSObject* object = JSScope::objectAtScope(scope); - if (!object->hasCustomProperties()) - continue; - PropertySlot slot(object); - if (!object->getPropertySlot(callFrame, identifier, slot)) - continue; + if (callFrame->hadException()) + return JSValue(); - JSValue result = slot.getValue(callFrame, identifier); - if (callFrame->globalData().exception) - return JSValue(); - return result; + PropertySlot slot; + if (JSScope::resolveContainingScope<ReturnValue>(callFrame, identifier, slot, operations, 0, false)) { + ASSERT(operations->size()); + return slot.getValue(callFrame, identifier); } + ASSERT(operations->size()); - return resolveGlobal(callFrame, identifier, callFrame->lexicalGlobalObject(), cachedStructure, cachedOffset); + return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); } -JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict) +JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations) { - JSScope* scope = callFrame->scope(); - ASSERT(scope); - - do { - JSObject* object = JSScope::objectAtScope(scope); + 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(); + } - PropertySlot slot(object); - if (!object->getPropertySlot(callFrame, identifier, slot)) - continue; + if (callFrame->hadException()) + return JSValue(); - return JSValue(object); - } while ((scope = scope->next())); + PropertySlot slot; + if (JSObject* base = JSScope::resolveContainingScope<ReturnBase>(callFrame, identifier, slot, operations, putToBaseOperations, isStrict)) { + ASSERT(operations->size()); + return base; + } if (!isStrict) return callFrame->lexicalGlobalObject(); @@ -213,50 +475,157 @@ JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, return throwError(callFrame, createErrorForInvalidGlobalAssignment(callFrame, identifier.string())); } -JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base) +JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations) { - JSScope* scope = callFrame->scope(); - ASSERT(scope); - - do { - JSObject* object = JSScope::objectAtScope(scope); + 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(); + } - PropertySlot slot(object); - if (!object->getPropertySlot(callFrame, identifier, slot)) - continue; + 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->globalData().exception) return JSValue(); - *base = JSValue(object); + *base = propertyBase; return value; - } while ((scope = scope->next())); + } + ASSERT(operations->size()); return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); } -JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base) +JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations) { - JSScope* scope = callFrame->scope(); - ASSERT(scope); - - do { - JSObject* object = JSScope::objectAtScope(scope); + 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(); + } - PropertySlot slot(object); - if (!object->getPropertySlot(callFrame, identifier, slot)) - continue; + 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->globalData().exception) return JSValue(); - - *base = object->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(object); + ASSERT(value); + *base = propertyBase->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(propertyBase); return value; - } while ((scope = scope->next())); + } + 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->globalData(), 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->globalData(), variableObject, value); + return; + } + + case PutToBaseOperation::GlobalPropertyPut: { + JSObject* object = jsCast<JSObject*>(base); + if (operation->m_structure.get() != object->structure()) + break; + object->putDirectOffset(callFrame->globalData(), 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->globalData(), 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 |