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