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