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

Last change on this file since 35900 was 35830, checked in by Darin Adler, 17 years ago

JavaScriptCore:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • eliminate JSValue::type()

This will make it slightly easier to change the JSImmediate design without
having to touch so many call sites.

SunSpider says this change is a wash (looked like a slight speedup, but not
statistically significant).

  • API/JSStringRef.cpp: Removed include of JSType.h.
  • API/JSValueRef.cpp: Removed include of JSType.h. (JSValueGetType): Replaced use of JSValue::type() with JSValue::is functions.
  • VM/JSPropertyNameIterator.cpp: Removed type() implementation. (KJS::JSPropertyNameIterator::toPrimitive): Changed to take PreferredPrimitiveType argument instead of JSType.
  • VM/JSPropertyNameIterator.h: Ditto.
  • VM/Machine.cpp: (KJS::fastIsNumber): Updated for name change. (KJS::fastToInt32): Ditto. (KJS::fastToUInt32): Ditto. (KJS::jsAddSlowCase): Updated toPrimitive caller for change from JSType to PreferredPrimitiveType. (KJS::jsAdd): Replaced calls to JSValue::type() with calls to JSValue::isString(). (KJS::jsTypeStringForValue): Replaced calls to JSValue::type() with multiple calls to JSValue::is -- we could make this a virtual function instead if we want to have faster performance. (KJS::Machine::privateExecute): Renamed JSImmediate::toTruncatedUInt32 to JSImmediate::getTruncatedUInt32 for consistency with other functions. Changed two calls of JSValue::type() to JSValue::isString().
  • kjs/GetterSetter.cpp: (KJS::GetterSetter::toPrimitive): Changed to take PreferredPrimitiveType argument instead of JSType. (KJS::GetterSetter::isGetterSetter): Added.
  • kjs/GetterSetter.h:
  • kjs/JSCell.cpp: (KJS::JSCell::isString): Added. (KJS::JSCell::isGetterSetter): Added. (KJS::JSCell::isObject): Added.
  • kjs/JSCell.h: Eliminated type function. Added isGetterSetter. Made isString and isObject virtual. Changed toPrimitive to take PreferredPrimitiveType argument instead of JSType. (KJS::JSCell::isNumber): Use Heap::isNumber for faster performance. (KJS::JSValue::isGetterSetter): Added. (KJS::JSValue::toPrimitive): Changed to take PreferredPrimitiveType argument instead of JSType.
  • kjs/JSImmediate.h: Removed JSValue::type() and replaced JSValue::toTruncatedUInt32 with JSValue::getTruncatedUInt32. (KJS::JSImmediate::isEitherImmediate): Added.
  • kjs/JSNotAnObject.cpp: (KJS::JSNotAnObject::toPrimitive): Changed to take PreferredPrimitiveType argument instead of JSType.
  • kjs/JSNotAnObject.h: Ditto.
  • kjs/JSNumberCell.cpp: (KJS::JSNumberCell::toPrimitive): Ditto.
  • kjs/JSNumberCell.h: (KJS::JSNumberCell::toInt32): Renamed from fastToInt32. There's no other "slow" version of this once you have a JSNumberCell, so there's no need for "fast" in the name. It's a feature that this hides the base class toInt32, which does the same job less efficiently (and has an additional ExecState argument). (KJS::JSNumberCell::toUInt32): Ditto.
  • kjs/JSObject.cpp: (KJS::callDefaultValueFunction): Use isGetterSetter instead of type. (KJS::JSObject::getPrimitiveNumber): Use PreferredPrimitiveType. (KJS::JSObject::defaultValue): Ditto. (KJS::JSObject::defineGetter): Use isGetterSetter. (KJS::JSObject::defineSetter): Ditto. (KJS::JSObject::lookupGetter): Ditto. (KJS::JSObject::lookupSetter): Ditto. (KJS::JSObject::toNumber): Use PreferredPrimitiveType. (KJS::JSObject::toString): Ditto. (KJS::JSObject::isObject): Added.
  • kjs/JSObject.h: (KJS::JSObject::inherits): Call the isObject from JSCell; it's now hidden by our override of isObject. (KJS::JSObject::getOwnPropertySlotForWrite): Use isGetterSetter instead of type. (KJS::JSObject::getOwnPropertySlot): Ditto. (KJS::JSObject::toPrimitive): Use PreferredPrimitiveType.
  • kjs/JSString.cpp: (KJS::JSString::toPrimitive): Use PreferredPrimitiveType. (KJS::JSString::isString): Added.
  • kjs/JSString.h: Ditto.
  • kjs/JSValue.h: Removed type(), added isGetterSetter(). Added PreferredPrimitiveType enum and used it as the argument for the toPrimitive function. (KJS::JSValue::getBoolean): Simplified a bit an removed a branch.
  • kjs/collector.cpp: (KJS::typeName): Changed to use JSCell::is functions instead of calling JSCell::type.
  • kjs/collector.h: (KJS::Heap::isNumber): Renamed from fastIsNumber.
  • kjs/nodes.h: Added now-needed include of JSType, since the type is used here to record types of values in the tree.
  • kjs/operations.cpp: (KJS::equal): Rewrote to no longer depend on type(). (KJS::strictEqual): Ditto.

