RegExp matches arrays should use contiguous indexing.
[WebKit-https.git] / Source / JavaScriptCore / 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, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013, 2014 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     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     JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const;
471     JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
472     bool hasOwnProperty(ExecState*, PropertyName) const;
473     bool hasOwnProperty(ExecState*, unsigned) const;
474
475     JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
476     JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
477
478     JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
479
480     bool hasInstance(ExecState*, JSValue);
481     static bool defaultHasInstance(ExecState*, JSValue, JSValue prototypeProperty);
482
483     JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
484     JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
485     JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
486
487     JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*);
488     JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
489     JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
490
491     JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
492     bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
493     JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
494     JS_EXPORT_PRIVATE JSString* toString(ExecState*) const;
495
496     JS_EXPORT_PRIVATE static JSValue toThis(JSCell*, ExecState*, ECMAMode);
497
498     // This get function only looks at the property map.
499     JSValue getDirect(VM& vm, PropertyName propertyName) const
500     {
501         Structure* structure = this->structure(vm);
502         PropertyOffset offset = structure->get(vm, propertyName);
503         checkOffset(offset, structure->inlineCapacity());
504         return offset != invalidOffset ? getDirect(offset) : JSValue();
505     }
506     
507     JSValue getDirect(VM& vm, PropertyName propertyName, unsigned& attributes) const
508     {
509         Structure* structure = this->structure(vm);
510         PropertyOffset offset = structure->get(vm, propertyName, attributes);
511         checkOffset(offset, structure->inlineCapacity());
512         return offset != invalidOffset ? getDirect(offset) : JSValue();
513     }
514
515     PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName)
516     {
517         Structure* structure = this->structure(vm);
518         PropertyOffset offset = structure->get(vm, propertyName);
519         checkOffset(offset, structure->inlineCapacity());
520         return offset;
521     }
522
523     PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName, unsigned& attributes)
524     {
525         Structure* structure = this->structure(vm);
526         PropertyOffset offset = structure->get(vm, propertyName, attributes);
527         checkOffset(offset, structure->inlineCapacity());
528         return offset;
529     }
530
531     bool hasInlineStorage() const { return structure()->hasInlineStorage(); }
532     ConstPropertyStorage inlineStorageUnsafe() const
533     {
534         return bitwise_cast<ConstPropertyStorage>(this + 1);
535     }
536     PropertyStorage inlineStorageUnsafe()
537     {
538         return bitwise_cast<PropertyStorage>(this + 1);
539     }
540     ConstPropertyStorage inlineStorage() const
541     {
542         ASSERT(hasInlineStorage());
543         return inlineStorageUnsafe();
544     }
545     PropertyStorage inlineStorage()
546     {
547         ASSERT(hasInlineStorage());
548         return inlineStorageUnsafe();
549     }
550         
551     const Butterfly* butterfly() const { return m_butterfly.get(); }
552     Butterfly* butterfly() { return m_butterfly.get(); }
553         
554     ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); }
555     PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); }
556
557     const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const
558     {
559         if (isInlineOffset(offset))
560             return &inlineStorage()[offsetInInlineStorage(offset)];
561         return &outOfLineStorage()[offsetInOutOfLineStorage(offset)];
562     }
563
564     WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset)
565     {
566         if (isInlineOffset(offset))
567             return &inlineStorage()[offsetInInlineStorage(offset)];
568         return &outOfLineStorage()[offsetInOutOfLineStorage(offset)];
569     }
570
571     void transitionTo(VM&, Structure*);
572
573     JS_EXPORT_PRIVATE bool removeDirect(VM&, PropertyName); // Return true if anything is removed.
574     bool hasCustomProperties() { return structure()->didTransition(); }
575     bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
576     bool hasCustomGetterSetterProperties() { return structure()->hasCustomGetterSetterProperties(); }
577
578     // putOwnDataProperty has 'put' like semantics, however this method:
579     //  - assumes the object contains no own getter/setter properties.
580     //  - provides no special handling for __proto__
581     //  - does not walk the prototype chain (to check for accessors or non-writable properties).
582     // This is used by JSLexicalEnvironment.
583     bool putOwnDataProperty(VM&, PropertyName, JSValue, PutPropertySlot&);
584
585     // Fast access to known property offsets.
586     JSValue getDirect(PropertyOffset offset) const { return locationForOffset(offset)->get(); }
587     void putDirect(VM& vm, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(vm, this, value); }
588     void putDirectUndefined(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); }
589
590     JS_EXPORT_PRIVATE void putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
591     JS_EXPORT_PRIVATE JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
592     JSFunction* putDirectBuiltinFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
593     JS_EXPORT_PRIVATE void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
594
595     JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
596
597     bool isGlobalObject() const;
598     bool isVariableObject() const;
599     bool isStaticScopeObject() const;
600     bool isNameScopeObject() const;
601     bool isCatchScopeObject() const;
602     bool isFunctionNameScopeObject() const;
603     bool isActivationObject() const;
604     bool isErrorInstance() const;
605     bool isWithScope() const;
606
607     JS_EXPORT_PRIVATE void seal(VM&);
608     JS_EXPORT_PRIVATE void freeze(VM&);
609     JS_EXPORT_PRIVATE void preventExtensions(VM&);
610     bool isSealed(VM& vm) { return structure(vm)->isSealed(vm); }
611     bool isFrozen(VM& vm) { return structure(vm)->isFrozen(vm); }
612     bool isExtensible() { return structure()->isExtensible(); }
613     bool indexingShouldBeSparse()
614     {
615         return !isExtensible()
616             || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
617     }
618
619     bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
620     void reifyStaticFunctionsForDelete(ExecState* exec);
621
622     JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(VM&, size_t oldSize, size_t newSize);
623     void setButterflyWithoutChangingStructure(VM&, Butterfly*);
624         
625     void setStructure(VM&, Structure*);
626     void setStructureAndButterfly(VM&, Structure*, Butterfly*);
627     void setStructureAndReallocateStorageIfNecessary(VM&, unsigned oldCapacity, Structure*);
628     void setStructureAndReallocateStorageIfNecessary(VM&, Structure*);
629
630     void convertToDictionary(VM& vm)
631     {
632         setStructure(vm, Structure::toCacheableDictionaryTransition(vm, structure(vm)));
633     }
634
635     void flattenDictionaryObject(VM& vm)
636     {
637         structure(vm)->flattenDictionaryStructure(vm, this);
638     }
639     void shiftButterflyAfterFlattening(VM&, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter);
640
641     JSGlobalObject* globalObject() const
642     {
643         ASSERT(structure()->globalObject());
644         ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this);
645         return structure()->globalObject();
646     }
647         
648     void switchToSlowPutArrayStorage(VM&);
649         
650     // The receiver is the prototype in this case. The following:
651     //
652     // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...)
653     //
654     // is equivalent to:
655     //
656     // foo->attemptToInterceptPutByIndexOnHole(...);
657     bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow);
658         
659     // Returns 0 if int32 storage cannot be created - either because
660     // indexing should be sparse, we're having a bad time, or because
661     // we already have a more general form of storage (double,
662     // contiguous, array storage).
663     ContiguousJSValues ensureInt32(VM& vm)
664     {
665         if (LIKELY(hasInt32(indexingType())))
666             return m_butterfly->contiguousInt32();
667             
668         return ensureInt32Slow(vm);
669     }
670         
671     // Returns 0 if double storage cannot be created - either because
672     // indexing should be sparse, we're having a bad time, or because
673     // we already have a more general form of storage (contiguous,
674     // or array storage).
675     ContiguousDoubles ensureDouble(VM& vm)
676     {
677         if (LIKELY(hasDouble(indexingType())))
678             return m_butterfly->contiguousDouble();
679             
680         return ensureDoubleSlow(vm);
681     }
682         
683     // Returns 0 if contiguous storage cannot be created - either because
684     // indexing should be sparse or because we're having a bad time.
685     ContiguousJSValues ensureContiguous(VM& vm)
686     {
687         if (LIKELY(hasContiguous(indexingType())))
688             return m_butterfly->contiguous();
689             
690         return ensureContiguousSlow(vm);
691     }
692         
693     // Same as ensureContiguous(), except that if the indexed storage is in
694     // double mode, then it does a rage conversion to contiguous: it
695     // attempts to convert each double to an int32.
696     ContiguousJSValues rageEnsureContiguous(VM& vm)
697     {
698         if (LIKELY(hasContiguous(indexingType())))
699             return m_butterfly->contiguous();
700             
701         return rageEnsureContiguousSlow(vm);
702     }
703         
704     // Ensure that the object is in a mode where it has array storage. Use
705     // this if you're about to perform actions that would have required the
706     // object to be converted to have array storage, if it didn't have it
707     // already.
708     ArrayStorage* ensureArrayStorage(VM& vm)
709     {
710         if (LIKELY(hasAnyArrayStorage(indexingType())))
711             return m_butterfly->arrayStorage();
712
713         return ensureArrayStorageSlow(vm);
714     }
715         
716     static size_t offsetOfInlineStorage();
717         
718     static ptrdiff_t butterflyOffset()
719     {
720         return OBJECT_OFFSETOF(JSObject, m_butterfly);
721     }
722         
723     void* butterflyAddress()
724     {
725         return &m_butterfly;
726     }
727
728     DECLARE_EXPORT_INFO;
729
730 protected:
731     void finishCreation(VM& vm)
732     {
733         Base::finishCreation(vm);
734         ASSERT(inherits(info()));
735         ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
736         ASSERT(structure()->isObject());
737         ASSERT(classInfo());
738     }
739
740     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
741     {
742         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
743     }
744
745     // To instantiate objects you likely want JSFinalObject, below.
746     // To create derived types you likely want JSNonFinalObject, below.
747     JSObject(VM&, Structure*, Butterfly* = 0);
748         
749     void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize);
750     void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize);
751
752     // Call this if you know that the object is in a mode where it has array
753     // storage. This will assert otherwise.
754     ArrayStorage* arrayStorage()
755     {
756         ASSERT(hasAnyArrayStorage(indexingType()));
757         return m_butterfly->arrayStorage();
758     }
759         
760     // Call this if you want to predicate some actions on whether or not the
761     // object is in a mode where it has array storage.
762     ArrayStorage* arrayStorageOrNull()
763     {
764         switch (indexingType()) {
765         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
766             return m_butterfly->arrayStorage();
767                 
768         default:
769             return 0;
770         }
771     }
772         
773     size_t butterflyTotalSize();
774     size_t butterflyPreCapacity();
775
776     Butterfly* createInitialUndecided(VM&, unsigned length);
777     ContiguousJSValues createInitialInt32(VM&, unsigned length);
778     ContiguousDoubles createInitialDouble(VM&, unsigned length);
779     ContiguousJSValues createInitialContiguous(VM&, unsigned length);
780         
781     void convertUndecidedForValue(VM&, JSValue);
782     void createInitialForValueAndSet(VM&, unsigned index, JSValue);
783     void convertInt32ForValue(VM&, JSValue);
784         
785     ArrayStorage* createArrayStorage(VM&, unsigned length, unsigned vectorLength);
786     ArrayStorage* createInitialArrayStorage(VM&);
787         
788     ContiguousJSValues convertUndecidedToInt32(VM&);
789     ContiguousDoubles convertUndecidedToDouble(VM&);
790     ContiguousJSValues convertUndecidedToContiguous(VM&);
791     ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition);
792     ArrayStorage* convertUndecidedToArrayStorage(VM&);
793         
794     ContiguousDoubles convertInt32ToDouble(VM&);
795     ContiguousJSValues convertInt32ToContiguous(VM&);
796     ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition);
797     ArrayStorage* convertInt32ToArrayStorage(VM&);
798     
799     ContiguousJSValues convertDoubleToContiguous(VM&);
800     ContiguousJSValues rageConvertDoubleToContiguous(VM&);
801     ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition);
802     ArrayStorage* convertDoubleToArrayStorage(VM&);
803         
804     ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition);
805     ArrayStorage* convertContiguousToArrayStorage(VM&);
806
807         
808     ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM&);
809         
810     bool defineOwnNonIndexProperty(ExecState*, PropertyName, const PropertyDescriptor&, bool throwException);
811
812     template<IndexingType indexingShape>
813     void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
814     void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
815
816     bool increaseVectorLength(VM&, unsigned newLength);
817     void deallocateSparseIndexMap();
818     bool defineOwnIndexedProperty(ExecState*, unsigned, const PropertyDescriptor&, bool throwException);
819     SparseArrayValueMap* allocateSparseIndexMap(VM&);
820         
821     void notifyPresenceOfIndexedAccessors(VM&);
822         
823     bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow);
824         
825     // Call this if you want setIndexQuickly to succeed and you're sure that
826     // the array is contiguous.
827     void ensureLength(VM& vm, unsigned length)
828     {
829         ASSERT(length < MAX_ARRAY_INDEX);
830         ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
831             
832         if (m_butterfly->vectorLength() < length)
833             ensureLengthSlow(vm, length);
834             
835         if (m_butterfly->publicLength() < length)
836             m_butterfly->setPublicLength(length);
837     }
838         
839     template<IndexingType indexingShape>
840     unsigned countElements(Butterfly*);
841         
842     // This is relevant to undecided, int32, double, and contiguous.
843     unsigned countElements();
844         
845     // This strange method returns a pointer to the start of the indexed data
846     // as if it contained JSValues. But it won't always contain JSValues.
847     // Make sure you cast this to the appropriate type before using.
848     template<IndexingType indexingType>
849     ContiguousJSValues indexingData()
850     {
851         switch (indexingType) {
852         case ALL_INT32_INDEXING_TYPES:
853         case ALL_DOUBLE_INDEXING_TYPES:
854         case ALL_CONTIGUOUS_INDEXING_TYPES:
855             return m_butterfly->contiguous();
856                 
857         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
858             return m_butterfly->arrayStorage()->vector();
859
860         default:
861             CRASH();
862             return ContiguousJSValues();
863         }
864     }
865
866     ContiguousJSValues currentIndexingData()
867     {
868         switch (indexingType()) {
869         case ALL_INT32_INDEXING_TYPES:
870         case ALL_CONTIGUOUS_INDEXING_TYPES:
871             return m_butterfly->contiguous();
872
873         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
874             return m_butterfly->arrayStorage()->vector();
875
876         default:
877             CRASH();
878             return ContiguousJSValues();
879         }
880     }
881         
882     JSValue getHolyIndexQuickly(unsigned i)
883     {
884         ASSERT(i < m_butterfly->vectorLength());
885         switch (indexingType()) {
886         case ALL_INT32_INDEXING_TYPES:
887         case ALL_CONTIGUOUS_INDEXING_TYPES:
888             return m_butterfly->contiguous()[i].get();
889         case ALL_DOUBLE_INDEXING_TYPES: {
890             double value = m_butterfly->contiguousDouble()[i];
891             if (value == value)
892                 return JSValue(JSValue::EncodeAsDouble, value);
893             return JSValue();
894         }
895         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
896             return m_butterfly->arrayStorage()->m_vector[i].get();
897         default:
898             CRASH();
899             return JSValue();
900         }
901     }
902         
903     template<IndexingType indexingType>
904     unsigned relevantLength()
905     {
906         switch (indexingType) {
907         case ALL_INT32_INDEXING_TYPES:
908         case ALL_DOUBLE_INDEXING_TYPES:
909         case ALL_CONTIGUOUS_INDEXING_TYPES:
910             return m_butterfly->publicLength();
911                 
912         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
913             return std::min(
914                 m_butterfly->arrayStorage()->length(),
915                 m_butterfly->arrayStorage()->vectorLength());
916                 
917         default:
918             CRASH();
919             return 0;
920         }
921     }
922
923     unsigned currentRelevantLength()
924     {
925         switch (indexingType()) {
926         case ALL_INT32_INDEXING_TYPES:
927         case ALL_DOUBLE_INDEXING_TYPES:
928         case ALL_CONTIGUOUS_INDEXING_TYPES:
929             return m_butterfly->publicLength();
930
931         case ALL_ARRAY_STORAGE_INDEXING_TYPES:
932             return std::min(
933                 m_butterfly->arrayStorage()->length(),
934                 m_butterfly->arrayStorage()->vectorLength());
935
936         default:
937             CRASH();
938             return 0;
939         }
940     }
941
942 private:
943     friend class LLIntOffsetsExtractor;
944         
945     // Nobody should ever ask any of these questions on something already known to be a JSObject.
946     using JSCell::isAPIValueWrapper;
947     using JSCell::isGetterSetter;
948     void getObject();
949     void getString(ExecState* exec);
950     void isObject();
951     void isString();
952         
953     Butterfly* createInitialIndexedStorage(VM&, unsigned length, size_t elementSize);
954         
955     ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*);
956         
957     template<PutMode>
958     bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&);
959
960     bool inlineGetOwnPropertySlot(VM&, Structure&, PropertyName, PropertySlot&);
961     JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset);
962     void fillCustomGetterPropertySlot(PropertySlot&, JSValue, unsigned, Structure&);
963
964     const HashTableValue* findPropertyHashEntry(PropertyName) const;
965         
966     void putIndexedDescriptor(ExecState*, SparseArrayEntry*, const PropertyDescriptor&, PropertyDescriptor& old);
967         
968     void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
969     bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode, ArrayStorage*);
970     JS_EXPORT_PRIVATE bool putDirectIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode);
971         
972     unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength);
973     unsigned getNewVectorLength(unsigned desiredLength);
974
975     ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(VM&, unsigned neededLength);
976         
977     JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(VM&, unsigned index, JSValue);
978     JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue);
979     JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(VM&, unsigned index, JSValue);
980         
981     void ensureLengthSlow(VM&, unsigned length);
982         
983     ContiguousJSValues ensureInt32Slow(VM&);
984     ContiguousDoubles ensureDoubleSlow(VM&);
985     ContiguousJSValues ensureContiguousSlow(VM&);
986     ContiguousJSValues rageEnsureContiguousSlow(VM&);
987     JS_EXPORT_PRIVATE ArrayStorage* ensureArrayStorageSlow(VM&);
988     
989     enum DoubleToContiguousMode { EncodeValueAsDouble, RageConvertDoubleToValue };
990     template<DoubleToContiguousMode mode>
991     ContiguousJSValues genericConvertDoubleToContiguous(VM&);
992     ContiguousJSValues ensureContiguousSlow(VM&, DoubleToContiguousMode);
993     
994 protected:
995     CopyWriteBarrier<Butterfly> m_butterfly;
996 #if USE(JSVALUE32_64)
997 private:
998     uint32_t m_padding;
999 #endif
1000 };
1001
1002 // JSNonFinalObject is a type of JSObject that has some internal storage,
1003 // but also preserves some space in the collector cell for additional
1004 // data members in derived types.
1005 class JSNonFinalObject : public JSObject {
1006     friend class JSObject;
1007
1008 public:
1009     typedef JSObject Base;
1010
1011     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
1012     {
1013         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
1014     }
1015
1016 protected:
1017     explicit JSNonFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = 0)
1018         : JSObject(vm, structure, butterfly)
1019     {
1020     }
1021
1022     void finishCreation(VM& vm)
1023     {
1024         Base::finishCreation(vm);
1025         ASSERT(!this->structure()->totalStorageCapacity());
1026         ASSERT(classInfo());
1027     }
1028 };
1029
1030 class JSFinalObject;
1031
1032 // JSFinalObject is a type of JSObject that contains sufficent internal
1033 // storage to fully make use of the colloctor cell containing it.
1034 class JSFinalObject : public JSObject {
1035     friend class JSObject;
1036
1037 public:
1038     typedef JSObject Base;
1039     static const unsigned StructureFlags = Base::StructureFlags;
1040
1041     static size_t allocationSize(size_t inlineCapacity)
1042     {
1043         return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>);
1044     }
1045         
1046     static const unsigned defaultSize = 64;
1047     static inline unsigned defaultInlineCapacity()
1048     {
1049         return (defaultSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
1050     }
1051
1052     static const unsigned maxSize = 512;
1053     static inline unsigned maxInlineCapacity()
1054     {
1055         return (maxSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
1056     }
1057
1058     static JSFinalObject* create(ExecState*, Structure*, Butterfly* = nullptr);
1059     static JSFinalObject* create(VM&, Structure*);
1060     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, unsigned inlineCapacity)
1061     {
1062         return Structure::create(vm, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), info(), NonArray, inlineCapacity);
1063     }
1064
1065     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
1066
1067     DECLARE_EXPORT_INFO;
1068
1069 protected:
1070     void visitChildrenCommon(SlotVisitor&);
1071         
1072     void finishCreation(VM& vm)
1073     {
1074         Base::finishCreation(vm);
1075         ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity());
1076         ASSERT(classInfo());
1077     }
1078
1079 private:
1080     friend class LLIntOffsetsExtractor;
1081
1082     explicit JSFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = nullptr)
1083         : JSObject(vm, structure, butterfly)
1084     {
1085     }
1086 };
1087
1088 inline JSFinalObject* JSFinalObject::create(
1089     ExecState* exec, Structure* structure, Butterfly* butterfly)
1090 {
1091     JSFinalObject* finalObject = new (
1092         NotNull, 
1093         allocateCell<JSFinalObject>(
1094             *exec->heap(),
1095             allocationSize(structure->inlineCapacity())
1096         )
1097     ) JSFinalObject(exec->vm(), structure, butterfly);
1098     finalObject->finishCreation(exec->vm());
1099     return finalObject;
1100 }
1101
1102 inline JSFinalObject* JSFinalObject::create(VM& vm, Structure* structure)
1103 {
1104     JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(vm.heap, allocationSize(structure->inlineCapacity()))) JSFinalObject(vm, structure);
1105     finalObject->finishCreation(vm);
1106     return finalObject;
1107 }
1108
1109 inline bool isJSFinalObject(JSCell* cell)
1110 {
1111     return cell->classInfo() == JSFinalObject::info();
1112 }
1113
1114 inline bool isJSFinalObject(JSValue value)
1115 {
1116     return value.isCell() && isJSFinalObject(value.asCell());
1117 }
1118
1119 inline size_t JSObject::offsetOfInlineStorage()
1120 {
1121     return sizeof(JSObject);
1122 }
1123
1124 inline bool JSObject::isGlobalObject() const
1125 {
1126     return type() == GlobalObjectType;
1127 }
1128
1129 inline bool JSObject::isVariableObject() const
1130 {
1131     return type() == GlobalObjectType || type() == ActivationObjectType;
1132 }
1133
1134 inline bool JSObject::isStaticScopeObject() const
1135 {
1136     JSType type = this->type();
1137     return type == NameScopeObjectType || type == ActivationObjectType;
1138 }
1139
1140 inline bool JSObject::isNameScopeObject() const
1141 {
1142     return type() == NameScopeObjectType;
1143 }
1144
1145 inline bool JSObject::isActivationObject() const
1146 {
1147     return type() == ActivationObjectType;
1148 }
1149
1150 inline bool JSObject::isErrorInstance() const
1151 {
1152     return type() == ErrorInstanceType;
1153 }
1154
1155 inline bool JSObject::isWithScope() const
1156 {
1157     return type() == WithScopeType;
1158 }
1159
1160 inline void JSObject::setStructureAndButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
1161 {
1162     ASSERT(structure);
1163     ASSERT(!butterfly == (!structure->outOfLineCapacity() && !structure->hasIndexingHeader(this)));
1164     m_butterfly.set(vm, this, butterfly);
1165     setStructure(vm, structure);
1166 }
1167
1168 inline void JSObject::setStructure(VM& vm, Structure* structure)
1169 {
1170     ASSERT(structure);
1171     ASSERT(!m_butterfly == !(structure->outOfLineCapacity() || structure->hasIndexingHeader(this)));
1172     JSCell::setStructure(vm, structure);
1173 }
1174
1175 inline void JSObject::setButterflyWithoutChangingStructure(VM& vm, Butterfly* butterfly)
1176 {
1177     m_butterfly.set(vm, this, butterfly);
1178 }
1179
1180 inline CallType getCallData(JSValue value, CallData& callData)
1181 {
1182     CallType result = value.isCell() ? value.asCell()->methodTable()->getCallData(value.asCell(), callData) : CallTypeNone;
1183     ASSERT(result == CallTypeNone || value.isValidCallee());
1184     return result;
1185 }
1186
1187 inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
1188 {
1189     ConstructType result = value.isCell() ? value.asCell()->methodTable()->getConstructData(value.asCell(), constructData) : ConstructTypeNone;
1190     ASSERT(result == ConstructTypeNone || value.isValidCallee());
1191     return result;
1192 }
1193
1194 inline JSObject* asObject(JSCell* cell)
1195 {
1196     ASSERT(cell->isObject());
1197     return jsCast<JSObject*>(cell);
1198 }
1199
1200 inline JSObject* asObject(JSValue value)
1201 {
1202     return asObject(value.asCell());
1203 }
1204
1205 inline JSObject::JSObject(VM& vm, Structure* structure, Butterfly* butterfly)
1206     : JSCell(vm, structure)
1207     , m_butterfly(vm, this, butterfly)
1208 {
1209     vm.heap.ascribeOwner(this, butterfly);
1210 }
1211
1212 inline JSValue JSObject::prototype() const
1213 {
1214     return structure()->storedPrototype();
1215 }
1216
1217 ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot)
1218 {
1219     unsigned attributes;
1220     PropertyOffset offset = structure.get(vm, propertyName, attributes);
1221     if (!isValidOffset(offset))
1222         return false;
1223
1224     JSValue value = getDirect(offset);
1225     if (structure.hasGetterSetterProperties() && value.isGetterSetter())
1226         fillGetterPropertySlot(slot, value, attributes, offset);
1227     else if (structure.hasCustomGetterSetterProperties() && value.isCustomGetterSetter())
1228         fillCustomGetterPropertySlot(slot, value, attributes, structure);
1229     else
1230         slot.setValue(this, attributes, value, offset);
1231
1232     return true;
1233 }
1234
1235 ALWAYS_INLINE void JSObject::fillCustomGetterPropertySlot(PropertySlot& slot, JSValue customGetterSetter, unsigned attributes, Structure& structure)
1236 {
1237     if (structure.isDictionary()) {
1238         slot.setCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
1239         return;
1240     }
1241     slot.setCacheableCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
1242 }
1243
1244 // It may seem crazy to inline a function this large, especially a virtual function,
1245 // but it makes a big difference to property lookup that derived classes can inline their
1246 // base class call to this.
1247 ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1248 {
1249     VM& vm = exec->vm();
1250     Structure& structure = *object->structure(vm);
1251     if (object->inlineGetOwnPropertySlot(vm, structure, propertyName, slot))
1252         return true;
1253     if (Optional<uint32_t> index = parseIndex(propertyName))
1254         return getOwnPropertySlotByIndex(object, exec, index.value(), slot);
1255     return false;
1256 }
1257
1258 ALWAYS_INLINE bool JSObject::fastGetOwnPropertySlot(ExecState* exec, VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot)
1259 {
1260     if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(inlineTypeFlags())))
1261         return inlineGetOwnPropertySlot(vm, structure, propertyName, slot);
1262     return structure.classInfo()->methodTable.getOwnPropertySlot(this, exec, propertyName, slot);
1263 }
1264
1265 // It may seem crazy to inline a function this large but it makes a big difference
1266 // since this is function very hot in variable lookup
1267 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
1268 {
1269     VM& vm = exec->vm();
1270     auto& structureIDTable = vm.heap.structureIDTable();
1271     JSObject* object = this;
1272     while (true) {
1273         Structure& structure = *structureIDTable.get(object->structureID());
1274         if (object->fastGetOwnPropertySlot(exec, vm, structure, propertyName, slot))
1275             return true;
1276         JSValue prototype = structure.storedPrototype();
1277         if (!prototype.isObject())
1278             break;
1279         object = asObject(prototype);
1280     }
1281
1282     if (Optional<uint32_t> index = parseIndex(propertyName))
1283         return getPropertySlot(exec, index.value(), slot);
1284     return false;
1285 }
1286
1287 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
1288 {
1289     VM& vm = exec->vm();
1290     auto& structureIDTable = vm.heap.structureIDTable();
1291     JSObject* object = this;
1292     while (true) {
1293         Structure& structure = *structureIDTable.get(object->structureID());
1294         if (structure.classInfo()->methodTable.getOwnPropertySlotByIndex(object, exec, propertyName, slot))
1295             return true;
1296         JSValue prototype = structure.storedPrototype();
1297         if (!prototype.isObject())
1298             return false;
1299         object = asObject(prototype);
1300     }
1301 }
1302
1303 inline JSValue JSObject::get(ExecState* exec, PropertyName propertyName) const
1304 {
1305     PropertySlot slot(this);
1306     if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
1307         return slot.getValue(exec, propertyName);
1308     
1309     return jsUndefined();
1310 }
1311
1312 inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
1313 {
1314     PropertySlot slot(this);
1315     if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
1316         return slot.getValue(exec, propertyName);
1317
1318     return jsUndefined();
1319 }
1320
1321 template<JSObject::PutMode mode>
1322 inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
1323 {
1324     ASSERT(value);
1325     ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
1326     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
1327     ASSERT(!parseIndex(propertyName));
1328
1329     Structure* structure = this->structure(vm);
1330     if (structure->isDictionary()) {
1331         unsigned currentAttributes;
1332         PropertyOffset offset = structure->get(vm, propertyName, currentAttributes);
1333         if (offset != invalidOffset) {
1334             if ((mode == PutModePut) && currentAttributes & ReadOnly)
1335                 return false;
1336
1337             putDirect(vm, offset, value);
1338             structure->didReplaceProperty(offset);
1339             
1340             slot.setExistingProperty(this, offset);
1341             return true;
1342         }
1343
1344         if ((mode == PutModePut) && !isExtensible())
1345             return false;
1346
1347         DeferGC deferGC(vm.heap);
1348         Butterfly* newButterfly = butterfly();
1349         if (this->structure()->putWillGrowOutOfLineStorage())
1350             newButterfly = growOutOfLineStorage(vm, this->structure()->outOfLineCapacity(), this->structure()->suggestedNewOutOfLineStorageCapacity());
1351         offset = this->structure()->addPropertyWithoutTransition(vm, propertyName, attributes);
1352         setStructureAndButterfly(vm, this->structure(), newButterfly);
1353
1354         validateOffset(offset);
1355         ASSERT(this->structure()->isValidOffset(offset));
1356         putDirect(vm, offset, value);
1357         slot.setNewProperty(this, offset);
1358         if (attributes & ReadOnly)
1359             this->structure()->setContainsReadOnlyProperties();
1360         return true;
1361     }
1362
1363     PropertyOffset offset;
1364     size_t currentCapacity = this->structure()->outOfLineCapacity();
1365     if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, offset)) {
1366         DeferGC deferGC(vm.heap);
1367         Butterfly* newButterfly = butterfly();
1368         if (currentCapacity != structure->outOfLineCapacity()) {
1369             ASSERT(structure != this->structure());
1370             newButterfly = growOutOfLineStorage(vm, currentCapacity, structure->outOfLineCapacity());
1371         }
1372
1373         validateOffset(offset);
1374         ASSERT(structure->isValidOffset(offset));
1375         setStructureAndButterfly(vm, structure, newButterfly);
1376         putDirect(vm, offset, value);
1377         slot.setNewProperty(this, offset);
1378         return true;
1379     }
1380
1381     unsigned currentAttributes;
1382     offset = structure->get(vm, propertyName, currentAttributes);
1383     if (offset != invalidOffset) {
1384         if ((mode == PutModePut) && currentAttributes & ReadOnly)
1385             return false;
1386
1387         structure->didReplaceProperty(offset);
1388         slot.setExistingProperty(this, offset);
1389         putDirect(vm, offset, value);
1390         return true;
1391     }
1392
1393     if ((mode == PutModePut) && !isExtensible())
1394         return false;
1395
1396     structure = Structure::addPropertyTransition(vm, structure, propertyName, attributes, offset, slot.context());
1397     
1398     validateOffset(offset);
1399     ASSERT(structure->isValidOffset(offset));
1400     setStructureAndReallocateStorageIfNecessary(vm, structure);
1401
1402     putDirect(vm, offset, value);
1403     slot.setNewProperty(this, offset);
1404     if (attributes & ReadOnly)
1405         structure->setContainsReadOnlyProperties();
1406     return true;
1407 }
1408
1409 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, unsigned oldCapacity, Structure* newStructure)
1410 {
1411     ASSERT(oldCapacity <= newStructure->outOfLineCapacity());
1412     
1413     if (oldCapacity == newStructure->outOfLineCapacity()) {
1414         setStructure(vm, newStructure);
1415         return;
1416     }
1417
1418     DeferGC deferGC(vm.heap); 
1419     Butterfly* newButterfly = growOutOfLineStorage(
1420         vm, oldCapacity, newStructure->outOfLineCapacity());
1421     setStructureAndButterfly(vm, newStructure, newButterfly);
1422 }
1423
1424 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, Structure* newStructure)
1425 {
1426     setStructureAndReallocateStorageIfNecessary(
1427         vm, structure(vm)->outOfLineCapacity(), newStructure);
1428 }
1429
1430 inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1431 {
1432     ASSERT(value);
1433     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
1434     ASSERT(!structure()->hasGetterSetterProperties());
1435     ASSERT(!structure()->hasCustomGetterSetterProperties());
1436
1437     return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
1438 }
1439
1440 inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1441 {
1442     ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
1443     ASSERT(!value.isCustomGetterSetter());
1444     PutPropertySlot slot(this);
1445     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
1446 }
1447
1448 inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
1449 {
1450     ASSERT(!value.isGetterSetter());
1451     ASSERT(!value.isCustomGetterSetter());
1452     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot);
1453 }
1454
1455 inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
1456 {
1457     DeferGC deferGC(vm.heap);
1458     ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
1459     ASSERT(!value.isCustomGetterSetter());
1460     Butterfly* newButterfly = m_butterfly.get();
1461     if (structure()->putWillGrowOutOfLineStorage())
1462         newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
1463     PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes);
1464     setStructureAndButterfly(vm, structure(), newButterfly);
1465     putDirect(vm, offset, value);
1466 }
1467
1468 inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
1469 {
1470     return methodTable()->defaultValue(this, exec, preferredType);
1471 }
1472
1473 ALWAYS_INLINE JSObject* Register::function() const
1474 {
1475     if (!jsValue())
1476         return 0;
1477     return asObject(jsValue());
1478 }
1479
1480 ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
1481 {
1482     Register r;
1483     r = JSValue(callee);
1484     return r;
1485 }
1486
1487 inline size_t offsetInButterfly(PropertyOffset offset)
1488 {
1489     return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
1490 }
1491
1492 inline size_t JSObject::butterflyPreCapacity()
1493 {
1494     if (UNLIKELY(hasIndexingHeader()))
1495         return butterfly()->indexingHeader()->preCapacity(structure());
1496     return 0;
1497 }
1498
1499 inline size_t JSObject::butterflyTotalSize()
1500 {
1501     Structure* structure = this->structure();
1502     Butterfly* butterfly = this->butterfly();
1503     size_t preCapacity;
1504     size_t indexingPayloadSizeInBytes;
1505     bool hasIndexingHeader = this->hasIndexingHeader();
1506
1507     if (UNLIKELY(hasIndexingHeader)) {
1508         preCapacity = butterfly->indexingHeader()->preCapacity(structure);
1509         indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
1510     } else {
1511         preCapacity = 0;
1512         indexingPayloadSizeInBytes = 0;
1513     }
1514
1515     return Butterfly::totalSize(preCapacity, structure->outOfLineCapacity(), hasIndexingHeader, indexingPayloadSizeInBytes);
1516 }
1517
1518 // Helpers for patching code where you want to emit a load or store and
1519 // the base is:
1520 // For inline offsets: a pointer to the out-of-line storage pointer.
1521 // For out-of-line offsets: the base of the out-of-line storage.
1522 inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset)
1523 {
1524     if (isOutOfLineOffset(offset))
1525         return sizeof(EncodedJSValue) * offsetInButterfly(offset);
1526     return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
1527 }
1528
1529 // Returns the maximum offset (away from zero) a load instruction will encode.
1530 inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset)
1531 {
1532     ptrdiff_t addressOffset = static_cast<ptrdiff_t>(offsetRelativeToPatchedStorage(offset));
1533 #if USE(JSVALUE32_64)
1534     if (addressOffset >= 0)
1535         return static_cast<size_t>(addressOffset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag);
1536 #endif
1537     return static_cast<size_t>(addressOffset);
1538 }
1539
1540 inline int indexRelativeToBase(PropertyOffset offset)
1541 {
1542     if (isOutOfLineOffset(offset))
1543         return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
1544     ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue)));
1545     return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue) + offsetInInlineStorage(offset);
1546 }
1547
1548 inline int offsetRelativeToBase(PropertyOffset offset)
1549 {
1550     if (isOutOfLineOffset(offset))
1551         return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue) + Butterfly::offsetOfPropertyStorage();
1552     return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
1553 }
1554
1555 COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject_inline_storage_has_correct_alignment);
1556
1557 ALWAYS_INLINE Identifier makeIdentifier(VM& vm, const char* name)
1558 {
1559     return Identifier::fromString(&vm, name);
1560 }
1561
1562 ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name)
1563 {
1564     return name;
1565 }
1566
1567 // Helper for defining native functions, if you're not using a static hash table.
1568 // Use this macro from within finishCreation() methods in prototypes. This assumes
1569 // you've defined variables called exec, globalObject, and vm, and they
1570 // have the expected meanings.
1571 #define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
1572     putDirectNativeFunction(\
1573         vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
1574         (intrinsic), (attributes))
1575
1576 // As above, but this assumes that the function you're defining doesn't have an
1577 // intrinsic.
1578 #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
1579     JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
1580
1581 } // namespace JSC
1582
1583 #endif // JSObject_h