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