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