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