KJS

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

KDE's Doxygen guidelines are available online.