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