source: webkit/trunk/JavaScriptCore/runtime/JSObject.h@ 67583

Last change on this file since 67583 was 64684, checked in by [email protected], 15 years ago

2010-08-04 Sheriff Bot <[email protected]>

Unreviewed, rolling out r64655.
http://trac.webkit.org/changeset/64655
https://bugs.webkit.org/show_bug.cgi?id=43496

JavaScriptCore references patch seems to have caused
regressions in QT and GTK builds (Requested by nlawrence on
#webkit).

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::markAggregate):
  • runtime/Collector.cpp: (JSC::Heap::markConservatively):
  • runtime/JSCell.h: (JSC::JSValue::asCell): (JSC::MarkStack::append):
  • runtime/JSGlobalObject.cpp: (JSC::markIfNeeded):
  • runtime/JSONObject.cpp: (JSC::Stringifier::Holder::object):
  • runtime/JSObject.h: (JSC::JSObject::prototype):
  • runtime/JSStaticScopeObject.cpp: (JSC::JSStaticScopeObject::markChildren):
  • runtime/JSValue.h: (JSC::JSValue::): (JSC::JSValue::JSValue): (JSC::JSValue::asCell):
  • runtime/MarkStack.h:
  • runtime/NativeErrorConstructor.cpp:
  • runtime/NativeErrorConstructor.h:
  • runtime/Structure.h: (JSC::Structure::storedPrototype):

2010-08-04 Sheriff Bot <[email protected]>

Unreviewed, rolling out r64655.
http://trac.webkit.org/changeset/64655
https://bugs.webkit.org/show_bug.cgi?id=43496

