JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / runtime / JSScope.cpp
1 /*
2 * Copyright (C) 2012 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26 #include "config.h"
27 #include "JSScope.h"
28
29 #include "JSActivation.h"
30 #include "JSGlobalObject.h"
31 #include "JSNameScope.h"
32 #include "JSWithScope.h"
33 #include "Operations.h"
34
35 namespace JSC {
36
37 ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSScope);
38
39 void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
40 {
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());
45
46 Base::visitChildren(thisObject, visitor);
47 visitor.append(&thisObject->m_next);
48 }
49
50 bool JSScope::isDynamicScope(bool& requiresDynamicChecks) const
51 {
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);
59 default:
60 RELEASE_ASSERT_NOT_REACHED();
61 break;
62 }
63
64 return false;
65 }
66
67 JSObject* JSScope::objectAtScope(JSScope* scope)
68 {
69 JSObject* object = scope;
70 if (object->structure()->typeInfo().type() == WithScopeType)
71 return jsCast<JSWithScope*>(object)->object();
72
73 return object;
74 }
75
76 int JSScope::localDepth()
77 {
78 int scopeDepth = 0;
79 ScopeChainIterator iter = this->begin();
80 ScopeChainIterator end = this->end();
81 while (!iter->inherits(&JSActivation::s_info)) {
82 ++iter;
83 if (iter == end)
84 break;
85 ++scopeDepth;
86 }
87 return scopeDepth;
88 }
89
90 struct LookupResult {
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; }
95
96 private:
97 JSValue m_base;
98 JSValue m_value;
99 };
100
101
102 static void setPutPropertyAccessOffset(PutToBaseOperation* operation, PropertyOffset offset)
103 {
104 ASSERT(isOutOfLineOffset(offset));
105 operation->m_offset = offset;
106 operation->m_offsetInButterfly = offsetInButterfly(offset);
107 }
108
109 static bool executeResolveOperations(CallFrame* callFrame, JSScope* scope, const Identifier& propertyName, ResolveOperation* pc, LookupResult& result)
110 {
111 while (true) {
112 switch (pc->m_operation) {
113 case ResolveOperation::Fail:
114 return false;
115 case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope: {
116 while (JSScope* nextScope = scope->next()) {
117 if (scope->isActivationObject() && scope->structure() != scope->globalObject()->activationStructure())
118 return false;
119 ASSERT(scope->isNameScopeObject() || scope->isVariableObject() || scope->isGlobalObject());
120 scope = nextScope;
121 }
122 pc++;
123 break;
124 }
125 case ResolveOperation::SetBaseToUndefined:
126 result.setBase(jsUndefined());
127 pc++;
128 continue;
129 case ResolveOperation::SetBaseToScope:
130 result.setBase(scope);
131 pc++;
132 continue;
133 case ResolveOperation::ReturnScopeAsBase:
134 result.setBase(scope);
135 return true;
136 case ResolveOperation::SetBaseToGlobal:
137 result.setBase(scope->globalObject());
138 pc++;
139 continue;
140 case ResolveOperation::SkipScopes: {
141 int count = pc->m_scopesToSkip;
142 while (count--)
143 scope = scope->next();
144 ASSERT(scope);
145 pc++;
146 continue;
147 }
148 case ResolveOperation::SkipTopScopeNode:
149 if (callFrame->r(pc->m_activationRegister).jsValue())
150 scope = scope->next();
151 ASSERT(scope);
152 pc++;
153 continue;
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());
157 return true;
158 case ResolveOperation::GetAndReturnGlobalVar:
159 result.setValue(pc->m_registerAddress->get());
160 return true;
161 case ResolveOperation::GetAndReturnGlobalVarWatchable:
162 result.setValue(pc->m_registerAddress->get());
163 return true;
164 case ResolveOperation::ReturnGlobalObjectAsBase:
165 result.setBase(callFrame->lexicalGlobalObject());
166 return true;
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));
171 return true;
172 }
173
174 PropertySlot slot(globalObject);
175 if (!globalObject->getPropertySlot(callFrame, propertyName, slot))
176 return false;
177
178 JSValue value = slot.getValue(callFrame, propertyName);
179 if (callFrame->hadException())
180 return false;
181
182 Structure* structure = globalObject->structure();
183
184 // Don't try to cache prototype lookups
185 if (globalObject != slot.slotBase() || !slot.isCacheableValue() || !structure->propertyAccessesAreCacheable()) {
186 result.setValue(value);
187 return true;
188 }
189
190 pc->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), structure);
191 pc->m_offset = slot.cachedOffset();
192 result.setValue(value);
193 return true;
194 }
195 }
196 }
197 }
198
199 template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScopeInternal(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool )
200 {
201 JSScope* scope = callFrame->scope();
202 ASSERT(scope);
203 int scopeCount = 0;
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();
214
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();
222 ASSERT(scope);
223 skipTopScopeNode = true;
224 }
225 } else if (!activation)
226 skipTopScopeNode = true;
227 }
228 } else
229 ASSERT(operations->size());
230
231 if (codeBlock->codeType() == EvalCode && scope->next())
232 requiresDynamicChecks = true;
233
234 if (mode == UnknownResolve && putToBaseOperation)
235 putToBaseOperation->m_kind = PutToBaseOperation::Generic;
236
237 do {
238 JSObject* object = JSScope::objectAtScope(scope);
239 slot = PropertySlot(object);
240
241 bool currentScopeNeedsDynamicChecks = false;
242 if (!(scope->isVariableObject() || scope->isNameScopeObject()) || (scope->next() && scope->isDynamicScope(currentScopeNeedsDynamicChecks)))
243 seenGenericObjectScope = true;
244
245 requiresDynamicChecks = requiresDynamicChecks || currentScopeNeedsDynamicChecks;
246
247 if (object->getPropertySlot(callFrame, identifier, slot)) {
248 if (mode == UnknownResolve) {
249 if (seenGenericObjectScope)
250 goto fail;
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());
260
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();
268 } else
269 putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePut;
270 putToBaseOperation->m_registerAddress = &globalObject->registerAt(entry.getIndex());
271 }
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) {
277 case ReturnValue:
278 ASSERT(!putToBaseOperation);
279 operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
280 break;
281 case ReturnBase:
282 ASSERT(putToBaseOperation);
283 operations->append(ResolveOperation::returnGlobalObjectAsBase());
284 break;
285 case ReturnBaseAndValue:
286 ASSERT(putToBaseOperation);
287 operations->append(ResolveOperation::setBaseToGlobal());
288 operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
289 break;
290 case ReturnThisAndValue:
291 ASSERT(!putToBaseOperation);
292 operations->append(ResolveOperation::setBaseToUndefined());
293 operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
294 break;
295 }
296 } else {
297 if (!slot.isCacheableValue() || slot.slotBase() != globalObject)
298 goto fail;
299
300 if (requiresDynamicChecks)
301 operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
302
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());
316 }
317 switch (returnValues) {
318 case ReturnValue:
319 ASSERT(!putToBaseOperation);
320 operations->append(ResolveOperation::getAndReturnGlobalProperty());
321 break;
322 case ReturnBase:
323 ASSERT(putToBaseOperation);
324 operations->append(ResolveOperation::returnGlobalObjectAsBase());
325 break;
326 case ReturnBaseAndValue:
327 ASSERT(putToBaseOperation);
328 operations->append(ResolveOperation::setBaseToGlobal());
329 operations->append(ResolveOperation::getAndReturnGlobalProperty());
330 break;
331 case ReturnThisAndValue:
332 ASSERT(!putToBaseOperation);
333 operations->append(ResolveOperation::setBaseToUndefined());
334 operations->append(ResolveOperation::getAndReturnGlobalProperty());
335 break;
336 }
337 }
338 return object;
339 }
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));
349 goto fail;
350 }
351 // If we're getting the 'arguments' then give up on life.
352 if (identifier == callFrame->propertyNames().arguments)
353 goto fail;
354
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;
360 }
361
362 if (skipTopScopeNode)
363 operations->append(ResolveOperation::skipTopScopeNode(activationRegister));
364
365 operations->append(ResolveOperation::skipScopes(scopeCount));
366 switch (returnValues) {
367 case ReturnBaseAndValue:
368 operations->append(ResolveOperation::setBaseToScope());
369 operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex()));
370 break;
371
372 case ReturnBase:
373 operations->append(ResolveOperation::returnScopeAsBase());
374 break;
375
376 case ReturnThisAndValue:
377 operations->append(ResolveOperation::setBaseToUndefined());
378 // fallthrough
379 case ReturnValue:
380 operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex()));
381 break;
382 }
383 return object;
384 }
385 fail:
386 if (!operations->size())
387 operations->append(ResolveOperation::resolveFail());
388 }
389 return object;
390 }
391 scopeCount++;
392 } while ((scope = scope->next()));
393
394 if (mode == UnknownResolve) {
395 ASSERT(operations->isEmpty());
396 if (seenGenericObjectScope) {
397 operations->append(ResolveOperation::resolveFail());
398 return 0;
399 }
400 if (putToBaseOperation) {
401 putToBaseOperation->m_isDynamic = requiresDynamicChecks;
402 putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut;
403 putToBaseOperation->m_structure.clear();
404 putToBaseOperation->m_offset = -1;
405 }
406 if (requiresDynamicChecks)
407 operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
408 switch (returnValues) {
409 case ReturnValue:
410 ASSERT(!putToBaseOperation);
411 operations->append(ResolveOperation::getAndReturnGlobalProperty());
412 break;
413 case ReturnBase:
414 ASSERT(putToBaseOperation);
415 operations->append(ResolveOperation::returnGlobalObjectAsBase());
416 break;
417 case ReturnBaseAndValue:
418 ASSERT(putToBaseOperation);
419 operations->append(ResolveOperation::setBaseToGlobal());
420 operations->append(ResolveOperation::getAndReturnGlobalProperty());
421 break;
422 case ReturnThisAndValue:
423 ASSERT(!putToBaseOperation);
424 operations->append(ResolveOperation::setBaseToUndefined());
425 operations->append(ResolveOperation::getAndReturnGlobalProperty());
426 break;
427 }
428 }
429 return 0;
430 }
431
432 template <JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScope(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool isStrict)
433 {
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();
438 return result;
439 }
440
441 JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier, ResolveOperations* operations)
442 {
443 ASSERT(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();
449 }
450
451 if (callFrame->hadException())
452 return JSValue();
453
454 PropertySlot slot;
455 if (JSScope::resolveContainingScope<ReturnValue>(callFrame, identifier, slot, operations, 0, false)) {
456 ASSERT(operations->size());
457 return slot.getValue(callFrame, identifier);
458 }
459 ASSERT(operations->size());
460
461 return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
462 }
463
464 JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
465 {
466 ASSERT(operations);
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();
473 }
474
475 if (callFrame->hadException())
476 return JSValue();
477
478 PropertySlot slot;
479 if (JSObject* base = JSScope::resolveContainingScope<ReturnBase>(callFrame, identifier, slot, operations, putToBaseOperations, isStrict)) {
480 ASSERT(operations->size());
481 return base;
482 }
483
484 if (!isStrict)
485 return callFrame->lexicalGlobalObject();
486
487 return throwError(callFrame, createErrorForInvalidGlobalAssignment(callFrame, identifier.string()));
488 }
489
490 JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
491 {
492 ASSERT(operations);
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();
501 }
502
503 if (callFrame->hadException())
504 return JSValue();
505
506 PropertySlot slot;
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)
511 return JSValue();
512
513 *base = propertyBase;
514 return value;
515 }
516 ASSERT(operations->size());
517
518 return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
519 }
520
521 JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations)
522 {
523 ASSERT(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();
531 }
532
533 if (callFrame->hadException())
534 return JSValue();
535
536 PropertySlot slot;
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)
541 return JSValue();
542 ASSERT(value);
543 *base = propertyBase->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(propertyBase);
544 return value;
545 }
546 ASSERT(operations->size());
547
548 return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
549 }
550
551 void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& property, JSValue value, PutToBaseOperation* operation)
552 {
553 ASSERT_UNUSED(operation, operation);
554 ASSERT(base);
555 ASSERT(value);
556 switch (operation->m_kind) {
557 case PutToBaseOperation::Uninitialised:
558 CRASH();
559
560 case PutToBaseOperation::Readonly:
561 return;
562
563 case PutToBaseOperation::GlobalVariablePutChecked:
564 if (*operation->m_predicatePointer)
565 goto genericHandler;
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));
572 goto genericHandler;
573 }
574 }
575 operation->m_registerAddress->set(callFrame->vm(), base.asCell(), value);
576 return;
577
578 case PutToBaseOperation::VariablePut: {
579 if (operation->m_isDynamic) {
580 JSObject* baseObject = jsCast<JSObject*>(base);
581 if (baseObject->structure() != operation->m_structure.get())
582 goto genericHandler;
583 }
584 JSVariableObject* variableObject = jsCast<JSVariableObject*>(base);
585 variableObject->registerAt(operation->m_offset).set(callFrame->vm(), variableObject, value);
586 return;
587 }
588
589 case PutToBaseOperation::GlobalPropertyPut: {
590 JSObject* object = jsCast<JSObject*>(base);
591 if (operation->m_structure.get() != object->structure())
592 break;
593 object->putDirect(callFrame->vm(), operation->m_offset, value);
594 return;
595 }
596
597 genericHandler:
598 case PutToBaseOperation::Generic:
599 PutPropertySlot slot(operation->m_isStrict);
600 base.put(callFrame, property, value, slot);
601 return;
602 }
603 ASSERT(operation->m_kind == PutToBaseOperation::GlobalPropertyPut);
604 PutPropertySlot slot(operation->m_isStrict);
605 base.put(callFrame, property, value, slot);
606 if (!slot.isCacheable())
607 return;
608 if (callFrame->hadException())
609 return;
610 JSObject* baseObject = jsCast<JSObject*>(base);
611 if (!baseObject->structure()->propertyAccessesAreCacheable())
612 return;
613 if (slot.base() != callFrame->lexicalGlobalObject())
614 return;
615 if (slot.base() != baseObject)
616 return;
617 ASSERT(!baseObject->hasInlineStorage());
618 operation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), baseObject->structure());
619 setPutPropertyAccessOffset(operation, slot.cachedOffset());
620 return;
621 }
622
623 JSValue JSScope::resolveGlobal(CallFrame* callFrame, const Identifier& identifier, JSGlobalObject* globalObject, ResolveOperation* resolveOperation)
624 {
625 ASSERT(resolveOperation);
626 ASSERT(resolveOperation->m_operation == ResolveOperation::GetAndReturnGlobalProperty);
627 ASSERT_UNUSED(globalObject, callFrame->lexicalGlobalObject() == globalObject);
628
629 LookupResult fastResult;
630 if (executeResolveOperations(callFrame, callFrame->scope(), identifier, resolveOperation, fastResult)) {
631 ASSERT(fastResult.value());
632 ASSERT(!callFrame->hadException());
633 return fastResult.value();
634 }
635
636 if (callFrame->hadException())
637 return JSValue();
638
639 return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
640 }
641
642
643 } // namespace JSC