JavaScriptGlue:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • eliminate JSValue::type()
  • JSUtils.cpp: (KJSValueToCFTypeInternal): Replaced uses of JSValue::type() with JSValue::is functions.
  • UserObjectImp.cpp: (UserObjectImp::getOwnPropertySlot): Ditto. (UserObjectImp::toPrimitive): Take PreferredPrimitiveType argument instead of JSType argument.
  • UserObjectImp.h: Ditto.

WebCore:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • eliminate JSValue::type()
  • bridge/c/c_instance.cpp: (KJS::Bindings::CInstance::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument. Removed unneeded code to handle boolean, since that's never passed.
  • bridge/c/c_instance.h: Ditto.
  • bridge/c/c_utility.cpp: (KJS::Bindings::convertValueToNPVariant): Use JSValue::is functions instead of JSValue::type(). Removed unneeded code to handle "unspecified".
  • bridge/jni/jni_instance.cpp: (JavaInstance::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument. Removed unneeded code to handle boolean.
  • bridge/jni/jni_instance.h: Ditto.
  • bridge/jni/jni_jsobject.mm: (JavaJSObject::convertValueToJObject): Use JSValue::is functions instead of JSValue::type().
  • bridge/objc/objc_instance.h: Take PreferredPrimitiveType argument instead of JSType argument. Removed unused argument.
  • bridge/objc/objc_instance.mm: (ObjcInstance::getValueOfUndefinedField): Removed unused argument. (ObjcInstance::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument. Removed unneeded code to handle boolean and another dead code path for unknown types.
  • bridge/objc/objc_runtime.h: Take PreferredPrimitiveType argument instead of JSType argument. Removed override of type() that caused the fallback object to return "UndefinedType" when there is no invokeUndefinedMethodFromWebScript:withArguments: method defined. That didn't accomplish much, since most checks for undefined don't ever call type().
  • bridge/objc/objc_runtime.mm: (ObjcFallbackObjectImp::defaultValue): Ditto.
  • bridge/qt/qt_instance.cpp: (KJS::Bindings::QtInstance::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument. Removed unneeded code to handle boolean.
  • bridge/qt/qt_instance.h: Ditto.
  • bridge/runtime.h: (KJS::Bindings::Instance::getValueOfUndefinedField): Removed unsed argument.
  • bridge/runtime_object.cpp: (RuntimeObjectImp::defaultValue): Take PreferredPrimitiveType argument instead of JSType argument.
  • bridge/runtime_object.h: Ditto.

WebKit/mac:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • eliminate JSValue::type()
  • WebView/WebView.mm: (aeDescFromJSValue): Rewrite to use the JSValue::is functions instead of a switch on JSValue::type().

LayoutTests:

2008-08-12 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • added a test since I had to rewrite the == and === operators
  • fast/js/equality-expected.txt: Added.
  • fast/js/equality.html: Added.
  • fast/js/resources/equality.js: Added.
  • Property svn:eol-style set to native
File size: 13.8 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 "ScopeChain.h"
34
35namespace KJS {
36
37 class InternalFunction;
38 class PropertyNameArray;
39 struct HashEntry;
40 struct HashTable;
41
42 // ECMA 262-3 8.6.1
43 // Property attributes
44 enum Attribute {
45 None = 0,
46 ReadOnly = 1 << 1, // property can be only read, not written
47 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
48 DontDelete = 1 << 3, // property can't be deleted
49 Function = 1 << 4, // property is a function - only used by static hashtables
50 IsGetterSetter = 1 << 5 // property is a getter or setter
51 };
52
53 class JSObject : public JSCell {
54 public:
55 /**
56 * Creates a new JSObject with the specified prototype
57 *
58 * @param prototype The prototype
59 */
60 JSObject(JSValue* prototype);
61
62 /**
63 * Creates a new JSObject with a prototype of jsNull()
64 * (that is, the ECMAScript "null" value, not a null object pointer).
65 */
66 JSObject();
67
68 virtual void mark();
69
70 bool inherits(const ClassInfo* classInfo) const { return JSCell::isObject(classInfo); }
71
72 JSValue* prototype() const;
73 void setPrototype(JSValue* prototype);
74
75 virtual UString className() const;
76
77 JSValue* get(ExecState*, const Identifier& propertyName) const;
78 JSValue* get(ExecState*, unsigned propertyName) const;
79
80 bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
81 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
82
83 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
84 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
85
86 virtual void put(ExecState*, const Identifier& propertyName, JSValue* value);
87 virtual void put(ExecState*, unsigned propertyName, JSValue* value);
88
89 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes);
90 virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue* value, unsigned attributes);
91
92 bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
93
94 bool hasProperty(ExecState*, const Identifier& propertyName) const;
95 bool hasProperty(ExecState*, unsigned propertyName) const;
96 bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
97
98 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
99 virtual bool deleteProperty(ExecState*, unsigned propertyName);
100
101 virtual JSValue* defaultValue(ExecState*, PreferredPrimitiveType) const;
102
103 virtual bool implementsHasInstance() const;
104 virtual bool hasInstance(ExecState*, JSValue*);
105
106 virtual void getPropertyNames(ExecState*, PropertyNameArray&);
107
108 virtual JSValue* toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
109 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
110 virtual bool toBoolean(ExecState*) const;
111 virtual double toNumber(ExecState*) const;
112 virtual UString toString(ExecState*) const;
113 virtual JSObject* toObject(ExecState*) const;
114
115 virtual JSObject* toThisObject(ExecState*) const;
116 virtual JSGlobalObject* toGlobalObject(ExecState*) const;
117
118 virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
119
120 // WebCore uses this to make document.all and style.filter undetectable
121 virtual bool masqueradeAsUndefined() const { return false; }
122
123 // This get function only looks at the property map.
124 JSValue* getDirect(const Identifier& propertyName) const { return m_propertyMap.get(propertyName); }
125 JSValue** getDirectLocation(const Identifier& propertyName) { return m_propertyMap.getLocation(propertyName); }
126 JSValue** getDirectLocation(const Identifier& propertyName, bool& isWriteable) { return m_propertyMap.getLocation(propertyName, isWriteable); }
127 void putDirect(const Identifier& propertyName, JSValue* value, unsigned attr = 0);
128 void putDirect(ExecState*, const Identifier& propertyName, int value, unsigned attr = 0);
129 void removeDirect(const Identifier& propertyName);
130 bool hasCustomProperties() { return !m_propertyMap.isEmpty(); }
131
132 // convenience to add a function property under the function's own built-in name
133 void putDirectFunction(ExecState*, InternalFunction*, unsigned attr = 0);
134
135 void fillGetterPropertySlot(PropertySlot&, JSValue** location);
136
137 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction);
138 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction);
139 virtual JSValue* lookupGetter(ExecState*, const Identifier& propertyName);
140 virtual JSValue* lookupSetter(ExecState*, const Identifier& propertyName);
141
142 virtual bool isActivationObject() const { return false; }
143 virtual bool isGlobalObject() const { return false; }
144 virtual bool isVariableObject() const { return false; }
145
146 virtual bool isWatchdogException() const { return false; }
147
148 virtual bool isNotAnObjectErrorStub() const { return false; }
149
150 protected:
151 PropertyMap m_propertyMap;
152 bool getOwnPropertySlotForWrite(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
153
154 private:
155 virtual bool isObject() const;
156
157 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
158 JSValue* m_prototype;
159 };
160
161 JSObject* constructEmptyObject(ExecState*);
162
163inline JSObject::JSObject(JSValue* prototype)
164 : m_prototype(prototype)
165{
166 ASSERT(prototype);
167 ASSERT(prototype == jsNull() || Heap::heap(this) == Heap::heap(prototype));
168}
169
170inline JSObject::JSObject()
171 : m_prototype(jsNull())
172{
173}
174
175inline JSValue* JSObject::prototype() const
176{
177 return m_prototype;
178}
179
180inline void JSObject::setPrototype(JSValue* prototype)
181{
182 ASSERT(prototype);
183 m_prototype = prototype;
184}
185
186inline bool JSCell::isObject(const ClassInfo* info) const
187{
188 for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) {
189 if (ci == info)
190 return true;
191 }
192 return false;
193}
194
195// this method is here to be after the inline declaration of JSCell::isObject
196inline bool JSValue::isObject(const ClassInfo* classInfo) const
197{
198 return !JSImmediate::isImmediate(this) && asCell()->isObject(classInfo);
199}
200
201inline JSValue* JSObject::get(ExecState* exec, const Identifier& propertyName) const
202{
203 PropertySlot slot(const_cast<JSObject*>(this));
204 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
205 return slot.getValue(exec, propertyName);
206
207 return jsUndefined();
208}
209
210inline JSValue* JSObject::get(ExecState* exec, unsigned propertyName) const
211{
212 PropertySlot slot(const_cast<JSObject*>(this));
213 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
214 return slot.getValue(exec, propertyName);
215
216 return jsUndefined();
217}
218
219// It may seem crazy to inline a function this large but it makes a big difference
220// since this is function very hot in variable lookup
221inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
222{
223 JSObject* object = this;
224 while (true) {
225 if (object->getOwnPropertySlot(exec, propertyName, slot))
226 return true;
227
228 JSValue* prototype = object->m_prototype;
229 if (!prototype->isObject())
230 return false;
231
232 object = static_cast<JSObject*>(prototype);
233 }
234}
235
236inline bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
237{
238 JSObject* object = this;
239
240 while (true) {
241 if (object->getOwnPropertySlot(exec, propertyName, slot))
242 return true;
243
244 JSValue* prototype = object->m_prototype;
245 if (!prototype->isObject())
246 break;
247
248 object = static_cast<JSObject*>(prototype);
249 }
250
251 return false;
252}
253
254// It may seem crazy to inline a function this large, especially a virtual function,
255// but it makes a big difference to property lookup that derived classes can inline their
256// base class call to this.
257ALWAYS_INLINE bool JSObject::getOwnPropertySlotForWrite(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable)
258{
259 if (JSValue** location = getDirectLocation(propertyName, slotIsWriteable)) {
260 if (m_propertyMap.hasGetterSetterProperties() && location[0]->isGetterSetter()) {
261 slotIsWriteable = false;
262 fillGetterPropertySlot(slot, location);
263 } else
264 slot.setValueSlot(location);
265 return true;
266 }
267
268 // non-standard Netscape extension
269 if (propertyName == exec->propertyNames().underscoreProto) {
270 slot.setValueSlot(&m_prototype);
271 slotIsWriteable = false;
272 return true;
273 }
274
275 return false;
276}
277
278// It may seem crazy to inline a function this large, especially a virtual function,
279// but it makes a big difference to property lookup that derived classes can inline their
280// base class call to this.
281ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
282{
283 if (JSValue** location = getDirectLocation(propertyName)) {
284 if (m_propertyMap.hasGetterSetterProperties() && location[0]->isGetterSetter())
285 fillGetterPropertySlot(slot, location);
286 else
287 slot.setValueSlot(location);
288 return true;
289 }
290
291 // non-standard Netscape extension
292 if (propertyName == exec->propertyNames().underscoreProto) {
293 slot.setValueSlot(&m_prototype);
294 return true;
295 }
296
297 return false;
298}
299
300inline void JSObject::putDirect(const Identifier& propertyName, JSValue* value, unsigned attr)
301{
302 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
303
304 m_propertyMap.put(propertyName, value, attr);
305}
306
307inline void JSObject::putDirect(ExecState* exec, const Identifier& propertyName, int value, unsigned attr)
308{
309 m_propertyMap.put(propertyName, jsNumber(exec, value), attr);
310}
311
312inline JSValue* JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
313{
314 return defaultValue(exec, preferredType);
315}
316
317inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName) const
318{
319 if (UNLIKELY(JSImmediate::isImmediate(this))) {
320 JSObject* prototype = JSImmediate::prototype(this, exec);
321 PropertySlot slot(const_cast<JSValue*>(this));
322 if (!prototype->getPropertySlot(exec, propertyName, slot))
323 return jsUndefined();
324 return slot.getValue(exec, propertyName);
325 }
326 JSCell* cell = static_cast<JSCell*>(const_cast<JSValue*>(this));
327 PropertySlot slot(cell);
328 while (true) {
329 if (cell->getOwnPropertySlot(exec, propertyName, slot))
330 return slot.getValue(exec, propertyName);
331 ASSERT(cell->isObject());
332 JSValue* prototype = static_cast<JSObject*>(cell)->prototype();
333 if (!prototype->isObject())
334 return jsUndefined();
335 cell = static_cast<JSCell*>(prototype);
336 }
337}
338
339inline JSValue* JSValue::get(ExecState* exec, unsigned propertyName) const
340{
341 if (UNLIKELY(JSImmediate::isImmediate(this))) {
342 JSObject* prototype = JSImmediate::prototype(this, exec);
343 PropertySlot slot(const_cast<JSValue*>(this));
344 if (!prototype->getPropertySlot(exec, propertyName, slot))
345 return jsUndefined();
346 return slot.getValue(exec, propertyName);
347 }
348 JSCell* cell = const_cast<JSCell*>(asCell());
349 PropertySlot slot(cell);
350 while (true) {
351 if (cell->getOwnPropertySlot(exec, propertyName, slot))
352 return slot.getValue(exec, propertyName);
353 ASSERT(cell->isObject());
354 JSValue* prototype = static_cast<JSObject*>(cell)->prototype();
355 if (!prototype->isObject())
356 return jsUndefined();
357 cell = static_cast<JSCell*>(prototype);
358 }
359}
360
361inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
362{
363 if (UNLIKELY(JSImmediate::isImmediate(this))) {
364 JSImmediate::toObject(this, exec)->put(exec, propertyName, value);
365 return;
366 }
367 asCell()->put(exec, propertyName, value);
368}
369
370inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue* value)
371{
372 if (UNLIKELY(JSImmediate::isImmediate(this))) {
373 JSImmediate::toObject(this, exec)->put(exec, propertyName, value);
374 return;
375 }
376 asCell()->put(exec, propertyName, value);
377}
378
379} // namespace KJS
380
381#endif // JSObject_h
Note: See TracBrowser for help on using the repository browser.