- }
- }
-}
-
-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));