]>
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) | |
4 | * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Library General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Library General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Library General Public License | |
17 | * along with this library; see the file COPYING.LIB. If not, write to | |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
19 | * Boston, MA 02110-1301, USA. | |
20 | * | |
21 | */ | |
22 | ||
23 | #ifndef JSObject_h | |
24 | #define JSObject_h | |
25 | ||
26 | #include "ArgList.h" | |
27 | #include "ClassInfo.h" | |
28 | #include "CommonIdentifiers.h" | |
29 | #include "CallFrame.h" | |
30 | #include "JSNumberCell.h" | |
31 | #include "PropertySlot.h" | |
32 | #include "PutPropertySlot.h" | |
33 | #include "ScopeChain.h" | |
34 | #include "Structure.h" | |
35 | ||
36 | namespace JSC { | |
37 | ||
38 | class InternalFunction; | |
39 | class PropertyNameArray; | |
40 | class Structure; | |
41 | struct HashEntry; | |
42 | struct HashTable; | |
43 | ||
44 | // ECMA 262-3 8.6.1 | |
45 | // Property attributes | |
46 | enum Attribute { | |
47 | None = 0, | |
48 | ReadOnly = 1 << 1, // property can be only read, not written | |
49 | DontEnum = 1 << 2, // property doesn't appear in (for .. in ..) | |
50 | DontDelete = 1 << 3, // property can't be deleted | |
51 | Function = 1 << 4, // property is a function - only used by static hashtables | |
52 | }; | |
53 | ||
54 | typedef JSValuePtr* PropertyStorage; | |
55 | ||
56 | class JSObject : public JSCell { | |
57 | friend class BatchedTransitionOptimizer; | |
58 | friend class JIT; | |
59 | friend class JSCell; | |
60 | ||
61 | public: | |
62 | explicit JSObject(PassRefPtr<Structure>); | |
63 | ||
64 | virtual void mark(); | |
65 | ||
66 | // The inline virtual destructor cannot be the first virtual function declared | |
67 | // in the class as it results in the vtable being generated as a weak symbol | |
68 | virtual ~JSObject(); | |
69 | ||
70 | bool inherits(const ClassInfo* classInfo) const { return JSCell::isObject(classInfo); } | |
71 | ||
72 | JSValuePtr prototype() const; | |
73 | void setPrototype(JSValuePtr prototype); | |
74 | ||
75 | void setStructure(PassRefPtr<Structure>); | |
76 | Structure* inheritorID(); | |
77 | ||
78 | PropertyStorage& propertyStorage() { return m_propertyStorage; } | |
79 | ||
80 | virtual UString className() const; | |
81 | ||
82 | JSValuePtr get(ExecState*, const Identifier& propertyName) const; | |
83 | JSValuePtr get(ExecState*, unsigned propertyName) const; | |
84 | ||
85 | bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | |
86 | bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); | |
87 | ||
88 | virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | |
89 | virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); | |
90 | ||
91 | virtual void put(ExecState*, const Identifier& propertyName, JSValuePtr value, PutPropertySlot&); | |
92 | virtual void put(ExecState*, unsigned propertyName, JSValuePtr value); | |
93 | ||
94 | virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValuePtr value, unsigned attributes); | |
95 | virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValuePtr value, unsigned attributes); | |
96 | ||
97 | bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const; | |
98 | ||
99 | bool hasProperty(ExecState*, const Identifier& propertyName) const; | |
100 | bool hasProperty(ExecState*, unsigned propertyName) const; | |
101 | bool hasOwnProperty(ExecState*, const Identifier& propertyName) const; | |
102 | ||
103 | virtual bool deleteProperty(ExecState*, const Identifier& propertyName); | |
104 | virtual bool deleteProperty(ExecState*, unsigned propertyName); | |
105 | ||
106 | virtual JSValuePtr defaultValue(ExecState*, PreferredPrimitiveType) const; | |
107 | ||
108 | virtual bool hasInstance(ExecState*, JSValuePtr, JSValuePtr prototypeProperty); | |
109 | ||
110 | virtual void getPropertyNames(ExecState*, PropertyNameArray&); | |
111 | ||
112 | virtual JSValuePtr toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; | |
113 | virtual bool getPrimitiveNumber(ExecState*, double& number, JSValuePtr& value); | |
114 | virtual bool toBoolean(ExecState*) const; | |
115 | virtual double toNumber(ExecState*) const; | |
116 | virtual UString toString(ExecState*) const; | |
117 | virtual JSObject* toObject(ExecState*) const; | |
118 | ||
119 | virtual JSObject* toThisObject(ExecState*) const; | |
120 | virtual JSObject* unwrappedObject(); | |
121 | ||
122 | virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; | |
123 | ||
124 | // This get function only looks at the property map. | |
125 | JSValuePtr getDirect(const Identifier& propertyName) const | |
126 | { | |
127 | size_t offset = m_structure->get(propertyName); | |
128 | return offset != WTF::notFound ? m_propertyStorage[offset] : noValue(); | |
129 | } | |
130 | ||
131 | JSValuePtr* getDirectLocation(const Identifier& propertyName) | |
132 | { | |
133 | size_t offset = m_structure->get(propertyName); | |
134 | return offset != WTF::notFound ? locationForOffset(offset) : 0; | |
135 | } | |
136 | ||
137 | JSValuePtr* getDirectLocation(const Identifier& propertyName, unsigned& attributes) | |
138 | { | |
139 | size_t offset = m_structure->get(propertyName, attributes); | |
140 | return offset != WTF::notFound ? locationForOffset(offset) : 0; | |
141 | } | |
142 | ||
143 | size_t offsetForLocation(JSValuePtr* location) | |
144 | { | |
145 | return location - m_propertyStorage; | |
146 | } | |
147 | ||
148 | JSValuePtr* locationForOffset(size_t offset) | |
149 | { | |
150 | return &m_propertyStorage[offset]; | |
151 | } | |
152 | ||
153 | void transitionTo(Structure*); | |
154 | ||
155 | void removeDirect(const Identifier& propertyName); | |
156 | bool hasCustomProperties() { return !m_structure->isEmpty(); } | |
157 | bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); } | |
158 | ||
159 | void putDirect(const Identifier& propertyName, JSValuePtr value, unsigned attr = 0); | |
160 | void putDirect(const Identifier& propertyName, JSValuePtr value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); | |
161 | void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0); | |
162 | void putDirectWithoutTransition(const Identifier& propertyName, JSValuePtr value, unsigned attr = 0); | |
163 | void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0); | |
164 | ||
165 | // Fast access to known property offsets. | |
166 | JSValuePtr getDirectOffset(size_t offset) { return m_propertyStorage[offset]; } | |
167 | void putDirectOffset(size_t offset, JSValuePtr value) { m_propertyStorage[offset] = value; } | |
168 | ||
169 | void fillGetterPropertySlot(PropertySlot&, JSValuePtr* location); | |
170 | ||
171 | virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction); | |
172 | virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction); | |
173 | virtual JSValuePtr lookupGetter(ExecState*, const Identifier& propertyName); | |
174 | virtual JSValuePtr lookupSetter(ExecState*, const Identifier& propertyName); | |
175 | ||
176 | virtual bool isGlobalObject() const { return false; } | |
177 | virtual bool isVariableObject() const { return false; } | |
178 | virtual bool isActivationObject() const { return false; } | |
179 | virtual bool isWatchdogException() const { return false; } | |
180 | virtual bool isNotAnObjectErrorStub() const { return false; } | |
181 | ||
182 | void allocatePropertyStorage(size_t oldSize, size_t newSize); | |
183 | void allocatePropertyStorageInline(size_t oldSize, size_t newSize); | |
184 | bool usingInlineStorage() const { return m_propertyStorage == m_inlineStorage; } | |
185 | ||
186 | static const size_t inlineStorageCapacity = 2; | |
187 | static const size_t nonInlineBaseStorageCapacity = 16; | |
188 | ||
189 | static PassRefPtr<Structure> createStructure(JSValuePtr prototype) | |
190 | { | |
191 | return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); | |
192 | } | |
193 | ||
194 | protected: | |
195 | bool getOwnPropertySlotForWrite(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable); | |
196 | ||
197 | private: | |
198 | bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | |
199 | ||
200 | const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const; | |
201 | Structure* createInheritorID(); | |
202 | ||
203 | RefPtr<Structure> m_inheritorID; | |
204 | ||
205 | PropertyStorage m_propertyStorage; | |
206 | JSValuePtr m_inlineStorage[inlineStorageCapacity]; | |
207 | }; | |
208 | ||
209 | JSObject* asObject(JSValuePtr); | |
210 | ||
211 | JSObject* constructEmptyObject(ExecState*); | |
212 | ||
213 | inline JSObject* asObject(JSValuePtr value) | |
214 | { | |
215 | ASSERT(asCell(value)->isObject()); | |
216 | return static_cast<JSObject*>(asCell(value)); | |
217 | } | |
218 | ||
219 | inline JSObject::JSObject(PassRefPtr<Structure> structure) | |
220 | : JSCell(structure.releaseRef()) // ~JSObject balances this ref() | |
221 | , m_propertyStorage(m_inlineStorage) | |
222 | { | |
223 | ASSERT(m_structure); | |
224 | ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity); | |
225 | ASSERT(m_structure->isEmpty()); | |
226 | ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); | |
227 | } | |
228 | ||
229 | inline JSObject::~JSObject() | |
230 | { | |
231 | ASSERT(m_structure); | |
232 | if (m_propertyStorage != m_inlineStorage) | |
233 | delete [] m_propertyStorage; | |
234 | m_structure->deref(); | |
235 | } | |
236 | ||
237 | inline JSValuePtr JSObject::prototype() const | |
238 | { | |
239 | return m_structure->storedPrototype(); | |
240 | } | |
241 | ||
242 | inline void JSObject::setPrototype(JSValuePtr prototype) | |
243 | { | |
244 | ASSERT(prototype); | |
245 | RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype); | |
246 | setStructure(newStructure.release()); | |
247 | } | |
248 | ||
249 | inline void JSObject::setStructure(PassRefPtr<Structure> structure) | |
250 | { | |
251 | m_structure->deref(); | |
252 | m_structure = structure.releaseRef(); // ~JSObject balances this ref() | |
253 | } | |
254 | ||
255 | inline Structure* JSObject::inheritorID() | |
256 | { | |
257 | if (m_inheritorID) | |
258 | return m_inheritorID.get(); | |
259 | return createInheritorID(); | |
260 | } | |
261 | ||
262 | inline bool JSCell::isObject(const ClassInfo* info) const | |
263 | { | |
264 | for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) { | |
265 | if (ci == info) | |
266 | return true; | |
267 | } | |
268 | return false; | |
269 | } | |
270 | ||
271 | // this method is here to be after the inline declaration of JSCell::isObject | |
272 | inline bool JSValuePtr::isObject(const ClassInfo* classInfo) const | |
273 | { | |
274 | return isCell() && asCell()->isObject(classInfo); | |
275 | } | |
276 | ||
277 | ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
278 | { | |
279 | if (JSValuePtr* location = getDirectLocation(propertyName)) { | |
280 | if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter()) | |
281 | fillGetterPropertySlot(slot, location); | |
282 | else | |
283 | slot.setValueSlot(this, location, offsetForLocation(location)); | |
284 | return true; | |
285 | } | |
286 | ||
287 | // non-standard Netscape extension | |
288 | if (propertyName == exec->propertyNames().underscoreProto) { | |
289 | slot.setValue(prototype()); | |
290 | return true; | |
291 | } | |
292 | ||
293 | return false; | |
294 | } | |
295 | ||
296 | ALWAYS_INLINE bool JSObject::getOwnPropertySlotForWrite(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable) | |
297 | { | |
298 | unsigned attributes; | |
299 | if (JSValuePtr* location = getDirectLocation(propertyName, attributes)) { | |
300 | if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter()) { | |
301 | slotIsWriteable = false; | |
302 | fillGetterPropertySlot(slot, location); | |
303 | } else { | |
304 | slotIsWriteable = !(attributes & ReadOnly); | |
305 | slot.setValueSlot(this, location, offsetForLocation(location)); | |
306 | } | |
307 | return true; | |
308 | } | |
309 | ||
310 | // non-standard Netscape extension | |
311 | if (propertyName == exec->propertyNames().underscoreProto) { | |
312 | slot.setValue(prototype()); | |
313 | slotIsWriteable = false; | |
314 | return true; | |
315 | } | |
316 | ||
317 | return false; | |
318 | } | |
319 | ||
320 | // It may seem crazy to inline a function this large, especially a virtual function, | |
321 | // but it makes a big difference to property lookup that derived classes can inline their | |
322 | // base class call to this. | |
323 | ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
324 | { | |
325 | return inlineGetOwnPropertySlot(exec, propertyName, slot); | |
326 | } | |
327 | ||
328 | ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
329 | { | |
330 | if (structure()->typeInfo().hasStandardGetOwnPropertySlot()) | |
331 | return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot); | |
332 | return getOwnPropertySlot(exec, propertyName, slot); | |
333 | } | |
334 | ||
335 | // It may seem crazy to inline a function this large but it makes a big difference | |
336 | // since this is function very hot in variable lookup | |
337 | inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
338 | { | |
339 | JSObject* object = this; | |
340 | while (true) { | |
341 | if (object->fastGetOwnPropertySlot(exec, propertyName, slot)) | |
342 | return true; | |
343 | JSValuePtr prototype = object->prototype(); | |
344 | if (!prototype.isObject()) | |
345 | return false; | |
346 | object = asObject(prototype); | |
347 | } | |
348 | } | |
349 | ||
350 | inline bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) | |
351 | { | |
352 | JSObject* object = this; | |
353 | while (true) { | |
354 | if (object->getOwnPropertySlot(exec, propertyName, slot)) | |
355 | return true; | |
356 | JSValuePtr prototype = object->prototype(); | |
357 | if (!prototype.isObject()) | |
358 | return false; | |
359 | object = asObject(prototype); | |
360 | } | |
361 | } | |
362 | ||
363 | inline JSValuePtr JSObject::get(ExecState* exec, const Identifier& propertyName) const | |
364 | { | |
365 | PropertySlot slot(this); | |
366 | if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) | |
367 | return slot.getValue(exec, propertyName); | |
368 | ||
369 | return jsUndefined(); | |
370 | } | |
371 | ||
372 | inline JSValuePtr JSObject::get(ExecState* exec, unsigned propertyName) const | |
373 | { | |
374 | PropertySlot slot(this); | |
375 | if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) | |
376 | return slot.getValue(exec, propertyName); | |
377 | ||
378 | return jsUndefined(); | |
379 | } | |
380 | ||
381 | inline void JSObject::putDirect(const Identifier& propertyName, JSValuePtr value, unsigned attr) | |
382 | { | |
383 | PutPropertySlot slot; | |
384 | putDirect(propertyName, value, attr, false, slot); | |
385 | } | |
386 | ||
387 | inline void JSObject::putDirect(const Identifier& propertyName, JSValuePtr value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) | |
388 | { | |
389 | ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); | |
390 | ||
391 | if (m_structure->isDictionary()) { | |
392 | unsigned currentAttributes; | |
393 | size_t offset = m_structure->get(propertyName, currentAttributes); | |
394 | if (offset != WTF::notFound) { | |
395 | if (checkReadOnly && currentAttributes & ReadOnly) | |
396 | return; | |
397 | m_propertyStorage[offset] = value; | |
398 | slot.setExistingProperty(this, offset); | |
399 | return; | |
400 | } | |
401 | ||
402 | size_t currentCapacity = m_structure->propertyStorageCapacity(); | |
403 | offset = m_structure->addPropertyWithoutTransition(propertyName, attributes); | |
404 | if (currentCapacity != m_structure->propertyStorageCapacity()) | |
405 | allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); | |
406 | ||
407 | ASSERT(offset < m_structure->propertyStorageCapacity()); | |
408 | m_propertyStorage[offset] = value; | |
409 | slot.setNewProperty(this, offset); | |
410 | return; | |
411 | } | |
412 | ||
413 | size_t offset; | |
414 | size_t currentCapacity = m_structure->propertyStorageCapacity(); | |
415 | if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, offset)) { | |
416 | if (currentCapacity != structure->propertyStorageCapacity()) | |
417 | allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); | |
418 | ||
419 | ASSERT(offset < structure->propertyStorageCapacity()); | |
420 | m_propertyStorage[offset] = value; | |
421 | slot.setNewProperty(this, offset); | |
422 | slot.setWasTransition(true); | |
423 | setStructure(structure.release()); | |
424 | return; | |
425 | } | |
426 | ||
427 | unsigned currentAttributes; | |
428 | offset = m_structure->get(propertyName, currentAttributes); | |
429 | if (offset != WTF::notFound) { | |
430 | if (checkReadOnly && currentAttributes & ReadOnly) | |
431 | return; | |
432 | m_propertyStorage[offset] = value; | |
433 | slot.setExistingProperty(this, offset); | |
434 | return; | |
435 | } | |
436 | ||
437 | RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, offset); | |
438 | if (currentCapacity != structure->propertyStorageCapacity()) | |
439 | allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); | |
440 | ||
441 | ASSERT(offset < structure->propertyStorageCapacity()); | |
442 | m_propertyStorage[offset] = value; | |
443 | slot.setNewProperty(this, offset); | |
444 | slot.setWasTransition(true); | |
445 | setStructure(structure.release()); | |
446 | } | |
447 | ||
448 | inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValuePtr value, unsigned attributes) | |
449 | { | |
450 | size_t currentCapacity = m_structure->propertyStorageCapacity(); | |
451 | size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes); | |
452 | if (currentCapacity != m_structure->propertyStorageCapacity()) | |
453 | allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); | |
454 | m_propertyStorage[offset] = value; | |
455 | } | |
456 | ||
457 | inline void JSObject::transitionTo(Structure* newStructure) | |
458 | { | |
459 | if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity()) | |
460 | allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity()); | |
461 | setStructure(newStructure); | |
462 | } | |
463 | ||
464 | inline JSValuePtr JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const | |
465 | { | |
466 | return defaultValue(exec, preferredType); | |
467 | } | |
468 | ||
469 | inline JSValuePtr JSValuePtr::get(ExecState* exec, const Identifier& propertyName) const | |
470 | { | |
471 | PropertySlot slot(asValue()); | |
472 | return get(exec, propertyName, slot); | |
473 | } | |
474 | ||
475 | inline JSValuePtr JSValuePtr::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const | |
476 | { | |
477 | if (UNLIKELY(!isCell())) { | |
478 | JSObject* prototype = JSImmediate::prototype(asValue(), exec); | |
479 | if (!prototype->getPropertySlot(exec, propertyName, slot)) | |
480 | return jsUndefined(); | |
481 | return slot.getValue(exec, propertyName); | |
482 | } | |
483 | JSCell* cell = asCell(); | |
484 | while (true) { | |
485 | if (cell->fastGetOwnPropertySlot(exec, propertyName, slot)) | |
486 | return slot.getValue(exec, propertyName); | |
487 | ASSERT(cell->isObject()); | |
488 | JSValuePtr prototype = static_cast<JSObject*>(cell)->prototype(); | |
489 | if (!prototype.isObject()) | |
490 | return jsUndefined(); | |
491 | cell = asObject(prototype); | |
492 | } | |
493 | } | |
494 | ||
495 | inline JSValuePtr JSValuePtr::get(ExecState* exec, unsigned propertyName) const | |
496 | { | |
497 | PropertySlot slot(asValue()); | |
498 | return get(exec, propertyName, slot); | |
499 | } | |
500 | ||
501 | inline JSValuePtr JSValuePtr::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const | |
502 | { | |
503 | if (UNLIKELY(!isCell())) { | |
504 | JSObject* prototype = JSImmediate::prototype(asValue(), exec); | |
505 | if (!prototype->getPropertySlot(exec, propertyName, slot)) | |
506 | return jsUndefined(); | |
507 | return slot.getValue(exec, propertyName); | |
508 | } | |
509 | JSCell* cell = const_cast<JSCell*>(asCell()); | |
510 | while (true) { | |
511 | if (cell->getOwnPropertySlot(exec, propertyName, slot)) | |
512 | return slot.getValue(exec, propertyName); | |
513 | ASSERT(cell->isObject()); | |
514 | JSValuePtr prototype = static_cast<JSObject*>(cell)->prototype(); | |
515 | if (!prototype.isObject()) | |
516 | return jsUndefined(); | |
517 | cell = prototype.asCell(); | |
518 | } | |
519 | } | |
520 | ||
521 | inline void JSValuePtr::put(ExecState* exec, const Identifier& propertyName, JSValuePtr value, PutPropertySlot& slot) | |
522 | { | |
523 | if (UNLIKELY(!isCell())) { | |
524 | JSImmediate::toObject(asValue(), exec)->put(exec, propertyName, value, slot); | |
525 | return; | |
526 | } | |
527 | asCell()->put(exec, propertyName, value, slot); | |
528 | } | |
529 | ||
530 | inline void JSValuePtr::put(ExecState* exec, unsigned propertyName, JSValuePtr value) | |
531 | { | |
532 | if (UNLIKELY(!isCell())) { | |
533 | JSImmediate::toObject(asValue(), exec)->put(exec, propertyName, value); | |
534 | return; | |
535 | } | |
536 | asCell()->put(exec, propertyName, value); | |
537 | } | |
538 | ||
539 | ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize) | |
540 | { | |
541 | ASSERT(newSize > oldSize); | |
542 | ||
543 | JSValuePtr* oldPropertyStorage = m_propertyStorage; | |
544 | m_propertyStorage = new JSValuePtr[newSize]; | |
545 | ||
546 | for (unsigned i = 0; i < oldSize; ++i) | |
547 | m_propertyStorage[i] = oldPropertyStorage[i]; | |
548 | ||
549 | if (oldPropertyStorage != m_inlineStorage) | |
550 | delete [] oldPropertyStorage; | |
551 | } | |
552 | ||
553 | } // namespace JSC | |
554 | ||
555 | #endif // JSObject_h |