JavaScriptCore references patch seems to have caused
regressions in QT and GTK builds (Requested by nlawrence on
#webkit).

  • JSValueWrapper.cpp: (JSValueWrapper::JSObjectMark):
  • Property svn:eol-style set to native
File size: 30.9 KB
Line 
1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 "Completion.h"
30#include "CallFrame.h"
31#include "JSCell.h"
32#include "JSNumberCell.h"
33#include "MarkStack.h"
34#include "PropertySlot.h"
35#include "PutPropertySlot.h"
36#include "ScopeChain.h"
37#include "Structure.h"
38#include "JSGlobalData.h"
39#include "JSString.h"
40#include <wtf/StdLibExtras.h>
41
42namespace JSC {
43
44 inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value)
45 {
46 if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr))
47 return value.asCell();
48 return 0;
49 }
50
51 class HashEntry;
52 class InternalFunction;
53 class PropertyDescriptor;
54 class PropertyNameArray;
55 class Structure;
56 struct HashTable;
57
58 // ECMA 262-3 8.6.1
59 // Property attributes
60 enum Attribute {
61 None = 0,
62 ReadOnly = 1 << 1, // property can be only read, not written
63 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
64 DontDelete = 1 << 3, // property can't be deleted
65 Function = 1 << 4, // property is a function - only used by static hashtables
66 Getter = 1 << 5, // property is a getter
67 Setter = 1 << 6 // property is a setter
68 };
69
70 typedef EncodedJSValue* PropertyStorage;
71 typedef const EncodedJSValue* ConstPropertyStorage;
72
73 class JSObject : public JSCell {
74 friend class BatchedTransitionOptimizer;
75 friend class JIT;
76 friend class JSCell;
77 friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
78
79 public:
80 explicit JSObject(NonNullPassRefPtr<Structure>);
81
82 virtual void markChildren(MarkStack&);
83 ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack);
84
85 // The inline virtual destructor cannot be the first virtual function declared
86 // in the class as it results in the vtable being generated as a weak symbol
87 virtual ~JSObject();
88
89 JSValue prototype() const;
90 void setPrototype(JSValue prototype);
91 bool setPrototypeWithCycleCheck(JSValue prototype);
92
93 void setStructure(NonNullPassRefPtr<Structure>);
94 Structure* inheritorID();
95
96 virtual UString className() const;
97
98 JSValue get(ExecState*, const Identifier& propertyName) const;
99 JSValue get(ExecState*, unsigned propertyName) const;
100
101 bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
102 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
103 bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
104
105 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
106 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
107 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
108
109 virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
110 virtual void put(ExecState*, unsigned propertyName, JSValue value);
111
112 virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
113 virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes);
114 virtual void putWithAttributes(JSGlobalData*, unsigned propertyName, JSValue value, unsigned attributes);
115 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
116 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
117 virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes);
118
119 bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
120
121 bool hasProperty(ExecState*, const Identifier& propertyName) const;
122 bool hasProperty(ExecState*, unsigned propertyName) const;
123 bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
124
125 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
126 virtual bool deleteProperty(ExecState*, unsigned propertyName);
127
128 virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const;
129
130 virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty);
131
132 virtual void getPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
133 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
134
135 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
136 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
137 virtual bool toBoolean(ExecState*) const;
138 virtual double toNumber(ExecState*) const;
139 virtual UString toString(ExecState*) const;
140 virtual JSObject* toObject(ExecState*) const;
141
142 virtual JSObject* toThisObject(ExecState*) const;
143 virtual JSObject* unwrappedObject();
144
145 bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
146
147 // This get function only looks at the property map.
148 JSValue getDirect(const Identifier& propertyName) const
149 {
150 size_t offset = m_structure->get(propertyName);
151 return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
152 }
153
154 JSValue* getDirectLocation(const Identifier& propertyName)
155 {
156 size_t offset = m_structure->get(propertyName);
157 return offset != WTF::notFound ? locationForOffset(offset) : 0;
158 }
159
160 JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
161 {
162 JSCell* specificFunction;
163 size_t offset = m_structure->get(propertyName, attributes, specificFunction);
164 return offset != WTF::notFound ? locationForOffset(offset) : 0;
165 }
166
167 size_t offsetForLocation(JSValue* location) const
168 {
169 return location - reinterpret_cast<const JSValue*>(propertyStorage());
170 }
171
172 void transitionTo(Structure*);
173
174 void removeDirect(const Identifier& propertyName);
175 bool hasCustomProperties() { return !m_structure->isEmpty(); }
176 bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
177
178 void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
179 void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
180 void putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot&);
181
182 void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
183 void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
184 void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
185 void putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr = 0);
186
187 void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
188 void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
189 void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
190 void putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr = 0);
191
192 // Fast access to known property offsets.
193 JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); }
194 void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); }
195
196 void fillGetterPropertySlot(PropertySlot&, JSValue* location);
197
198 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0);
199 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0);
200 virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName);
201 virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName);
202 virtual bool defineOwnProperty(ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
203
204 virtual bool isGlobalObject() const { return false; }
205 virtual bool isVariableObject() const { return false; }
206 virtual bool isActivationObject() const { return false; }
207 virtual bool isNotAnObjectErrorStub() const { return false; }
208
209 virtual ComplType exceptionType() const { return Throw; }
210
211 void allocatePropertyStorage(size_t oldSize, size_t newSize);
212 void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
213 bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
214
215 static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
216 static const unsigned nonInlineBaseStorageCapacity = 16;
217
218 static PassRefPtr<Structure> createStructure(JSValue prototype)
219 {
220 return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
221 }
222
223 void flattenDictionaryObject()
224 {
225 m_structure->flattenDictionaryStructure(this);
226 }
227
228 void putAnonymousValue(unsigned index, JSValue value)
229 {
230 ASSERT(index < m_structure->anonymousSlotCount());
231 *locationForOffset(index) = value;
232 }
233 JSValue getAnonymousValue(unsigned index) const
234 {
235 ASSERT(index < m_structure->anonymousSlotCount());
236 return *locationForOffset(index);
237 }
238
239 protected:
240 static const unsigned StructureFlags = 0;
241
242 private:
243 // Nobody should ever ask any of these questions on something already known to be a JSObject.
244 using JSCell::isAPIValueWrapper;
245 using JSCell::isGetterSetter;
246 using JSCell::toObject;
247 void getObject();
248 void getString(ExecState* exec);
249 void isObject();
250 void isString();
251#if USE(JSVALUE32)
252 void isNumber();
253#endif
254
255 ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
256 PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
257
258 const JSValue* locationForOffset(size_t offset) const
259 {
260 return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]);
261 }
262
263 JSValue* locationForOffset(size_t offset)
264 {
265 return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
266 }
267
268 void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
269 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
270 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
271
272 bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
273
274 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
275 Structure* createInheritorID();
276
277 union {
278 PropertyStorage m_externalStorage;
279 EncodedJSValue m_inlineStorage[inlineStorageCapacity];
280 };
281
282 RefPtr<Structure> m_inheritorID;
283 };
284
285inline JSObject* asObject(JSCell* cell)
286{
287 ASSERT(cell->isObject());
288 return static_cast<JSObject*>(cell);
289}
290
291inline JSObject* asObject(JSValue value)
292{
293 return asObject(value.asCell());
294}
295
296inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure)
297 : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
298{
299 ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
300 ASSERT(m_structure->isEmpty());
301 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
302#if USE(JSVALUE64) || USE(JSVALUE32_64)
303 ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
304#endif
305}
306
307inline JSObject::~JSObject()
308{
309 ASSERT(m_structure);
310 if (!isUsingInlineStorage())
311 delete [] m_externalStorage;
312 m_structure->deref();
313}
314
315inline JSValue JSObject::prototype() const
316{
317 return m_structure->storedPrototype();
318}
319
320inline bool JSObject::setPrototypeWithCycleCheck(JSValue prototype)
321{
322 JSValue nextPrototypeValue = prototype;
323 while (nextPrototypeValue && nextPrototypeValue.isObject()) {
324 JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
325 if (nextPrototype == this)
326 return false;
327 nextPrototypeValue = nextPrototype->prototype();
328 }
329 setPrototype(prototype);
330 return true;
331}
332
333inline void JSObject::setPrototype(JSValue prototype)
334{
335 ASSERT(prototype);
336 RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype);
337 setStructure(newStructure.release());
338}
339
340inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure)
341{
342 m_structure->deref();
343 m_structure = structure.releaseRef(); // ~JSObject balances this ref()
344}
345
346inline Structure* JSObject::inheritorID()
347{
348 if (m_inheritorID)
349 return m_inheritorID.get();
350 return createInheritorID();
351}
352
353inline bool Structure::isUsingInlineStorage() const
354{
355 return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
356}
357
358inline bool JSCell::inherits(const ClassInfo* info) const
359{
360 for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) {
361 if (ci == info)
362 return true;
363 }
364 return false;
365}
366
367// this method is here to be after the inline declaration of JSCell::inherits
368inline bool JSValue::inherits(const ClassInfo* classInfo) const
369{
370 return isCell() && asCell()->inherits(classInfo);
371}
372
373ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
374{
375 if (JSValue* location = getDirectLocation(propertyName)) {
376 if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter())
377 fillGetterPropertySlot(slot, location);
378 else
379 slot.setValueSlot(this, location, offsetForLocation(location));
380 return true;
381 }
382
383 // non-standard Netscape extension
384 if (propertyName == exec->propertyNames().underscoreProto) {
385 slot.setValue(prototype());
386 return true;
387 }
388
389 return false;
390}
391
392// It may seem crazy to inline a function this large, especially a virtual function,
393// but it makes a big difference to property lookup that derived classes can inline their
394// base class call to this.
395ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
396{
397 return inlineGetOwnPropertySlot(exec, propertyName, slot);
398}
399
400ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
401{
402 if (!structure()->typeInfo().overridesGetOwnPropertySlot())
403 return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
404 return getOwnPropertySlot(exec, propertyName, slot);
405}
406
407// It may seem crazy to inline a function this large but it makes a big difference
408// since this is function very hot in variable lookup
409ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
410{
411 JSObject* object = this;
412 while (true) {
413 if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
414 return true;
415 JSValue prototype = object->prototype();
416 if (!prototype.isObject())
417 return false;
418 object = asObject(prototype);
419 }
420}
421
422ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
423{
424 JSObject* object = this;
425 while (true) {
426 if (object->getOwnPropertySlot(exec, propertyName, slot))
427 return true;
428 JSValue prototype = object->prototype();
429 if (!prototype.isObject())
430 return false;
431 object = asObject(prototype);
432 }
433}
434
435inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const
436{
437 PropertySlot slot(this);
438 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
439 return slot.getValue(exec, propertyName);
440
441 return jsUndefined();
442}
443
444inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
445{
446 PropertySlot slot(this);
447 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
448 return slot.getValue(exec, propertyName);
449
450 return jsUndefined();
451}
452
453inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
454{
455 ASSERT(value);
456 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
457
458 if (m_structure->isDictionary()) {
459 unsigned currentAttributes;
460 JSCell* currentSpecificFunction;
461 size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
462 if (offset != WTF::notFound) {
463 // If there is currently a specific function, and there now either isn't,
464 // or the new value is different, then despecify.
465 if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
466 m_structure->despecifyDictionaryFunction(propertyName);
467 if (checkReadOnly && currentAttributes & ReadOnly)
468 return;
469 putDirectOffset(offset, value);
470 // At this point, the objects structure only has a specific value set if previously there
471 // had been one set, and if the new value being specified is the same (otherwise we would
472 // have despecified, above). So, if currentSpecificFunction is not set, or if the new
473 // value is different (or there is no new value), then the slot now has no value - and
474 // as such it is cachable.
475 // If there was previously a value, and the new value is the same, then we cannot cache.
476 if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
477 slot.setExistingProperty(this, offset);
478 return;
479 }
480
481 size_t currentCapacity = m_structure->propertyStorageCapacity();
482 offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction);
483 if (currentCapacity != m_structure->propertyStorageCapacity())
484 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
485
486 ASSERT(offset < m_structure->propertyStorageCapacity());
487 putDirectOffset(offset, value);
488 // See comment on setNewProperty call below.
489 if (!specificFunction)
490 slot.setNewProperty(this, offset);
491 return;
492 }
493
494 size_t offset;
495 size_t currentCapacity = m_structure->propertyStorageCapacity();
496 if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) {
497 if (currentCapacity != structure->propertyStorageCapacity())
498 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
499
500 ASSERT(offset < structure->propertyStorageCapacity());
501 setStructure(structure.release());
502 putDirectOffset(offset, value);
503 // This is a new property; transitions with specific values are not currently cachable,
504 // so leave the slot in an uncachable state.
505 if (!specificFunction)
506 slot.setNewProperty(this, offset);
507 return;
508 }
509
510 unsigned currentAttributes;
511 JSCell* currentSpecificFunction;
512 offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
513 if (offset != WTF::notFound) {
514 if (checkReadOnly && currentAttributes & ReadOnly)
515 return;
516
517 // There are three possibilities here:
518 // (1) There is an existing specific value set, and we're overwriting with *the same value*.
519 // * Do nothing - no need to despecify, but that means we can't cache (a cached
520 // put could write a different value). Leave the slot in an uncachable state.
521 // (2) There is a specific value currently set, but we're writing a different value.
522 // * First, we have to despecify. Having done so, this is now a regular slot
523 // with no specific value, so go ahead & cache like normal.
524 // (3) Normal case, there is no specific value set.
525 // * Go ahead & cache like normal.
526 if (currentSpecificFunction) {
527 // case (1) Do the put, then return leaving the slot uncachable.
528 if (specificFunction == currentSpecificFunction) {
529 putDirectOffset(offset, value);
530 return;
531 }
532 // case (2) Despecify, fall through to (3).
533 setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName));
534 }
535
536 // case (3) set the slot, do the put, return.
537 slot.setExistingProperty(this, offset);
538 putDirectOffset(offset, value);
539 return;
540 }
541
542 // If we have a specific function, we may have got to this point if there is
543 // already a transition with the correct property name and attributes, but
544 // specialized to a different function. In this case we just want to give up
545 // and despecialize the transition.
546 // In this case we clear the value of specificFunction which will result
547 // in us adding a non-specific transition, and any subsequent lookup in
548 // Structure::addPropertyTransitionToExistingStructure will just use that.
549 if (specificFunction && m_structure->hasTransition(propertyName, attributes))
550 specificFunction = 0;
551
552 RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
553
554 if (currentCapacity != structure->propertyStorageCapacity())
555 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
556
557 ASSERT(offset < structure->propertyStorageCapacity());
558 setStructure(structure.release());
559 putDirectOffset(offset, value);
560 // This is a new property; transitions with specific values are not currently cachable,
561 // so leave the slot in an uncachable state.
562 if (!specificFunction)
563 slot.setNewProperty(this, offset);
564}
565
566inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
567{
568 ASSERT(value);
569 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
570
571 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
572}
573
574inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
575{
576 PutPropertySlot slot;
577 putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
578}
579
580inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
581{
582 ASSERT(value);
583 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
584
585 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
586}
587
588inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
589{
590 PutPropertySlot slot;
591 putDirectInternal(propertyName, value, attributes, false, slot, 0);
592}
593
594inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
595{
596 putDirectInternal(propertyName, value, 0, false, slot, 0);
597}
598
599inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
600{
601 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
602}
603
604inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr)
605{
606 PutPropertySlot slot;
607 putDirectInternal(propertyName, value, attr, false, slot, value);
608}
609
610inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes)
611{
612 size_t currentCapacity = m_structure->propertyStorageCapacity();
613 size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0);
614 if (currentCapacity != m_structure->propertyStorageCapacity())
615 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
616 putDirectOffset(offset, value);
617}
618
619inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes)
620{
621 size_t currentCapacity = m_structure->propertyStorageCapacity();
622 size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value);
623 if (currentCapacity != m_structure->propertyStorageCapacity())
624 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
625 putDirectOffset(offset, value);
626}
627
628inline void JSObject::transitionTo(Structure* newStructure)
629{
630 if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
631 allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
632 setStructure(newStructure);
633}
634
635inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
636{
637 return defaultValue(exec, preferredType);
638}
639
640inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
641{
642 PropertySlot slot(asValue());
643 return get(exec, propertyName, slot);
644}
645
646inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
647{
648 if (UNLIKELY(!isCell())) {
649 JSObject* prototype = synthesizePrototype(exec);
650 if (propertyName == exec->propertyNames().underscoreProto)
651 return prototype;
652 if (!prototype->getPropertySlot(exec, propertyName, slot))
653 return jsUndefined();
654 return slot.getValue(exec, propertyName);
655 }
656 JSCell* cell = asCell();
657 while (true) {
658 if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
659 return slot.getValue(exec, propertyName);
660 JSValue prototype = asObject(cell)->prototype();
661 if (!prototype.isObject())
662 return jsUndefined();
663 cell = asObject(prototype);
664 }
665}
666
667inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
668{
669 PropertySlot slot(asValue());
670 return get(exec, propertyName, slot);
671}
672
673inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
674{
675 if (UNLIKELY(!isCell())) {
676 JSObject* prototype = synthesizePrototype(exec);
677 if (!prototype->getPropertySlot(exec, propertyName, slot))
678 return jsUndefined();
679 return slot.getValue(exec, propertyName);
680 }
681 JSCell* cell = const_cast<JSCell*>(asCell());
682 while (true) {
683 if (cell->getOwnPropertySlot(exec, propertyName, slot))
684 return slot.getValue(exec, propertyName);
685 JSValue prototype = asObject(cell)->prototype();
686 if (!prototype.isObject())
687 return jsUndefined();
688 cell = prototype.asCell();
689 }
690}
691
692inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
693{
694 if (UNLIKELY(!isCell())) {
695 synthesizeObject(exec)->put(exec, propertyName, value, slot);
696 return;
697 }
698 asCell()->put(exec, propertyName, value, slot);
699}
700
701inline void JSValue::putDirect(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
702{
703 ASSERT(isCell() && isObject());
704 asObject(asCell())->putDirect(propertyName, value, slot);
705}
706
707inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
708{
709 if (UNLIKELY(!isCell())) {
710 synthesizeObject(exec)->put(exec, propertyName, value);
711 return;
712 }
713 asCell()->put(exec, propertyName, value);
714}
715
716ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
717{
718 ASSERT(newSize > oldSize);
719
720 // It's important that this function not rely on m_structure, since
721 // we might be in the middle of a transition.
722 bool wasInline = (oldSize == JSObject::inlineStorageCapacity);
723
724 PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage);
725 PropertyStorage newPropertyStorage = new EncodedJSValue[newSize];
726
727 for (unsigned i = 0; i < oldSize; ++i)
728 newPropertyStorage[i] = oldPropertyStorage[i];
729
730 if (!wasInline)
731 delete [] oldPropertyStorage;
732
733 m_externalStorage = newPropertyStorage;
734}
735
736ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
737{
738 JSCell::markChildren(markStack);
739
740 markStack.append(prototype());
741
742 PropertyStorage storage = propertyStorage();
743 size_t storageSize = m_structure->propertyStorageSize();
744 markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
745}
746
747// --- JSValue inlines ----------------------------
748
749ALWAYS_INLINE UString JSValue::toThisString(ExecState* exec) const
750{
751 return isString() ? static_cast<JSString*>(asCell())->value(exec) : toThisObject(exec)->toString(exec);
752}
753
754inline JSString* JSValue::toThisJSString(ExecState* exec) const
755{
756 return isString() ? static_cast<JSString*>(asCell()) : jsString(exec, toThisObject(exec)->toString(exec));
757}
758
759} // namespace JSC
760
761#endif // JSObject_h
Note: See TracBrowser for help on using the repository browser.