source: webkit/trunk/JavaScriptCore/kjs/JSObject.h@ 37068

Last change on this file since 37068 was 37068, checked in by [email protected], 17 years ago

2008-09-29 Cameron Zwarich <[email protected]>

Reviewed by Sam Weinig.

Remove the isActivationObject() virtual method on JSObject and use
StructureID information instead. This should be slightly faster, but
isActivationObject() is only used in assertions and unwinding the stack
for exceptions.

  • VM/Machine.cpp: (JSC::depth): (JSC::Machine::unwindCallFrame): (JSC::Machine::privateExecute): (JSC::Machine::cti_op_ret_activation):
  • kjs/JSActivation.cpp:
  • kjs/JSActivation.h:
  • kjs/JSObject.h:
  • Property svn:eol-style set to native
File size: 17.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 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 "ExecState.h"
30#include "JSNumberCell.h"
31#include "PropertyMap.h"
32#include "PropertySlot.h"
33#include "PutPropertySlot.h"
34#include "ScopeChain.h"
35#include "StructureID.h"
36
37namespace JSC {
38
39 class InternalFunction;
40 class PropertyNameArray;
41 class StructureID;
42 struct HashEntry;
43 struct HashTable;
44
45 // ECMA 262-3 8.6.1
46 // Property attributes
47 enum Attribute {
48 None = 0,
49 ReadOnly = 1 << 1, // property can be only read, not written
50 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
51 DontDelete = 1 << 3, // property can't be deleted
52 Function = 1 << 4, // property is a function - only used by static hashtables
53 };
54
55 class JSObject : public JSCell {
56 friend class BatchedTransitionOptimizer;
57 friend class CTI;
58
59 public:
60 explicit JSObject(PassRefPtr<StructureID>);
61
62 virtual void mark();
63
64 // The inline virtual destructor cannot be the first virtual function declared
65 // in the class as it results in the vtable being generated as a weak symbol
66 virtual ~JSObject();
67
68 bool inherits(const ClassInfo* classInfo) const { return JSCell::isObject(classInfo); }
69
70 JSValue* prototype() const;
71 void setPrototype(JSValue* prototype);
72
73 void setStructureID(PassRefPtr<StructureID>);
74 StructureID* inheritorID();
75
76 PropertyStorage& propertyStorage() { return m_propertyStorage; }
77
78 virtual UString className() const;
79
80 JSValue* get(ExecState*, const Identifier& propertyName) const;
81 JSValue* get(ExecState*, unsigned propertyName) const;
82
83 bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
84 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
85
86 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
87 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
88
89 virtual void put(ExecState*, const Identifier& propertyName, JSValue* value, PutPropertySlot&);
90 virtual void put(ExecState*, unsigned propertyName, JSValue* value);
91
92 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes);
93 virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue* value, unsigned attributes);
94
95 bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
96
97 bool hasProperty(ExecState*, const Identifier& propertyName) const;
98 bool hasProperty(ExecState*, unsigned propertyName) const;
99 bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
100
101 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
102 virtual bool deleteProperty(ExecState*, unsigned propertyName);
103
104 virtual JSValue* defaultValue(ExecState*, PreferredPrimitiveType) const;
105
106 virtual bool hasInstance(ExecState*, JSValue*, JSValue* prototypeProperty);
107
108 virtual void getPropertyNames(ExecState*, PropertyNameArray&);
109
110 virtual JSValue* toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
111 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
112 virtual bool toBoolean(ExecState*) const;
113 virtual double toNumber(ExecState*) const;
114 virtual UString toString(ExecState*) const;
115 virtual JSObject* toObject(ExecState*) const;
116
117 virtual JSObject* toThisObject(ExecState*) const;
118 virtual JSGlobalObject* toGlobalObject(ExecState*) const;
119
120 virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
121
122 // This get function only looks at the property map.
123 JSValue* getDirect(const Identifier& propertyName) const
124 {
125 size_t offset = m_structureID->propertyMap().getOffset(propertyName);
126 return offset != WTF::notFound ? m_propertyStorage[offset] : 0;
127 }
128
129 JSValue** getDirectLocation(const Identifier& propertyName)
130 {
131 size_t offset = m_structureID->propertyMap().getOffset(propertyName);
132 return offset != WTF::notFound ? locationForOffset(offset) : 0;
133 }
134
135 JSValue** getDirectLocation(const Identifier& propertyName, unsigned& attributes)
136 {
137 size_t offset = m_structureID->propertyMap().getOffset(propertyName, attributes);
138 return offset != WTF::notFound ? locationForOffset(offset) : 0;
139 }
140
141 size_t offsetForLocation(JSValue** location)
142 {
143 return location - m_propertyStorage;
144 }
145
146 JSValue** locationForOffset(size_t offset)
147 {
148 return &m_propertyStorage[offset];
149 }
150
151 void transitionTo(StructureID*);
152
153 void removeDirect(const Identifier& propertyName);
154 bool hasCustomProperties() { return !m_structureID->propertyMap().isEmpty(); }
155 bool hasGetterSetterProperties() { return m_structureID->propertyMap().hasGetterSetterProperties(); }
156
157 void putDirect(const Identifier& propertyName, JSValue* value, unsigned attr = 0);
158 void putDirect(const Identifier& propertyName, JSValue* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
159 void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
160
161 // Fast access to known property offsets.
162 JSValue* getDirectOffset(size_t offset) { return m_propertyStorage[offset]; }
163 void putDirectOffset(size_t offset, JSValue* value) { m_propertyStorage[offset] = value; }
164
165 void fillGetterPropertySlot(PropertySlot&, JSValue** location);
166
167 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction);
168 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction);
169 virtual JSValue* lookupGetter(ExecState*, const Identifier& propertyName);
170 virtual JSValue* lookupSetter(ExecState*, const Identifier& propertyName);
171
172 virtual bool isGlobalObject() const { return false; }
173 virtual bool isVariableObject() const { return false; }
174 virtual bool isWatchdogException() const { return false; }
175 virtual bool isNotAnObjectErrorStub() const { return false; }
176
177 void allocatePropertyStorage(size_t oldSize, size_t newSize);
178 bool usingInlineStorage() const { return m_propertyStorage == m_inlineStorage; }
179
180 static const size_t inlineStorageCapacity = 2;
181
182 static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(ObjectType)); }
183
184 protected:
185 bool getOwnPropertySlotForWrite(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
186
187 private:
188 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
189 StructureID* createInheritorID();
190
191 RefPtr<StructureID> m_inheritorID;
192
193 PropertyStorage m_propertyStorage;
194 JSValue* m_inlineStorage[inlineStorageCapacity];
195 };
196
197 JSObject* constructEmptyObject(ExecState*);
198
199inline JSObject::JSObject(PassRefPtr<StructureID> structureID)
200 : JSCell(structureID.releaseRef()) // ~JSObject balances this ref()
201 , m_propertyStorage(m_inlineStorage)
202{
203 ASSERT(m_structureID);
204 ASSERT(prototype()->isNull() || Heap::heap(this) == Heap::heap(prototype()));
205}
206
207inline JSObject::~JSObject()
208{
209 ASSERT(m_structureID);
210 if (m_propertyStorage != m_inlineStorage)
211 delete [] m_propertyStorage;
212 m_structureID->deref();
213}
214
215inline JSValue* JSObject::prototype() const
216{
217 return m_structureID->storedPrototype();
218}
219
220inline void JSObject::setPrototype(JSValue* prototype)
221{
222 ASSERT(prototype);
223 RefPtr<StructureID> newStructureID = StructureID::changePrototypeTransition(m_structureID, prototype);
224 setStructureID(newStructureID.release());
225}
226
227inline void JSObject::setStructureID(PassRefPtr<StructureID> structureID)
228{
229 m_structureID->deref();
230 m_structureID = structureID.releaseRef(); // ~JSObject balances this ref()
231}
232
233inline StructureID* JSObject::inheritorID()
234{
235 if (m_inheritorID)
236 return m_inheritorID.get();
237 return createInheritorID();
238}
239
240inline bool JSCell::isObject(const ClassInfo* info) const
241{
242 for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) {
243 if (ci == info)
244 return true;
245 }
246 return false;
247}
248
249// this method is here to be after the inline declaration of JSCell::isObject
250inline bool JSValue::isObject(const ClassInfo* classInfo) const
251{
252 return !JSImmediate::isImmediate(this) && asCell()->isObject(classInfo);
253}
254
255inline JSValue* JSObject::get(ExecState* exec, const Identifier& propertyName) const
256{
257 PropertySlot slot(const_cast<JSObject*>(this));
258 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
259 return slot.getValue(exec, propertyName);
260
261 return jsUndefined();
262}
263
264inline JSValue* JSObject::get(ExecState* exec, unsigned propertyName) const
265{
266 PropertySlot slot(const_cast<JSObject*>(this));
267 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
268 return slot.getValue(exec, propertyName);
269
270 return jsUndefined();
271}
272
273// It may seem crazy to inline a function this large but it makes a big difference
274// since this is function very hot in variable lookup
275inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
276{
277 JSObject* object = this;
278 while (true) {
279 if (object->getOwnPropertySlot(exec, propertyName, slot))
280 return true;
281
282 JSValue* prototype = object->prototype();
283 if (!prototype->isObject())
284 return false;
285
286 object = static_cast<JSObject*>(prototype);
287 }
288}
289
290inline bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
291{
292 JSObject* object = this;
293
294 while (true) {
295 if (object->getOwnPropertySlot(exec, propertyName, slot))
296 return true;
297
298 JSValue* prototype = object->prototype();
299 if (!prototype->isObject())
300 break;
301
302 object = static_cast<JSObject*>(prototype);
303 }
304
305 return false;
306}
307
308// It may seem crazy to inline a function this large, especially a virtual function,
309// but it makes a big difference to property lookup that derived classes can inline their
310// base class call to this.
311ALWAYS_INLINE bool JSObject::getOwnPropertySlotForWrite(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable)
312{
313 unsigned attributes;
314 if (JSValue** location = getDirectLocation(propertyName, attributes)) {
315 if (m_structureID->propertyMap().hasGetterSetterProperties() && location[0]->isGetterSetter()) {
316 slotIsWriteable = false;
317 fillGetterPropertySlot(slot, location);
318 } else {
319 slotIsWriteable = !(attributes & ReadOnly);
320 slot.setValueSlot(this, location, offsetForLocation(location));
321 }
322 return true;
323 }
324
325 // non-standard Netscape extension
326 if (propertyName == exec->propertyNames().underscoreProto) {
327 slot.setValue(prototype());
328 slotIsWriteable = false;
329 return true;
330 }
331
332 return false;
333}
334
335// It may seem crazy to inline a function this large, especially a virtual function,
336// but it makes a big difference to property lookup that derived classes can inline their
337// base class call to this.
338ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
339{
340 if (JSValue** location = getDirectLocation(propertyName)) {
341 if (m_structureID->propertyMap().hasGetterSetterProperties() && location[0]->isGetterSetter())
342 fillGetterPropertySlot(slot, location);
343 else
344 slot.setValueSlot(this, location, offsetForLocation(location));
345 return true;
346 }
347
348 // non-standard Netscape extension
349 if (propertyName == exec->propertyNames().underscoreProto) {
350 slot.setValue(prototype());
351 return true;
352 }
353
354 return false;
355}
356
357inline void JSObject::putDirect(const Identifier& propertyName, JSValue* value, unsigned attr)
358{
359 PutPropertySlot slot;
360 putDirect(propertyName, value, attr, false, slot);
361}
362
363inline void JSObject::putDirect(const Identifier& propertyName, JSValue* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
364{
365 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
366
367 if (m_structureID->isDictionary()) {
368 unsigned currentAttributes;
369 size_t offset = m_structureID->propertyMap().getOffset(propertyName, currentAttributes);
370 if (offset != WTF::notFound) {
371 if (checkReadOnly && currentAttributes & ReadOnly)
372 return;
373 m_propertyStorage[offset] = value;
374 slot.setExistingProperty(this, offset);
375 return;
376 }
377
378 if (m_structureID->propertyMap().storageSize() == inlineStorageCapacity)
379 allocatePropertyStorage(m_structureID->propertyMap().storageSize(), m_structureID->propertyMap().size());
380 m_structureID->propertyMap().put(propertyName, value, attributes, checkReadOnly, this, slot, m_propertyStorage);
381 m_structureID->clearEnumerationCache();
382 return;
383 }
384
385 unsigned currentAttributes;
386 size_t offset = m_structureID->propertyMap().getOffset(propertyName, currentAttributes);
387 if (offset != WTF::notFound) {
388 if (checkReadOnly && currentAttributes & ReadOnly)
389 return;
390 m_propertyStorage[offset] = value;
391 slot.setExistingProperty(this, offset);
392 return;
393 }
394
395 if (m_structureID->propertyMap().storageSize() == inlineStorageCapacity)
396 allocatePropertyStorage(m_structureID->propertyMap().storageSize(), m_structureID->propertyMap().size());
397
398 RefPtr<StructureID> structureID = StructureID::addPropertyTransition(m_structureID, propertyName, value, attributes, this, slot, m_propertyStorage);
399 slot.setWasTransition(true);
400 setStructureID(structureID.release());
401}
402
403inline void JSObject::transitionTo(StructureID* newStructureID)
404{
405 StructureID::transitionTo(m_structureID, newStructureID, this);
406 setStructureID(newStructureID);
407}
408
409inline JSValue* JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
410{
411 return defaultValue(exec, preferredType);
412}
413
414inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName) const
415{
416 PropertySlot slot(const_cast<JSValue*>(this));
417 return get(exec, propertyName, slot);
418}
419
420inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
421{
422 if (UNLIKELY(JSImmediate::isImmediate(this))) {
423 JSObject* prototype = JSImmediate::prototype(this, exec);
424 if (!prototype->getPropertySlot(exec, propertyName, slot))
425 return jsUndefined();
426 return slot.getValue(exec, propertyName);
427 }
428 JSCell* cell = static_cast<JSCell*>(const_cast<JSValue*>(this));
429 while (true) {
430 if (cell->getOwnPropertySlot(exec, propertyName, slot))
431 return slot.getValue(exec, propertyName);
432 ASSERT(cell->isObject());
433 JSValue* prototype = static_cast<JSObject*>(cell)->prototype();
434 if (!prototype->isObject())
435 return jsUndefined();
436 cell = static_cast<JSCell*>(prototype);
437 }
438}
439
440inline JSValue* JSValue::get(ExecState* exec, unsigned propertyName) const
441{
442 PropertySlot slot(const_cast<JSValue*>(this));
443 return get(exec, propertyName, slot);
444}
445
446inline JSValue* JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
447{
448 if (UNLIKELY(JSImmediate::isImmediate(this))) {
449 JSObject* prototype = JSImmediate::prototype(this, exec);
450 if (!prototype->getPropertySlot(exec, propertyName, slot))
451 return jsUndefined();
452 return slot.getValue(exec, propertyName);
453 }
454 JSCell* cell = const_cast<JSCell*>(asCell());
455 while (true) {
456 if (cell->getOwnPropertySlot(exec, propertyName, slot))
457 return slot.getValue(exec, propertyName);
458 ASSERT(cell->isObject());
459 JSValue* prototype = static_cast<JSObject*>(cell)->prototype();
460 if (!prototype->isObject())
461 return jsUndefined();
462 cell = static_cast<JSCell*>(prototype);
463 }
464}
465
466inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue* value, PutPropertySlot& slot)
467{
468 if (UNLIKELY(JSImmediate::isImmediate(this))) {
469 JSImmediate::toObject(this, exec)->put(exec, propertyName, value, slot);
470 return;
471 }
472 asCell()->put(exec, propertyName, value, slot);
473}
474
475inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue* value)
476{
477 if (UNLIKELY(JSImmediate::isImmediate(this))) {
478 JSImmediate::toObject(this, exec)->put(exec, propertyName, value);
479 return;
480 }
481 asCell()->put(exec, propertyName, value);
482}
483
484} // namespace JSC
485
486#endif // JSObject_h
Note: See TracBrowser for help on using the repository browser.