source: webkit/trunk/JavaScriptCore/kjs/object.h@ 32652

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

Reviewed by Darin.

Fix run-webkit-tests --threading
and provisionally fix <https://bugs.webkit.org/show_bug.cgi?id=18661>
Proxy server issue in Sunday's Nightly

Changed ClassInfo objects for built-in objects to hold a getter function returning
a per-thread instance. This makes it safe to share these ClassInfo objects between threads -
and these are the only ones that need to be shared.

  • Property svn:eol-style set to native
File size: 21.0 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten ([email protected])
5 * Copyright (C) 2001 Peter Kelly ([email protected])
6 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#ifndef KJS_OBJECT_H
26#define KJS_OBJECT_H
27
28#include "CommonIdentifiers.h"
29#include "ExecState.h"
30#include "JSType.h"
31#include "list.h"
32#include "property_map.h"
33#include "property_slot.h"
34#include "scope_chain.h"
35
36namespace KJS {
37
38 class InternalFunctionImp;
39 class PropertyNameArray;
40
41 struct HashEntry;
42 struct HashTable;
43
44 // ECMA 262-3 8.6.1
45 // Property attributes
46 enum Attribute { None = 0,
47 ReadOnly = 1 << 1, // property can be only read, not written
48 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
49 DontDelete = 1 << 3, // property can't be deleted
50 Function = 1 << 4, // property is a function - only used by static hashtables
51 GetterSetter = 1 << 5 }; // property is a getter or setter
52
53 /**
54 * Class Information
55 */
56 struct ClassInfo {
57 /**
58 * A string denoting the class name. Example: "Window".
59 */
60 const char* className;
61 /**
62 * Pointer to the class information of the base class.
63 * 0L if there is none.
64 */
65 const ClassInfo* parentClass;
66 /**
67 * Static hash-table of properties.
68 * For classes that can be used from multiple threads, it is accessed via a getter function that would typically return a pointer to thread-specific value.
69 */
70 const HashTable* propHashTable(ExecState* exec) const
71 {
72 if (classPropHashTableGetterFunction)
73 return classPropHashTableGetterFunction(exec);
74 return staticPropHashTable;
75 }
76
77 const HashTable* staticPropHashTable;
78 typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*);
79 const ClassPropHashTableGetterFunction classPropHashTableGetterFunction;
80 };
81
82 // This is an internal value object which stores getter and setter functions
83 // for a property.
84 class GetterSetterImp : public JSCell {
85 public:
86 JSType type() const { return GetterSetterType; }
87
88 GetterSetterImp() : getter(0), setter(0) { }
89
90 virtual JSValue* toPrimitive(ExecState*, JSType preferred = UnspecifiedType) const;
91 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
92 virtual bool toBoolean(ExecState *exec) const;
93 virtual double toNumber(ExecState *exec) const;
94 virtual UString toString(ExecState *exec) const;
95 virtual JSObject *toObject(ExecState *exec) const;
96
97 virtual void mark();
98
99 JSObject *getGetter() { return getter; }
100 void setGetter(JSObject *g) { getter = g; }
101 JSObject *getSetter() { return setter; }
102 void setSetter(JSObject *s) { setter = s; }
103
104 private:
105 JSObject *getter;
106 JSObject *setter;
107 };
108
109 class JSObject : public JSCell {
110 public:
111 /**
112 * Creates a new JSObject with the specified prototype
113 *
114 * @param proto The prototype
115 */
116 JSObject(JSValue* proto);
117
118 /**
119 * Creates a new JSObject with a prototype of jsNull()
120 * (that is, the ECMAScript "null" value, not a null object pointer).
121 */
122 JSObject();
123
124 virtual void mark();
125 virtual JSType type() const;
126
127 /**
128 * A pointer to a ClassInfo struct for this class. This provides a basic
129 * facility for run-time type information, and can be used to check an
130 * object's class an inheritance (see inherits()). This should
131 * always return a statically declared pointer, or 0 to indicate that
132 * there is no class information.
133 *
134 * This is primarily useful if you have application-defined classes that you
135 * wish to check against for casting purposes.
136 *
137 * For example, to specify the class info for classes FooImp and BarImp,
138 * where FooImp inherits from BarImp, you would add the following in your
139 * class declarations:
140 *
141 * \code
142 * class BarImp : public JSObject {
143 * virtual const ClassInfo *classInfo() const { return &info; }
144 * static const ClassInfo info;
145 * // ...
146 * };
147 *
148 * class FooImp : public JSObject {
149 * virtual const ClassInfo *classInfo() const { return &info; }
150 * static const ClassInfo info;
151 * // ...
152 * };
153 * \endcode
154 *
155 * And in your source file:
156 *
157 * \code
158 * const ClassInfo BarImp::info = { "Bar", 0, 0, 0 }; // no parent class
159 * const ClassInfo FooImp::info = { "Foo", &BarImp::info, 0, 0 };
160 * \endcode
161 *
162 * @see inherits()
163 */
164 virtual const ClassInfo *classInfo() const;
165
166 /**
167 * Checks whether this object inherits from the class with the specified
168 * classInfo() pointer. This requires that both this class and the other
169 * class return a non-NULL pointer for their classInfo() methods (otherwise
170 * it will return false).
171 *
172 * For example, for two JSObject pointers obj1 and obj2, you can check
173 * if obj1's class inherits from obj2's class using the following:
174 *
175 * if (obj1->inherits(obj2->classInfo())) {
176 * // ...
177 * }
178 *
179 * If you have a handle to a statically declared ClassInfo, such as in the
180 * classInfo() example, you can check for inheritance without needing
181 * an instance of the other class:
182 *
183 * if (obj1->inherits(FooImp::info)) {
184 * // ...
185 * }
186 *
187 * @param cinfo The ClassInfo pointer for the class you want to check
188 * inheritance against.
189 * @return true if this object's class inherits from class with the
190 * ClassInfo pointer specified in cinfo
191 */
192 bool inherits(const ClassInfo *cinfo) const;
193
194 // internal properties (ECMA 262-3 8.6.2)
195
196 /**
197 * Returns the prototype of this object. Note that this is not the same as
198 * the "prototype" property.
199 *
200 * See ECMA 8.6.2
201 *
202 * @return The object's prototype
203 */
204 JSValue *prototype() const;
205 void setPrototype(JSValue *proto);
206
207 /**
208 * Returns the class name of the object
209 *
210 * See ECMA 8.6.2
211 *
212 * @return The object's class name
213 */
214 /**
215 * Implementation of the [[Class]] internal property (implemented by all
216 * Objects)
217 *
218 * The default implementation uses classInfo().
219 * You should either implement classInfo(), or
220 * if you simply need a classname, you can reimplement className()
221 * instead.
222 */
223 virtual UString className() const;
224
225 /**
226 * Retrieves the specified property from the object. If neither the object
227 * or any other object in it's prototype chain have the property, this
228 * function will return Undefined.
229 *
230 * See ECMA 8.6.2.1
231 *
232 * @param exec The current execution state
233 * @param propertyName The name of the property to retrieve
234 *
235 * @return The specified property, or Undefined
236 */
237 JSValue *get(ExecState *exec, const Identifier &propertyName) const;
238 JSValue *get(ExecState *exec, unsigned propertyName) const;
239
240 bool getPropertySlot(ExecState *, const Identifier&, PropertySlot&);
241 bool getPropertySlot(ExecState *, unsigned, PropertySlot&);
242
243 virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
244 virtual bool getOwnPropertySlot(ExecState *, unsigned index, PropertySlot&);
245
246 /**
247 * Sets the specified property.
248 *
249 * See ECMA 8.6.2.2
250 *
251 * @param exec The current execution state
252 * @param propertyName The name of the property to set
253 * @param propertyValue The value to set
254 */
255 virtual void put(ExecState*, const Identifier& propertyName, JSValue* value);
256 virtual void put(ExecState*, unsigned propertyName, JSValue* value);
257
258 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes);
259 virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue* value, unsigned attributes);
260
261 /**
262 * Checks if a property is enumerable, that is if it doesn't have the DontEnum
263 * flag set
264 *
265 * See ECMA 15.2.4
266 * @param exec The current execution state
267 * @param propertyName The name of the property
268 * @return true if the property is enumerable, otherwise false
269 */
270 bool propertyIsEnumerable(ExecState *exec, const Identifier &propertyName) const;
271
272 /**
273 * Checks to see whether the object (or any object in it's prototype chain)
274 * has a property with the specified name.
275 *
276 * See ECMA 8.6.2.4
277 *
278 * @param exec The current execution state
279 * @param propertyName The name of the property to check for
280 * @return true if the object has the property, otherwise false
281 */
282 bool hasProperty(ExecState*, const Identifier&) const;
283 bool hasProperty(ExecState*, unsigned) const;
284 bool hasOwnProperty(ExecState*, const Identifier&) const;
285
286 /**
287 * Removes the specified property from the object.
288 *
289 * See ECMA 8.6.2.5
290 *
291 * @param exec The current execution state
292 * @param propertyName The name of the property to delete
293 * @return true if the property was successfully deleted or did not
294 * exist on the object. false if deleting the specified property is not
295 * allowed.
296 */
297 virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName);
298 virtual bool deleteProperty(ExecState *exec, unsigned propertyName);
299
300 /**
301 * Converts the object into a primitive value. The value return may differ
302 * depending on the supplied hint
303 *
304 * See ECMA 8.6.2.6
305 *
306 * @param exec The current execution state
307 * @param hint The desired primitive type to convert to
308 * @return A primitive value converted from the objetc. Note that the
309 * type of primitive value returned may not be the same as the requested
310 * hint.
311 */
312 /**
313 * Implementation of the [[DefaultValue]] internal property (implemented by
314 * all Objects)
315 */
316 virtual JSValue *defaultValue(ExecState *exec, JSType hint) const;
317
318 /**
319 * Whether or not the object implements the construct() method. If this
320 * returns false you should not call the construct() method on this
321 * object (typically, an assertion will fail to indicate this).
322 *
323 * @return true if this object implements the construct() method, otherwise
324 * false
325 */
326 virtual bool implementsConstruct() const;
327
328 /**
329 * Creates a new object based on this object. Typically this means the
330 * following:
331 * 1. A new object is created
332 * 2. The prototype of the new object is set to the value of this object's
333 * "prototype" property
334 * 3. The call() method of this object is called, with the new object
335 * passed as the this value
336 * 4. The new object is returned
337 *
338 * In some cases, Host objects may differ from these semantics, although
339 * this is discouraged.
340 *
341 * If an error occurs during construction, the execution state's exception
342 * will be set. This can be tested for with ExecState::hadException().
343 * Under some circumstances, the exception object may also be returned.
344 *
345 * Note: This function should not be called if implementsConstruct() returns
346 * false, in which case it will result in an assertion failure.
347 *
348 * @param exec The current execution state
349 * @param args The arguments to be passed to call() once the new object has
350 * been created
351 * @return The newly created &amp; initialized object
352 */
353 /**
354 * Implementation of the [[Construct]] internal property
355 */
356 virtual JSObject* construct(ExecState* exec, const List& args);
357 virtual JSObject* construct(ExecState* exec, const List& args, const Identifier& functionName, const UString& sourceURL, int lineNumber);
358
359 /**
360 * Whether or not the object implements the call() method. If this returns
361 * false you should not call the call() method on this object (typically,
362 * an assertion will fail to indicate this).
363 *
364 * @return true if this object implements the call() method, otherwise
365 * false
366 */
367 virtual bool implementsCall() const;
368
369 /**
370 * Calls this object as if it is a function.
371 *
372 * Note: This function should not be called if implementsCall() returns
373 * false, in which case it will result in an assertion failure.
374 *
375 * See ECMA 8.6.2.3
376 *
377 * @param exec The current execution state
378 * @param thisObj The obj to be used as "this" within function execution.
379 * Note that in most cases this will be different from the C++ "this"
380 * object. For example, if the ECMAScript code "window.location->toString()"
381 * is executed, call() will be invoked on the C++ object which implements
382 * the toString method, with the thisObj being window.location
383 * @param args List of arguments to be passed to the function
384 * @return The return value from the function
385 */
386 JSValue *call(ExecState *exec, JSObject *thisObj, const List &args);
387 virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
388
389 /**
390 * Whether or not the object implements the hasInstance() method. If this
391 * returns false you should not call the hasInstance() method on this
392 * object (typically, an assertion will fail to indicate this).
393 *
394 * @return true if this object implements the hasInstance() method,
395 * otherwise false
396 */
397 virtual bool implementsHasInstance() const;
398
399 /**
400 * Checks whether value delegates behavior to this object. Used by the
401 * instanceof operator.
402 *
403 * @param exec The current execution state
404 * @param value The value to check
405 * @return true if value delegates behavior to this object, otherwise
406 * false
407 */
408 virtual bool hasInstance(ExecState *exec, JSValue *value);
409
410 virtual void getPropertyNames(ExecState*, PropertyNameArray&);
411
412 virtual JSValue* toPrimitive(ExecState*, JSType preferredType = UnspecifiedType) const;
413 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
414 virtual bool toBoolean(ExecState *exec) const;
415 virtual double toNumber(ExecState *exec) const;
416 virtual UString toString(ExecState *exec) const;
417 virtual JSObject *toObject(ExecState *exec) const;
418
419 virtual JSObject* toThisObject(ExecState*) const;
420 virtual JSGlobalObject* toGlobalObject(ExecState*) const;
421
422 virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
423
424 // WebCore uses this to make document.all and style.filter undetectable
425 virtual bool masqueradeAsUndefined() const { return false; }
426
427 // This get function only looks at the property map.
428 // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
429 // to look up in the prototype, it might already exist there)
430 JSValue *getDirect(const Identifier& propertyName) const
431 { return _prop.get(propertyName); }
432 JSValue **getDirectLocation(const Identifier& propertyName)
433 { return _prop.getLocation(propertyName); }
434 void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0);
435 void putDirect(const Identifier &propertyName, int value, int attr = 0);
436 void removeDirect(const Identifier &propertyName);
437
438 // convenience to add a function property under the function's own built-in name
439 void putDirectFunction(InternalFunctionImp*, int attr = 0);
440
441 void fillGetterPropertySlot(PropertySlot& slot, JSValue **location);
442
443 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction);
444 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction);
445 virtual JSValue* lookupGetter(ExecState*, const Identifier& propertyName);
446 virtual JSValue* lookupSetter(ExecState*, const Identifier& propertyName);
447
448 virtual bool isActivationObject() const { return false; }
449 virtual bool isGlobalObject() const { return false; }
450 virtual bool isVariableObject() const { return false; }
451
452 protected:
453 PropertyMap _prop;
454
455 private:
456 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
457 JSValue *_proto;
458 };
459
460 /**
461 * Types of Native Errors available. For custom errors, GeneralError
462 * should be used.
463 */
464 enum ErrorType { GeneralError = 0,
465 EvalError = 1,
466 RangeError = 2,
467 ReferenceError = 3,
468 SyntaxError = 4,
469 TypeError = 5,
470 URIError = 6};
471
472 /**
473 * @short Factory methods for error objects.
474 */
475 class Error {
476 public:
477 /**
478 * Factory method for error objects.
479 *
480 * @param exec The current execution state
481 * @param errtype Type of error.
482 * @param message Optional error message.
483 * @param lineNumber Optional line number.
484 * @param sourceId Optional source id.
485 * @param sourceURL Optional source URL.
486 */
487 static JSObject *create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL);
488 static JSObject *create(ExecState *, ErrorType, const char *message);
489
490 /**
491 * Array of error names corresponding to ErrorType
492 */
493 static const char * const * const errorNames;
494 };
495
496JSObject *throwError(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL);
497JSObject *throwError(ExecState *, ErrorType, const UString &message);
498JSObject *throwError(ExecState *, ErrorType, const char *message);
499JSObject *throwError(ExecState *, ErrorType);
500
501inline JSObject::JSObject(JSValue* proto)
502 : _proto(proto)
503{
504 ASSERT(proto);
505}
506
507inline JSObject::JSObject()
508 : _proto(jsNull())
509{
510}
511
512inline JSValue *JSObject::prototype() const
513{
514 return _proto;
515}
516
517inline void JSObject::setPrototype(JSValue *proto)
518{
519 ASSERT(proto);
520 _proto = proto;
521}
522
523inline bool JSObject::inherits(const ClassInfo *info) const
524{
525 for (const ClassInfo *ci = classInfo(); ci; ci = ci->parentClass)
526 if (ci == info)
527 return true;
528 return false;
529}
530
531// this method is here to be after the inline declaration of JSObject::inherits
532inline bool JSCell::isObject(const ClassInfo *info) const
533{
534 return isObject() && static_cast<const JSObject *>(this)->inherits(info);
535}
536
537// this method is here to be after the inline declaration of JSCell::isObject
538inline bool JSValue::isObject(const ClassInfo *c) const
539{
540 return !JSImmediate::isImmediate(this) && asCell()->isObject(c);
541}
542
543// It may seem crazy to inline a function this large but it makes a big difference
544// since this is function very hot in variable lookup
545inline bool JSObject::getPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
546{
547 JSObject *object = this;
548 while (true) {
549 if (object->getOwnPropertySlot(exec, propertyName, slot))
550 return true;
551
552 JSValue *proto = object->_proto;
553 if (!proto->isObject())
554 return false;
555
556 object = static_cast<JSObject *>(proto);
557 }
558}
559
560// It may seem crazy to inline a function this large, especially a virtual function,
561// but it makes a big difference to property lookup that derived classes can inline their
562// base class call to this.
563ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
564{
565 if (JSValue **location = getDirectLocation(propertyName)) {
566 if (_prop.hasGetterSetterProperties() && location[0]->type() == GetterSetterType)
567 fillGetterPropertySlot(slot, location);
568 else
569 slot.setValueSlot(this, location);
570 return true;
571 }
572
573 // non-standard Netscape extension
574 if (propertyName == exec->propertyNames().underscoreProto) {
575 slot.setValueSlot(this, &_proto);
576 return true;
577 }
578
579 return false;
580}
581
582inline void ScopeChain::release()
583{
584 // This function is only called by deref(),
585 // Deref ensures these conditions are true.
586 ASSERT(_node && _node->refCount == 0);
587 ScopeChainNode *n = _node;
588 do {
589 ScopeChainNode *next = n->next;
590 delete n;
591 n = next;
592 } while (n && --n->refCount == 0);
593}
594
595inline JSValue* JSObject::toPrimitive(ExecState* exec, JSType preferredType) const
596{
597 return defaultValue(exec, preferredType);
598}
599
600} // namespace
601
602#endif // KJS_OBJECT_H
Note: See TracBrowser for help on using the repository browser.