]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/JSObject.h
JavaScriptCore-1097.3.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)
f9bf01c6 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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"
27#include "ClassInfo.h"
28#include "CommonIdentifiers.h"
29#include "CallFrame.h"
f9bf01c6 30#include "JSCell.h"
9dae56ea
A
31#include "PropertySlot.h"
32#include "PutPropertySlot.h"
33#include "ScopeChain.h"
6fe7ccc8 34#include "StorageBarrier.h"
9dae56ea 35#include "Structure.h"
ba379fdc 36#include "JSGlobalData.h"
4e4e5a6f 37#include "JSString.h"
ba379fdc 38#include <wtf/StdLibExtras.h>
9dae56ea
A
39
40namespace JSC {
41
6fe7ccc8 42 inline JSCell* getJSFunction(JSValue value)
ba379fdc 43 {
6fe7ccc8 44 if (value.isCell() && (value.asCell()->structure()->typeInfo().type() == JSFunctionType))
ba379fdc
A
45 return value.asCell();
46 return 0;
47 }
6fe7ccc8
A
48
49 class GetterSetter;
f9bf01c6 50 class HashEntry;
9dae56ea 51 class InternalFunction;
6fe7ccc8
A
52 class LLIntOffsetsExtractor;
53 class MarkedBlock;
f9bf01c6 54 class PropertyDescriptor;
9dae56ea
A
55 class PropertyNameArray;
56 class Structure;
9dae56ea
A
57 struct HashTable;
58
6fe7ccc8
A
59 JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const UString&);
60 extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError;
14957cd0 61
9dae56ea
A
62 // ECMA 262-3 8.6.1
63 // Property attributes
64 enum Attribute {
65 None = 0,
66 ReadOnly = 1 << 1, // property can be only read, not written
67 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
68 DontDelete = 1 << 3, // property can't be deleted
69 Function = 1 << 4, // property is a function - only used by static hashtables
6fe7ccc8 70 Accessor = 1 << 5, // property is a getter/setter
9dae56ea
A
71 };
72
9dae56ea
A
73 class JSObject : public JSCell {
74 friend class BatchedTransitionOptimizer;
75 friend class JIT;
76 friend class JSCell;
6fe7ccc8
A
77 friend class MarkedBlock;
78 JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
79
80 enum PutMode {
81 PutModePut,
82 PutModeDefineOwnProperty,
83 };
9dae56ea
A
84
85 public:
6fe7ccc8
A
86 typedef JSCell Base;
87
88 JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
9dae56ea 89
6fe7ccc8 90 JS_EXPORT_PRIVATE static UString className(const JSObject*);
9dae56ea 91
ba379fdc 92 JSValue prototype() const;
14957cd0
A
93 void setPrototype(JSGlobalData&, JSValue prototype);
94 bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype);
9dae56ea 95
14957cd0 96 Structure* inheritorID(JSGlobalData&);
9dae56ea 97
ba379fdc
A
98 JSValue get(ExecState*, const Identifier& propertyName) const;
99 JSValue get(ExecState*, unsigned propertyName) const;
9dae56ea
A
100
101 bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
102 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
6fe7ccc8
A
103 JS_EXPORT_PRIVATE bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
104
105 static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
106 JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
107 JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
9dae56ea 108
6fe7ccc8 109 bool allowsAccessFrom(ExecState*);
9dae56ea 110
6fe7ccc8
A
111 JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
112 JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
9dae56ea 113
6fe7ccc8
A
114 // putDirect is effectively an unchecked vesion of 'defineOwnProperty':
115 // - the prototype chain is not consulted
116 // - accessors are not called.
117 // - attributes will be respected (after the call the property will exist with the given attributes)
118 JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes);
119 void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0);
120 void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
121 void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes = 0);
122 void putDirectAccessor(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attributes);
9dae56ea
A
123
124 bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
125
6fe7ccc8
A
126 JS_EXPORT_PRIVATE bool hasProperty(ExecState*, const Identifier& propertyName) const;
127 JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
9dae56ea
A
128 bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
129
6fe7ccc8
A
130 JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
131 JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
9dae56ea 132
6fe7ccc8 133 JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
9dae56ea 134
6fe7ccc8 135 JS_EXPORT_PRIVATE static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty);
9dae56ea 136
6fe7ccc8
A
137 JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
138 JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
9dae56ea 139
6fe7ccc8
A
140 JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
141 JS_EXPORT_PRIVATE bool toBoolean(ExecState*) const;
142 bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
143 JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
144 JS_EXPORT_PRIVATE JSString* toString(ExecState*) const;
9dae56ea 145
6fe7ccc8
A
146 // NOTE: JSObject and its subclasses must be able to gracefully handle ExecState* = 0,
147 // because this call may come from inside the compiler.
148 JS_EXPORT_PRIVATE static JSObject* toThisObject(JSCell*, ExecState*);
149 JSObject* unwrappedObject();
9dae56ea 150
ba379fdc 151 bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
9dae56ea
A
152
153 // This get function only looks at the property map.
14957cd0 154 JSValue getDirect(JSGlobalData& globalData, const Identifier& propertyName) const
9dae56ea 155 {
6fe7ccc8 156 size_t offset = structure()->get(globalData, propertyName);
ba379fdc 157 return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
9dae56ea
A
158 }
159
14957cd0 160 WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName)
9dae56ea 161 {
6fe7ccc8 162 size_t offset = structure()->get(globalData, propertyName);
9dae56ea
A
163 return offset != WTF::notFound ? locationForOffset(offset) : 0;
164 }
165
14957cd0 166 WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes)
9dae56ea 167 {
ba379fdc 168 JSCell* specificFunction;
6fe7ccc8 169 size_t offset = structure()->get(globalData, propertyName, attributes, specificFunction);
9dae56ea
A
170 return offset != WTF::notFound ? locationForOffset(offset) : 0;
171 }
172
14957cd0 173 size_t offsetForLocation(WriteBarrierBase<Unknown>* location) const
9dae56ea 174 {
14957cd0 175 return location - propertyStorage();
9dae56ea
A
176 }
177
14957cd0 178 void transitionTo(JSGlobalData&, Structure*);
9dae56ea 179
14957cd0 180 void removeDirect(JSGlobalData&, const Identifier& propertyName);
6fe7ccc8
A
181 bool hasCustomProperties() { return structure()->didTransition(); }
182 bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
ba379fdc 183
6fe7ccc8
A
184 // putOwnDataProperty has 'put' like semantics, however this method:
185 // - assumes the object contains no own getter/setter properties.
186 // - provides no special handling for __proto__
187 // - does not walk the prototype chain (to check for accessors or non-writable properties).
188 // This is used by JSActivation.
189 bool putOwnDataProperty(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
9dae56ea
A
190
191 // Fast access to known property offsets.
14957cd0
A
192 JSValue getDirectOffset(size_t offset) const { return propertyStorage()[offset].get(); }
193 void putDirectOffset(JSGlobalData& globalData, size_t offset, JSValue value) { propertyStorage()[offset].set(globalData, this, value); }
194 void putUndefinedAtDirectOffset(size_t offset) { propertyStorage()[offset].setUndefined(); }
9dae56ea 195
6fe7ccc8 196 JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
9dae56ea 197
6fe7ccc8
A
198 bool isGlobalObject() const;
199 bool isVariableObject() const;
200 bool isStaticScopeObject() const;
201 bool isActivationObject() const;
202 bool isErrorInstance() const;
203 bool isGlobalThis() const;
14957cd0
A
204
205 void seal(JSGlobalData&);
206 void freeze(JSGlobalData&);
6fe7ccc8
A
207 JS_EXPORT_PRIVATE void preventExtensions(JSGlobalData&);
208 bool isSealed(JSGlobalData& globalData) { return structure()->isSealed(globalData); }
209 bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); }
210 bool isExtensible() { return structure()->isExtensible(); }
9dae56ea 211
6fe7ccc8
A
212 bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
213 void reifyStaticFunctionsForDelete(ExecState* exec);
4e4e5a6f 214
6fe7ccc8
A
215 JS_EXPORT_PRIVATE PropertyStorage growPropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
216 bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); }
217 void setPropertyStorage(JSGlobalData&, PropertyStorage, Structure*);
218
219 void* addressOfPropertyStorage()
220 {
221 return &m_propertyStorage;
222 }
9dae56ea 223
14957cd0 224 static const unsigned baseExternalStorageCapacity = 16;
9dae56ea 225
14957cd0 226 void flattenDictionaryObject(JSGlobalData& globalData)
9dae56ea 227 {
6fe7ccc8 228 structure()->flattenDictionaryStructure(globalData, this);
9dae56ea
A
229 }
230
6fe7ccc8 231 JSGlobalObject* globalObject() const
14957cd0 232 {
6fe7ccc8
A
233 ASSERT(structure()->globalObject());
234 ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this);
235 return structure()->globalObject();
14957cd0 236 }
14957cd0 237
6fe7ccc8
A
238 static size_t offsetOfInlineStorage();
239 static size_t offsetOfPropertyStorage();
240 static size_t offsetOfInheritorID();
241
14957cd0
A
242 static JS_EXPORTDATA const ClassInfo s_info;
243
f9bf01c6 244 protected:
6fe7ccc8 245 void finishCreation(JSGlobalData& globalData, PropertyStorage inlineStorage)
14957cd0 246 {
6fe7ccc8
A
247 Base::finishCreation(globalData);
248 ASSERT(inherits(&s_info));
249 ASSERT(structure()->propertyStorageCapacity() < baseExternalStorageCapacity);
250 ASSERT(structure()->isEmpty());
251 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
252 ASSERT_UNUSED(inlineStorage, static_cast<void*>(inlineStorage) == static_cast<void*>(this + 1));
253 ASSERT(structure()->isObject());
254 ASSERT(classInfo());
14957cd0
A
255 }
256
6fe7ccc8 257 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
f9bf01c6 258 {
6fe7ccc8 259 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
f9bf01c6 260 }
14957cd0 261
6fe7ccc8
A
262 static const unsigned StructureFlags = 0;
263
14957cd0
A
264 // To instantiate objects you likely want JSFinalObject, below.
265 // To create derived types you likely want JSNonFinalObject, below.
266 JSObject(JSGlobalData&, Structure*, PropertyStorage inlineStorage);
6fe7ccc8
A
267
268 void resetInheritorID()
f9bf01c6 269 {
6fe7ccc8 270 m_inheritorID.clear();
f9bf01c6
A
271 }
272
9dae56ea 273 private:
6fe7ccc8
A
274 friend class LLIntOffsetsExtractor;
275
f9bf01c6
A
276 // Nobody should ever ask any of these questions on something already known to be a JSObject.
277 using JSCell::isAPIValueWrapper;
278 using JSCell::isGetterSetter;
f9bf01c6
A
279 void getObject();
280 void getString(ExecState* exec);
281 void isObject();
282 void isString();
14957cd0 283
6fe7ccc8
A
284 ConstPropertyStorage propertyStorage() const { return m_propertyStorage.get(); }
285 PropertyStorage propertyStorage() { return m_propertyStorage.get(); }
ba379fdc 286
14957cd0 287 const WriteBarrierBase<Unknown>* locationForOffset(size_t offset) const
ba379fdc 288 {
14957cd0 289 return &propertyStorage()[offset];
ba379fdc
A
290 }
291
14957cd0 292 WriteBarrierBase<Unknown>* locationForOffset(size_t offset)
ba379fdc 293 {
14957cd0 294 return &propertyStorage()[offset];
ba379fdc
A
295 }
296
6fe7ccc8
A
297 template<PutMode>
298 bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*);
ba379fdc 299
9dae56ea 300 bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
6fe7ccc8 301 JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
9dae56ea
A
302
303 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
14957cd0 304 Structure* createInheritorID(JSGlobalData&);
9dae56ea 305
6fe7ccc8 306 StorageBarrier m_propertyStorage;
14957cd0 307 WriteBarrier<Structure> m_inheritorID;
9dae56ea 308 };
14957cd0
A
309
310
311#if USE(JSVALUE32_64)
312#define JSNonFinalObject_inlineStorageCapacity 4
313#define JSFinalObject_inlineStorageCapacity 6
314#else
315#define JSNonFinalObject_inlineStorageCapacity 2
316#define JSFinalObject_inlineStorageCapacity 4
317#endif
318
319COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final);
320
321 // JSNonFinalObject is a type of JSObject that has some internal storage,
322 // but also preserves some space in the collector cell for additional
323 // data members in derived types.
324 class JSNonFinalObject : public JSObject {
325 friend class JSObject;
326
327 public:
6fe7ccc8
A
328 typedef JSObject Base;
329
330 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
14957cd0 331 {
6fe7ccc8 332 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
14957cd0
A
333 }
334
335 protected:
14957cd0
A
336 explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
337 : JSObject(globalData, structure, m_inlineStorage)
338 {
6fe7ccc8
A
339 }
340
341 void finishCreation(JSGlobalData& globalData)
342 {
343 Base::finishCreation(globalData, m_inlineStorage);
14957cd0
A
344 ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double)));
345 ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity);
6fe7ccc8 346 ASSERT(classInfo());
14957cd0
A
347 }
348
349 private:
350 WriteBarrier<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
351 };
352
6fe7ccc8
A
353 class JSFinalObject;
354
14957cd0
A
355 // JSFinalObject is a type of JSObject that contains sufficent internal
356 // storage to fully make use of the colloctor cell containing it.
357 class JSFinalObject : public JSObject {
358 friend class JSObject;
359
360 public:
6fe7ccc8
A
361 typedef JSObject Base;
362
363 static JSFinalObject* create(ExecState*, Structure*);
364 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
14957cd0 365 {
6fe7ccc8 366 return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info);
14957cd0
A
367 }
368
6fe7ccc8
A
369 static JS_EXPORTDATA const ClassInfo s_info;
370
371 protected:
372 void finishCreation(JSGlobalData& globalData)
14957cd0 373 {
6fe7ccc8
A
374 Base::finishCreation(globalData, m_inlineStorage);
375 ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double)));
376 ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
377 ASSERT(classInfo());
14957cd0
A
378 }
379
380 private:
6fe7ccc8
A
381 friend class LLIntOffsetsExtractor;
382
14957cd0
A
383 explicit JSFinalObject(JSGlobalData& globalData, Structure* structure)
384 : JSObject(globalData, structure, m_inlineStorage)
385 {
14957cd0
A
386 }
387
6fe7ccc8 388 static const unsigned StructureFlags = JSObject::StructureFlags;
14957cd0
A
389
390 WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
391 };
392
6fe7ccc8
A
393inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure)
394{
395 JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure);
396 finalObject->finishCreation(exec->globalData());
397 return finalObject;
398}
399
400inline bool isJSFinalObject(JSCell* cell)
401{
402 return cell->classInfo() == &JSFinalObject::s_info;
403}
404
405inline bool isJSFinalObject(JSValue value)
406{
407 return value.isCell() && isJSFinalObject(value.asCell());
408}
409
14957cd0
A
410inline size_t JSObject::offsetOfInlineStorage()
411{
412 ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
413 return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
414}
415
6fe7ccc8
A
416inline size_t JSObject::offsetOfPropertyStorage()
417{
418 return OBJECT_OFFSETOF(JSObject, m_propertyStorage);
419}
420
421inline size_t JSObject::offsetOfInheritorID()
422{
423 return OBJECT_OFFSETOF(JSObject, m_inheritorID);
424}
425
426inline bool JSObject::isGlobalObject() const
427{
428 return structure()->typeInfo().type() == GlobalObjectType;
429}
430
431inline bool JSObject::isVariableObject() const
432{
433 return structure()->typeInfo().type() >= VariableObjectType;
434}
435
436inline bool JSObject::isStaticScopeObject() const
437{
438 return structure()->typeInfo().type() == StaticScopeObjectType;
439}
440
441inline bool JSObject::isActivationObject() const
442{
443 return structure()->typeInfo().type() == ActivationObjectType;
444}
445
446inline bool JSObject::isErrorInstance() const
447{
448 return structure()->typeInfo().type() == ErrorInstanceType;
449}
450
451inline bool JSObject::isGlobalThis() const
452{
453 return structure()->typeInfo().type() == GlobalThisType;
454}
455
456inline void JSObject::setPropertyStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure)
457{
458 ASSERT(storage);
459 ASSERT(structure);
460 setStructure(globalData, structure);
461 m_propertyStorage.set(globalData, this, storage);
462}
463
14957cd0
A
464inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
465{
466 return JSFinalObject::create(exec, structure);
467}
468
6fe7ccc8
A
469inline CallType getCallData(JSValue value, CallData& callData)
470{
471 CallType result = value.isCell() ? value.asCell()->methodTable()->getCallData(value.asCell(), callData) : CallTypeNone;
472 ASSERT(result == CallTypeNone || value.isValidCallee());
473 return result;
474}
475
476inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
14957cd0 477{
6fe7ccc8
A
478 ConstructType result = value.isCell() ? value.asCell()->methodTable()->getConstructData(value.asCell(), constructData) : ConstructTypeNone;
479 ASSERT(result == ConstructTypeNone || value.isValidCallee());
480 return result;
481}
482
483inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
484{
485 return JSFinalObject::createStructure(globalData, globalObject, prototype);
14957cd0
A
486}
487
f9bf01c6
A
488inline JSObject* asObject(JSCell* cell)
489{
490 ASSERT(cell->isObject());
6fe7ccc8 491 return jsCast<JSObject*>(cell);
f9bf01c6 492}
9dae56ea 493
ba379fdc 494inline JSObject* asObject(JSValue value)
9dae56ea 495{
f9bf01c6 496 return asObject(value.asCell());
9dae56ea
A
497}
498
14957cd0
A
499inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, PropertyStorage inlineStorage)
500 : JSCell(globalData, structure)
6fe7ccc8 501 , m_propertyStorage(globalData, this, inlineStorage)
9dae56ea 502{
9dae56ea
A
503}
504
ba379fdc 505inline JSValue JSObject::prototype() const
9dae56ea 506{
6fe7ccc8 507 return structure()->storedPrototype();
14957cd0
A
508}
509
510inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
9dae56ea
A
511{
512 ASSERT(prototype);
6fe7ccc8 513 setStructure(globalData, Structure::changePrototypeTransition(globalData, structure(), prototype));
9dae56ea
A
514}
515
14957cd0 516inline Structure* JSObject::inheritorID(JSGlobalData& globalData)
9dae56ea 517{
14957cd0
A
518 if (m_inheritorID) {
519 ASSERT(m_inheritorID->isEmpty());
9dae56ea 520 return m_inheritorID.get();
14957cd0
A
521 }
522 return createInheritorID(globalData);
9dae56ea
A
523}
524
ba379fdc
A
525inline bool Structure::isUsingInlineStorage() const
526{
14957cd0 527 return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
ba379fdc
A
528}
529
f9bf01c6 530inline bool JSCell::inherits(const ClassInfo* info) const
9dae56ea 531{
6fe7ccc8
A
532 return classInfo()->isSubClassOf(info);
533}
534
535inline const MethodTable* JSCell::methodTable() const
536{
537 return &classInfo()->methodTable;
9dae56ea
A
538}
539
f9bf01c6
A
540// this method is here to be after the inline declaration of JSCell::inherits
541inline bool JSValue::inherits(const ClassInfo* classInfo) const
9dae56ea 542{
f9bf01c6 543 return isCell() && asCell()->inherits(classInfo);
9dae56ea
A
544}
545
6fe7ccc8
A
546inline JSObject* JSValue::toThisObject(ExecState* exec) const
547{
548 return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec) : toThisObjectSlowCase(exec);
549}
550
9dae56ea
A
551ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
552{
14957cd0 553 if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
6fe7ccc8 554 if (structure()->hasGetterSetterProperties() && location->isGetterSetter())
9dae56ea
A
555 fillGetterPropertySlot(slot, location);
556 else
14957cd0 557 slot.setValue(this, location->get(), offsetForLocation(location));
9dae56ea
A
558 return true;
559 }
560
9dae56ea
A
561 return false;
562}
563
9dae56ea
A
564// It may seem crazy to inline a function this large, especially a virtual function,
565// but it makes a big difference to property lookup that derived classes can inline their
566// base class call to this.
6fe7ccc8 567ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
9dae56ea 568{
6fe7ccc8 569 return jsCast<JSObject*>(cell)->inlineGetOwnPropertySlot(exec, propertyName, slot);
9dae56ea
A
570}
571
572ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
573{
f9bf01c6 574 if (!structure()->typeInfo().overridesGetOwnPropertySlot())
9dae56ea 575 return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
6fe7ccc8
A
576 return methodTable()->getOwnPropertySlot(this, exec, propertyName, slot);
577}
578
579// Fast call to get a property where we may not yet have converted the string to an
580// identifier. The first time we perform a property access with a given string, try
581// performing the property map lookup without forming an identifier. We detect this
582// case by checking whether the hash has yet been set for this string.
583ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const UString& name)
584{
585 if (!structure()->typeInfo().overridesGetOwnPropertySlot() && !structure()->hasGetterSetterProperties()) {
586 size_t offset = name.impl()->hasHash()
587 ? structure()->get(exec->globalData(), Identifier(exec, name))
588 : structure()->get(exec->globalData(), name);
589 if (offset != WTF::notFound)
590 return asObject(this)->locationForOffset(offset)->get();
591 }
592 return JSValue();
9dae56ea
A
593}
594
595// It may seem crazy to inline a function this large but it makes a big difference
596// since this is function very hot in variable lookup
f9bf01c6 597ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
9dae56ea
A
598{
599 JSObject* object = this;
600 while (true) {
601 if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
602 return true;
ba379fdc 603 JSValue prototype = object->prototype();
9dae56ea
A
604 if (!prototype.isObject())
605 return false;
606 object = asObject(prototype);
607 }
608}
609
f9bf01c6 610ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
9dae56ea
A
611{
612 JSObject* object = this;
613 while (true) {
6fe7ccc8 614 if (object->methodTable()->getOwnPropertySlotByIndex(object, exec, propertyName, slot))
9dae56ea 615 return true;
ba379fdc 616 JSValue prototype = object->prototype();
9dae56ea
A
617 if (!prototype.isObject())
618 return false;
619 object = asObject(prototype);
620 }
621}
622
ba379fdc 623inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const
9dae56ea
A
624{
625 PropertySlot slot(this);
626 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
627 return slot.getValue(exec, propertyName);
628
629 return jsUndefined();
630}
631
ba379fdc 632inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
9dae56ea
A
633{
634 PropertySlot slot(this);
635 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
636 return slot.getValue(exec, propertyName);
637
638 return jsUndefined();
639}
640
6fe7ccc8
A
641template<JSObject::PutMode mode>
642inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction)
9dae56ea 643{
ba379fdc 644 ASSERT(value);
6fe7ccc8 645 ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
9dae56ea
A
646 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
647
6fe7ccc8 648 if (structure()->isDictionary()) {
9dae56ea 649 unsigned currentAttributes;
ba379fdc 650 JSCell* currentSpecificFunction;
6fe7ccc8 651 size_t offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
9dae56ea 652 if (offset != WTF::notFound) {
4e4e5a6f
A
653 // If there is currently a specific function, and there now either isn't,
654 // or the new value is different, then despecify.
ba379fdc 655 if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
6fe7ccc8
A
656 structure()->despecifyDictionaryFunction(globalData, propertyName);
657 if ((mode == PutModePut) && currentAttributes & ReadOnly)
14957cd0
A
658 return false;
659
660 putDirectOffset(globalData, offset, value);
4e4e5a6f
A
661 // At this point, the objects structure only has a specific value set if previously there
662 // had been one set, and if the new value being specified is the same (otherwise we would
663 // have despecified, above). So, if currentSpecificFunction is not set, or if the new
664 // value is different (or there is no new value), then the slot now has no value - and
665 // as such it is cachable.
666 // If there was previously a value, and the new value is the same, then we cannot cache.
667 if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
ba379fdc 668 slot.setExistingProperty(this, offset);
14957cd0 669 return true;
9dae56ea
A
670 }
671
6fe7ccc8 672 if ((mode == PutModePut) && !isExtensible())
14957cd0
A
673 return false;
674
6fe7ccc8
A
675 PropertyStorage newStorage = propertyStorage();
676 if (structure()->shouldGrowPropertyStorage())
677 newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
678 offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
679 setPropertyStorage(globalData, newStorage, structure());
9dae56ea 680
6fe7ccc8 681 ASSERT(offset < structure()->propertyStorageCapacity());
14957cd0 682 putDirectOffset(globalData, offset, value);
ba379fdc
A
683 // See comment on setNewProperty call below.
684 if (!specificFunction)
685 slot.setNewProperty(this, offset);
14957cd0 686 return true;
9dae56ea
A
687 }
688
689 size_t offset;
6fe7ccc8
A
690 size_t currentCapacity = structure()->propertyStorageCapacity();
691 if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
692 PropertyStorage newStorage = propertyStorage();
9dae56ea 693 if (currentCapacity != structure->propertyStorageCapacity())
6fe7ccc8 694 newStorage = growPropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
9dae56ea
A
695
696 ASSERT(offset < structure->propertyStorageCapacity());
6fe7ccc8 697 setPropertyStorage(globalData, newStorage, structure);
14957cd0 698 putDirectOffset(globalData, offset, value);
4e4e5a6f
A
699 // This is a new property; transitions with specific values are not currently cachable,
700 // so leave the slot in an uncachable state.
ba379fdc
A
701 if (!specificFunction)
702 slot.setNewProperty(this, offset);
14957cd0 703 return true;
9dae56ea
A
704 }
705
706 unsigned currentAttributes;
ba379fdc 707 JSCell* currentSpecificFunction;
6fe7ccc8 708 offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
9dae56ea 709 if (offset != WTF::notFound) {
6fe7ccc8 710 if ((mode == PutModePut) && currentAttributes & ReadOnly)
14957cd0 711 return false;
ba379fdc 712
4e4e5a6f
A
713 // There are three possibilities here:
714 // (1) There is an existing specific value set, and we're overwriting with *the same value*.
715 // * Do nothing - no need to despecify, but that means we can't cache (a cached
716 // put could write a different value). Leave the slot in an uncachable state.
717 // (2) There is a specific value currently set, but we're writing a different value.
718 // * First, we have to despecify. Having done so, this is now a regular slot
719 // with no specific value, so go ahead & cache like normal.
720 // (3) Normal case, there is no specific value set.
721 // * Go ahead & cache like normal.
722 if (currentSpecificFunction) {
723 // case (1) Do the put, then return leaving the slot uncachable.
724 if (specificFunction == currentSpecificFunction) {
14957cd0
A
725 putDirectOffset(globalData, offset, value);
726 return true;
4e4e5a6f
A
727 }
728 // case (2) Despecify, fall through to (3).
6fe7ccc8 729 setStructure(globalData, Structure::despecifyFunctionTransition(globalData, structure(), propertyName));
ba379fdc 730 }
4e4e5a6f
A
731
732 // case (3) set the slot, do the put, return.
9dae56ea 733 slot.setExistingProperty(this, offset);
14957cd0
A
734 putDirectOffset(globalData, offset, value);
735 return true;
9dae56ea
A
736 }
737
6fe7ccc8 738 if ((mode == PutModePut) && !isExtensible())
14957cd0 739 return false;
ba379fdc 740
6fe7ccc8
A
741 PropertyStorage newStorage = propertyStorage();
742 if (structure()->shouldGrowPropertyStorage())
743 newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
ba379fdc 744
6fe7ccc8 745 Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
9dae56ea
A
746
747 ASSERT(offset < structure->propertyStorageCapacity());
6fe7ccc8 748 setPropertyStorage(globalData, newStorage, structure);
14957cd0 749 putDirectOffset(globalData, offset, value);
4e4e5a6f
A
750 // This is a new property; transitions with specific values are not currently cachable,
751 // so leave the slot in an uncachable state.
ba379fdc
A
752 if (!specificFunction)
753 slot.setNewProperty(this, offset);
14957cd0 754 return true;
ba379fdc
A
755}
756
6fe7ccc8 757inline bool JSObject::putOwnDataProperty(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
ba379fdc
A
758{
759 ASSERT(value);
760 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
6fe7ccc8 761 ASSERT(!structure()->hasGetterSetterProperties());
ba379fdc 762
6fe7ccc8 763 return putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value));
ba379fdc
A
764}
765
14957cd0 766inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
ba379fdc 767{
6fe7ccc8 768 ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
ba379fdc 769 PutPropertySlot slot;
6fe7ccc8 770 putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value));
ba379fdc
A
771}
772
6fe7ccc8 773inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
4e4e5a6f 774{
6fe7ccc8
A
775 ASSERT(!value.isGetterSetter());
776 putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, 0, slot, getJSFunction(value));
ba379fdc
A
777}
778
14957cd0 779inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
ba379fdc 780{
6fe7ccc8
A
781 ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
782 PropertyStorage newStorage = propertyStorage();
783 if (structure()->shouldGrowPropertyStorage())
784 newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
785 size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
786 setPropertyStorage(globalData, newStorage, structure());
14957cd0 787 putDirectOffset(globalData, offset, value);
9dae56ea
A
788}
789
14957cd0 790inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
9dae56ea 791{
6fe7ccc8
A
792 PropertyStorage newStorage = propertyStorage();
793 if (structure()->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
794 newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
795 setPropertyStorage(globalData, newStorage, newStructure);
9dae56ea
A
796}
797
ba379fdc 798inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
9dae56ea 799{
6fe7ccc8 800 return methodTable()->defaultValue(this, exec, preferredType);
9dae56ea
A
801}
802
ba379fdc 803inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
9dae56ea
A
804{
805 PropertySlot slot(asValue());
806 return get(exec, propertyName, slot);
807}
808
ba379fdc 809inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
9dae56ea
A
810{
811 if (UNLIKELY(!isCell())) {
ba379fdc 812 JSObject* prototype = synthesizePrototype(exec);
9dae56ea
A
813 if (!prototype->getPropertySlot(exec, propertyName, slot))
814 return jsUndefined();
815 return slot.getValue(exec, propertyName);
816 }
817 JSCell* cell = asCell();
818 while (true) {
819 if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
820 return slot.getValue(exec, propertyName);
f9bf01c6 821 JSValue prototype = asObject(cell)->prototype();
9dae56ea
A
822 if (!prototype.isObject())
823 return jsUndefined();
824 cell = asObject(prototype);
825 }
826}
827
ba379fdc 828inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
9dae56ea
A
829{
830 PropertySlot slot(asValue());
831 return get(exec, propertyName, slot);
832}
833
ba379fdc 834inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
9dae56ea
A
835{
836 if (UNLIKELY(!isCell())) {
ba379fdc 837 JSObject* prototype = synthesizePrototype(exec);
9dae56ea
A
838 if (!prototype->getPropertySlot(exec, propertyName, slot))
839 return jsUndefined();
840 return slot.getValue(exec, propertyName);
841 }
842 JSCell* cell = const_cast<JSCell*>(asCell());
843 while (true) {
6fe7ccc8 844 if (cell->methodTable()->getOwnPropertySlotByIndex(cell, exec, propertyName, slot))
9dae56ea 845 return slot.getValue(exec, propertyName);
f9bf01c6 846 JSValue prototype = asObject(cell)->prototype();
9dae56ea
A
847 if (!prototype.isObject())
848 return jsUndefined();
849 cell = prototype.asCell();
850 }
851}
852
ba379fdc 853inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
9dae56ea
A
854{
855 if (UNLIKELY(!isCell())) {
6fe7ccc8 856 putToPrimitive(exec, propertyName, value, slot);
9dae56ea
A
857 return;
858 }
6fe7ccc8 859 asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot);
4e4e5a6f
A
860}
861
6fe7ccc8 862inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
9dae56ea
A
863{
864 if (UNLIKELY(!isCell())) {
6fe7ccc8
A
865 PutPropertySlot slot(shouldThrow);
866 putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
9dae56ea
A
867 return;
868 }
6fe7ccc8 869 asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
f9bf01c6
A
870}
871
4e4e5a6f
A
872// --- JSValue inlines ----------------------------
873
14957cd0
A
874ALWAYS_INLINE JSObject* Register::function() const
875{
876 if (!jsValue())
877 return 0;
878 return asObject(jsValue());
879}
880
881ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
882{
883 Register r;
884 r = JSValue(callee);
885 return r;
886}
887
9dae56ea
A
888} // namespace JSC
889
890#endif // JSObject_h