JSScope.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  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. #include "config.h"
  26. #include "JSScope.h"
  27. #include "JSActivation.h"
  28. #include "JSGlobalObject.h"
  29. #include "JSNameScope.h"
  30. #include "JSWithScope.h"
  31. #include "Operations.h"
  32. namespace JSC {
  33. ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSScope);
  34. void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
  35. {
  36. JSScope* thisObject = jsCast<JSScope*>(cell);
  37. ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
  38. COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
  39. ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
  40. Base::visitChildren(thisObject, visitor);
  41. visitor.append(&thisObject->m_next);
  42. }
  43. bool JSScope::isDynamicScope(bool& requiresDynamicChecks) const
  44. {
  45. switch (structure()->typeInfo().type()) {
  46. case GlobalObjectType:
  47. return static_cast<const JSGlobalObject*>(this)->isDynamicScope(requiresDynamicChecks);
  48. case ActivationObjectType:
  49. return static_cast<const JSActivation*>(this)->isDynamicScope(requiresDynamicChecks);
  50. case NameScopeObjectType:
  51. return static_cast<const JSNameScope*>(this)->isDynamicScope(requiresDynamicChecks);
  52. default:
  53. RELEASE_ASSERT_NOT_REACHED();
  54. break;
  55. }
  56. return false;
  57. }
  58. JSObject* JSScope::objectAtScope(JSScope* scope)
  59. {
  60. JSObject* object = scope;
  61. if (object->structure()->typeInfo().type() == WithScopeType)
  62. return jsCast<JSWithScope*>(object)->object();
  63. return object;
  64. }
  65. int JSScope::localDepth()
  66. {
  67. int scopeDepth = 0;
  68. ScopeChainIterator iter = this->begin();
  69. ScopeChainIterator end = this->end();
  70. while (!iter->inherits(&JSActivation::s_info)) {
  71. ++iter;
  72. if (iter == end)
  73. break;
  74. ++scopeDepth;
  75. }
  76. return scopeDepth;
  77. }
  78. struct LookupResult {
  79. JSValue base() const { return m_base; }
  80. JSValue value() const { return m_value; }
  81. void setBase(JSValue base) { ASSERT(base); m_base = base; }
  82. void setValue(JSValue value) { ASSERT(value); m_value = value; }
  83. private:
  84. JSValue m_base;
  85. JSValue m_value;
  86. };
  87. static void setPutPropertyAccessOffset(PutToBaseOperation* operation, PropertyOffset offset)
  88. {
  89. ASSERT(isOutOfLineOffset(offset));
  90. operation->m_offset = offset;
  91. operation->m_offsetInButterfly = offsetInButterfly(offset);
  92. }
  93. static bool executeResolveOperations(CallFrame* callFrame, JSScope* scope, const Identifier& propertyName, ResolveOperation* pc, LookupResult& result)
  94. {
  95. while (true) {
  96. switch (pc->m_operation) {
  97. case ResolveOperation::Fail:
  98. return false;
  99. case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope: {
  100. while (JSScope* nextScope = scope->next()) {
  101. if (scope->isActivationObject() && scope->structure() != scope->globalObject()->activationStructure())
  102. return false;
  103. ASSERT(scope->isNameScopeObject() || scope->isVariableObject() || scope->isGlobalObject());
  104. scope = nextScope;
  105. }
  106. pc++;
  107. break;
  108. }
  109. case ResolveOperation::SetBaseToUndefined:
  110. result.setBase(jsUndefined());
  111. pc++;
  112. continue;
  113. case ResolveOperation::SetBaseToScope:
  114. result.setBase(scope);
  115. pc++;
  116. continue;
  117. case ResolveOperation::ReturnScopeAsBase:
  118. result.setBase(scope);
  119. return true;
  120. case ResolveOperation::SetBaseToGlobal:
  121. result.setBase(scope->globalObject());
  122. pc++;
  123. continue;
  124. case ResolveOperation::SkipScopes: {
  125. int count = pc->m_scopesToSkip;
  126. while (count--)
  127. scope = scope->next();
  128. ASSERT(scope);
  129. pc++;
  130. continue;
  131. }
  132. case ResolveOperation::SkipTopScopeNode:
  133. if (callFrame->r(pc->m_activationRegister).jsValue())
  134. scope = scope->next();
  135. ASSERT(scope);
  136. pc++;
  137. continue;
  138. case ResolveOperation::GetAndReturnScopedVar:
  139. ASSERT(jsCast<JSVariableObject*>(scope)->registerAt(pc->m_offset).get());
  140. result.setValue(jsCast<JSVariableObject*>(scope)->registerAt(pc->m_offset).get());
  141. return true;
  142. case ResolveOperation::GetAndReturnGlobalVar:
  143. result.setValue(pc->m_registerAddress->get());
  144. return true;
  145. case ResolveOperation::GetAndReturnGlobalVarWatchable:
  146. result.setValue(pc->m_registerAddress->get());
  147. return true;
  148. case ResolveOperation::ReturnGlobalObjectAsBase:
  149. result.setBase(callFrame->lexicalGlobalObject());
  150. return true;
  151. case ResolveOperation::GetAndReturnGlobalProperty: {
  152. JSGlobalObject* globalObject = scope->globalObject();
  153. if (globalObject->structure() == pc->m_structure.get()) {
  154. result.setValue(globalObject->getDirect(pc->m_offset));
  155. return true;
  156. }
  157. PropertySlot slot(globalObject);
  158. if (!globalObject->getPropertySlot(callFrame, propertyName, slot))
  159. return false;
  160. JSValue value = slot.getValue(callFrame, propertyName);
  161. if (callFrame->hadException())
  162. return false;
  163. Structure* structure = globalObject->structure();
  164. // Don't try to cache prototype lookups
  165. if (globalObject != slot.slotBase() || !slot.isCacheableValue() || !structure->propertyAccessesAreCacheable()) {
  166. result.setValue(value);
  167. return true;
  168. }
  169. pc->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), structure);
  170. pc->m_offset = slot.cachedOffset();
  171. result.setValue(value);
  172. return true;
  173. }
  174. }
  175. }
  176. }
  177. template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScopeInternal(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector_shared<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool )
  178. {
  179. JSScope* scope = callFrame->scope();
  180. ASSERT(scope);
  181. int scopeCount = 0;
  182. bool seenGenericObjectScope = false;
  183. bool requiresDynamicChecks = false;
  184. bool skipTopScopeNode = false;
  185. int activationRegister = 0;
  186. CodeBlock* codeBlock = callFrame->codeBlock();
  187. if (mode == UnknownResolve) {
  188. ASSERT(operations->isEmpty());
  189. if (codeBlock->codeType() == FunctionCode && codeBlock->needsActivation()) {
  190. activationRegister = codeBlock->activationRegister();
  191. JSValue activation = callFrame->r(activationRegister).jsValue();
  192. // If the activation register doesn't match our actual scope, a dynamic
  193. // scope has been inserted so we shouldn't skip the top scope node.
  194. if (activation == scope) {
  195. jsCast<JSActivation*>(activation.asCell())->isDynamicScope(requiresDynamicChecks);
  196. if (!requiresDynamicChecks) {
  197. ASSERT(jsCast<JSActivation*>(activation.asCell())->symbolTable()->get(identifier.impl()).isNull());
  198. scope = scope->next();
  199. ASSERT(scope);
  200. skipTopScopeNode = true;
  201. }
  202. } else if (!activation)
  203. skipTopScopeNode = true;
  204. }
  205. } else
  206. ASSERT(operations->size());
  207. if (codeBlock->codeType() == EvalCode && scope->next())
  208. requiresDynamicChecks = true;
  209. if (mode == UnknownResolve && putToBaseOperation)
  210. putToBaseOperation->m_kind = PutToBaseOperation::Generic;
  211. do {
  212. JSObject* object = JSScope::objectAtScope(scope);
  213. slot = PropertySlot(object);
  214. bool currentScopeNeedsDynamicChecks = false;
  215. if (!(scope->isVariableObject() || scope->isNameScopeObject()) || (scope->next() && scope->isDynamicScope(currentScopeNeedsDynamicChecks)))
  216. seenGenericObjectScope = true;
  217. requiresDynamicChecks = requiresDynamicChecks || currentScopeNeedsDynamicChecks;
  218. if (object->getPropertySlot(callFrame, identifier, slot)) {
  219. if (mode == UnknownResolve) {
  220. if (seenGenericObjectScope)
  221. goto fail;
  222. if (putToBaseOperation)
  223. putToBaseOperation->m_isDynamic = requiresDynamicChecks;
  224. if (!scope->next()) {
  225. // Global lookup of some kind
  226. JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(scope);
  227. SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl());
  228. if (!entry.isNull()) {
  229. if (requiresDynamicChecks)
  230. operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
  231. if (putToBaseOperation) {
  232. putToBaseOperation->m_isDynamic = requiresDynamicChecks;
  233. if (entry.isReadOnly())
  234. putToBaseOperation->m_kind = PutToBaseOperation::Readonly;
  235. else if (entry.couldBeWatched()) {
  236. putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePutChecked;
  237. putToBaseOperation->m_predicatePointer = entry.addressOfIsWatched();
  238. } else
  239. putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePut;
  240. putToBaseOperation->m_registerAddress = &globalObject->registerAt(entry.getIndex());
  241. }
  242. // Override custom accessor behaviour that the DOM introduces for some
  243. // event handlers declared on function declarations.
  244. if (!requiresDynamicChecks)
  245. slot.setValue(globalObject, globalObject->registerAt(entry.getIndex()).get());
  246. switch (returnValues) {
  247. case ReturnValue:
  248. ASSERT(!putToBaseOperation);
  249. operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
  250. break;
  251. case ReturnBase:
  252. ASSERT(putToBaseOperation);
  253. operations->append(ResolveOperation::returnGlobalObjectAsBase());
  254. break;
  255. case ReturnBaseAndValue:
  256. ASSERT(putToBaseOperation);
  257. operations->append(ResolveOperation::setBaseToGlobal());
  258. operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
  259. break;
  260. case ReturnThisAndValue:
  261. ASSERT(!putToBaseOperation);
  262. operations->append(ResolveOperation::setBaseToUndefined());
  263. operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched()));
  264. break;
  265. }
  266. } else {
  267. if (!slot.isCacheableValue() || slot.slotBase() != globalObject)
  268. goto fail;
  269. if (requiresDynamicChecks)
  270. operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
  271. if (putToBaseOperation) {
  272. putToBaseOperation->m_isDynamic = requiresDynamicChecks;
  273. putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut;
  274. putToBaseOperation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure());
  275. setPutPropertyAccessOffset(putToBaseOperation, slot.cachedOffset());
  276. }
  277. switch (returnValues) {
  278. case ReturnValue:
  279. ASSERT(!putToBaseOperation);
  280. operations->append(ResolveOperation::getAndReturnGlobalProperty());
  281. break;
  282. case ReturnBase:
  283. ASSERT(putToBaseOperation);
  284. operations->append(ResolveOperation::returnGlobalObjectAsBase());
  285. break;
  286. case ReturnBaseAndValue:
  287. ASSERT(putToBaseOperation);
  288. operations->append(ResolveOperation::setBaseToGlobal());
  289. operations->append(ResolveOperation::getAndReturnGlobalProperty());
  290. break;
  291. case ReturnThisAndValue:
  292. ASSERT(!putToBaseOperation);
  293. operations->append(ResolveOperation::setBaseToUndefined());
  294. operations->append(ResolveOperation::getAndReturnGlobalProperty());
  295. break;
  296. }
  297. }
  298. return object;
  299. }
  300. if (!requiresDynamicChecks) {
  301. // Normal lexical lookup
  302. JSVariableObject* variableObject = jsCast<JSVariableObject*>(scope);
  303. ASSERT(variableObject);
  304. ASSERT(variableObject->symbolTable());
  305. SymbolTableEntry entry = variableObject->symbolTable()->get(identifier.impl());
  306. // Defend against the variable being actually inserted by eval.
  307. if (entry.isNull()) {
  308. ASSERT(!jsDynamicCast<JSNameScope*>(variableObject));
  309. goto fail;
  310. }
  311. // If we're getting the 'arguments' then give up on life.
  312. if (identifier == callFrame->propertyNames().arguments)
  313. goto fail;
  314. if (putToBaseOperation) {
  315. putToBaseOperation->m_kind = entry.isReadOnly() ? PutToBaseOperation::Readonly : PutToBaseOperation::VariablePut;
  316. putToBaseOperation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), callFrame->lexicalGlobalObject()->activationStructure());
  317. putToBaseOperation->m_offset = entry.getIndex();
  318. putToBaseOperation->m_scopeDepth = (skipTopScopeNode ? 1 : 0) + scopeCount;
  319. }
  320. if (skipTopScopeNode)
  321. operations->append(ResolveOperation::skipTopScopeNode(activationRegister));
  322. operations->append(ResolveOperation::skipScopes(scopeCount));
  323. switch (returnValues) {
  324. case ReturnBaseAndValue:
  325. operations->append(ResolveOperation::setBaseToScope());
  326. operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex()));
  327. break;
  328. case ReturnBase:
  329. operations->append(ResolveOperation::returnScopeAsBase());
  330. break;
  331. case ReturnThisAndValue:
  332. operations->append(ResolveOperation::setBaseToUndefined());
  333. // fallthrough
  334. case ReturnValue:
  335. operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex()));
  336. break;
  337. }
  338. return object;
  339. }
  340. fail:
  341. if (!operations->size())
  342. operations->append(ResolveOperation::resolveFail());
  343. }
  344. return object;
  345. }
  346. scopeCount++;
  347. } while ((scope = scope->next()));
  348. if (mode == UnknownResolve) {
  349. ASSERT(operations->isEmpty());
  350. if (seenGenericObjectScope) {
  351. operations->append(ResolveOperation::resolveFail());
  352. return 0;
  353. }
  354. if (putToBaseOperation) {
  355. putToBaseOperation->m_isDynamic = requiresDynamicChecks;
  356. putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut;
  357. putToBaseOperation->m_structure.clear();
  358. putToBaseOperation->m_offset = -1;
  359. }
  360. if (requiresDynamicChecks)
  361. operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
  362. switch (returnValues) {
  363. case ReturnValue:
  364. ASSERT(!putToBaseOperation);
  365. operations->append(ResolveOperation::getAndReturnGlobalProperty());
  366. break;
  367. case ReturnBase:
  368. ASSERT(putToBaseOperation);
  369. operations->append(ResolveOperation::returnGlobalObjectAsBase());
  370. break;
  371. case ReturnBaseAndValue:
  372. ASSERT(putToBaseOperation);
  373. operations->append(ResolveOperation::setBaseToGlobal());
  374. operations->append(ResolveOperation::getAndReturnGlobalProperty());
  375. break;
  376. case ReturnThisAndValue:
  377. ASSERT(!putToBaseOperation);
  378. operations->append(ResolveOperation::setBaseToUndefined());
  379. operations->append(ResolveOperation::getAndReturnGlobalProperty());
  380. break;
  381. }
  382. }
  383. return 0;
  384. }
  385. template <JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScope(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector_shared<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool isStrict)
  386. {
  387. if (operations->size())
  388. return resolveContainingScopeInternal<KnownResolve, returnValues>(callFrame, identifier, slot, operations, putToBaseOperation, isStrict);
  389. JSObject* result = resolveContainingScopeInternal<UnknownResolve, returnValues>(callFrame, identifier, slot, operations, putToBaseOperation, isStrict);
  390. operations->shrinkToFit();
  391. return result;
  392. }
  393. JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier, ResolveOperations* operations)
  394. {
  395. ASSERT(operations);
  396. LookupResult fastResult;
  397. if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
  398. ASSERT(fastResult.value());
  399. ASSERT(!callFrame->hadException());
  400. return fastResult.value();
  401. }
  402. if (callFrame->hadException())
  403. return JSValue();
  404. PropertySlot slot;
  405. if (JSScope::resolveContainingScope<ReturnValue>(callFrame, identifier, slot, operations, 0, false)) {
  406. ASSERT(operations->size());
  407. return slot.getValue(callFrame, identifier);
  408. }
  409. ASSERT(operations->size());
  410. return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
  411. }
  412. JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
  413. {
  414. ASSERT(operations);
  415. ASSERT_UNUSED(putToBaseOperations, putToBaseOperations);
  416. LookupResult fastResult;
  417. if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
  418. ASSERT(fastResult.base());
  419. ASSERT(!callFrame->hadException());
  420. return fastResult.base();
  421. }
  422. if (callFrame->hadException())
  423. return JSValue();
  424. PropertySlot slot;
  425. if (JSObject* base = JSScope::resolveContainingScope<ReturnBase>(callFrame, identifier, slot, operations, putToBaseOperations, isStrict)) {
  426. ASSERT(operations->size());
  427. return base;
  428. }
  429. if (!isStrict)
  430. return callFrame->lexicalGlobalObject();
  431. return throwError(callFrame, createErrorForInvalidGlobalAssignment(callFrame, identifier.string()));
  432. }
  433. JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations)
  434. {
  435. ASSERT(operations);
  436. ASSERT_UNUSED(putToBaseOperations, putToBaseOperations);
  437. LookupResult fastResult;
  438. if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
  439. ASSERT(fastResult.base());
  440. ASSERT(fastResult.value());
  441. ASSERT(!callFrame->hadException());
  442. *base = fastResult.base();
  443. return fastResult.value();
  444. }
  445. if (callFrame->hadException())
  446. return JSValue();
  447. PropertySlot slot;
  448. if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnBaseAndValue>(callFrame, identifier, slot, operations, putToBaseOperations, false)) {
  449. ASSERT(operations->size());
  450. JSValue value = slot.getValue(callFrame, identifier);
  451. if (callFrame->vm().exception)
  452. return JSValue();
  453. *base = propertyBase;
  454. return value;
  455. }
  456. ASSERT(operations->size());
  457. return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
  458. }
  459. JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations)
  460. {
  461. ASSERT(operations);
  462. LookupResult fastResult;
  463. if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) {
  464. ASSERT(fastResult.base());
  465. ASSERT(fastResult.value());
  466. ASSERT(!callFrame->hadException());
  467. *base = fastResult.base();
  468. return fastResult.value();
  469. }
  470. if (callFrame->hadException())
  471. return JSValue();
  472. PropertySlot slot;
  473. if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnThisAndValue>(callFrame, identifier, slot, operations, 0, false)) {
  474. ASSERT(operations->size());
  475. JSValue value = slot.getValue(callFrame, identifier);
  476. if (callFrame->vm().exception)
  477. return JSValue();
  478. ASSERT(value);
  479. *base = propertyBase->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(propertyBase);
  480. return value;
  481. }
  482. ASSERT(operations->size());
  483. return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
  484. }
  485. void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& property, JSValue value, PutToBaseOperation* operation)
  486. {
  487. ASSERT_UNUSED(operation, operation);
  488. ASSERT(base);
  489. ASSERT(value);
  490. switch (operation->m_kind) {
  491. case PutToBaseOperation::Uninitialised:
  492. CRASH();
  493. case PutToBaseOperation::Readonly:
  494. return;
  495. case PutToBaseOperation::GlobalVariablePutChecked:
  496. if (*operation->m_predicatePointer)
  497. goto genericHandler;
  498. case PutToBaseOperation::GlobalVariablePut:
  499. if (operation->m_isDynamic) {
  500. JSObject* baseObject = jsCast<JSObject*>(base);
  501. if (baseObject != callFrame->lexicalGlobalObject()) {
  502. if (baseObject->isGlobalObject())
  503. ASSERT(!jsCast<JSGlobalObject*>(baseObject)->assertRegisterIsInThisObject(operation->m_registerAddress));
  504. goto genericHandler;
  505. }
  506. }
  507. operation->m_registerAddress->set(callFrame->vm(), base.asCell(), value);
  508. return;
  509. case PutToBaseOperation::VariablePut: {
  510. if (operation->m_isDynamic) {
  511. JSObject* baseObject = jsCast<JSObject*>(base);
  512. if (baseObject->structure() != operation->m_structure.get())
  513. goto genericHandler;
  514. }
  515. JSVariableObject* variableObject = jsCast<JSVariableObject*>(base);
  516. variableObject->registerAt(operation->m_offset).set(callFrame->vm(), variableObject, value);
  517. return;
  518. }
  519. case PutToBaseOperation::GlobalPropertyPut: {
  520. JSObject* object = jsCast<JSObject*>(base);
  521. if (operation->m_structure.get() != object->structure())
  522. break;
  523. object->putDirect(callFrame->vm(), operation->m_offset, value);
  524. return;
  525. }
  526. genericHandler:
  527. case PutToBaseOperation::Generic:
  528. PutPropertySlot slot(operation->m_isStrict);
  529. base.put(callFrame, property, value, slot);
  530. return;
  531. }
  532. ASSERT(operation->m_kind == PutToBaseOperation::GlobalPropertyPut);
  533. PutPropertySlot slot(operation->m_isStrict);
  534. base.put(callFrame, property, value, slot);
  535. if (!slot.isCacheable())
  536. return;
  537. if (callFrame->hadException())
  538. return;
  539. JSObject* baseObject = jsCast<JSObject*>(base);
  540. if (!baseObject->structure()->propertyAccessesAreCacheable())
  541. return;
  542. if (slot.base() != callFrame->lexicalGlobalObject())
  543. return;
  544. if (slot.base() != baseObject)
  545. return;
  546. ASSERT(!baseObject->hasInlineStorage());
  547. operation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), baseObject->structure());
  548. setPutPropertyAccessOffset(operation, slot.cachedOffset());
  549. return;
  550. }
  551. JSValue JSScope::resolveGlobal(CallFrame* callFrame, const Identifier& identifier, JSGlobalObject* globalObject, ResolveOperation* resolveOperation)
  552. {
  553. ASSERT(resolveOperation);
  554. ASSERT(resolveOperation->m_operation == ResolveOperation::GetAndReturnGlobalProperty);
  555. ASSERT_UNUSED(globalObject, callFrame->lexicalGlobalObject() == globalObject);
  556. LookupResult fastResult;
  557. if (executeResolveOperations(callFrame, callFrame->scope(), identifier, resolveOperation, fastResult)) {
  558. ASSERT(fastResult.value());
  559. ASSERT(!callFrame->hadException());
  560. return fastResult.value();
  561. }
  562. if (callFrame->hadException())
  563. return JSValue();
  564. return throwError(callFrame, createUndefinedVariableError(callFrame, identifier));
  565. }
  566. } // namespace JSC