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