]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSObject.h
5c9622cc4de4adabe51136c239c5ea1732382f2f
[apple/javascriptcore.git] / runtime / JSObject.h
1 /*
2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003-2009, 2012-2015 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #ifndef JSObject_h
24 #define JSObject_h
25
26 #include "ArgList.h"
27 #include "ArrayConventions.h"
28 #include "ArrayStorage.h"
29 #include "Butterfly.h"
30 #include "CallFrame.h"
31 #include "ClassInfo.h"
32 #include "CommonIdentifiers.h"
33 #include "CopyWriteBarrier.h"
34 #include "CustomGetterSetter.h"
35 #include "DeferGC.h"
36 #include "Heap.h"
37 #include "HeapInlines.h"
38 #include "IndexingHeaderInlines.h"
39 #include "JSCell.h"
40 #include "PropertySlot.h"
41 #include "PropertyStorage.h"
42 #include "PutDirectIndexMode.h"
43 #include "PutPropertySlot.h"
44
45 #include "Structure.h"
46 #include "VM.h"
47 #include "JSString.h"
48 #include "SparseArrayValueMap.h"
49 #include <wtf/StdLibExtras.h>
50
51 namespace JSC {
52
53 inline JSCell* getJSFunction(JSValue value)
54 {
55 if (value.isCell() && (value.asCell()->type() == JSFunctionType))
56 return value.asCell();
57 return 0;
58 }
59
60 class GetterSetter;
61 class InternalFunction;
62 class JSFunction;
63 class LLIntOffsetsExtractor;
64 class MarkedBlock;
65 class PropertyDescriptor;
66 class PropertyNameArray;
67 class Structure;
68 struct HashTable;
69 struct HashTableValue;
70
71 JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const String&);
72 extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError;
73
74 COMPILE_ASSERT(None < FirstInternalAttribute, None_is_below_FirstInternalAttribute);
75 COMPILE_ASSERT(ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute);
76 COMPILE_ASSERT(DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute);
77 COMPILE_ASSERT(DontDelete < FirstInternalAttribute, DontDelete_is_below_FirstInternalAttribute);
78 COMPILE_ASSERT(Function < FirstInternalAttribute, Function_is_below_FirstInternalAttribute);
79 COMPILE_ASSERT(Accessor < FirstInternalAttribute, Accessor_is_below_FirstInternalAttribute);
80
81 class JSFinalObject;
82
83 class JSObject : public JSCell {
84 friend class BatchedTransitionOptimizer;
85 friend class JIT;
86 friend class JSCell;
87 friend class JSFinalObject;
88 friend class MarkedBlock;
89 JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject*, PropertyName, PropertySlot&);
90
91 enum PutMode {
92 PutModePut,
93 PutModeDefineOwnProperty,
94 };
95
96 public:
97 typedef JSCell Base;
98
99 JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
100 JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
101
102 JS_EXPORT_PRIVATE static String className(const JSObject*);
103 JS_EXPORT_PRIVATE static String calculatedClassName(JSObject*);
104
105 JSValue prototype() const;
106 JS_EXPORT_PRIVATE void setPrototype(VM&, JSValue prototype);
107 JS_EXPORT_PRIVATE bool setPrototypeWithCycleCheck(ExecState*, JSValue prototype);
108
109 bool mayInterceptIndexedAccesses()
110 {
111 return structure()->mayInterceptIndexedAccesses();
112 }
113
114 JSValue get(ExecState*, PropertyName) const;
115 JSValue get(ExecState*, unsigned propertyName) const;
116
117 bool fastGetOwnPropertySlot(ExecState*, VM&, Structure&, PropertyName, PropertySlot&);
118 bool getPropertySlot(ExecState*, PropertyName, PropertySlot&);
119 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
120
121 static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
122 JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
123
124 // The key difference between this and getOwnPropertySlot is that getOwnPropertySlot
125 // currently returns incorrect results for the DOM window (with non-own properties)
126 // being returned. Once this is fixed we should migrate code & remove this method.
127 JS_EXPORT_PRIVATE bool getOwnPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
128
129 JS_EXPORT_PRIVATE bool allowsAccessFrom(ExecState*);
130
131 unsigned getArrayLength() const
132 {
133 if (!hasIndexedProperties(indexingType()))
134 return 0;
135 return m_butterfly->publicLength();
136 }
137
138 unsigned getVectorLength()
139 {
140 if (!hasIndexedProperties(indexingType()))
141 return 0;
142 return m_butterfly->vectorLength();
143 }
144
145 JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
146 JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
147
148 ALWAYS_INLINE void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
149 {
150 if (canSetIndexQuickly(propertyName)) {
151 setIndexQuickly(exec->vm(), propertyName, value);
152 return;
153 }
154 methodTable(exec->vm())->putByIndex(this, exec, propertyName, value, shouldThrow);
155 }
156
157 // This is similar to the putDirect* methods:
158 // - the prototype chain is not consulted
159 // - accessors are not called.
160 // - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default).
161 // This method creates a property with attributes writable, enumerable and configurable all set to true.
162 bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes, PutDirectIndexMode mode)
163 {
164 if (!attributes && canSetIndexQuicklyForPutDirect(propertyName)) {
165 setIndexQuickly(exec->vm(), propertyName, value);
166 return true;
167 }
168 return putDirectIndexBeyondVectorLength(exec, propertyName, value, attributes, mode);
169 }
170 bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value)
171 {
172 return putDirectIndex(exec, propertyName, value, 0, PutDirectIndexLikePutDirect);
173 }
174
175 // A non-throwing version of putDirect and putDirectIndex.
176 JS_EXPORT_PRIVATE void putDirectMayBeIndex(ExecState*, PropertyName, JSValue);
177
178 bool hasIndexingHeader() const
179 {
180 return structure()->hasIndexingHeader(this);
181 }
182
183 bool canGetIndexQuickly(unsigned i)
184 {
185 switch (indexingType()) {
186 case ALL_BLANK_INDEXING_TYPES:
187 case ALL_UNDECIDED_INDEXING_TYPES:
188 return false;
189 case ALL_INT32_INDEXING_TYPES:
190 case ALL_CONTIGUOUS_INDEXING_TYPES:
191 return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i];
192 case ALL_DOUBLE_INDEXING_TYPES: {
193 if (i >= m_butterfly->vectorLength())
194 return false;
195 double value = m_butterfly->contiguousDouble()[i];
196 if (value != value)
197 return false;
198 return true;
199 }
200 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
201 return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
202 default:
203 RELEASE_ASSERT_NOT_REACHED();
204 return false;
205 }
206 }
207
208 JSValue getIndexQuickly(unsigned i)
209 {
210 switch (indexingType()) {
211 case ALL_INT32_INDEXING_TYPES:
212 return jsNumber(m_butterfly->contiguous()[i].get().asInt32());
213 case ALL_CONTIGUOUS_INDEXING_TYPES:
214 return m_butterfly->contiguous()[i].get();
215 case ALL_DOUBLE_INDEXING_TYPES:
216 return JSValue(JSValue::EncodeAsDouble, m_butterfly->contiguousDouble()[i]);
217 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
218 return m_butterfly->arrayStorage()->m_vector[i].get();
219 default:
220 RELEASE_ASSERT_NOT_REACHED();
221 return JSValue();
222 }
223 }
224
225 JSValue tryGetIndexQuickly(unsigned i)
226 {
227 switch (indexingType()) {
228 case ALL_BLANK_INDEXING_TYPES:
229 case ALL_UNDECIDED_INDEXING_TYPES:
230 break;
231 case ALL_INT32_INDEXING_TYPES:
232 if (i < m_butterfly->publicLength()) {
233 JSValue result = m_butterfly->contiguous()[i].get();
234 ASSERT(result.isInt32() || !result);
235 return result;
236 }
237 break;
238 case ALL_CONTIGUOUS_INDEXING_TYPES:
239 if (i < m_butterfly->publicLength())
240 return m_butterfly->contiguous()[i].get();
241 break;
242 case ALL_DOUBLE_INDEXING_TYPES: {
243 if (i >= m_butterfly->publicLength())
244 break;
245 double result = m_butterfly->contiguousDouble()[i];
246 if (result != result)
247 break;
248 return JSValue(JSValue::EncodeAsDouble, result);
249 }
250 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
251 if (i < m_butterfly->arrayStorage()->vectorLength())
252 return m_butterfly->arrayStorage()->m_vector[i].get();
253 break;
254 default:
255 RELEASE_ASSERT_NOT_REACHED();
256 break;
257 }
258 return JSValue();
259 }
260
261 JSValue getDirectIndex(ExecState* exec, unsigned i)
262 {
263 if (JSValue result = tryGetIndexQuickly(i))
264 return result;
265 PropertySlot slot(this);
266 if (methodTable(exec->vm())->getOwnPropertySlotByIndex(this, exec, i, slot))
267 return slot.getValue(exec, i);
268 return JSValue();
269 }
270
271 JSValue getIndex(ExecState* exec, unsigned i)
272 {
273 if (JSValue result = tryGetIndexQuickly(i))
274 return result;
275 return get(exec, i);
276 }
277
278 bool canSetIndexQuickly(unsigned i)
279 {
280 switch (indexingType()) {
281 case ALL_BLANK_INDEXING_TYPES:
282 case ALL_UNDECIDED_INDEXING_TYPES:
283 return false;
284 case ALL_INT32_INDEXING_TYPES:
285 case ALL_DOUBLE_INDEXING_TYPES:
286 case ALL_CONTIGUOUS_INDEXING_TYPES:
287 case NonArrayWithArrayStorage:
288 case ArrayWithArrayStorage:
289 return i < m_butterfly->vectorLength();
290 case NonArrayWithSlowPutArrayStorage:
291 case ArrayWithSlowPutArrayStorage:
292 return i < m_butterfly->arrayStorage()->vectorLength()
293 && !!m_butterfly->arrayStorage()->m_vector[i];
294 default:
295 RELEASE_ASSERT_NOT_REACHED();
296 return false;
297 }
298 }
299
300 bool canSetIndexQuicklyForPutDirect(unsigned i)
301 {
302 switch (indexingType()) {
303 case ALL_BLANK_INDEXING_TYPES:
304 case ALL_UNDECIDED_INDEXING_TYPES:
305 return false;
306 case ALL_INT32_INDEXING_TYPES:
307 case ALL_DOUBLE_INDEXING_TYPES:
308 case ALL_CONTIGUOUS_INDEXING_TYPES:
309 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
310 return i < m_butterfly->vectorLength();
311 default:
312 RELEASE_ASSERT_NOT_REACHED();
313 return false;
314 }
315 }
316
317 void setIndexQuickly(VM& vm, unsigned i, JSValue v)
318 {
319 switch (indexingType()) {
320 case ALL_INT32_INDEXING_TYPES: {
321 ASSERT(i < m_butterfly->vectorLength());
322 if (!v.isInt32()) {
323 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm, i, v);
324 return;
325 }
326 FALLTHROUGH;
327 }
328 case ALL_CONTIGUOUS_INDEXING_TYPES: {
329 ASSERT(i < m_butterfly->vectorLength());
330 m_butterfly->contiguous()[i].set(vm, this, v);
331 if (i >= m_butterfly->publicLength())
332 m_butterfly->setPublicLength(i + 1);
333 break;
334 }
335 case ALL_DOUBLE_INDEXING_TYPES: {
336 ASSERT(i < m_butterfly->vectorLength());
337 if (!v.isNumber()) {
338 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
339 return;
340 }
341 double value = v.asNumber();
342 if (value != value) {
343 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
344 return;
345 }
346 m_butterfly->contiguousDouble()[i] = value;
347 if (i >= m_butterfly->publicLength())
348 m_butterfly->setPublicLength(i + 1);
349 break;
350 }
351 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
352 ArrayStorage* storage = m_butterfly->arrayStorage();
353 WriteBarrier<Unknown>& x = storage->m_vector[i];
354 JSValue old = x.get();
355 x.set(vm, this, v);
356 if (!old) {
357 ++storage->m_numValuesInVector;
358 if (i >= storage->length())
359 storage->setLength(i + 1);
360 }
361 break;
362 }
363 default:
364 RELEASE_ASSERT_NOT_REACHED();
365 }
366 }
367
368 void initializeIndex(VM& vm, unsigned i, JSValue v)
369 {
370 initializeIndex(vm, i, v, indexingType());
371 }
372
373 void initializeIndex(VM& vm, unsigned i, JSValue v, IndexingType indexingType)
374 {
375 switch (indexingType) {
376 case ALL_UNDECIDED_INDEXING_TYPES: {
377 setIndexQuicklyToUndecided(vm, i, v);
378 break;
379 }
380 case ALL_INT32_INDEXING_TYPES: {
381 ASSERT(i < m_butterfly->publicLength());
382 ASSERT(i < m_butterfly->vectorLength());
383 if (!v.isInt32()) {
384 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm, i, v);
385 break;
386 }
387 FALLTHROUGH;
388 }
389 case ALL_CONTIGUOUS_INDEXING_TYPES: {
390 ASSERT(i < m_butterfly->publicLength());
391 ASSERT(i < m_butterfly->vectorLength());
392 m_butterfly->contiguous()[i].set(vm, this, v);
393 break;
394 }
395 case ALL_DOUBLE_INDEXING_TYPES: {
396 ASSERT(i < m_butterfly->publicLength());
397 ASSERT(i < m_butterfly->vectorLength());
398 if (!v.isNumber()) {
399 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
400 return;
401 }
402 double value = v.asNumber();
403 if (value != value) {
404 convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
405 return;
406 }
407 m_butterfly->contiguousDouble()[i] = value;
408 break;
409 }
410 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
411 ArrayStorage* storage = m_butterfly->arrayStorage();
412 ASSERT(i < storage->length());
413 ASSERT(i < storage->m_numValuesInVector);
414 storage->m_vector[i].set(vm, this, v);
415 break;
416 }
417 default:
418 RELEASE_ASSERT_NOT_REACHED();
419 }
420 }
421
422 bool hasSparseMap()
423 {
424 switch (indexingType()) {
425 case ALL_BLANK_INDEXING_TYPES:
426 case ALL_UNDECIDED_INDEXING_TYPES:
427 case ALL_INT32_INDEXING_TYPES:
428 case ALL_DOUBLE_INDEXING_TYPES:
429 case ALL_CONTIGUOUS_INDEXING_TYPES:
430 return false;
431 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
432 return !!m_butterfly->arrayStorage()->m_sparseMap;
433 default:
434 RELEASE_ASSERT_NOT_REACHED();
435 return false;
436 }
437 }
438
439 bool inSparseIndexingMode()
440 {
441 switch (indexingType()) {
442 case ALL_BLANK_INDEXING_TYPES:
443 case ALL_UNDECIDED_INDEXING_TYPES:
444 case ALL_INT32_INDEXING_TYPES:
445 case ALL_DOUBLE_INDEXING_TYPES:
446 case ALL_CONTIGUOUS_INDEXING_TYPES:
447 return false;
448 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
449 return m_butterfly->arrayStorage()->inSparseMode();
450 default:
451 RELEASE_ASSERT_NOT_REACHED();
452 return false;
453 }
454 }
455
456 void enterDictionaryIndexingMode(VM&);
457
458 // putDirect is effectively an unchecked vesion of 'defineOwnProperty':
459 // - the prototype chain is not consulted
460 // - accessors are not called.
461 // - attributes will be respected (after the call the property will exist with the given attributes)
462 // - the property name is assumed to not be an index.
463 void putDirect(VM&, PropertyName, JSValue, unsigned attributes = 0);
464 void putDirect(VM&, PropertyName, JSValue, PutPropertySlot&);
465 void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0);
466 void putDirectNonIndexAccessor(VM&, PropertyName, JSValue, unsigned attributes);
467 void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes);
468 JS_EXPORT_PRIVATE void putDirectCustomAccessor(VM&, PropertyName, JSValue, unsigned attributes);
469
470 void putGetter(ExecState*, PropertyName, JSValue);
471 void putSetter(ExecState*, PropertyName, JSValue);
472
473 JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const;
474 JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
475 bool hasOwnProperty(ExecState*, PropertyName) const;
476 bool hasOwnProperty(ExecState*, unsigned) const;
477
478 JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
479 JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
480
481 JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
482
483 bool hasInstance(ExecState*, JSValue);
484 static bool defaultHasInstance(ExecState*, JSValue, JSValue prototypeProperty);
485
486 JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
487 JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
488 JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
489
490 JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*);
491 JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
492 JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
493
494 JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
495 bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
496 JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
497 JS_EXPORT_PRIVATE JSString* toString(ExecState*) const;
498
499 JS_EXPORT_PRIVATE static JSValue toThis(JSCell*, ExecState*, ECMAMode);
500
501 // This get function only looks at the property map.
502 JSValue getDirect(VM& vm, PropertyName propertyName) const
503 {
504 Structure* structure = this->structure(vm);
505 PropertyOffset offset = structure->get(vm, propertyName);
506 checkOffset(offset, structure->inlineCapacity());
507 return offset != invalidOffset ? getDirect(offset) : JSValue();
508 }
509
510 JSValue getDirect(VM& vm, PropertyName propertyName, unsigned& attributes) const
511 {
512 Structure* structure = this->structure(vm);
513 PropertyOffset offset = structure->get(vm, propertyName, attributes);
514 checkOffset(offset, structure->inlineCapacity());
515 return offset != invalidOffset ? getDirect(offset) : JSValue();
516 }
517
518 PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName)
519 {
520 Structure* structure = this->structure(vm);
521 PropertyOffset offset = structure->get(vm, propertyName);
522 checkOffset(offset, structure->inlineCapacity());
523 return offset;
524 }
525
526 PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName, unsigned& attributes)
527 {
528 Structure* structure = this->structure(vm);
529 PropertyOffset offset = structure->get(vm, propertyName, attributes);
530 checkOffset(offset, structure->inlineCapacity());
531 return offset;
532 }
533
534 bool hasInlineStorage() const { return structure()->hasInlineStorage(); }
535 ConstPropertyStorage inlineStorageUnsafe() const
536 {
537 return bitwise_cast<ConstPropertyStorage>(this + 1);
538 }
539 PropertyStorage inlineStorageUnsafe()
540 {
541 return bitwise_cast<PropertyStorage>(this + 1);
542 }
543 ConstPropertyStorage inlineStorage() const
544 {
545 ASSERT(hasInlineStorage());
546 return inlineStorageUnsafe();
547 }
548 PropertyStorage inlineStorage()
549 {
550 ASSERT(hasInlineStorage());
551 return inlineStorageUnsafe();
552 }
553
554 const Butterfly* butterfly() const { return m_butterfly.get(); }
555 Butterfly* butterfly() { return m_butterfly.get(); }
556
557 ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); }
558 PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); }
559
560 const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const
561 {
562 if (isInlineOffset(offset))
563 return &inlineStorage()[offsetInInlineStorage(offset)];
564 return &outOfLineStorage()[offsetInOutOfLineStorage(offset)];
565 }
566
567 WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset)
568 {
569 if (isInlineOffset(offset))
570 return &inlineStorage()[offsetInInlineStorage(offset)];
571 return &outOfLineStorage()[offsetInOutOfLineStorage(offset)];
572 }
573
574 void transitionTo(VM&, Structure*);
575
576 JS_EXPORT_PRIVATE bool removeDirect(VM&, PropertyName); // Return true if anything is removed.
577 bool hasCustomProperties() { return structure()->didTransition(); }
578 bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
579 bool hasCustomGetterSetterProperties() { return structure()->hasCustomGetterSetterProperties(); }
580
581 // putOwnDataProperty has 'put' like semantics, however this method:
582 // - assumes the object contains no own getter/setter properties.
583 // - provides no special handling for __proto__
584 // - does not walk the prototype chain (to check for accessors or non-writable properties).
585 // This is used by JSLexicalEnvironment.
586 bool putOwnDataProperty(VM&, PropertyName, JSValue, PutPropertySlot&);
587
588 // Fast access to known property offsets.
589 JSValue getDirect(PropertyOffset offset) const { return locationForOffset(offset)->get(); }
590 void putDirect(VM& vm, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(vm, this, value); }
591 void putDirectUndefined(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); }
592
593 JS_EXPORT_PRIVATE void putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
594 JS_EXPORT_PRIVATE JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
595 JSFunction* putDirectBuiltinFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
596 JS_EXPORT_PRIVATE void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
597
598 JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
599
600 bool isGlobalObject() const;
601 bool isVariableObject() const;
602 bool isStaticScopeObject() const;
603 bool isNameScopeObject() const;
604 bool isCatchScopeObject() const;
605 bool isFunctionNameScopeObject() const;
606 bool isActivationObject() const;
607 bool isErrorInstance() const;
608 bool isWithScope() const;
609
610 JS_EXPORT_PRIVATE void seal(VM&);
611 JS_EXPORT_PRIVATE void freeze(VM&);
612 JS_EXPORT_PRIVATE void preventExtensions(VM&);
613 bool isSealed(VM& vm) { return structure(vm)->isSealed(vm); }
614 bool isFrozen(VM& vm) { return structure(vm)->isFrozen(vm); }
615 bool isExtensible() { return structure()->isExtensible(); }
616 bool indexingShouldBeSparse()
617 {
618 return !isExtensible()
619 || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
620 }
621
622 bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
623 void reifyStaticFunctionsForDelete(ExecState* exec);
624
625 JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(VM&, size_t oldSize, size_t newSize);
626 void setButterflyWithoutChangingStructure(VM&, Butterfly*);
627
628 void setStructure(VM&, Structure*);
629 void setStructureAndButterfly(VM&, Structure*, Butterfly*);
630 void setStructureAndReallocateStorageIfNecessary(VM&, unsigned oldCapacity, Structure*);
631 void setStructureAndReallocateStorageIfNecessary(VM&, Structure*);
632
633 void convertToDictionary(VM& vm)
634 {
635 setStructure(vm, Structure::toCacheableDictionaryTransition(vm, structure(vm)));
636 }
637
638 void flattenDictionaryObject(VM& vm)
639 {
640 structure(vm)->flattenDictionaryStructure(vm, this);
641 }
642 void shiftButterflyAfterFlattening(VM&, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter);
643
644 JSGlobalObject* globalObject() const
645 {
646 ASSERT(structure()->globalObject());
647 ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this);
648 return structure()->globalObject();
649 }
650
651 void switchToSlowPutArrayStorage(VM&);
652
653 // The receiver is the prototype in this case. The following:
654 //
655 // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...)
656 //
657 // is equivalent to:
658 //
659 // foo->attemptToInterceptPutByIndexOnHole(...);
660 bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow);
661
662 // Returns 0 if int32 storage cannot be created - either because
663 // indexing should be sparse, we're having a bad time, or because
664 // we already have a more general form of storage (double,
665 // contiguous, array storage).
666 ContiguousJSValues ensureInt32(VM& vm)
667 {
668 if (LIKELY(hasInt32(indexingType())))
669 return m_butterfly->contiguousInt32();
670
671 return ensureInt32Slow(vm);
672 }
673
674 // Returns 0 if double storage cannot be created - either because
675 // indexing should be sparse, we're having a bad time, or because
676 // we already have a more general form of storage (contiguous,
677 // or array storage).
678 ContiguousDoubles ensureDouble(VM& vm)
679 {
680 if (LIKELY(hasDouble(indexingType())))
681 return m_butterfly->contiguousDouble();
682
683 return ensureDoubleSlow(vm);
684 }
685
686 // Returns 0 if contiguous storage cannot be created - either because
687 // indexing should be sparse or because we're having a bad time.
688 ContiguousJSValues ensureContiguous(VM& vm)
689 {
690 if (LIKELY(hasContiguous(indexingType())))
691 return m_butterfly->contiguous();
692
693 return ensureContiguousSlow(vm);
694 }
695
696 // Ensure that the object is in a mode where it has array storage. Use
697 // this if you're about to perform actions that would have required the
698 // object to be converted to have array storage, if it didn't have it
699 // already.
700 ArrayStorage* ensureArrayStorage(VM& vm)
701 {
702 if (LIKELY(hasAnyArrayStorage(indexingType())))
703 return m_butterfly->arrayStorage();
704
705 return ensureArrayStorageSlow(vm);
706 }
707
708 static size_t offsetOfInlineStorage();
709
710 static ptrdiff_t butterflyOffset()
711 {
712 return OBJECT_OFFSETOF(JSObject, m_butterfly);
713 }
714
715 void* butterflyAddress()
716 {
717 return &m_butterfly;
718 }
719
720 DECLARE_EXPORT_INFO;
721
722 protected:
723 void finishCreation(VM& vm)
724 {
725 Base::finishCreation(vm);
726 ASSERT(inherits(info()));
727 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
728 ASSERT(structure()->isObject());
729 ASSERT(classInfo());
730 }
731
732 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
733 {
734 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
735 }
736
737 // To instantiate objects you likely want JSFinalObject, below.
738 // To create derived types you likely want JSNonFinalObject, below.
739 JSObject(VM&, Structure*, Butterfly* = 0);
740
741 void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize);
742 void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize);
743
744 // Call this if you know that the object is in a mode where it has array
745 // storage. This will assert otherwise.
746 ArrayStorage* arrayStorage()
747 {
748 ASSERT(hasAnyArrayStorage(indexingType()));
749 return m_butterfly->arrayStorage();
750 }
751
752 // Call this if you want to predicate some actions on whether or not the
753 // object is in a mode where it has array storage.
754 ArrayStorage* arrayStorageOrNull()
755 {
756 switch (indexingType()) {
757 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
758 return m_butterfly->arrayStorage();
759
760 default:
761 return 0;
762 }
763 }
764
765 size_t butterflyTotalSize();
766 size_t butterflyPreCapacity();
767
768 Butterfly* createInitialUndecided(VM&, unsigned length);
769 ContiguousJSValues createInitialInt32(VM&, unsigned length);
770 ContiguousDoubles createInitialDouble(VM&, unsigned length);
771 ContiguousJSValues createInitialContiguous(VM&, unsigned length);
772
773 void convertUndecidedForValue(VM&, JSValue);
774 void createInitialForValueAndSet(VM&, unsigned index, JSValue);
775 void convertInt32ForValue(VM&, JSValue);
776
777 ArrayStorage* createArrayStorage(VM&, unsigned length, unsigned vectorLength);
778 ArrayStorage* createInitialArrayStorage(VM&);
779
780 ContiguousJSValues convertUndecidedToInt32(VM&);
781 ContiguousDoubles convertUndecidedToDouble(VM&);
782 ContiguousJSValues convertUndecidedToContiguous(VM&);
783 ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition);
784 ArrayStorage* convertUndecidedToArrayStorage(VM&);
785
786 ContiguousDoubles convertInt32ToDouble(VM&);
787 ContiguousJSValues convertInt32ToContiguous(VM&);
788 ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition);
789 ArrayStorage* convertInt32ToArrayStorage(VM&);
790
791 ContiguousJSValues convertDoubleToContiguous(VM&);
792 ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition);
793 ArrayStorage* convertDoubleToArrayStorage(VM&);
794
795 ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition);
796 ArrayStorage* convertContiguousToArrayStorage(VM&);
797
798
799 ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM&);
800
801 bool defineOwnNonIndexProperty(ExecState*, PropertyName, const PropertyDescriptor&, bool throwException);
802
803 template<IndexingType indexingShape>
804 void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
805 void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
806
807 bool increaseVectorLength(VM&, unsigned newLength);
808 void deallocateSparseIndexMap();
809 bool defineOwnIndexedProperty(ExecState*, unsigned, const PropertyDescriptor&, bool throwException);
810 SparseArrayValueMap* allocateSparseIndexMap(VM&);
811
812 void notifyPresenceOfIndexedAccessors(VM&);
813
814 bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow);
815
816 // Call this if you want setIndexQuickly to succeed and you're sure that
817 // the array is contiguous.
818 void ensureLength(VM& vm, unsigned length)
819 {
820 ASSERT(length < MAX_ARRAY_INDEX);
821 ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
822
823 if (m_butterfly->vectorLength() < length)
824 ensureLengthSlow(vm, length);
825
826 if (m_butterfly->publicLength() < length)
827 m_butterfly->setPublicLength(length);
828 }
829
830 // Call this if you want to shrink the butterfly backing store, and you're
831 // sure that the array is contiguous.
832 void reallocateAndShrinkButterfly(VM&, unsigned length);
833
834 template<IndexingType indexingShape>
835 unsigned countElements(Butterfly*);
836
837 // This is relevant to undecided, int32, double, and contiguous.
838 unsigned countElements();
839
840 private:
841 friend class LLIntOffsetsExtractor;
842
843 // Nobody should ever ask any of these questions on something already known to be a JSObject.
844 using JSCell::isAPIValueWrapper;
845 using JSCell::isGetterSetter;
846 void getObject();
847 void getString(ExecState* exec);
848 void isObject();
849 void isString();
850
851 Butterfly* createInitialIndexedStorage(VM&, unsigned length, size_t elementSize);
852
853 ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*);
854
855 template<PutMode>
856 bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&);
857
858 bool inlineGetOwnPropertySlot(VM&, Structure&, PropertyName, PropertySlot&);
859 JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset);
860 void fillCustomGetterPropertySlot(PropertySlot&, JSValue, unsigned, Structure&);
861
862 const HashTableValue* findPropertyHashEntry(PropertyName) const;
863
864 void putIndexedDescriptor(ExecState*, SparseArrayEntry*, const PropertyDescriptor&, PropertyDescriptor& old);
865
866 void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
867 bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode, ArrayStorage*);
868 JS_EXPORT_PRIVATE bool putDirectIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode);
869
870 unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength);
871 unsigned getNewVectorLength(unsigned desiredLength);
872
873 ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(VM&, unsigned neededLength);
874
875 JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(VM&, unsigned index, JSValue);
876 JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue);
877 JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue);
878
879 void ensureLengthSlow(VM&, unsigned length);
880
881 ContiguousJSValues ensureInt32Slow(VM&);
882 ContiguousDoubles ensureDoubleSlow(VM&);
883 ContiguousJSValues ensureContiguousSlow(VM&);
884 JS_EXPORT_PRIVATE ArrayStorage* ensureArrayStorageSlow(VM&);
885
886 protected:
887 CopyWriteBarrier<Butterfly> m_butterfly;
888 #if USE(JSVALUE32_64)
889 private:
890 uint32_t m_padding;
891 #endif
892 };
893
894 // JSNonFinalObject is a type of JSObject that has some internal storage,
895 // but also preserves some space in the collector cell for additional
896 // data members in derived types.
897 class JSNonFinalObject : public JSObject {
898 friend class JSObject;
899
900 public:
901 typedef JSObject Base;
902
903 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
904 {
905 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
906 }
907
908 protected:
909 explicit JSNonFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = 0)
910 : JSObject(vm, structure, butterfly)
911 {
912 }
913
914 void finishCreation(VM& vm)
915 {
916 Base::finishCreation(vm);
917 ASSERT(!this->structure()->hasInlineStorage());
918 ASSERT(classInfo());
919 }
920 };
921
922 class JSFinalObject;
923
924 // JSFinalObject is a type of JSObject that contains sufficent internal
925 // storage to fully make use of the colloctor cell containing it.
926 class JSFinalObject : public JSObject {
927 friend class JSObject;
928
929 public:
930 typedef JSObject Base;
931 static const unsigned StructureFlags = Base::StructureFlags;
932
933 static size_t allocationSize(size_t inlineCapacity)
934 {
935 return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>);
936 }
937
938 static const unsigned defaultSize = 64;
939 static inline unsigned defaultInlineCapacity()
940 {
941 return (defaultSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
942 }
943
944 static const unsigned maxSize = 512;
945 static inline unsigned maxInlineCapacity()
946 {
947 return (maxSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
948 }
949
950 static JSFinalObject* create(ExecState*, Structure*, Butterfly* = nullptr);
951 static JSFinalObject* create(VM&, Structure*);
952 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, unsigned inlineCapacity)
953 {
954 return Structure::create(vm, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), info(), NonArray, inlineCapacity);
955 }
956
957 JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
958
959 DECLARE_EXPORT_INFO;
960
961 protected:
962 void visitChildrenCommon(SlotVisitor&);
963
964 void finishCreation(VM& vm)
965 {
966 Base::finishCreation(vm);
967 ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity());
968 ASSERT(classInfo());
969 }
970
971 private:
972 friend class LLIntOffsetsExtractor;
973
974 explicit JSFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = nullptr)
975 : JSObject(vm, structure, butterfly)
976 {
977 }
978 };
979
980 inline JSFinalObject* JSFinalObject::create(
981 ExecState* exec, Structure* structure, Butterfly* butterfly)
982 {
983 JSFinalObject* finalObject = new (
984 NotNull,
985 allocateCell<JSFinalObject>(
986 *exec->heap(),
987 allocationSize(structure->inlineCapacity())
988 )
989 ) JSFinalObject(exec->vm(), structure, butterfly);
990 finalObject->finishCreation(exec->vm());
991 return finalObject;
992 }
993
994 inline JSFinalObject* JSFinalObject::create(VM& vm, Structure* structure)
995 {
996 JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(vm.heap, allocationSize(structure->inlineCapacity()))) JSFinalObject(vm, structure);
997 finalObject->finishCreation(vm);
998 return finalObject;
999 }
1000
1001 inline bool isJSFinalObject(JSCell* cell)
1002 {
1003 return cell->classInfo() == JSFinalObject::info();
1004 }
1005
1006 inline bool isJSFinalObject(JSValue value)
1007 {
1008 return value.isCell() && isJSFinalObject(value.asCell());
1009 }
1010
1011 inline size_t JSObject::offsetOfInlineStorage()
1012 {
1013 return sizeof(JSObject);
1014 }
1015
1016 inline bool JSObject::isGlobalObject() const
1017 {
1018 return type() == GlobalObjectType;
1019 }
1020
1021 inline bool JSObject::isVariableObject() const
1022 {
1023 return type() == GlobalObjectType || type() == ActivationObjectType;
1024 }
1025
1026 inline bool JSObject::isStaticScopeObject() const
1027 {
1028 JSType type = this->type();
1029 return type == NameScopeObjectType || type == ActivationObjectType;
1030 }
1031
1032 inline bool JSObject::isNameScopeObject() const
1033 {
1034 return type() == NameScopeObjectType;
1035 }
1036
1037 inline bool JSObject::isActivationObject() const
1038 {
1039 return type() == ActivationObjectType;
1040 }
1041
1042 inline bool JSObject::isErrorInstance() const
1043 {
1044 return type() == ErrorInstanceType;
1045 }
1046
1047 inline bool JSObject::isWithScope() const
1048 {
1049 return type() == WithScopeType;
1050 }
1051
1052 inline void JSObject::setStructureAndButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
1053 {
1054 ASSERT(structure);
1055 ASSERT(!butterfly == (!structure->outOfLineCapacity() && !structure->hasIndexingHeader(this)));
1056 m_butterfly.set(vm, this, butterfly);
1057 setStructure(vm, structure);
1058 }
1059
1060 inline void JSObject::setStructure(VM& vm, Structure* structure)
1061 {
1062 ASSERT(structure);
1063 ASSERT(!m_butterfly == !(structure->outOfLineCapacity() || structure->hasIndexingHeader(this)));
1064 JSCell::setStructure(vm, structure);
1065 }
1066
1067 inline void JSObject::setButterflyWithoutChangingStructure(VM& vm, Butterfly* butterfly)
1068 {
1069 m_butterfly.set(vm, this, butterfly);
1070 }
1071
1072 inline CallType getCallData(JSValue value, CallData& callData)
1073 {
1074 CallType result = value.isCell() ? value.asCell()->methodTable()->getCallData(value.asCell(), callData) : CallTypeNone;
1075 ASSERT(result == CallTypeNone || value.isValidCallee());
1076 return result;
1077 }
1078
1079 inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
1080 {
1081 ConstructType result = value.isCell() ? value.asCell()->methodTable()->getConstructData(value.asCell(), constructData) : ConstructTypeNone;
1082 ASSERT(result == ConstructTypeNone || value.isValidCallee());
1083 return result;
1084 }
1085
1086 inline JSObject* asObject(JSCell* cell)
1087 {
1088 ASSERT(cell->isObject());
1089 return jsCast<JSObject*>(cell);
1090 }
1091
1092 inline JSObject* asObject(JSValue value)
1093 {
1094 return asObject(value.asCell());
1095 }
1096
1097 inline JSObject::JSObject(VM& vm, Structure* structure, Butterfly* butterfly)
1098 : JSCell(vm, structure)
1099 , m_butterfly(vm, this, butterfly)
1100 {
1101 vm.heap.ascribeOwner(this, butterfly);
1102 }
1103
1104 inline JSValue JSObject::prototype() const
1105 {
1106 return structure()->storedPrototype();
1107 }
1108
1109 ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot)
1110 {
1111 unsigned attributes;
1112 PropertyOffset offset = structure.get(vm, propertyName, attributes);
1113 if (!isValidOffset(offset))
1114 return false;
1115
1116 JSValue value = getDirect(offset);
1117 if (structure.hasGetterSetterProperties() && value.isGetterSetter())
1118 fillGetterPropertySlot(slot, value, attributes, offset);
1119 else if (structure.hasCustomGetterSetterProperties() && value.isCustomGetterSetter())
1120 fillCustomGetterPropertySlot(slot, value, attributes, structure);
1121 else
1122 slot.setValue(this, attributes, value, offset);
1123
1124 return true;
1125 }
1126
1127 ALWAYS_INLINE void JSObject::fillCustomGetterPropertySlot(PropertySlot& slot, JSValue customGetterSetter, unsigned attributes, Structure& structure)
1128 {
1129 if (structure.isDictionary()) {
1130 slot.setCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
1131 return;
1132 }
1133 slot.setCacheableCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
1134 }
1135
1136 // It may seem crazy to inline a function this large, especially a virtual function,
1137 // but it makes a big difference to property lookup that derived classes can inline their
1138 // base class call to this.
1139 ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1140 {
1141 VM& vm = exec->vm();
1142 Structure& structure = *object->structure(vm);
1143 if (object->inlineGetOwnPropertySlot(vm, structure, propertyName, slot))
1144 return true;
1145 if (Optional<uint32_t> index = parseIndex(propertyName))
1146 return getOwnPropertySlotByIndex(object, exec, index.value(), slot);
1147 return false;
1148 }
1149
1150 ALWAYS_INLINE bool JSObject::fastGetOwnPropertySlot(ExecState* exec, VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot)
1151 {
1152 if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(inlineTypeFlags())))
1153 return inlineGetOwnPropertySlot(vm, structure, propertyName, slot);
1154 return structure.classInfo()->methodTable.getOwnPropertySlot(this, exec, propertyName, slot);
1155 }
1156
1157 // It may seem crazy to inline a function this large but it makes a big difference
1158 // since this is function very hot in variable lookup
1159 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1160 {
1161 VM& vm = exec->vm();
1162 auto& structureIDTable = vm.heap.structureIDTable();
1163 JSObject* object = this;
1164 while (true) {
1165 Structure& structure = *structureIDTable.get(object->structureID());
1166 if (object->fastGetOwnPropertySlot(exec, vm, structure, propertyName, slot))
1167 return true;
1168 JSValue prototype = structure.storedPrototype();
1169 if (!prototype.isObject())
1170 break;
1171 object = asObject(prototype);
1172 }
1173
1174 if (Optional<uint32_t> index = parseIndex(propertyName))
1175 return getPropertySlot(exec, index.value(), slot);
1176 return false;
1177 }
1178
1179 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
1180 {
1181 VM& vm = exec->vm();
1182 auto& structureIDTable = vm.heap.structureIDTable();
1183 JSObject* object = this;
1184 while (true) {
1185 Structure& structure = *structureIDTable.get(object->structureID());
1186 if (structure.classInfo()->methodTable.getOwnPropertySlotByIndex(object, exec, propertyName, slot))
1187 return true;
1188 JSValue prototype = structure.storedPrototype();
1189 if (!prototype.isObject())
1190 return false;
1191 object = asObject(prototype);
1192 }
1193 }
1194
1195 inline JSValue JSObject::get(ExecState* exec, PropertyName propertyName) const
1196 {
1197 PropertySlot slot(this);
1198 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
1199 return slot.getValue(exec, propertyName);
1200
1201 return jsUndefined();
1202 }
1203
1204 inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
1205 {
1206 PropertySlot slot(this);
1207 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
1208 return slot.getValue(exec, propertyName);
1209
1210 return jsUndefined();
1211 }
1212
1213 template<JSObject::PutMode mode>
1214 inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
1215 {
1216 ASSERT(value);
1217 ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
1218 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
1219 ASSERT(!parseIndex(propertyName));
1220
1221 Structure* structure = this->structure(vm);
1222 if (structure->isDictionary()) {
1223 unsigned currentAttributes;
1224 PropertyOffset offset = structure->get(vm, propertyName, currentAttributes);
1225 if (offset != invalidOffset) {
1226 if ((mode == PutModePut) && currentAttributes & ReadOnly)
1227 return false;
1228
1229 putDirect(vm, offset, value);
1230 structure->didReplaceProperty(offset);
1231 slot.setExistingProperty(this, offset);
1232
1233 if ((attributes & Accessor) != (currentAttributes & Accessor)) {
1234 ASSERT(!(attributes & ReadOnly));
1235 setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes));
1236 }
1237 return true;
1238 }
1239
1240 if ((mode == PutModePut) && !isExtensible())
1241 return false;
1242
1243 DeferGC deferGC(vm.heap);
1244 Butterfly* newButterfly = butterfly();
1245 if (this->structure()->putWillGrowOutOfLineStorage())
1246 newButterfly = growOutOfLineStorage(vm, this->structure()->outOfLineCapacity(), this->structure()->suggestedNewOutOfLineStorageCapacity());
1247 offset = this->structure()->addPropertyWithoutTransition(vm, propertyName, attributes);
1248 setStructureAndButterfly(vm, this->structure(), newButterfly);
1249
1250 validateOffset(offset);
1251 ASSERT(this->structure()->isValidOffset(offset));
1252 putDirect(vm, offset, value);
1253 slot.setNewProperty(this, offset);
1254 if (attributes & ReadOnly)
1255 this->structure()->setContainsReadOnlyProperties();
1256 return true;
1257 }
1258
1259 PropertyOffset offset;
1260 size_t currentCapacity = this->structure()->outOfLineCapacity();
1261 if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, offset)) {
1262 DeferGC deferGC(vm.heap);
1263 Butterfly* newButterfly = butterfly();
1264 if (currentCapacity != structure->outOfLineCapacity()) {
1265 ASSERT(structure != this->structure());
1266 newButterfly = growOutOfLineStorage(vm, currentCapacity, structure->outOfLineCapacity());
1267 }
1268
1269 validateOffset(offset);
1270 ASSERT(structure->isValidOffset(offset));
1271 setStructureAndButterfly(vm, structure, newButterfly);
1272 putDirect(vm, offset, value);
1273 slot.setNewProperty(this, offset);
1274 return true;
1275 }
1276
1277 unsigned currentAttributes;
1278 offset = structure->get(vm, propertyName, currentAttributes);
1279 if (offset != invalidOffset) {
1280 if ((mode == PutModePut) && currentAttributes & ReadOnly)
1281 return false;
1282
1283 structure->didReplaceProperty(offset);
1284 slot.setExistingProperty(this, offset);
1285 putDirect(vm, offset, value);
1286
1287 if ((attributes & Accessor) != (currentAttributes & Accessor)) {
1288 ASSERT(!(attributes & ReadOnly));
1289 setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes));
1290 }
1291 return true;
1292 }
1293
1294 if ((mode == PutModePut) && !isExtensible())
1295 return false;
1296
1297 structure = Structure::addPropertyTransition(vm, structure, propertyName, attributes, offset, slot.context());
1298
1299 validateOffset(offset);
1300 ASSERT(structure->isValidOffset(offset));
1301 setStructureAndReallocateStorageIfNecessary(vm, structure);
1302
1303 putDirect(vm, offset, value);
1304 slot.setNewProperty(this, offset);
1305 if (attributes & ReadOnly)
1306 structure->setContainsReadOnlyProperties();
1307 return true;
1308 }
1309
1310 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, unsigned oldCapacity, Structure* newStructure)
1311 {
1312 ASSERT(oldCapacity <= newStructure->outOfLineCapacity());
1313
1314 if (oldCapacity == newStructure->outOfLineCapacity()) {
1315 setStructure(vm, newStructure);
1316 return;
1317 }
1318
1319 DeferGC deferGC(vm.heap);
1320 Butterfly* newButterfly = growOutOfLineStorage(
1321 vm, oldCapacity, newStructure->outOfLineCapacity());
1322 setStructureAndButterfly(vm, newStructure, newButterfly);
1323 }
1324
1325 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, Structure* newStructure)
1326 {
1327 setStructureAndReallocateStorageIfNecessary(
1328 vm, structure(vm)->outOfLineCapacity(), newStructure);
1329 }
1330
1331 inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1332 {
1333 ASSERT(value);
1334 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
1335 ASSERT(!structure()->hasGetterSetterProperties());
1336 ASSERT(!structure()->hasCustomGetterSetterProperties());
1337
1338 return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
1339 }
1340
1341 inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1342 {
1343 ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
1344 ASSERT(!value.isCustomGetterSetter());
1345 PutPropertySlot slot(this);
1346 putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
1347 }
1348
1349 inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1350 {
1351 ASSERT(!value.isGetterSetter());
1352 ASSERT(!value.isCustomGetterSetter());
1353 putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot);
1354 }
1355
1356 inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1357 {
1358 DeferGC deferGC(vm.heap);
1359 ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
1360 ASSERT(!value.isCustomGetterSetter());
1361 Butterfly* newButterfly = m_butterfly.get();
1362 if (structure()->putWillGrowOutOfLineStorage())
1363 newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
1364 PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes);
1365 setStructureAndButterfly(vm, structure(), newButterfly);
1366 putDirect(vm, offset, value);
1367 }
1368
1369 inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
1370 {
1371 return methodTable()->defaultValue(this, exec, preferredType);
1372 }
1373
1374 ALWAYS_INLINE JSObject* Register::object() const
1375 {
1376 return asObject(jsValue());
1377 }
1378
1379 ALWAYS_INLINE Register& Register::operator=(JSObject* object)
1380 {
1381 u.value = JSValue::encode(JSValue(object));
1382 return *this;
1383 }
1384
1385 inline size_t offsetInButterfly(PropertyOffset offset)
1386 {
1387 return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
1388 }
1389
1390 inline size_t JSObject::butterflyPreCapacity()
1391 {
1392 if (UNLIKELY(hasIndexingHeader()))
1393 return butterfly()->indexingHeader()->preCapacity(structure());
1394 return 0;
1395 }
1396
1397 inline size_t JSObject::butterflyTotalSize()
1398 {
1399 Structure* structure = this->structure();
1400 Butterfly* butterfly = this->butterfly();
1401 size_t preCapacity;
1402 size_t indexingPayloadSizeInBytes;
1403 bool hasIndexingHeader = this->hasIndexingHeader();
1404
1405 if (UNLIKELY(hasIndexingHeader)) {
1406 preCapacity = butterfly->indexingHeader()->preCapacity(structure);
1407 indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
1408 } else {
1409 preCapacity = 0;
1410 indexingPayloadSizeInBytes = 0;
1411 }
1412
1413 return Butterfly::totalSize(preCapacity, structure->outOfLineCapacity(), hasIndexingHeader, indexingPayloadSizeInBytes);
1414 }
1415
1416 // Helpers for patching code where you want to emit a load or store and
1417 // the base is:
1418 // For inline offsets: a pointer to the out-of-line storage pointer.
1419 // For out-of-line offsets: the base of the out-of-line storage.
1420 inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset)
1421 {
1422 if (isOutOfLineOffset(offset))
1423 return sizeof(EncodedJSValue) * offsetInButterfly(offset);
1424 return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
1425 }
1426
1427 // Returns the maximum offset (away from zero) a load instruction will encode.
1428 inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset)
1429 {
1430 ptrdiff_t addressOffset = static_cast<ptrdiff_t>(offsetRelativeToPatchedStorage(offset));
1431 #if USE(JSVALUE32_64)
1432 if (addressOffset >= 0)
1433 return static_cast<size_t>(addressOffset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag);
1434 #endif
1435 return static_cast<size_t>(addressOffset);
1436 }
1437
1438 inline int indexRelativeToBase(PropertyOffset offset)
1439 {
1440 if (isOutOfLineOffset(offset))
1441 return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
1442 ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue)));
1443 return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue) + offsetInInlineStorage(offset);
1444 }
1445
1446 inline int offsetRelativeToBase(PropertyOffset offset)
1447 {
1448 if (isOutOfLineOffset(offset))
1449 return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue) + Butterfly::offsetOfPropertyStorage();
1450 return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
1451 }
1452
1453 COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject_inline_storage_has_correct_alignment);
1454
1455 ALWAYS_INLINE Identifier makeIdentifier(VM& vm, const char* name)
1456 {
1457 return Identifier::fromString(&vm, name);
1458 }
1459
1460 ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name)
1461 {
1462 return name;
1463 }
1464
1465 // Helper for defining native functions, if you're not using a static hash table.
1466 // Use this macro from within finishCreation() methods in prototypes. This assumes
1467 // you've defined variables called exec, globalObject, and vm, and they
1468 // have the expected meanings.
1469 #define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
1470 putDirectNativeFunction(\
1471 vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
1472 (intrinsic), (attributes))
1473
1474 // As above, but this assumes that the function you're defining doesn't have an
1475 // intrinsic.
1476 #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
1477 JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
1478
1479 // Identical helpers but for builtins. Note that currently, we don't support builtins that are
1480 // also intrinsics, but we probably will do that eventually.
1481 #define JSC_BUILTIN_FUNCTION(jsName, generatorName, attributes) \
1482 putDirectBuiltinFunction(\
1483 vm, globalObject, makeIdentifier(vm, (jsName)), (generatorName)(vm), (attributes))
1484
1485 } // namespace JSC
1486
1487 #endif // JSObject_h