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

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

JavaScriptCore:

2009-01-28 Sam Weinig <[email protected]>

Reviewed by Geoff Garen.

Fix for <rdar://problem/6129678>
REGRESSION (Safari 3-4): Local variable not accessible from Dashcode console or variables view

Iterating the properties of activation objects accessed through the WebKit debugging
APIs was broken by forced conversion of JSActivation to the global object. To fix this,
we use a proxy activation object that acts more like a normal JSObject.

  • debugger/DebuggerActivation.cpp: Added. (JSC::DebuggerActivation::DebuggerActivation): (JSC::DebuggerActivation::mark): (JSC::DebuggerActivation::className): (JSC::DebuggerActivation::getOwnPropertySlot): (JSC::DebuggerActivation::put): (JSC::DebuggerActivation::putWithAttributes): (JSC::DebuggerActivation::deleteProperty): (JSC::DebuggerActivation::getPropertyNames): (JSC::DebuggerActivation::getPropertyAttributes): (JSC::DebuggerActivation::defineGetter): (JSC::DebuggerActivation::defineSetter): (JSC::DebuggerActivation::lookupGetter): (JSC::DebuggerActivation::lookupSetter):
  • debugger/DebuggerActivation.h: Added. Proxy JSActivation object for Debugging.
  • runtime/JSActivation.h: (JSC::JSActivation::isActivationObject): Added.
  • runtime/JSObject.h: (JSC::JSObject::isActivationObject): Added.

WebCore:

2009-01-28 Sam Weinig <[email protected]>

Reviewed by Geoff Garen.

Add forwarding header.

  • ForwardingHeaders/debugger/DebuggerActivation.h: Added.

WebKit/mac:

2009-01-28 Sam Weinig <[email protected]>

Reviewed by Geoff Garen.

Fix for <rdar://problem/6129678>
REGRESSION (Safari 3-4): Local variable not accessible from Dashcode console or variables view

  • WebView/WebScriptDebugDelegate.mm: (-[WebScriptCallFrame scopeChain]): Wrap JSActivations in DebuggerActivations.
  • Property svn:eol-style set to native
File size: 20.5 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 "CallFrame.h"
30#include "JSNumberCell.h"
31#include "PropertySlot.h"
32#include "PutPropertySlot.h"
33#include "ScopeChain.h"
34#include "Structure.h"
35
36namespace 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
213inline JSObject* asObject(JSValuePtr value)
214{
215 ASSERT(asCell(value)->isObject());
216 return static_cast<JSObject*>(asCell(value));
217}
218
219inline 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
229inline JSObject::~JSObject()
230{
231 ASSERT(m_structure);
232 if (m_propertyStorage != m_inlineStorage)
233 delete [] m_propertyStorage;
234 m_structure->deref();
235}
236
237inline JSValuePtr JSObject::prototype() const
238{
239 return m_structure->storedPrototype();
240}
241
242inline void JSObject::setPrototype(JSValuePtr prototype)
243{
244 ASSERT(prototype);
245 RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype);
246 setStructure(newStructure.release());
247}
248
249inline void JSObject::setStructure(PassRefPtr<Structure> structure)
250{
251 m_structure->deref();
252 m_structure = structure.releaseRef(); // ~JSObject balances this ref()
253}
254
255inline Structure* JSObject::inheritorID()
256{
257 if (m_inheritorID)
258 return m_inheritorID.get();
259 return createInheritorID();
260}
261
262inline 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
272inline bool JSValuePtr::isObject(const ClassInfo* classInfo) const
273{
274 return isCell() && asCell()->isObject(classInfo);
275}
276
277ALWAYS_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
296ALWAYS_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.
323ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
324{
325 return inlineGetOwnPropertySlot(exec, propertyName, slot);
326}
327
328ALWAYS_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
337inline 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
350inline 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
363inline 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
372inline 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
381inline void JSObject::putDirect(const Identifier& propertyName, JSValuePtr value, unsigned attr)
382{
383 PutPropertySlot slot;
384 putDirect(propertyName, value, attr, false, slot);
385}
386
387inline 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
448inline 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
457inline 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
464inline JSValuePtr JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
465{
466 return defaultValue(exec, preferredType);
467}
468
469inline JSValuePtr JSValuePtr::get(ExecState* exec, const Identifier& propertyName) const
470{
471 PropertySlot slot(asValue());
472 return get(exec, propertyName, slot);
473}
474
475inline 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
495inline JSValuePtr JSValuePtr::get(ExecState* exec, unsigned propertyName) const
496{
497 PropertySlot slot(asValue());
498 return get(exec, propertyName, slot);
499}
500
501inline 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
521inline 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
530inline 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
539ALWAYS_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
Note: See TracBrowser for help on using the repository browser.