PageRenderTime 32ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/src/qt/qtwebkit/Source/JavaScriptCore/runtime/JSObject.cpp

https://gitlab.com/x33n/phantomjs
C++ | 1388 lines | 1089 code | 238 blank | 61 comment | 183 complexity | 76a08c3e0f7784e53dbcef3eca0e3ada MD5 | raw file
  1. /*
  2. * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  3. * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  4. * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
  5. * Copyright (C) 2007 Eric Seidel (eric@webkit.org)
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Library General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public License
  18. * along with this library; see the file COPYING.LIB. If not, write to
  19. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  20. * Boston, MA 02110-1301, USA.
  21. *
  22. */
  23. #include "config.h"
  24. #include "JSObject.h"
  25. #include "ButterflyInlines.h"
  26. #include "CopiedSpaceInlines.h"
  27. #include "CopyVisitor.h"
  28. #include "CopyVisitorInlines.h"
  29. #include "DatePrototype.h"
  30. #include "ErrorConstructor.h"
  31. #include "Executable.h"
  32. #include "GetterSetter.h"
  33. #include "IndexingHeaderInlines.h"
  34. #include "JSFunction.h"
  35. #include "JSGlobalObject.h"
  36. #include "Lookup.h"
  37. #include "NativeErrorConstructor.h"
  38. #include "Nodes.h"
  39. #include "ObjectPrototype.h"
  40. #include "Operations.h"
  41. #include "PropertyDescriptor.h"
  42. #include "PropertyNameArray.h"
  43. #include "Reject.h"
  44. #include "SlotVisitorInlines.h"
  45. #include <math.h>
  46. #include <wtf/Assertions.h>
  47. namespace JSC {
  48. // We keep track of the size of the last array after it was grown. We use this
  49. // as a simple heuristic for as the value to grow the next array from size 0.
  50. // This value is capped by the constant FIRST_VECTOR_GROW defined in
  51. // ArrayConventions.h.
  52. static unsigned lastArraySize = 0;
  53. JSCell* getCallableObjectSlow(JSCell* cell)
  54. {
  55. Structure* structure = cell->structure();
  56. if (structure->typeInfo().type() == JSFunctionType)
  57. return cell;
  58. if (structure->classInfo()->isSubClassOf(&InternalFunction::s_info))
  59. return cell;
  60. return 0;
  61. }
  62. ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject);
  63. ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject);
  64. const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
  65. const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSObject) };
  66. const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) };
  67. static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify)
  68. {
  69. // Add properties from the static hashtables of properties
  70. for (; classInfo; classInfo = classInfo->parentClass) {
  71. const HashTable* table = classInfo->propHashTable(exec);
  72. if (!table)
  73. continue;
  74. table->initializeIfNeeded(exec);
  75. ASSERT(table->table);
  76. int hashSizeMask = table->compactSize - 1;
  77. const HashEntry* entry = table->table;
  78. for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
  79. if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & Function) && didReify))
  80. propertyNames.add(entry->key());
  81. }
  82. }
  83. }
  84. ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize)
  85. {
  86. ASSERT(butterfly);
  87. Structure* structure = this->structure();
  88. size_t propertyCapacity = structure->outOfLineCapacity();
  89. size_t preCapacity;
  90. size_t indexingPayloadSizeInBytes;
  91. bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
  92. if (UNLIKELY(hasIndexingHeader)) {
  93. preCapacity = butterfly->indexingHeader()->preCapacity(structure);
  94. indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
  95. } else {
  96. preCapacity = 0;
  97. indexingPayloadSizeInBytes = 0;
  98. }
  99. size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
  100. if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity))) {
  101. Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
  102. // Copy the properties.
  103. PropertyStorage currentTarget = newButterfly->propertyStorage();
  104. PropertyStorage currentSource = butterfly->propertyStorage();
  105. for (size_t count = storageSize; count--;)
  106. (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get());
  107. if (UNLIKELY(hasIndexingHeader)) {
  108. *newButterfly->indexingHeader() = *butterfly->indexingHeader();
  109. // Copy the array if appropriate.
  110. WriteBarrier<Unknown>* currentTarget;
  111. WriteBarrier<Unknown>* currentSource;
  112. size_t count;
  113. switch (structure->indexingType()) {
  114. case ALL_UNDECIDED_INDEXING_TYPES:
  115. case ALL_CONTIGUOUS_INDEXING_TYPES:
  116. case ALL_INT32_INDEXING_TYPES:
  117. case ALL_DOUBLE_INDEXING_TYPES: {
  118. currentTarget = newButterfly->contiguous().data();
  119. currentSource = butterfly->contiguous().data();
  120. RELEASE_ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
  121. count = newButterfly->vectorLength();
  122. break;
  123. }
  124. case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
  125. newButterfly->arrayStorage()->copyHeaderFromDuringGC(*butterfly->arrayStorage());
  126. currentTarget = newButterfly->arrayStorage()->m_vector;
  127. currentSource = butterfly->arrayStorage()->m_vector;
  128. count = newButterfly->arrayStorage()->vectorLength();
  129. break;
  130. }
  131. default:
  132. CRASH();
  133. currentTarget = 0;
  134. currentSource = 0;
  135. count = 0;
  136. break;
  137. }
  138. memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
  139. }
  140. m_butterfly = newButterfly;
  141. visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
  142. }
  143. }
  144. ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize)
  145. {
  146. ASSERT(butterfly);
  147. Structure* structure = this->structure();
  148. size_t propertyCapacity = structure->outOfLineCapacity();
  149. size_t preCapacity;
  150. size_t indexingPayloadSizeInBytes;
  151. bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
  152. if (UNLIKELY(hasIndexingHeader)) {
  153. preCapacity = butterfly->indexingHeader()->preCapacity(structure);
  154. indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
  155. } else {
  156. preCapacity = 0;
  157. indexingPayloadSizeInBytes = 0;
  158. }
  159. size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
  160. // Mark the properties.
  161. visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
  162. visitor.copyLater(this, butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
  163. // Mark the array if appropriate.
  164. switch (structure->indexingType()) {
  165. case ALL_CONTIGUOUS_INDEXING_TYPES:
  166. visitor.appendValues(butterfly->contiguous().data(), butterfly->publicLength());
  167. break;
  168. case ALL_ARRAY_STORAGE_INDEXING_TYPES:
  169. visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength());
  170. if (butterfly->arrayStorage()->m_sparseMap)
  171. visitor.append(&butterfly->arrayStorage()->m_sparseMap);
  172. break;
  173. default:
  174. break;
  175. }
  176. }
  177. void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
  178. {
  179. JSObject* thisObject = jsCast<JSObject*>(cell);
  180. ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
  181. #if !ASSERT_DISABLED
  182. bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
  183. visitor.m_isCheckingForDefaultMarkViolation = false;
  184. #endif
  185. JSCell::visitChildren(thisObject, visitor);
  186. Butterfly* butterfly = thisObject->butterfly();
  187. if (butterfly)
  188. thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
  189. #if !ASSERT_DISABLED
  190. visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
  191. #endif
  192. }
  193. void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor)
  194. {
  195. JSObject* thisObject = jsCast<JSObject*>(cell);
  196. ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
  197. Butterfly* butterfly = thisObject->butterfly();
  198. if (butterfly)
  199. thisObject->copyButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
  200. }
  201. void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
  202. {
  203. JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell);
  204. ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
  205. #if !ASSERT_DISABLED
  206. bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
  207. visitor.m_isCheckingForDefaultMarkViolation = false;
  208. #endif
  209. JSCell::visitChildren(thisObject, visitor);
  210. Butterfly* butterfly = thisObject->butterfly();
  211. if (butterfly)
  212. thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
  213. size_t storageSize = thisObject->structure()->inlineSize();
  214. visitor.appendValues(thisObject->inlineStorage(), storageSize);
  215. #if !ASSERT_DISABLED
  216. visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
  217. #endif
  218. }
  219. String JSObject::className(const JSObject* object)
  220. {
  221. const ClassInfo* info = object->classInfo();
  222. ASSERT(info);
  223. return info->className;
  224. }
  225. bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
  226. {
  227. // NB. The fact that we're directly consulting our indexed storage implies that it is not
  228. // legal for anyone to override getOwnPropertySlot() without also overriding
  229. // getOwnPropertySlotByIndex().
  230. JSObject* thisObject = jsCast<JSObject*>(cell);
  231. if (i > MAX_ARRAY_INDEX)
  232. return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
  233. switch (thisObject->structure()->indexingType()) {
  234. case ALL_BLANK_INDEXING_TYPES:
  235. case ALL_UNDECIDED_INDEXING_TYPES:
  236. break;
  237. case ALL_INT32_INDEXING_TYPES:
  238. case ALL_CONTIGUOUS_INDEXING_TYPES: {
  239. Butterfly* butterfly = thisObject->m_butterfly;
  240. if (i >= butterfly->vectorLength())
  241. return false;
  242. JSValue value = butterfly->contiguous()[i].get();
  243. if (value) {
  244. slot.setValue(value);
  245. return true;
  246. }
  247. return false;
  248. }
  249. case ALL_DOUBLE_INDEXING_TYPES: {
  250. Butterfly* butterfly = thisObject->m_butterfly;
  251. if (i >= butterfly->vectorLength())
  252. return false;
  253. double value = butterfly->contiguousDouble()[i];
  254. if (value == value) {
  255. slot.setValue(JSValue(JSValue::EncodeAsDouble, value));
  256. return true;
  257. }
  258. return false;
  259. }
  260. case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
  261. ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
  262. if (i >= storage->length())
  263. return false;
  264. if (i < storage->vectorLength()) {
  265. JSValue value = storage->m_vector[i].get();
  266. if (value) {
  267. slot.setValue(value);
  268. return true;
  269. }
  270. } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
  271. SparseArrayValueMap::iterator it = map->find(i);
  272. if (it != map->notFound()) {
  273. it->value.get(slot);
  274. return true;
  275. }
  276. }
  277. break;
  278. }
  279. default:
  280. RELEASE_ASSERT_NOT_REACHED();
  281. break;
  282. }
  283. return false;
  284. }
  285. // ECMA 8.6.2.2
  286. void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
  287. {
  288. JSObject* thisObject = jsCast<JSObject*>(cell);
  289. ASSERT(value);
  290. ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
  291. VM& vm = exec->vm();
  292. // Try indexed put first. This is required for correctness, since loads on property names that appear like
  293. // valid indices will never look in the named property storage.
  294. unsigned i = propertyName.asIndex();
  295. if (i != PropertyName::NotAnIndex) {
  296. putByIndex(thisObject, exec, i, value, slot.isStrictMode());
  297. return;
  298. }
  299. // Check if there are any setters or getters in the prototype chain
  300. JSValue prototype;
  301. if (propertyName != exec->propertyNames().underscoreProto) {
  302. for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
  303. prototype = obj->prototype();
  304. if (prototype.isNull()) {
  305. ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
  306. if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value))
  307. && slot.isStrictMode())
  308. throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
  309. return;
  310. }
  311. }
  312. }
  313. JSObject* obj;
  314. for (obj = thisObject; ; obj = asObject(prototype)) {
  315. unsigned attributes;
  316. JSCell* specificValue;
  317. PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
  318. if (isValidOffset(offset)) {
  319. if (attributes & ReadOnly) {
  320. ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
  321. if (slot.isStrictMode())
  322. throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
  323. return;
  324. }
  325. JSValue gs = obj->getDirect(offset);
  326. if (gs.isGetterSetter()) {
  327. ASSERT(attributes & Accessor);
  328. ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
  329. JSObject* setterFunc = asGetterSetter(gs)->setter();
  330. if (!setterFunc) {
  331. if (slot.isStrictMode())
  332. throwError(exec, createTypeError(exec, ASCIILiteral("setting a property that has only a getter")));
  333. return;
  334. }
  335. CallData callData;
  336. CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
  337. MarkedArgumentBuffer args;
  338. args.append(value);
  339. // If this is WebCore's global object then we need to substitute the shell.
  340. call(exec, setterFunc, callType, callData, thisObject->methodTable()->toThisObject(thisObject, exec), args);
  341. return;
  342. } else
  343. ASSERT(!(attributes & Accessor));
  344. // If there's an existing property on the object or one of its
  345. // prototypes it should be replaced, so break here.
  346. break;
  347. }
  348. prototype = obj->prototype();
  349. if (prototype.isNull())
  350. break;
  351. }
  352. ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
  353. if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
  354. throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
  355. return;
  356. }
  357. void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
  358. {
  359. JSObject* thisObject = jsCast<JSObject*>(cell);
  360. if (propertyName > MAX_ARRAY_INDEX) {
  361. PutPropertySlot slot(shouldThrow);
  362. thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
  363. return;
  364. }
  365. switch (thisObject->structure()->indexingType()) {
  366. case ALL_BLANK_INDEXING_TYPES:
  367. break;
  368. case ALL_UNDECIDED_INDEXING_TYPES: {
  369. thisObject->convertUndecidedForValue(exec->vm(), value);
  370. // Reloop.
  371. putByIndex(cell, exec, propertyName, value, shouldThrow);
  372. return;
  373. }
  374. case ALL_INT32_INDEXING_TYPES: {
  375. if (!value.isInt32()) {
  376. thisObject->convertInt32ForValue(exec->vm(), value);
  377. putByIndex(cell, exec, propertyName, value, shouldThrow);
  378. return;
  379. }
  380. // Fall through.
  381. }
  382. case ALL_CONTIGUOUS_INDEXING_TYPES: {
  383. Butterfly* butterfly = thisObject->m_butterfly;
  384. if (propertyName >= butterfly->vectorLength())
  385. break;
  386. butterfly->contiguous()[propertyName].set(exec->vm(), thisObject, value);
  387. if (propertyName >= butterfly->publicLength())
  388. butterfly->setPublicLength(propertyName + 1);
  389. return;
  390. }
  391. case ALL_DOUBLE_INDEXING_TYPES: {
  392. if (!value.isNumber()) {
  393. thisObject->convertDoubleToContiguous(exec->vm());
  394. // Reloop.
  395. putByIndex(cell, exec, propertyName, value, shouldThrow);
  396. return;
  397. }
  398. double valueAsDouble = value.asNumber();
  399. if (valueAsDouble != valueAsDouble) {
  400. thisObject->convertDoubleToContiguous(exec->vm());
  401. // Reloop.
  402. putByIndex(cell, exec, propertyName, value, shouldThrow);
  403. return;
  404. }
  405. Butterfly* butterfly = thisObject->m_butterfly;
  406. if (propertyName >= butterfly->vectorLength())
  407. break;
  408. butterfly->contiguousDouble()[propertyName] = valueAsDouble;
  409. if (propertyName >= butterfly->publicLength())
  410. butterfly->setPublicLength(propertyName + 1);
  411. return;
  412. }
  413. case NonArrayWithArrayStorage:
  414. case ArrayWithArrayStorage: {
  415. ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
  416. if (propertyName >= storage->vectorLength())
  417. break;
  418. WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
  419. unsigned length = storage->length();
  420. // Update length & m_numValuesInVector as necessary.
  421. if (propertyName >= length) {
  422. length = propertyName + 1;
  423. storage->setLength(length);
  424. ++storage->m_numValuesInVector;
  425. } else if (!valueSlot)
  426. ++storage->m_numValuesInVector;
  427. valueSlot.set(exec->vm(), thisObject, value);
  428. return;
  429. }
  430. case NonArrayWithSlowPutArrayStorage:
  431. case ArrayWithSlowPutArrayStorage: {
  432. ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
  433. if (propertyName >= storage->vectorLength())
  434. break;
  435. WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
  436. unsigned length = storage->length();
  437. // Update length & m_numValuesInVector as necessary.
  438. if (propertyName >= length) {
  439. if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
  440. return;
  441. length = propertyName + 1;
  442. storage->setLength(length);
  443. ++storage->m_numValuesInVector;
  444. } else if (!valueSlot) {
  445. if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
  446. return;
  447. ++storage->m_numValuesInVector;
  448. }
  449. valueSlot.set(exec->vm(), thisObject, value);
  450. return;
  451. }
  452. default:
  453. RELEASE_ASSERT_NOT_REACHED();
  454. }
  455. thisObject->putByIndexBeyondVectorLength(exec, propertyName, value, shouldThrow);
  456. }
  457. ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM& vm, ArrayStorage* storage)
  458. {
  459. SparseArrayValueMap* map = storage->m_sparseMap.get();
  460. if (!map)
  461. map = allocateSparseIndexMap(vm);
  462. if (map->sparseMode())
  463. return storage;
  464. map->setSparseMode();
  465. unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
  466. for (unsigned i = 0; i < usedVectorLength; ++i) {
  467. JSValue value = storage->m_vector[i].get();
  468. // This will always be a new entry in the map, so no need to check we can write,
  469. // and attributes are default so no need to set them.
  470. if (value)
  471. map->add(this, i).iterator->value.set(vm, this, value);
  472. }
  473. Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, structure(), 0, ArrayStorage::sizeFor(0));
  474. RELEASE_ASSERT(newButterfly);
  475. m_butterfly = newButterfly;
  476. newButterfly->arrayStorage()->m_indexBias = 0;
  477. newButterfly->arrayStorage()->setVectorLength(0);
  478. newButterfly->arrayStorage()->m_sparseMap.set(vm, this, map);
  479. return newButterfly->arrayStorage();
  480. }
  481. void JSObject::enterDictionaryIndexingMode(VM& vm)
  482. {
  483. switch (structure()->indexingType()) {
  484. case ALL_BLANK_INDEXING_TYPES:
  485. case ALL_UNDECIDED_INDEXING_TYPES:
  486. case ALL_INT32_INDEXING_TYPES:
  487. case ALL_DOUBLE_INDEXING_TYPES:
  488. case ALL_CONTIGUOUS_INDEXING_TYPES:
  489. // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
  490. // this case if we ever cared.
  491. enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, ensureArrayStorageSlow(vm));
  492. break;
  493. case ALL_ARRAY_STORAGE_INDEXING_TYPES:
  494. enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
  495. break;
  496. default:
  497. break;
  498. }
  499. }
  500. void JSObject::notifyPresenceOfIndexedAccessors(VM& vm)
  501. {
  502. if (mayInterceptIndexedAccesses())
  503. return;
  504. setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors));
  505. if (!vm.prototypeMap.isPrototype(this))
  506. return;
  507. globalObject()->haveABadTime(vm);
  508. }
  509. Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t elementSize)
  510. {
  511. ASSERT(length < MAX_ARRAY_INDEX);
  512. IndexingType oldType = structure()->indexingType();
  513. ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
  514. ASSERT(!structure()->needsSlowPutIndexing());
  515. ASSERT(!indexingShouldBeSparse());
  516. unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
  517. Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly,
  518. vm, structure(), structure()->outOfLineCapacity(), false, 0,
  519. elementSize * vectorLength);
  520. newButterfly->setPublicLength(length);
  521. newButterfly->setVectorLength(vectorLength);
  522. return newButterfly;
  523. }
  524. Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length)
  525. {
  526. Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
  527. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateUndecided);
  528. setButterfly(vm, newButterfly, newStructure);
  529. return newButterfly;
  530. }
  531. ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length)
  532. {
  533. Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
  534. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateInt32);
  535. setButterfly(vm, newButterfly, newStructure);
  536. return newButterfly->contiguousInt32();
  537. }
  538. ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length)
  539. {
  540. Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(double));
  541. for (unsigned i = newButterfly->vectorLength(); i--;)
  542. newButterfly->contiguousDouble()[i] = QNaN;
  543. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateDouble);
  544. setButterfly(vm, newButterfly, newStructure);
  545. return newButterfly->contiguousDouble();
  546. }
  547. ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length)
  548. {
  549. Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
  550. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateContiguous);
  551. setButterfly(vm, newButterfly, newStructure);
  552. return newButterfly->contiguous();
  553. }
  554. ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
  555. {
  556. IndexingType oldType = structure()->indexingType();
  557. ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
  558. Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly,
  559. vm, structure(), structure()->outOfLineCapacity(), false, 0,
  560. ArrayStorage::sizeFor(vectorLength));
  561. RELEASE_ASSERT(newButterfly);
  562. ArrayStorage* result = newButterfly->arrayStorage();
  563. result->setLength(length);
  564. result->setVectorLength(vectorLength);
  565. result->m_sparseMap.clear();
  566. result->m_numValuesInVector = 0;
  567. result->m_indexBias = 0;
  568. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), structure()->suggestedArrayStorageTransition());
  569. setButterfly(vm, newButterfly, newStructure);
  570. return result;
  571. }
  572. ArrayStorage* JSObject::createInitialArrayStorage(VM& vm)
  573. {
  574. return createArrayStorage(vm, 0, BASE_VECTOR_LEN);
  575. }
  576. ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm)
  577. {
  578. ASSERT(hasUndecided(structure()->indexingType()));
  579. setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32));
  580. return m_butterfly->contiguousInt32();
  581. }
  582. ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm)
  583. {
  584. ASSERT(hasUndecided(structure()->indexingType()));
  585. for (unsigned i = m_butterfly->vectorLength(); i--;)
  586. m_butterfly->contiguousDouble()[i] = QNaN;
  587. setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
  588. return m_butterfly->contiguousDouble();
  589. }
  590. ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm)
  591. {
  592. ASSERT(hasUndecided(structure()->indexingType()));
  593. setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
  594. return m_butterfly->contiguous();
  595. }
  596. ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength)
  597. {
  598. unsigned publicLength = m_butterfly->publicLength();
  599. unsigned propertyCapacity = structure()->outOfLineCapacity();
  600. unsigned propertySize = structure()->outOfLineSize();
  601. Butterfly* newButterfly = Butterfly::createUninitialized(
  602. vm, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
  603. memcpy(
  604. newButterfly->propertyStorage() - propertySize,
  605. m_butterfly->propertyStorage() - propertySize,
  606. propertySize * sizeof(EncodedJSValue));
  607. ArrayStorage* newStorage = newButterfly->arrayStorage();
  608. newStorage->setVectorLength(neededLength);
  609. newStorage->setLength(publicLength);
  610. newStorage->m_sparseMap.clear();
  611. newStorage->m_indexBias = 0;
  612. newStorage->m_numValuesInVector = 0;
  613. return newStorage;
  614. }
  615. ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
  616. {
  617. ASSERT(hasUndecided(structure()->indexingType()));
  618. ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
  619. // No need to copy elements.
  620. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
  621. setButterfly(vm, storage->butterfly(), newStructure);
  622. return storage;
  623. }
  624. ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition)
  625. {
  626. return convertUndecidedToArrayStorage(vm, transition, m_butterfly->vectorLength());
  627. }
  628. ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm)
  629. {
  630. return convertUndecidedToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
  631. }
  632. ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm)
  633. {
  634. ASSERT(hasInt32(structure()->indexingType()));
  635. for (unsigned i = m_butterfly->vectorLength(); i--;) {
  636. WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i];
  637. double* currentAsDouble = bitwise_cast<double*>(current);
  638. JSValue v = current->get();
  639. if (!v) {
  640. *currentAsDouble = QNaN;
  641. continue;
  642. }
  643. ASSERT(v.isInt32());
  644. *currentAsDouble = v.asInt32();
  645. }
  646. setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
  647. return m_butterfly->contiguousDouble();
  648. }
  649. ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm)
  650. {
  651. ASSERT(hasInt32(structure()->indexingType()));
  652. setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
  653. return m_butterfly->contiguous();
  654. }
  655. ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
  656. {
  657. ASSERT(hasInt32(structure()->indexingType()));
  658. ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
  659. for (unsigned i = m_butterfly->publicLength(); i--;) {
  660. JSValue v = m_butterfly->contiguous()[i].get();
  661. if (!v)
  662. continue;
  663. newStorage->m_vector[i].setWithoutWriteBarrier(v);
  664. newStorage->m_numValuesInVector++;
  665. }
  666. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
  667. setButterfly(vm, newStorage->butterfly(), newStructure);
  668. return newStorage;
  669. }
  670. ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition)
  671. {
  672. return convertInt32ToArrayStorage(vm, transition, m_butterfly->vectorLength());
  673. }
  674. ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm)
  675. {
  676. return convertInt32ToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
  677. }
  678. template<JSObject::DoubleToContiguousMode mode>
  679. ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm)
  680. {
  681. ASSERT(hasDouble(structure()->indexingType()));
  682. for (unsigned i = m_butterfly->vectorLength(); i--;) {
  683. double* current = &m_butterfly->contiguousDouble()[i];
  684. WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
  685. double value = *current;
  686. if (value != value) {
  687. currentAsValue->clear();
  688. continue;
  689. }
  690. JSValue v;
  691. switch (mode) {
  692. case EncodeValueAsDouble:
  693. v = JSValue(JSValue::EncodeAsDouble, value);
  694. break;
  695. case RageConvertDoubleToValue:
  696. v = jsNumber(value);
  697. break;
  698. }
  699. ASSERT(v.isNumber());
  700. currentAsValue->setWithoutWriteBarrier(v);
  701. }
  702. setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
  703. return m_butterfly->contiguous();
  704. }
  705. ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm)
  706. {
  707. return genericConvertDoubleToContiguous<EncodeValueAsDouble>(vm);
  708. }
  709. ContiguousJSValues JSObject::rageConvertDoubleToContiguous(VM& vm)
  710. {
  711. return genericConvertDoubleToContiguous<RageConvertDoubleToValue>(vm);
  712. }
  713. ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
  714. {
  715. ASSERT(hasDouble(structure()->indexingType()));
  716. ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
  717. for (unsigned i = m_butterfly->publicLength(); i--;) {
  718. double value = m_butterfly->contiguousDouble()[i];
  719. if (value != value)
  720. continue;
  721. newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
  722. newStorage->m_numValuesInVector++;
  723. }
  724. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
  725. setButterfly(vm, newStorage->butterfly(), newStructure);
  726. return newStorage;
  727. }
  728. ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
  729. {
  730. return convertDoubleToArrayStorage(vm, transition, m_butterfly->vectorLength());
  731. }
  732. ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
  733. {
  734. return convertDoubleToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
  735. }
  736. ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
  737. {
  738. ASSERT(hasContiguous(structure()->indexingType()));
  739. ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
  740. for (unsigned i = m_butterfly->publicLength(); i--;) {
  741. JSValue v = m_butterfly->contiguous()[i].get();
  742. if (!v)
  743. continue;
  744. newStorage->m_vector[i].setWithoutWriteBarrier(v);
  745. newStorage->m_numValuesInVector++;
  746. }
  747. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
  748. setButterfly(vm, newStorage->butterfly(), newStructure);
  749. return newStorage;
  750. }
  751. ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
  752. {
  753. return convertContiguousToArrayStorage(vm, transition, m_butterfly->vectorLength());
  754. }
  755. ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
  756. {
  757. return convertContiguousToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
  758. }
  759. void JSObject::convertUndecidedForValue(VM& vm, JSValue value)
  760. {
  761. if (value.isInt32()) {
  762. convertUndecidedToInt32(vm);
  763. return;
  764. }
  765. if (value.isDouble()) {
  766. convertUndecidedToDouble(vm);
  767. return;
  768. }
  769. convertUndecidedToContiguous(vm);
  770. }
  771. void JSObject::convertInt32ForValue(VM& vm, JSValue value)
  772. {
  773. ASSERT(!value.isInt32());
  774. if (value.isDouble()) {
  775. convertInt32ToDouble(vm);
  776. return;
  777. }
  778. convertInt32ToContiguous(vm);
  779. }
  780. void JSObject::setIndexQuicklyToUndecided(VM& vm, unsigned index, JSValue value)
  781. {
  782. ASSERT(index < m_butterfly->publicLength());
  783. ASSERT(index < m_butterfly->vectorLength());
  784. convertUndecidedForValue(vm, value);
  785. setIndexQuickly(vm, index, value);
  786. }
  787. void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
  788. {
  789. ASSERT(!value.isInt32());
  790. convertInt32ForValue(vm, value);
  791. setIndexQuickly(vm, index, value);
  792. }
  793. void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
  794. {
  795. ASSERT(!value.isNumber() || value.asNumber() != value.asNumber());
  796. convertDoubleToContiguous(vm);
  797. setIndexQuickly(vm, index, value);
  798. }
  799. ContiguousJSValues JSObject::ensureInt32Slow(VM& vm)
  800. {
  801. ASSERT(inherits(&s_info));
  802. switch (structure()->indexingType()) {
  803. case ALL_BLANK_INDEXING_TYPES:
  804. if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
  805. return ContiguousJSValues();
  806. return createInitialInt32(vm, 0);
  807. case ALL_UNDECIDED_INDEXING_TYPES:
  808. return convertUndecidedToInt32(vm);
  809. case ALL_DOUBLE_INDEXING_TYPES:
  810. case ALL_CONTIGUOUS_INDEXING_TYPES:
  811. case ALL_ARRAY_STORAGE_INDEXING_TYPES:
  812. return ContiguousJSValues();
  813. default:
  814. CRASH();
  815. return ContiguousJSValues();
  816. }
  817. }
  818. ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm)
  819. {
  820. ASSERT(inherits(&s_info));
  821. switch (structure()->indexingType()) {
  822. case ALL_BLANK_INDEXING_TYPES:
  823. if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
  824. return ContiguousDoubles();
  825. return createInitialDouble(vm, 0);
  826. case ALL_UNDECIDED_INDEXING_TYPES:
  827. return convertUndecidedToDouble(vm);
  828. case ALL_INT32_INDEXING_TYPES:
  829. return convertInt32ToDouble(vm);
  830. case ALL_CONTIGUOUS_INDEXING_TYPES:
  831. case ALL_ARRAY_STORAGE_INDEXING_TYPES:
  832. return ContiguousDoubles();
  833. default:
  834. CRASH();
  835. return ContiguousDoubles();
  836. }
  837. }
  838. ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode mode)
  839. {
  840. ASSERT(inherits(&s_info));
  841. switch (structure()->indexingType()) {
  842. case ALL_BLANK_INDEXING_TYPES:
  843. if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
  844. return ContiguousJSValues();
  845. return createInitialContiguous(vm, 0);
  846. case ALL_UNDECIDED_INDEXING_TYPES:
  847. return convertUndecidedToContiguous(vm);
  848. case ALL_INT32_INDEXING_TYPES:
  849. return convertInt32ToContiguous(vm);
  850. case ALL_DOUBLE_INDEXING_TYPES:
  851. if (mode == RageConvertDoubleToValue)
  852. return rageConvertDoubleToContiguous(vm);
  853. return convertDoubleToContiguous(vm);
  854. case ALL_ARRAY_STORAGE_INDEXING_TYPES:
  855. return ContiguousJSValues();
  856. default:
  857. CRASH();
  858. return ContiguousJSValues();
  859. }
  860. }
  861. ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm)
  862. {
  863. return ensureContiguousSlow(vm, EncodeValueAsDouble);
  864. }
  865. ContiguousJSValues JSObject::rageEnsureContiguousSlow(VM& vm)
  866. {
  867. return ensureContiguousSlow(vm, RageConvertDoubleToValue);
  868. }
  869. ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
  870. {
  871. ASSERT(inherits(&s_info));
  872. switch (structure()->indexingType()) {
  873. case ALL_BLANK_INDEXING_TYPES:
  874. if (UNLIKELY(indexingShouldBeSparse()))
  875. return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
  876. return createInitialArrayStorage(vm);
  877. case ALL_UNDECIDED_INDEXING_TYPES:
  878. ASSERT(!indexingShouldBeSparse());
  879. ASSERT(!structure()->needsSlowPutIndexing());
  880. return convertUndecidedToArrayStorage(vm);
  881. case ALL_INT32_INDEXING_TYPES:
  882. ASSERT(!indexingShouldBeSparse());
  883. ASSERT(!structure()->needsSlowPutIndexing());
  884. return convertInt32ToArrayStorage(vm);
  885. case ALL_DOUBLE_INDEXING_TYPES:
  886. ASSERT(!indexingShouldBeSparse());
  887. ASSERT(!structure()->needsSlowPutIndexing());
  888. return convertDoubleToArrayStorage(vm);
  889. case ALL_CONTIGUOUS_INDEXING_TYPES:
  890. ASSERT(!indexingShouldBeSparse());
  891. ASSERT(!structure()->needsSlowPutIndexing());
  892. return convertContiguousToArrayStorage(vm);
  893. default:
  894. RELEASE_ASSERT_NOT_REACHED();
  895. return 0;
  896. }
  897. }
  898. ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm)
  899. {
  900. switch (structure()->indexingType()) {
  901. case ALL_BLANK_INDEXING_TYPES: {
  902. createArrayStorage(vm, 0, 0);
  903. SparseArrayValueMap* map = allocateSparseIndexMap(vm);
  904. map->setSparseMode();
  905. return arrayStorage();
  906. }
  907. case ALL_UNDECIDED_INDEXING_TYPES:
  908. return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertUndecidedToArrayStorage(vm));
  909. case ALL_INT32_INDEXING_TYPES:
  910. return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertInt32ToArrayStorage(vm));
  911. case ALL_DOUBLE_INDEXING_TYPES:
  912. return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertDoubleToArrayStorage(vm));
  913. case ALL_CONTIGUOUS_INDEXING_TYPES:
  914. return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertContiguousToArrayStorage(vm));
  915. case ALL_ARRAY_STORAGE_INDEXING_TYPES:
  916. return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
  917. default:
  918. CRASH();
  919. return 0;
  920. }
  921. }
  922. void JSObject::switchToSlowPutArrayStorage(VM& vm)
  923. {
  924. switch (structure()->indexingType()) {
  925. case ALL_UNDECIDED_INDEXING_TYPES:
  926. convertUndecidedToArrayStorage(vm, AllocateSlowPutArrayStorage);
  927. break;
  928. case ALL_INT32_INDEXING_TYPES:
  929. convertInt32ToArrayStorage(vm, AllocateSlowPutArrayStorage);
  930. break;
  931. case ALL_DOUBLE_INDEXING_TYPES:
  932. convertDoubleToArrayStorage(vm, AllocateSlowPutArrayStorage);
  933. break;
  934. case ALL_CONTIGUOUS_INDEXING_TYPES:
  935. convertContiguousToArrayStorage(vm, AllocateSlowPutArrayStorage);
  936. break;
  937. case NonArrayWithArrayStorage:
  938. case ArrayWithArrayStorage: {
  939. Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage);
  940. setStructure(vm, newStructure);
  941. break;
  942. }
  943. default:
  944. CRASH();
  945. break;
  946. }
  947. }
  948. void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
  949. {
  950. ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
  951. PutPropertySlot slot;
  952. object->putDirectInternal<PutModeDefineOwnProperty>(exec->vm(), propertyName, value, attributes, slot, getCallableObject(value));
  953. }
  954. void JSObject::setPrototype(VM& vm, JSValue prototype)
  955. {
  956. ASSERT(prototype);
  957. if (prototype.isObject())
  958. vm.prototypeMap.addPrototype(asObject(prototype));
  959. Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype);
  960. setStructure(vm, newStructure);
  961. if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
  962. return;
  963. if (vm.prototypeMap.isPrototype(this)) {
  964. newStructure->globalObject()->haveABadTime(vm);
  965. return;
  966. }
  967. if (!hasIndexingHeader(structure()->indexingType()))
  968. return;
  969. if (shouldUseSlowPut(structure()->indexingType()))
  970. return;
  971. switchToSlowPutArrayStorage(vm);
  972. }
  973. bool JSObject::setPrototypeWithCycleCheck(VM& vm, JSValue prototype)
  974. {
  975. JSValue checkFor = this;
  976. if (this->isGlobalObject())
  977. checkFor = jsCast<JSGlobalObject*>(this)->globalExec()->thisValue();
  978. JSValue nextPrototype = prototype;
  979. while (nextPrototype && nextPrototype.isObject()) {
  980. if (nextPrototype == checkFor)
  981. return false;
  982. nextPrototype = asObject(nextPrototype)->prototype();
  983. }
  984. setPrototype(vm, prototype);
  985. return true;
  986. }
  987. bool JSObject::allowsAccessFrom(ExecState* exec)
  988. {
  989. JSGlobalObject* globalObject = this->globalObject();
  990. return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
  991. }
  992. void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
  993. {
  994. ASSERT(value.isGetterSetter() && (attributes & Accessor));
  995. unsigned index = propertyName.asIndex();
  996. if (index != PropertyName::NotAnIndex) {
  997. putDirectIndex(exec, index, value, attributes, PutDirectIndexLikePutDirect);
  998. return;
  999. }
  1000. VM& vm = exec->vm();
  1001. PutPropertySlot slot;
  1002. putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
  1003. // putDirect will change our Structure if we add a new property. For
  1004. // getters and setters, though, we also need to change our Structure
  1005. // if we override an existing non-getter or non-setter.
  1006. if (slot.type() != PutPropertySlot::NewProperty)
  1007. setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes));
  1008. if (attributes & ReadOnly)
  1009. structure()->setContainsReadOnlyProperties();
  1010. structure()->setHasGetterSetterProperties(propertyName == vm.propertyNames->underscoreProto);
  1011. }
  1012. bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const
  1013. {
  1014. PropertySlot slot;
  1015. return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
  1016. }
  1017. bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
  1018. {
  1019. PropertySlot slot;
  1020. return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
  1021. }
  1022. // ECMA 8.6.2.5
  1023. bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
  1024. {
  1025. JSObject* thisObject = jsCast<JSObject*>(cell);
  1026. unsigned i = propertyName.asIndex();
  1027. if (i != PropertyName::NotAnIndex)
  1028. return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, i);
  1029. if (!thisObject->staticFunctionsReified())
  1030. thisObject->reifyStaticFunctionsForDelete(exec);
  1031. unsigned attributes;
  1032. JSCell* specificValue;
  1033. if (isValidOffset(thisObject->structure()->get(exec->vm(), propertyName, attributes, specificValue))) {
  1034. if (attributes & DontDelete && !exec->vm().isInDefineOwnProperty())
  1035. return false;
  1036. thisObject->removeDirect(exec->vm(), propertyName);
  1037. return true;
  1038. }
  1039. // Look in the static hashtable of properties
  1040. const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName);
  1041. if (entry) {
  1042. if (entry->attributes() & DontDelete && !exec->vm().isInDefineOwnProperty())
  1043. return false; // this builtin property can't be deleted
  1044. putEntry(exec, entry, propertyName, jsUndefined(), thisObject);
  1045. }
  1046. return true;
  1047. }
  1048. bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
  1049. {
  1050. PropertySlot slot;
  1051. return const_cast<JSObject*>(this)->methodTable()->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
  1052. }
  1053. bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
  1054. {
  1055. JSObject* thisObject = jsCast<JSObject*>(cell);
  1056. if (i > MAX_ARRAY_INDEX)
  1057. return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i));
  1058. switch (thisObject->structure()->indexingType()) {
  1059. case ALL_BLANK_INDEXING_TYPES:
  1060. case ALL_UNDECIDED_INDEXING_TYPES:
  1061. return true;
  1062. case ALL_INT32_INDEXING_TYPES:
  1063. case ALL_CONTIGUOUS_INDEXING_TYPES: {
  1064. Butterfly* butterfly = thisObject->m_butterfly;
  1065. if (i >= butterfly->vectorLength())
  1066. return true;
  1067. butterfly->contiguous()[i].clear();
  1068. return true;
  1069. }
  1070. case ALL_DOUBLE_INDEXING_TYPES: {
  1071. Butterfly* butterfly = thisObject->m_butterfly;
  1072. if (i >= butterfly->vectorLength())
  1073. return true;
  1074. butterfly->contiguousDouble()[i] = QNaN;
  1075. return true;
  1076. }
  1077. case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
  1078. ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
  1079. if (i < storage->vectorLength()) {
  1080. WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
  1081. if (valueSlot) {
  1082. valueSlot.clear();
  1083. --storage->m_numValuesInVector;
  1084. }
  1085. } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
  1086. SparseArrayValueMap::iterator it = map->find(i);
  1087. if (it != map->notFound()) {
  1088. if (it->value.attributes & DontDelete)
  1089. return false;
  1090. map->remove(it);
  1091. }
  1092. }
  1093. return true;
  1094. }
  1095. default:
  1096. RELEASE_ASSERT_NOT_REACHED();
  1097. return false;
  1098. }
  1099. }
  1100. static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, PropertyName propertyName)
  1101. {
  1102. JSValue function = object->get(exec, propertyName);
  1103. CallData callData;
  1104. CallType callType = getCallData(function, callData);
  1105. if (callType == CallTypeNone)
  1106. return exec->exception();
  1107. // Prevent "toString" and "valueOf" from observing execution if an exception
  1108. // is pending.
  1109. if (exec->hadException())
  1110. return exec->exception();
  1111. JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
  1112. ASSERT(!result.isGetterSetter());
  1113. if (exec->hadException())
  1114. return exec->exception();
  1115. if (result.isObject())
  1116. return JSValue();
  1117. return result;
  1118. }
  1119. bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
  1120. {
  1121. result = methodTable()->defaultValue(this, exec, PreferNumber);
  1122. number = result.toNumber(exec);
  1123. return !result.isString();
  1124. }
  1125. // ECMA 8.6.2.6
  1126. JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
  1127. {
  1128. // Must call toString first for Date objects.
  1129. if ((hint == PreferString) || (hint != PreferNumber && object->prototype() == exec->lexicalGlobalObject()->datePrototype())) {
  1130. JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
  1131. if (value)
  1132. return value;
  1133. value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
  1134. if (value)
  1135. return value;
  1136. } else {
  1137. JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
  1138. if (value)
  1139. return value;
  1140. value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
  1141. if (value)
  1142. return value;
  1143. }
  1144. ASSERT(!exec->hadException());
  1145. return throwError(exec, createTypeError(exec, ASCIILiteral("No default value")));
  1146. }
  1147. const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, PropertyName propertyName) const
  1148. {
  1149. for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
  1150. if (co