2 * Copyright (C) 2012 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "JSActivation.h"
30 #include "JSGlobalObject.h"
31 #include "JSNameScope.h"
32 #include "JSWithScope.h"
33 #include "Operations.h"
37 ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSScope
);
39 void JSScope::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
41 JSScope
* thisObject
= jsCast
<JSScope
*>(cell
);
42 ASSERT_GC_OBJECT_INHERITS(thisObject
, &s_info
);
43 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
44 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
46 Base::visitChildren(thisObject
, visitor
);
47 visitor
.append(&thisObject
->m_next
);
50 bool JSScope::isDynamicScope(bool& requiresDynamicChecks
) const
52 switch (structure()->typeInfo().type()) {
53 case GlobalObjectType
:
54 return static_cast<const JSGlobalObject
*>(this)->isDynamicScope(requiresDynamicChecks
);
55 case ActivationObjectType
:
56 return static_cast<const JSActivation
*>(this)->isDynamicScope(requiresDynamicChecks
);
57 case NameScopeObjectType
:
58 return static_cast<const JSNameScope
*>(this)->isDynamicScope(requiresDynamicChecks
);
60 RELEASE_ASSERT_NOT_REACHED();
67 JSObject
* JSScope::objectAtScope(JSScope
* scope
)
69 JSObject
* object
= scope
;
70 if (object
->structure()->typeInfo().type() == WithScopeType
)
71 return jsCast
<JSWithScope
*>(object
)->object();
76 int JSScope::localDepth()
79 ScopeChainIterator iter
= this->begin();
80 ScopeChainIterator end
= this->end();
81 while (!iter
->inherits(&JSActivation::s_info
)) {
91 JSValue
base() const { return m_base
; }
92 JSValue
value() const { return m_value
; }
93 void setBase(JSValue base
) { ASSERT(base
); m_base
= base
; }
94 void setValue(JSValue value
) { ASSERT(value
); m_value
= value
; }
102 static void setPutPropertyAccessOffset(PutToBaseOperation
* operation
, PropertyOffset offset
)
104 ASSERT(isOutOfLineOffset(offset
));
105 operation
->m_offset
= offset
;
106 operation
->m_offsetInButterfly
= offsetInButterfly(offset
);
109 static bool executeResolveOperations(CallFrame
* callFrame
, JSScope
* scope
, const Identifier
& propertyName
, ResolveOperation
* pc
, LookupResult
& result
)
112 switch (pc
->m_operation
) {
113 case ResolveOperation::Fail
:
115 case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope
: {
116 while (JSScope
* nextScope
= scope
->next()) {
117 if (scope
->isActivationObject() && scope
->structure() != scope
->globalObject()->activationStructure())
119 ASSERT(scope
->isNameScopeObject() || scope
->isVariableObject() || scope
->isGlobalObject());
125 case ResolveOperation::SetBaseToUndefined
:
126 result
.setBase(jsUndefined());
129 case ResolveOperation::SetBaseToScope
:
130 result
.setBase(scope
);
133 case ResolveOperation::ReturnScopeAsBase
:
134 result
.setBase(scope
);
136 case ResolveOperation::SetBaseToGlobal
:
137 result
.setBase(scope
->globalObject());
140 case ResolveOperation::SkipScopes
: {
141 int count
= pc
->m_scopesToSkip
;
143 scope
= scope
->next();
148 case ResolveOperation::SkipTopScopeNode
:
149 if (callFrame
->r(pc
->m_activationRegister
).jsValue())
150 scope
= scope
->next();
154 case ResolveOperation::GetAndReturnScopedVar
:
155 ASSERT(jsCast
<JSVariableObject
*>(scope
)->registerAt(pc
->m_offset
).get());
156 result
.setValue(jsCast
<JSVariableObject
*>(scope
)->registerAt(pc
->m_offset
).get());
158 case ResolveOperation::GetAndReturnGlobalVar
:
159 result
.setValue(pc
->m_registerAddress
->get());
161 case ResolveOperation::GetAndReturnGlobalVarWatchable
:
162 result
.setValue(pc
->m_registerAddress
->get());
164 case ResolveOperation::ReturnGlobalObjectAsBase
:
165 result
.setBase(callFrame
->lexicalGlobalObject());
167 case ResolveOperation::GetAndReturnGlobalProperty
: {
168 JSGlobalObject
* globalObject
= scope
->globalObject();
169 if (globalObject
->structure() == pc
->m_structure
.get()) {
170 result
.setValue(globalObject
->getDirect(pc
->m_offset
));
174 PropertySlot
slot(globalObject
);
175 if (!globalObject
->getPropertySlot(callFrame
, propertyName
, slot
))
178 JSValue value
= slot
.getValue(callFrame
, propertyName
);
179 if (callFrame
->hadException())
182 Structure
* structure
= globalObject
->structure();
184 // Don't try to cache prototype lookups
185 if (globalObject
!= slot
.slotBase() || !slot
.isCacheableValue() || !structure
->propertyAccessesAreCacheable()) {
186 result
.setValue(value
);
190 pc
->m_structure
.set(callFrame
->vm(), callFrame
->codeBlock()->ownerExecutable(), structure
);
191 pc
->m_offset
= slot
.cachedOffset();
192 result
.setValue(value
);
199 template <JSScope::LookupMode mode
, JSScope::ReturnValues returnValues
> JSObject
* JSScope::resolveContainingScopeInternal(CallFrame
* callFrame
, const Identifier
& identifier
, PropertySlot
& slot
, Vector
<ResolveOperation
>* operations
, PutToBaseOperation
* putToBaseOperation
, bool )
201 JSScope
* scope
= callFrame
->scope();
204 bool seenGenericObjectScope
= false;
205 bool requiresDynamicChecks
= false;
206 bool skipTopScopeNode
= false;
207 int activationRegister
= 0;
208 CodeBlock
* codeBlock
= callFrame
->codeBlock();
209 if (mode
== UnknownResolve
) {
210 ASSERT(operations
->isEmpty());
211 if (codeBlock
->codeType() == FunctionCode
&& codeBlock
->needsActivation()) {
212 activationRegister
= codeBlock
->activationRegister();
213 JSValue activation
= callFrame
->r(activationRegister
).jsValue();
215 // If the activation register doesn't match our actual scope, a dynamic
216 // scope has been inserted so we shouldn't skip the top scope node.
217 if (activation
== scope
) {
218 jsCast
<JSActivation
*>(activation
.asCell())->isDynamicScope(requiresDynamicChecks
);
219 if (!requiresDynamicChecks
) {
220 ASSERT(jsCast
<JSActivation
*>(activation
.asCell())->symbolTable()->get(identifier
.impl()).isNull());
221 scope
= scope
->next();
223 skipTopScopeNode
= true;
225 } else if (!activation
)
226 skipTopScopeNode
= true;
229 ASSERT(operations
->size());
231 if (codeBlock
->codeType() == EvalCode
&& scope
->next())
232 requiresDynamicChecks
= true;
234 if (mode
== UnknownResolve
&& putToBaseOperation
)
235 putToBaseOperation
->m_kind
= PutToBaseOperation::Generic
;
238 JSObject
* object
= JSScope::objectAtScope(scope
);
239 slot
= PropertySlot(object
);
241 bool currentScopeNeedsDynamicChecks
= false;
242 if (!(scope
->isVariableObject() || scope
->isNameScopeObject()) || (scope
->next() && scope
->isDynamicScope(currentScopeNeedsDynamicChecks
)))
243 seenGenericObjectScope
= true;
245 requiresDynamicChecks
= requiresDynamicChecks
|| currentScopeNeedsDynamicChecks
;
247 if (object
->getPropertySlot(callFrame
, identifier
, slot
)) {
248 if (mode
== UnknownResolve
) {
249 if (seenGenericObjectScope
)
251 if (putToBaseOperation
)
252 putToBaseOperation
->m_isDynamic
= requiresDynamicChecks
;
253 if (!scope
->next()) {
254 // Global lookup of some kind
255 JSGlobalObject
* globalObject
= jsCast
<JSGlobalObject
*>(scope
);
256 SymbolTableEntry entry
= globalObject
->symbolTable()->get(identifier
.impl());
257 if (!entry
.isNull()) {
258 if (requiresDynamicChecks
)
259 operations
->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
261 if (putToBaseOperation
) {
262 putToBaseOperation
->m_isDynamic
= requiresDynamicChecks
;
263 if (entry
.isReadOnly())
264 putToBaseOperation
->m_kind
= PutToBaseOperation::Readonly
;
265 else if (entry
.couldBeWatched()) {
266 putToBaseOperation
->m_kind
= PutToBaseOperation::GlobalVariablePutChecked
;
267 putToBaseOperation
->m_predicatePointer
= entry
.addressOfIsWatched();
269 putToBaseOperation
->m_kind
= PutToBaseOperation::GlobalVariablePut
;
270 putToBaseOperation
->m_registerAddress
= &globalObject
->registerAt(entry
.getIndex());
272 // Override custom accessor behaviour that the DOM introduces for some
273 // event handlers declared on function declarations.
274 if (!requiresDynamicChecks
)
275 slot
.setValue(globalObject
, globalObject
->registerAt(entry
.getIndex()).get());
276 switch (returnValues
) {
278 ASSERT(!putToBaseOperation
);
279 operations
->append(ResolveOperation::getAndReturnGlobalVar(&globalObject
->registerAt(entry
.getIndex()), entry
.couldBeWatched()));
282 ASSERT(putToBaseOperation
);
283 operations
->append(ResolveOperation::returnGlobalObjectAsBase());
285 case ReturnBaseAndValue
:
286 ASSERT(putToBaseOperation
);
287 operations
->append(ResolveOperation::setBaseToGlobal());
288 operations
->append(ResolveOperation::getAndReturnGlobalVar(&globalObject
->registerAt(entry
.getIndex()), entry
.couldBeWatched()));
290 case ReturnThisAndValue
:
291 ASSERT(!putToBaseOperation
);
292 operations
->append(ResolveOperation::setBaseToUndefined());
293 operations
->append(ResolveOperation::getAndReturnGlobalVar(&globalObject
->registerAt(entry
.getIndex()), entry
.couldBeWatched()));
297 if (!slot
.isCacheableValue() || slot
.slotBase() != globalObject
)
300 if (requiresDynamicChecks
)
301 operations
->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
303 if (putToBaseOperation
) {
304 unsigned currentAttributes
;
305 JSCell
* currentSpecificFunction
;
306 PropertyOffset offset
= globalObject
->structure()->get(callFrame
->vm(), identifier
, currentAttributes
, currentSpecificFunction
);
307 ASSERT_UNUSED(offset
, offset
!= invalidOffset
);
308 ASSERT_UNUSED(offset
, offset
== slot
.cachedOffset());
309 // We just assume that we are clobbering the global specialisation
310 if (currentSpecificFunction
)
311 globalObject
->setStructure(callFrame
->vm(), Structure::despecifyFunctionTransition(callFrame
->vm(), globalObject
->structure(), identifier
));
312 putToBaseOperation
->m_isDynamic
= requiresDynamicChecks
;
313 putToBaseOperation
->m_kind
= PutToBaseOperation::GlobalPropertyPut
;
314 putToBaseOperation
->m_structure
.set(callFrame
->vm(), callFrame
->codeBlock()->ownerExecutable(), globalObject
->structure());
315 setPutPropertyAccessOffset(putToBaseOperation
, slot
.cachedOffset());
317 switch (returnValues
) {
319 ASSERT(!putToBaseOperation
);
320 operations
->append(ResolveOperation::getAndReturnGlobalProperty());
323 ASSERT(putToBaseOperation
);
324 operations
->append(ResolveOperation::returnGlobalObjectAsBase());
326 case ReturnBaseAndValue
:
327 ASSERT(putToBaseOperation
);
328 operations
->append(ResolveOperation::setBaseToGlobal());
329 operations
->append(ResolveOperation::getAndReturnGlobalProperty());
331 case ReturnThisAndValue
:
332 ASSERT(!putToBaseOperation
);
333 operations
->append(ResolveOperation::setBaseToUndefined());
334 operations
->append(ResolveOperation::getAndReturnGlobalProperty());
340 if (!requiresDynamicChecks
) {
341 // Normal lexical lookup
342 JSVariableObject
* variableObject
= jsCast
<JSVariableObject
*>(scope
);
343 ASSERT(variableObject
);
344 ASSERT(variableObject
->symbolTable());
345 SymbolTableEntry entry
= variableObject
->symbolTable()->get(identifier
.impl());
346 // Defend against the variable being actually inserted by eval.
347 if (entry
.isNull()) {
348 ASSERT(!jsDynamicCast
<JSNameScope
*>(variableObject
));
351 // If we're getting the 'arguments' then give up on life.
352 if (identifier
== callFrame
->propertyNames().arguments
)
355 if (putToBaseOperation
) {
356 putToBaseOperation
->m_kind
= entry
.isReadOnly() ? PutToBaseOperation::Readonly
: PutToBaseOperation::VariablePut
;
357 putToBaseOperation
->m_structure
.set(callFrame
->vm(), callFrame
->codeBlock()->ownerExecutable(), callFrame
->lexicalGlobalObject()->activationStructure());
358 putToBaseOperation
->m_offset
= entry
.getIndex();
359 putToBaseOperation
->m_scopeDepth
= (skipTopScopeNode
? 1 : 0) + scopeCount
;
362 if (skipTopScopeNode
)
363 operations
->append(ResolveOperation::skipTopScopeNode(activationRegister
));
365 operations
->append(ResolveOperation::skipScopes(scopeCount
));
366 switch (returnValues
) {
367 case ReturnBaseAndValue
:
368 operations
->append(ResolveOperation::setBaseToScope());
369 operations
->append(ResolveOperation::getAndReturnScopedVar(entry
.getIndex()));
373 operations
->append(ResolveOperation::returnScopeAsBase());
376 case ReturnThisAndValue
:
377 operations
->append(ResolveOperation::setBaseToUndefined());
380 operations
->append(ResolveOperation::getAndReturnScopedVar(entry
.getIndex()));
386 if (!operations
->size())
387 operations
->append(ResolveOperation::resolveFail());
392 } while ((scope
= scope
->next()));
394 if (mode
== UnknownResolve
) {
395 ASSERT(operations
->isEmpty());
396 if (seenGenericObjectScope
) {
397 operations
->append(ResolveOperation::resolveFail());
400 if (putToBaseOperation
) {
401 putToBaseOperation
->m_isDynamic
= requiresDynamicChecks
;
402 putToBaseOperation
->m_kind
= PutToBaseOperation::GlobalPropertyPut
;
403 putToBaseOperation
->m_structure
.clear();
404 putToBaseOperation
->m_offset
= -1;
406 if (requiresDynamicChecks
)
407 operations
->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
408 switch (returnValues
) {
410 ASSERT(!putToBaseOperation
);
411 operations
->append(ResolveOperation::getAndReturnGlobalProperty());
414 ASSERT(putToBaseOperation
);
415 operations
->append(ResolveOperation::returnGlobalObjectAsBase());
417 case ReturnBaseAndValue
:
418 ASSERT(putToBaseOperation
);
419 operations
->append(ResolveOperation::setBaseToGlobal());
420 operations
->append(ResolveOperation::getAndReturnGlobalProperty());
422 case ReturnThisAndValue
:
423 ASSERT(!putToBaseOperation
);
424 operations
->append(ResolveOperation::setBaseToUndefined());
425 operations
->append(ResolveOperation::getAndReturnGlobalProperty());
432 template <JSScope::ReturnValues returnValues
> JSObject
* JSScope::resolveContainingScope(CallFrame
* callFrame
, const Identifier
& identifier
, PropertySlot
& slot
, Vector
<ResolveOperation
>* operations
, PutToBaseOperation
* putToBaseOperation
, bool isStrict
)
434 if (operations
->size())
435 return resolveContainingScopeInternal
<KnownResolve
, returnValues
>(callFrame
, identifier
, slot
, operations
, putToBaseOperation
, isStrict
);
436 JSObject
* result
= resolveContainingScopeInternal
<UnknownResolve
, returnValues
>(callFrame
, identifier
, slot
, operations
, putToBaseOperation
, isStrict
);
437 operations
->shrinkToFit();
441 JSValue
JSScope::resolve(CallFrame
* callFrame
, const Identifier
& identifier
, ResolveOperations
* operations
)
444 LookupResult fastResult
;
445 if (operations
->size() && executeResolveOperations(callFrame
, callFrame
->scope(), identifier
, operations
->data(), fastResult
)) {
446 ASSERT(fastResult
.value());
447 ASSERT(!callFrame
->hadException());
448 return fastResult
.value();
451 if (callFrame
->hadException())
455 if (JSScope::resolveContainingScope
<ReturnValue
>(callFrame
, identifier
, slot
, operations
, 0, false)) {
456 ASSERT(operations
->size());
457 return slot
.getValue(callFrame
, identifier
);
459 ASSERT(operations
->size());
461 return throwError(callFrame
, createUndefinedVariableError(callFrame
, identifier
));
464 JSValue
JSScope::resolveBase(CallFrame
* callFrame
, const Identifier
& identifier
, bool isStrict
, ResolveOperations
* operations
, PutToBaseOperation
* putToBaseOperations
)
467 ASSERT_UNUSED(putToBaseOperations
, putToBaseOperations
);
468 LookupResult fastResult
;
469 if (operations
->size() && executeResolveOperations(callFrame
, callFrame
->scope(), identifier
, operations
->data(), fastResult
)) {
470 ASSERT(fastResult
.base());
471 ASSERT(!callFrame
->hadException());
472 return fastResult
.base();
475 if (callFrame
->hadException())
479 if (JSObject
* base
= JSScope::resolveContainingScope
<ReturnBase
>(callFrame
, identifier
, slot
, operations
, putToBaseOperations
, isStrict
)) {
480 ASSERT(operations
->size());
485 return callFrame
->lexicalGlobalObject();
487 return throwError(callFrame
, createErrorForInvalidGlobalAssignment(callFrame
, identifier
.string()));
490 JSValue
JSScope::resolveWithBase(CallFrame
* callFrame
, const Identifier
& identifier
, Register
* base
, ResolveOperations
* operations
, PutToBaseOperation
* putToBaseOperations
)
493 ASSERT_UNUSED(putToBaseOperations
, putToBaseOperations
);
494 LookupResult fastResult
;
495 if (operations
->size() && executeResolveOperations(callFrame
, callFrame
->scope(), identifier
, operations
->data(), fastResult
)) {
496 ASSERT(fastResult
.base());
497 ASSERT(fastResult
.value());
498 ASSERT(!callFrame
->hadException());
499 *base
= fastResult
.base();
500 return fastResult
.value();
503 if (callFrame
->hadException())
507 if (JSObject
* propertyBase
= JSScope::resolveContainingScope
<ReturnBaseAndValue
>(callFrame
, identifier
, slot
, operations
, putToBaseOperations
, false)) {
508 ASSERT(operations
->size());
509 JSValue value
= slot
.getValue(callFrame
, identifier
);
510 if (callFrame
->vm().exception
)
513 *base
= propertyBase
;
516 ASSERT(operations
->size());
518 return throwError(callFrame
, createUndefinedVariableError(callFrame
, identifier
));
521 JSValue
JSScope::resolveWithThis(CallFrame
* callFrame
, const Identifier
& identifier
, Register
* base
, ResolveOperations
* operations
)
524 LookupResult fastResult
;
525 if (operations
->size() && executeResolveOperations(callFrame
, callFrame
->scope(), identifier
, operations
->data(), fastResult
)) {
526 ASSERT(fastResult
.base());
527 ASSERT(fastResult
.value());
528 ASSERT(!callFrame
->hadException());
529 *base
= fastResult
.base();
530 return fastResult
.value();
533 if (callFrame
->hadException())
537 if (JSObject
* propertyBase
= JSScope::resolveContainingScope
<ReturnThisAndValue
>(callFrame
, identifier
, slot
, operations
, 0, false)) {
538 ASSERT(operations
->size());
539 JSValue value
= slot
.getValue(callFrame
, identifier
);
540 if (callFrame
->vm().exception
)
543 *base
= propertyBase
->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(propertyBase
);
546 ASSERT(operations
->size());
548 return throwError(callFrame
, createUndefinedVariableError(callFrame
, identifier
));
551 void JSScope::resolvePut(CallFrame
* callFrame
, JSValue base
, const Identifier
& property
, JSValue value
, PutToBaseOperation
* operation
)
553 ASSERT_UNUSED(operation
, operation
);
556 switch (operation
->m_kind
) {
557 case PutToBaseOperation::Uninitialised
:
560 case PutToBaseOperation::Readonly
:
563 case PutToBaseOperation::GlobalVariablePutChecked
:
564 if (*operation
->m_predicatePointer
)
566 case PutToBaseOperation::GlobalVariablePut
:
567 if (operation
->m_isDynamic
) {
568 JSObject
* baseObject
= jsCast
<JSObject
*>(base
);
569 if (baseObject
!= callFrame
->lexicalGlobalObject()) {
570 if (baseObject
->isGlobalObject())
571 ASSERT(!jsCast
<JSGlobalObject
*>(baseObject
)->assertRegisterIsInThisObject(operation
->m_registerAddress
));
575 operation
->m_registerAddress
->set(callFrame
->vm(), base
.asCell(), value
);
578 case PutToBaseOperation::VariablePut
: {
579 if (operation
->m_isDynamic
) {
580 JSObject
* baseObject
= jsCast
<JSObject
*>(base
);
581 if (baseObject
->structure() != operation
->m_structure
.get())
584 JSVariableObject
* variableObject
= jsCast
<JSVariableObject
*>(base
);
585 variableObject
->registerAt(operation
->m_offset
).set(callFrame
->vm(), variableObject
, value
);
589 case PutToBaseOperation::GlobalPropertyPut
: {
590 JSObject
* object
= jsCast
<JSObject
*>(base
);
591 if (operation
->m_structure
.get() != object
->structure())
593 object
->putDirect(callFrame
->vm(), operation
->m_offset
, value
);
598 case PutToBaseOperation::Generic
:
599 PutPropertySlot
slot(operation
->m_isStrict
);
600 base
.put(callFrame
, property
, value
, slot
);
603 ASSERT(operation
->m_kind
== PutToBaseOperation::GlobalPropertyPut
);
604 PutPropertySlot
slot(operation
->m_isStrict
);
605 base
.put(callFrame
, property
, value
, slot
);
606 if (!slot
.isCacheable())
608 if (callFrame
->hadException())
610 JSObject
* baseObject
= jsCast
<JSObject
*>(base
);
611 if (!baseObject
->structure()->propertyAccessesAreCacheable())
613 if (slot
.base() != callFrame
->lexicalGlobalObject())
615 if (slot
.base() != baseObject
)
617 ASSERT(!baseObject
->hasInlineStorage());
618 operation
->m_structure
.set(callFrame
->vm(), callFrame
->codeBlock()->ownerExecutable(), baseObject
->structure());
619 setPutPropertyAccessOffset(operation
, slot
.cachedOffset());
623 JSValue
JSScope::resolveGlobal(CallFrame
* callFrame
, const Identifier
& identifier
, JSGlobalObject
* globalObject
, ResolveOperation
* resolveOperation
)
625 ASSERT(resolveOperation
);
626 ASSERT(resolveOperation
->m_operation
== ResolveOperation::GetAndReturnGlobalProperty
);
627 ASSERT_UNUSED(globalObject
, callFrame
->lexicalGlobalObject() == globalObject
);
629 LookupResult fastResult
;
630 if (executeResolveOperations(callFrame
, callFrame
->scope(), identifier
, resolveOperation
, fastResult
)) {
631 ASSERT(fastResult
.value());
632 ASSERT(!callFrame
->hadException());
633 return fastResult
.value();
636 if (callFrame
->hadException())
639 return throwError(callFrame
, createUndefinedVariableError(callFrame
, identifier
));