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