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