]>
Commit | Line | Data |
---|---|---|
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 | |
40 | namespace 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 | ||
319 | COMPILE_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 |
393 | inline 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 | ||
400 | inline bool isJSFinalObject(JSCell* cell) | |
401 | { | |
402 | return cell->classInfo() == &JSFinalObject::s_info; | |
403 | } | |
404 | ||
405 | inline bool isJSFinalObject(JSValue value) | |
406 | { | |
407 | return value.isCell() && isJSFinalObject(value.asCell()); | |
408 | } | |
409 | ||
14957cd0 A |
410 | inline 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 |
416 | inline size_t JSObject::offsetOfPropertyStorage() |
417 | { | |
418 | return OBJECT_OFFSETOF(JSObject, m_propertyStorage); | |
419 | } | |
420 | ||
421 | inline size_t JSObject::offsetOfInheritorID() | |
422 | { | |
423 | return OBJECT_OFFSETOF(JSObject, m_inheritorID); | |
424 | } | |
425 | ||
426 | inline bool JSObject::isGlobalObject() const | |
427 | { | |
428 | return structure()->typeInfo().type() == GlobalObjectType; | |
429 | } | |
430 | ||
431 | inline bool JSObject::isVariableObject() const | |
432 | { | |
433 | return structure()->typeInfo().type() >= VariableObjectType; | |
434 | } | |
435 | ||
436 | inline bool JSObject::isStaticScopeObject() const | |
437 | { | |
438 | return structure()->typeInfo().type() == StaticScopeObjectType; | |
439 | } | |
440 | ||
441 | inline bool JSObject::isActivationObject() const | |
442 | { | |
443 | return structure()->typeInfo().type() == ActivationObjectType; | |
444 | } | |
445 | ||
446 | inline bool JSObject::isErrorInstance() const | |
447 | { | |
448 | return structure()->typeInfo().type() == ErrorInstanceType; | |
449 | } | |
450 | ||
451 | inline bool JSObject::isGlobalThis() const | |
452 | { | |
453 | return structure()->typeInfo().type() == GlobalThisType; | |
454 | } | |
455 | ||
456 | inline 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 |
464 | inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure) |
465 | { | |
466 | return JSFinalObject::create(exec, structure); | |
467 | } | |
468 | ||
6fe7ccc8 A |
469 | inline 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 | ||
476 | inline 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 | ||
483 | inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) | |
484 | { | |
485 | return JSFinalObject::createStructure(globalData, globalObject, prototype); | |
14957cd0 A |
486 | } |
487 | ||
f9bf01c6 A |
488 | inline JSObject* asObject(JSCell* cell) |
489 | { | |
490 | ASSERT(cell->isObject()); | |
6fe7ccc8 | 491 | return jsCast<JSObject*>(cell); |
f9bf01c6 | 492 | } |
9dae56ea | 493 | |
ba379fdc | 494 | inline JSObject* asObject(JSValue value) |
9dae56ea | 495 | { |
f9bf01c6 | 496 | return asObject(value.asCell()); |
9dae56ea A |
497 | } |
498 | ||
14957cd0 A |
499 | inline 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 | 505 | inline JSValue JSObject::prototype() const |
9dae56ea | 506 | { |
6fe7ccc8 | 507 | return structure()->storedPrototype(); |
14957cd0 A |
508 | } |
509 | ||
510 | inline 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 | 516 | inline 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 |
525 | inline bool Structure::isUsingInlineStorage() const |
526 | { | |
14957cd0 | 527 | return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity; |
ba379fdc A |
528 | } |
529 | ||
f9bf01c6 | 530 | inline bool JSCell::inherits(const ClassInfo* info) const |
9dae56ea | 531 | { |
6fe7ccc8 A |
532 | return classInfo()->isSubClassOf(info); |
533 | } | |
534 | ||
535 | inline 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 |
541 | inline bool JSValue::inherits(const ClassInfo* classInfo) const | |
9dae56ea | 542 | { |
f9bf01c6 | 543 | return isCell() && asCell()->inherits(classInfo); |
9dae56ea A |
544 | } |
545 | ||
6fe7ccc8 A |
546 | inline JSObject* JSValue::toThisObject(ExecState* exec) const |
547 | { | |
548 | return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec) : toThisObjectSlowCase(exec); | |
549 | } | |
550 | ||
9dae56ea A |
551 | ALWAYS_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 | 567 | ALWAYS_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 | ||
572 | ALWAYS_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. | |
583 | ALWAYS_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 | 597 | ALWAYS_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 | 610 | ALWAYS_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 | 623 | inline 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 | 632 | inline 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 |
641 | template<JSObject::PutMode mode> |
642 | inline 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 | 757 | inline 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 | 766 | inline 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 | 773 | inline 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 | 779 | inline 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 | 790 | inline 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 | 798 | inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const |
9dae56ea | 799 | { |
6fe7ccc8 | 800 | return methodTable()->defaultValue(this, exec, preferredType); |
9dae56ea A |
801 | } |
802 | ||
ba379fdc | 803 | inline 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 | 809 | inline 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 | 828 | inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const |
9dae56ea A |
829 | { |
830 | PropertySlot slot(asValue()); | |
831 | return get(exec, propertyName, slot); | |
832 | } | |
833 | ||
ba379fdc | 834 | inline 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 | 853 | inline 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 | 862 | inline 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 |
874 | ALWAYS_INLINE JSObject* Register::function() const |
875 | { | |
876 | if (!jsValue()) | |
877 | return 0; | |
878 | return asObject(jsValue()); | |
879 | } | |
880 | ||
881 | ALWAYS_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 |