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