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

Last change on this file since 12512 was 12489, checked in by andersca, 19 years ago

2006-01-30 Anders Carlsson <[email protected]>

Reviewed by Darin.

Fix http://bugzilla.opendarwin.org/show_bug.cgi?id=6907
REGRESSION: United.com menus messed up due to document.all/MSIE sniff


  • kjs/nodes.cpp: (typeStringForValue): Return "undefined" if the given object should masquerade as undefined.


  • kjs/object.h: (KJS::JSObject::masqueradeAsUndefined): Rename from isEqualToNull.


  • kjs/operations.cpp: (KJS::equal): Update for name change.
  • Property svn:eol-style set to native
File size: 23.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 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// Objects
29
30// maximum global call stack size. Protects against accidental or
31// malicious infinite recursions. Define to -1 if you want no limit.
32#if __APPLE__
33// Given OS X stack sizes we run out of stack at about 350 levels.
34// If we improve our stack usage, we can bump this number.
35#define KJS_MAX_STACK 100
36#else
37#define KJS_MAX_STACK 1000
38#endif
39
40#include "interpreter.h"
41#include "property_map.h"
42#include "property_slot.h"
43#include "scope_chain.h"
44
45namespace KJS {
46
47 class HashTable;
48 class HashEntry;
49 class ListImp;
50
51 // ECMA 262-3 8.6.1
52 // Property attributes
53 enum Attribute { None = 0,
54 ReadOnly = 1 << 1, // property can be only read, not written
55 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
56 DontDelete = 1 << 3, // property can't be deleted
57 Internal = 1 << 4, // an internal property, set to bypass checks
58 Function = 1 << 5, // property is a function - only used by static hashtables
59 GetterSetter = 1 << 6 }; // property is a getter or setter
60
61 /**
62 * Class Information
63 */
64 struct ClassInfo {
65 /**
66 * A string denoting the class name. Example: "Window".
67 */
68 const char* className;
69 /**
70 * Pointer to the class information of the base class.
71 * 0L if there is none.
72 */
73 const ClassInfo *parentClass;
74 /**
75 * Static hash-table of properties.
76 */
77 const HashTable *propHashTable;
78 /**
79 * Reserved for future extension.
80 */
81 void *dummy;
82 };
83
84 // This is an internal value object which stores getter and setter functions
85 // for a property.
86 class GetterSetterImp : public JSCell {
87 public:
88 Type type() const { return GetterSetterType; }
89
90 GetterSetterImp() : getter(0), setter(0) { }
91
92 virtual JSValue *toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
93 virtual bool toBoolean(ExecState *exec) const;
94 virtual double toNumber(ExecState *exec) const;
95 virtual UString toString(ExecState *exec) const;
96 virtual JSObject *toObject(ExecState *exec) const;
97
98 virtual void mark();
99
100 JSObject *getGetter() { return getter; }
101 void setGetter(JSObject *g) { getter = g; }
102 JSObject *getSetter() { return setter; }
103 void setSetter(JSObject *s) { setter = s; }
104
105 private:
106 JSObject *getter;
107 JSObject *setter;
108 };
109
110 class JSObject : public JSCell {
111 public:
112 /**
113 * Creates a new JSObject with the specified prototype
114 *
115 * @param proto The prototype
116 */
117 JSObject(JSObject *proto);
118
119 /**
120 * Creates a new JSObject with a prototype of jsNull()
121 * (that is, the ECMAScript "null" value, not a null object pointer).
122 */
123 JSObject();
124
125 virtual void mark();
126 virtual Type type() const;
127
128 /**
129 * A pointer to a ClassInfo struct for this class. This provides a basic
130 * facility for run-time type information, and can be used to check an
131 * object's class an inheritance (see inherits()). This should
132 * always return a statically declared pointer, or 0 to indicate that
133 * there is no class information.
134 *
135 * This is primarily useful if you have application-defined classes that you
136 * wish to check against for casting purposes.
137 *
138 * For example, to specify the class info for classes FooImp and BarImp,
139 * where FooImp inherits from BarImp, you would add the following in your
140 * class declarations:
141 *
142 * \code
143 * class BarImp : public JSObject {
144 * virtual const ClassInfo *classInfo() const { return &info; }
145 * static const ClassInfo info;
146 * // ...
147 * };
148 *
149 * class FooImp : public JSObject {
150 * virtual const ClassInfo *classInfo() const { return &info; }
151 * static const ClassInfo info;
152 * // ...
153 * };
154 * \endcode
155 *
156 * And in your source file:
157 *
158 * \code
159 * const ClassInfo BarImp::info = {"Bar", 0, 0, 0}; // no parent class
160 * const ClassInfo FooImp::info = {"Foo", &BarImp::info, 0, 0};
161 * \endcode
162 *
163 * @see inherits()
164 */
165 virtual const ClassInfo *classInfo() const;
166
167 /**
168 * Checks whether this object inherits from the class with the specified
169 * classInfo() pointer. This requires that both this class and the other
170 * class return a non-NULL pointer for their classInfo() methods (otherwise
171 * it will return false).
172 *
173 * For example, for two JSObject pointers obj1 and obj2, you can check
174 * if obj1's class inherits from obj2's class using the following:
175 *
176 * if (obj1->inherits(obj2->classInfo())) {
177 * // ...
178 * }
179 *
180 * If you have a handle to a statically declared ClassInfo, such as in the
181 * classInfo() example, you can check for inheritance without needing
182 * an instance of the other class:
183 *
184 * if (obj1->inherits(FooImp::info)) {
185 * // ...
186 * }
187 *
188 * @param cinfo The ClassInfo pointer for the class you want to check
189 * inheritance against.
190 * @return true if this object's class inherits from class with the
191 * ClassInfo pointer specified in cinfo
192 */
193 bool inherits(const ClassInfo *cinfo) const;
194
195 // internal properties (ECMA 262-3 8.6.2)
196
197 /**
198 * Returns the prototype of this object. Note that this is not the same as
199 * the "prototype" property.
200 *
201 * See ECMA 8.6.2
202 *
203 * @return The object's prototype
204 */
205 JSValue *prototype() const;
206 void setPrototype(JSValue *proto);
207
208 /**
209 * Returns the class name of the object
210 *
211 * See ECMA 8.6.2
212 *
213 * @return The object's class name
214 */
215 /**
216 * Implementation of the [[Class]] internal property (implemented by all
217 * Objects)
218 *
219 * The default implementation uses classInfo().
220 * You should either implement classInfo(), or
221 * if you simply need a classname, you can reimplement className()
222 * instead.
223 */
224 virtual UString className() const;
225
226 /**
227 * Retrieves the specified property from the object. If neither the object
228 * or any other object in it's prototype chain have the property, this
229 * function will return Undefined.
230 *
231 * See ECMA 8.6.2.1
232 *
233 * @param exec The current execution state
234 * @param propertyName The name of the property to retrieve
235 *
236 * @return The specified property, or Undefined
237 */
238 JSValue *get(ExecState *exec, const Identifier &propertyName) const;
239 JSValue *get(ExecState *exec, unsigned propertyName) const;
240
241 bool getPropertySlot(ExecState *, const Identifier&, PropertySlot&);
242 bool getPropertySlot(ExecState *, unsigned, PropertySlot&);
243
244 virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
245 virtual bool getOwnPropertySlot(ExecState *, unsigned index, PropertySlot&);
246
247 /**
248 * Sets the specified property.
249 *
250 * See ECMA 8.6.2.2
251 *
252 * @param exec The current execution state
253 * @param propertyName The name of the property to set
254 * @param propertyValue The value to set
255 */
256 virtual void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr = None);
257 virtual void put(ExecState *exec, unsigned propertyName, JSValue *value, int attr = None);
258
259 /**
260 * Used to check whether or not a particular property is allowed to be set
261 * on an object
262 *
263 * See ECMA 8.6.2.3
264 *
265 * @param exec The current execution state
266 * @param propertyName The name of the property
267 * @return true if the property can be set, otherwise false
268 */
269 /**
270 * Implementation of the [[CanPut]] internal property (implemented by all
271 * Objects)
272 */
273 virtual bool canPut(ExecState *exec, const Identifier &propertyName) const;
274
275 /**
276 * Checks if a property is enumerable, that is if it doesn't have the DontEnum
277 * flag set
278 *
279 * See ECMA 15.2.4
280 * @param exec The current execution state
281 * @param propertyName The name of the property
282 * @return true if the property is enumerable, otherwise false
283 */
284 bool propertyIsEnumerable(ExecState *exec, const Identifier &propertyName) const;
285
286 /**
287 * Checks to see whether the object (or any object in it's prototype chain)
288 * has a property with the specified name.
289 *
290 * See ECMA 8.6.2.4
291 *
292 * @param exec The current execution state
293 * @param propertyName The name of the property to check for
294 * @return true if the object has the property, otherwise false
295 */
296 bool hasProperty(ExecState *exec, const Identifier &propertyName) const;
297 bool hasProperty(ExecState *exec, unsigned propertyName) const;
298
299 /**
300 * Removes the specified property from the object.
301 *
302 * See ECMA 8.6.2.5
303 *
304 * @param exec The current execution state
305 * @param propertyName The name of the property to delete
306 * @return true if the property was successfully deleted or did not
307 * exist on the object. false if deleting the specified property is not
308 * allowed.
309 */
310 virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName);
311 virtual bool deleteProperty(ExecState *exec, unsigned propertyName);
312
313 /**
314 * Converts the object into a primitive value. The value return may differ
315 * depending on the supplied hint
316 *
317 * See ECMA 8.6.2.6
318 *
319 * @param exec The current execution state
320 * @param hint The desired primitive type to convert to
321 * @return A primitive value converted from the objetc. Note that the
322 * type of primitive value returned may not be the same as the requested
323 * hint.
324 */
325 /**
326 * Implementation of the [[DefaultValue]] internal property (implemented by
327 * all Objects)
328 */
329 virtual JSValue *defaultValue(ExecState *exec, Type hint) const;
330
331 /**
332 * Whether or not the object implements the construct() method. If this
333 * returns false you should not call the construct() method on this
334 * object (typically, an assertion will fail to indicate this).
335 *
336 * @return true if this object implements the construct() method, otherwise
337 * false
338 */
339 virtual bool implementsConstruct() const;
340
341 /**
342 * Creates a new object based on this object. Typically this means the
343 * following:
344 * 1. A new object is created
345 * 2. The prototype of the new object is set to the value of this object's
346 * "prototype" property
347 * 3. The call() method of this object is called, with the new object
348 * passed as the this value
349 * 4. The new object is returned
350 *
351 * In some cases, Host objects may differ from these semantics, although
352 * this is discouraged.
353 *
354 * If an error occurs during construction, the execution state's exception
355 * will be set. This can be tested for with ExecState::hadException().
356 * Under some circumstances, the exception object may also be returned.
357 *
358 * Note: This function should not be called if implementsConstruct() returns
359 * false, in which case it will result in an assertion failure.
360 *
361 * @param exec The current execution state
362 * @param args The arguments to be passed to call() once the new object has
363 * been created
364 * @return The newly created &amp; initialized object
365 */
366 /**
367 * Implementation of the [[Construct]] internal property
368 */
369 virtual JSObject *construct(ExecState *exec, const List &args);
370 virtual JSObject *construct(ExecState *exec, const List &args, const UString &sourceURL, int lineNumber);
371
372 /**
373 * Whether or not the object implements the call() method. If this returns
374 * false you should not call the call() method on this object (typically,
375 * an assertion will fail to indicate this).
376 *
377 * @return true if this object implements the call() method, otherwise
378 * false
379 */
380 virtual bool implementsCall() const;
381
382 /**
383 * Calls this object as if it is a function.
384 *
385 * Note: This function should not be called if implementsCall() returns
386 * false, in which case it will result in an assertion failure.
387 *
388 * See ECMA 8.6.2.3
389 *
390 * @param exec The current execution state
391 * @param thisObj The obj to be used as "this" within function execution.
392 * Note that in most cases this will be different from the C++ "this"
393 * object. For example, if the ECMAScript code "window.location->toString()"
394 * is executed, call() will be invoked on the C++ object which implements
395 * the toString method, with the thisObj being window.location
396 * @param args List of arguments to be passed to the function
397 * @return The return value from the function
398 */
399 JSValue *call(ExecState *exec, JSObject *thisObj, const List &args);
400 virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
401
402 /**
403 * Whether or not the object implements the hasInstance() method. If this
404 * returns false you should not call the hasInstance() method on this
405 * object (typically, an assertion will fail to indicate this).
406 *
407 * @return true if this object implements the hasInstance() method,
408 * otherwise false
409 */
410 virtual bool implementsHasInstance() const;
411
412 /**
413 * Checks whether value delegates behavior to this object. Used by the
414 * instanceof operator.
415 *
416 * @param exec The current execution state
417 * @param value The value to check
418 * @return true if value delegates behavior to this object, otherwise
419 * false
420 */
421 virtual bool hasInstance(ExecState *exec, JSValue *value);
422
423 /**
424 * Returns the scope of this object. This is used when execution declared
425 * functions - the execution context for the function is initialized with
426 * extra object in it's scope. An example of this is functions declared
427 * inside other functions:
428 *
429 * \code
430 * function f() {
431 *
432 * function b() {
433 * return prototype;
434 * }
435 *
436 * var x = 4;
437 * // do some stuff
438 * }
439 * f.prototype = new String();
440 * \endcode
441 *
442 * When the function f.b is executed, its scope will include properties of
443 * f. So in the example above the return value of f.b() would be the new
444 * String object that was assigned to f.prototype.
445 *
446 * @param exec The current execution state
447 * @return The function's scope
448 */
449 const ScopeChain &scope() const { return _scope; }
450 void setScope(const ScopeChain &s) { _scope = s; }
451
452 /**
453 * Returns a List of References to all the properties of the object. Used
454 * in "for x in y" statements. The list is created new, so it can be freely
455 * modified without affecting the object's properties. It should be deleted
456 * by the caller.
457 *
458 * Subclasses can override this method in ObjectImpl to provide the
459 * appearance of
460 * having extra properties other than those set specifically with put().
461 *
462 * @param exec The current execution state
463 * @param recursive Whether or not properties in the object's prototype
464 * chain should be
465 * included in the list.
466 * @return A List of References to properties of the object.
467 **/
468 virtual ReferenceList propList(ExecState *exec, bool recursive = true);
469
470 /**
471 * Returns the internal value of the object. This is used for objects such
472 * as String and Boolean which are wrappers for native types. The interal
473 * value is the actual value represented by the wrapper objects.
474 *
475 * @see ECMA 8.6.2
476 * @return The internal value of the object
477 */
478 JSValue *internalValue() const;
479
480 /**
481 * Sets the internal value of the object
482 *
483 * @see internalValue()
484 *
485 * @param v The new internal value
486 */
487 void setInternalValue(JSValue *v);
488
489 JSValue *toPrimitive(ExecState *exec, Type preferredType = UnspecifiedType) const;
490 bool toBoolean(ExecState *exec) const;
491 double toNumber(ExecState *exec) const;
492 UString toString(ExecState *exec) const;
493 JSObject *toObject(ExecState *exec) const;
494
495 bool getPropertyAttributes(const Identifier& propertyName, int& attributes) const;
496
497 // Returns whether the object should be treated as undefined when doing equality comparisons
498 virtual bool masqueradeAsUndefined() const { return false; }
499
500 // This get function only looks at the property map.
501 // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
502 // to look up in the prototype, it might already exist there)
503 JSValue *getDirect(const Identifier& propertyName) const
504 { return _prop.get(propertyName); }
505 JSValue **getDirectLocation(const Identifier& propertyName)
506 { return _prop.getLocation(propertyName); }
507 void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0);
508 void putDirect(const Identifier &propertyName, int value, int attr = 0);
509
510 void fillGetterPropertySlot(PropertySlot& slot, JSValue **location);
511
512 void defineGetter(ExecState *exec, const Identifier& propertyName, JSObject *getterFunc);
513 void defineSetter(ExecState *exec, const Identifier& propertyName, JSObject *setterFunc);
514
515 /**
516 * Remove all properties from this object.
517 * This doesn't take DontDelete into account, and isn't in the ECMA spec.
518 * It's simply a quick way to remove everything stored in the property map.
519 */
520 void clearProperties() { _prop.clear(); }
521
522 void saveProperties(SavedProperties &p) const { _prop.save(p); }
523 void restoreProperties(const SavedProperties &p) { _prop.restore(p); }
524
525 virtual bool isActivation() { return false; }
526 protected:
527 PropertyMap _prop;
528 private:
529 const HashEntry* findPropertyHashEntry( const Identifier& propertyName ) const;
530 JSValue *_proto;
531 JSValue *_internalValue;
532 ScopeChain _scope;
533 };
534
535 /**
536 * Types of Native Errors available. For custom errors, GeneralError
537 * should be used.
538 */
539 enum ErrorType { GeneralError = 0,
540 EvalError = 1,
541 RangeError = 2,
542 ReferenceError = 3,
543 SyntaxError = 4,
544 TypeError = 5,
545 URIError = 6};
546
547 /**
548 * @short Factory methods for error objects.
549 */
550 class Error {
551 public:
552 /**
553 * Factory method for error objects.
554 *
555 * @param exec The current execution state
556 * @param errtype Type of error.
557 * @param message Optional error message.
558 * @param lineNumber Optional line number.
559 * @param sourceId Optional source id.
560 * @param sourceURL Optional source URL.
561 */
562 static JSObject *create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString *sourceURL);
563 static JSObject *create(ExecState *, ErrorType, const char *message);
564
565 /**
566 * Array of error names corresponding to ErrorType
567 */
568 static const char * const * const errorNames;
569 };
570
571JSObject *throwError(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString *sourceURL);
572JSObject *throwError(ExecState *, ErrorType, const UString &message);
573JSObject *throwError(ExecState *, ErrorType, const char *message);
574JSObject *throwError(ExecState *, ErrorType);
575
576inline JSObject::JSObject(JSObject *proto)
577 : _proto(proto), _internalValue(0)
578{
579 assert(proto);
580}
581
582inline JSObject::JSObject()
583 : _proto(jsNull()), _internalValue(0)
584{
585}
586
587inline JSValue *JSObject::internalValue() const
588{
589 return _internalValue;
590}
591
592inline void JSObject::setInternalValue(JSValue *v)
593{
594 _internalValue = v;
595}
596
597inline JSValue *JSObject::prototype() const
598{
599 return _proto;
600}
601
602inline void JSObject::setPrototype(JSValue *proto)
603{
604 assert(proto);
605 _proto = proto;
606}
607
608inline bool JSObject::inherits(const ClassInfo *info) const
609{
610 for (const ClassInfo *ci = classInfo(); ci; ci = ci->parentClass)
611 if (ci == info)
612 return true;
613 return false;
614}
615
616// this method is here to be after the inline declaration of JSObject::inherits
617inline bool JSCell::isObject(const ClassInfo *info) const
618{
619 return isObject() && static_cast<const JSObject *>(this)->inherits(info);
620}
621
622// this method is here to be after the inline declaration of JSCell::isObject
623inline bool JSValue::isObject(const ClassInfo *c) const
624{
625 return !SimpleNumber::is(this) && downcast()->isObject(c);
626}
627
628// It may seem crazy to inline a function this large but it makes a big difference
629// since this is function very hot in variable lookup
630inline bool JSObject::getPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
631{
632 JSObject *object = this;
633 while (true) {
634 if (object->getOwnPropertySlot(exec, propertyName, slot))
635 return true;
636
637 JSValue *proto = object->_proto;
638 if (!proto->isObject())
639 return false;
640
641 object = static_cast<JSObject *>(proto);
642 }
643}
644
645// It may seem crazy to inline a function this large, especially a virtual function,
646// but it makes a big difference to property lookup that derived classes can inline their
647// base class call to this.
648ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
649{
650 if (JSValue **location = getDirectLocation(propertyName)) {
651 if (_prop.hasGetterSetterProperties() && location[0]->type() == GetterSetterType)
652 fillGetterPropertySlot(slot, location);
653 else
654 slot.setValueSlot(this, location);
655 return true;
656 }
657
658 // non-standard Netscape extension
659 if (propertyName == exec->dynamicInterpreter()->specialPrototypeIdentifier()) {
660 slot.setValueSlot(this, &_proto);
661 return true;
662 }
663
664 return false;
665}
666
667// FIXME: Put this function in a separate file named something like scope_chain_mark.h -- can't put it in scope_chain.h since it depends on JSObject.
668
669inline void ScopeChain::mark()
670{
671 for (ScopeChainNode *n = _node; n; n = n->next) {
672 JSObject *o = n->object;
673 if (!o->marked())
674 o->mark();
675 }
676}
677
678} // namespace
679
680#endif // KJS_OBJECT_H
Note: See TracBrowser for help on using the repository browser.