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