File indexing completed on 2024-05-12 15:43:31
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 0004 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 0005 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 * 0022 */ 0023 0024 #ifndef KJS_OBJECT_H 0025 #define KJS_OBJECT_H 0026 0027 #include "global.h" 0028 #include "JSType.h" 0029 #include "interpreter.h" 0030 #include "property_map.h" 0031 #include "property_slot.h" 0032 #include "scope_chain.h" 0033 #include <wtf/AlwaysInline.h> 0034 #include "propertydescriptor.h" 0035 0036 namespace KJS 0037 { 0038 0039 struct HashTable; 0040 struct HashEntry; 0041 struct ListImp; 0042 class InternalFunctionImp; 0043 class PropertyNameArray; 0044 0045 /** 0046 * Class Information 0047 */ 0048 struct ClassInfo { 0049 /** 0050 * A string denoting the class name. Example: "Window". 0051 */ 0052 const char *className; 0053 /** 0054 * Pointer to the class information of the base class. 0055 * 0L if there is none. 0056 */ 0057 const ClassInfo *parentClass; 0058 /** 0059 * Static hash-table of properties. 0060 */ 0061 const HashTable *propHashTable; 0062 /** 0063 * Reserved for future extension. 0064 */ 0065 void *dummy; 0066 }; 0067 0068 // This is an internal value object which stores getter and setter functions 0069 // for a property. 0070 class GetterSetterImp : public JSCell 0071 { 0072 public: 0073 JSType type() const override 0074 { 0075 return GetterSetterType; 0076 } 0077 0078 GetterSetterImp() : getter(nullptr), setter(nullptr) { } 0079 0080 JSValue *toPrimitive(ExecState *exec, JSType preferred = UnspecifiedType) const override; 0081 bool getPrimitiveNumber(ExecState *, double &number, JSValue *&value) override; 0082 bool toBoolean(ExecState *exec) const override; 0083 double toNumber(ExecState *exec) const override; 0084 UString toString(ExecState *exec) const override; 0085 JSObject *toObject(ExecState *exec) const override; 0086 0087 void mark() override; 0088 0089 JSObject *getGetter() 0090 { 0091 return getter; 0092 } 0093 void setGetter(JSObject *g) 0094 { 0095 getter = g; 0096 } 0097 JSObject *getSetter() 0098 { 0099 return setter; 0100 } 0101 void setSetter(JSObject *s) 0102 { 0103 setter = s; 0104 } 0105 0106 private: 0107 JSObject *getter; 0108 JSObject *setter; 0109 }; 0110 0111 class KJS_EXPORT JSObject : public JSCell 0112 { 0113 public: 0114 /** 0115 * Creates a new JSObject with the specified prototype 0116 * 0117 * @param proto The prototype 0118 */ 0119 explicit JSObject(JSValue *proto); 0120 0121 /** 0122 * Creates a new JSObject with a prototype of jsNull() 0123 * (that is, the ECMAScript "null" value, not a null object pointer). 0124 */ 0125 explicit JSObject(); 0126 0127 void mark() override; 0128 JSType type() const override; 0129 0130 /** 0131 * A pointer to a ClassInfo struct for this class. This provides a basic 0132 * facility for run-time type information, and can be used to check an 0133 * object's class an inheritance (see inherits()). This should 0134 * always return a statically declared pointer, or 0 to indicate that 0135 * there is no class information. 0136 * 0137 * This is primarily useful if you have application-defined classes that you 0138 * wish to check against for casting purposes. 0139 * 0140 * For example, to specify the class info for classes FooImp and BarImp, 0141 * where FooImp inherits from BarImp, you would add the following in your 0142 * class declarations: 0143 * 0144 * \code 0145 * class BarImp : public JSObject { 0146 * virtual const ClassInfo *classInfo() const { return &info; } 0147 * static const ClassInfo info; 0148 * // ... 0149 * }; 0150 * 0151 * class FooImp : public JSObject { 0152 * virtual const ClassInfo *classInfo() const { return &info; } 0153 * static const ClassInfo info; 0154 * // ... 0155 * }; 0156 * \endcode 0157 * 0158 * And in your source file: 0159 * 0160 * \code 0161 * const ClassInfo BarImp::info = {"Bar", 0, 0, 0}; // no parent class 0162 * const ClassInfo FooImp::info = {"Foo", &BarImp::info, 0, 0}; 0163 * \endcode 0164 * 0165 * @see inherits() 0166 */ 0167 virtual const ClassInfo *classInfo() const; 0168 0169 /** 0170 * Checks whether this object inherits from the class with the specified 0171 * classInfo() pointer. This requires that both this class and the other 0172 * class return a non-NULL pointer for their classInfo() methods (otherwise 0173 * it will return false). 0174 * 0175 * For example, for two JSObject pointers obj1 and obj2, you can check 0176 * if obj1's class inherits from obj2's class using the following: 0177 * 0178 * if (obj1->inherits(obj2->classInfo())) { 0179 * // ... 0180 * } 0181 * 0182 * If you have a handle to a statically declared ClassInfo, such as in the 0183 * classInfo() example, you can check for inheritance without needing 0184 * an instance of the other class: 0185 * 0186 * if (obj1->inherits(FooImp::info)) { 0187 * // ... 0188 * } 0189 * 0190 * @param cinfo The ClassInfo pointer for the class you want to check 0191 * inheritance against. 0192 * @return true if this object's class inherits from class with the 0193 * ClassInfo pointer specified in cinfo 0194 */ 0195 bool inherits(const ClassInfo *cinfo) const; 0196 0197 // internal properties (ECMA 262-3 8.6.2) 0198 0199 /** 0200 * Returns the prototype of this object. Note that this is not the same as 0201 * the "prototype" property. 0202 * 0203 * See ECMA 8.6.2 0204 * 0205 * @return The object's prototype 0206 */ 0207 JSValue *prototype() const; 0208 void setPrototype(JSValue *proto); 0209 0210 /** 0211 * Returns the class name of the object 0212 * 0213 * See ECMA 8.6.2 0214 * 0215 * @return The object's class name 0216 */ 0217 /** 0218 * Implementation of the [[Class]] internal property (implemented by all 0219 * Objects) 0220 * 0221 * The default implementation uses classInfo(). 0222 * You should either implement classInfo(), or 0223 * if you simply need a classname, you can reimplement className() 0224 * instead. 0225 */ 0226 virtual UString className() const; 0227 0228 /** 0229 * Retrieves the specified property from the object. If neither the object 0230 * or any other object in its prototype chain have the property, this 0231 * function will return Undefined. 0232 * 0233 * See ECMA 8.6.2.1 0234 * 0235 * @param exec The current execution state 0236 * @param propertyName The name of the property to retrieve 0237 * 0238 * @return The specified property, or Undefined 0239 */ 0240 JSValue *get(ExecState *exec, const Identifier &propertyName) const; 0241 JSValue *get(ExecState *exec, unsigned propertyName) const; 0242 0243 bool getPropertySlot(ExecState *, const Identifier &, PropertySlot &); 0244 bool getPropertySlot(ExecState *, unsigned, PropertySlot &); 0245 // Fills the PropertyDescriptor looking the ownPropertys and all prototypes until found. 0246 bool getPropertyDescriptor(ExecState *, const Identifier &propertyName, PropertyDescriptor &); 0247 0248 virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot &); 0249 virtual bool getOwnPropertySlot(ExecState *, unsigned index, PropertySlot &); 0250 virtual bool getOwnPropertyDescriptor(ExecState *, const Identifier &, PropertyDescriptor &); 0251 0252 /** 0253 * Sets the specified property. 0254 * 0255 * See ECMA 8.6.2.2 0256 * 0257 * @param exec The current execution state 0258 * @param propertyName The name of the property to set 0259 * @param value The value to set 0260 * @param attr The attributes of the property 0261 */ 0262 virtual void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr = None); 0263 virtual void put(ExecState *exec, unsigned propertyName, JSValue *value, int attr = None); 0264 0265 /** 0266 * Used to check whether or not a particular property is allowed to be set 0267 * on an object 0268 * 0269 * See ECMA 8.6.2.3 0270 * 0271 * @param exec The current execution state 0272 * @param propertyName The name of the property 0273 * @return true if the property can be set, otherwise false 0274 */ 0275 /** 0276 * Implementation of the [[CanPut]] internal property (implemented by all 0277 * Objects) 0278 */ 0279 virtual bool canPut(ExecState *exec, const Identifier &propertyName) const; 0280 0281 /** 0282 * Checks if a property is enumerable, that is if it doesn't have the DontEnum 0283 * flag set 0284 * 0285 * See ECMA 15.2.4 0286 * @param exec The current execution state 0287 * @param propertyName The name of the property 0288 * @return true if the property is enumerable, otherwise false 0289 */ 0290 bool propertyIsEnumerable(ExecState *exec, const Identifier &propertyName) const; 0291 0292 /** 0293 * Checks to see whether the object (or any object in its prototype chain) 0294 * has a property with the specified name. 0295 * 0296 * See ECMA 8.6.2.4 0297 * 0298 * @param exec The current execution state 0299 * @param propertyName The name of the property to check for 0300 * @return true if the object has the property, otherwise false 0301 */ 0302 bool hasProperty(ExecState *exec, const Identifier &propertyName) const; 0303 bool hasProperty(ExecState *exec, unsigned propertyName) const; 0304 0305 /** 0306 * Removes the specified property from the object. 0307 * 0308 * See ECMA 8.6.2.5 0309 * 0310 * @param exec The current execution state 0311 * @param propertyName The name of the property to delete 0312 * @return true if the property was successfully deleted or did not 0313 * exist on the object. false if deleting the specified property is not 0314 * allowed. 0315 */ 0316 virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName); 0317 virtual bool deleteProperty(ExecState *exec, unsigned propertyName); 0318 0319 /** 0320 * Converts the object into a primitive value. The value return may differ 0321 * depending on the supplied hint 0322 * 0323 * See ECMA 8.6.2.6 0324 * 0325 * @param exec The current execution state 0326 * @param hint The desired primitive type to convert to 0327 * @return A primitive value converted from the object. Note that the 0328 * type of primitive value returned may not be the same as the requested 0329 * hint. 0330 */ 0331 /** 0332 * Implementation of the [[DefaultValue]] internal property (implemented by 0333 * all Objects) 0334 */ 0335 virtual JSValue *defaultValue(ExecState *exec, JSType hint) const; 0336 0337 /** 0338 * Whether or not the object implements the construct() method. If this 0339 * returns false you should not call the construct() method on this 0340 * object (typically, an assertion will fail to indicate this). 0341 * 0342 * @return true if this object implements the construct() method, otherwise 0343 * false 0344 */ 0345 virtual bool implementsConstruct() const; 0346 0347 /** 0348 * Creates a new object based on this object. Typically this means the 0349 * following: 0350 * 1. A new object is created 0351 * 2. The prototype of the new object is set to the value of this object's 0352 * "prototype" property 0353 * 3. The call() method of this object is called, with the new object 0354 * passed as the this value 0355 * 4. The new object is returned 0356 * 0357 * In some cases, Host objects may differ from these semantics, although 0358 * this is discouraged. 0359 * 0360 * If an error occurs during construction, the execution state's exception 0361 * will be set. This can be tested for with ExecState::hadException(). 0362 * Under some circumstances, the exception object may also be returned. 0363 * 0364 * Note: This function should not be called if implementsConstruct() returns 0365 * false, in which case it will result in an assertion failure. 0366 * 0367 * @param exec The current execution state 0368 * @param args The arguments to be passed to call() once the new object has 0369 * been created 0370 * @return The newly created & initialized object 0371 */ 0372 /** 0373 * Implementation of the [[Construct]] internal property 0374 */ 0375 virtual JSObject *construct(ExecState *exec, const List &args); 0376 virtual JSObject *construct(ExecState *exec, const List &args, const Identifier &functionName, const UString &sourceURL, int lineNumber); 0377 0378 /** 0379 * If this object represents a value, e.g. is a wrapper around a primitive, 0380 * a regexp or a date this will return a fresh object with the same value 0381 * (without cloning properties). Otherwise, returns 0 0382 * 0383 * The returned objects will use default prototypes from targetCtx 0384 */ 0385 virtual JSObject *valueClone(Interpreter *targetCtx) const; 0386 0387 /** 0388 * Whether or not this object should be considered a function for the purpose 0389 * of the typeof operator. Normally this is the same as implementsCall(), 0390 * which is what the default implementation delegates too, 0391 * but in some cases compatibility dictates that the object both be callable 0392 * and call itself an object and not a function. In this case, this method should 0393 * be overridden as well 0394 */ 0395 virtual bool isFunctionType() const; 0396 0397 /** 0398 * Calls this object as if it is a function. 0399 * 0400 * Note: This function should not be called if implementsCall() returns 0401 * false, in which case it will result in an assertion failure. 0402 * 0403 * See ECMA 8.6.2.3 0404 * 0405 * @param exec The current execution state 0406 * @param thisObj The obj to be used as "this" within function execution. 0407 * Note that in most cases this will be different from the C++ "this" 0408 * object. For example, if the ECMAScript code "window.location->toString()" 0409 * is executed, call() will be invoked on the C++ object which implements 0410 * the toString method, with the thisObj being window.location 0411 * @param args List of arguments to be passed to the function 0412 * @return The return value from the function 0413 */ 0414 JSValue *call(ExecState *exec, JSObject *thisObj, const List &args); // ### TODO: consolidate with below 0415 virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args); 0416 0417 /** 0418 * Whether or not the object implements the hasInstance() method. If this 0419 * returns false you should not call the hasInstance() method on this 0420 * object (typically, an assertion will fail to indicate this). 0421 * 0422 * @return true if this object implements the hasInstance() method, 0423 * otherwise false 0424 */ 0425 virtual bool implementsHasInstance() const; 0426 0427 /** 0428 * Checks whether value delegates behavior to this object. Used by the 0429 * instanceof operator. 0430 * 0431 * @param exec The current execution state 0432 * @param value The value to check 0433 * @return true if value delegates behavior to this object, otherwise 0434 * false 0435 */ 0436 virtual bool hasInstance(ExecState *exec, JSValue *value); 0437 0438 void getPropertyNames(ExecState *, PropertyNameArray &, PropertyMap::PropertyMode mode = PropertyMap::ExcludeDontEnumProperties); 0439 virtual void getOwnPropertyNames(ExecState *, PropertyNameArray &, PropertyMap::PropertyMode mode); 0440 0441 JSValue *toPrimitive(ExecState *exec, JSType preferredType = UnspecifiedType) const override; 0442 bool getPrimitiveNumber(ExecState *, double &number, JSValue *&value) override; 0443 bool toBoolean(ExecState *exec) const override; 0444 double toNumber(ExecState *exec) const override; 0445 UString toString(ExecState *exec) const override; 0446 JSObject *toObject(ExecState *exec) const override; 0447 0448 virtual bool getPropertyAttributes(const Identifier &propertyName, unsigned &attributes) const; 0449 0450 // Returns whether the object should be treated as undefined when doing equality comparisons 0451 virtual bool masqueradeAsUndefined() const 0452 { 0453 return false; 0454 } 0455 0456 // This get function only looks at the property map for Object. 0457 // It is virtual because for all custom-data classes we want to by-pass 0458 // the prototype and get it directly. For example called from 0459 // Object::defineOwnProperty to directly get GetterSetterImp and update it. 0460 // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want 0461 // to look up in the prototype, it might already exist there) 0462 virtual JSValue *getDirect(const Identifier &propertyName) const 0463 { 0464 return _prop.get(propertyName); 0465 } 0466 JSValue **getDirectLocation(const Identifier &propertyName) 0467 { 0468 return _prop.getLocation(propertyName); 0469 } 0470 0471 // If this method returns non-0, there is already a property 0472 // with name propertyName that's not readonly and not a setter-getter 0473 // which can be updated via the returned pointer. 0474 JSValue **getDirectWriteLocation(const Identifier &propertyName) 0475 { 0476 return _prop.getWriteLocation(propertyName); 0477 } 0478 0479 // This function is virtual to directly store, by-pass the prototype, values 0480 // for all custom-data classes like the Array. For example an Array with a prototype 0481 // to store values via getter/setter. It would be impossible to store a value 0482 // by-passing the getter/setter prototype. 0483 // This is for example called in Object::defineOwnProperty to directly store the values. 0484 // Same for removeDirect. 0485 virtual void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0) 0486 { 0487 _prop.put(propertyName, value, attr); 0488 } 0489 virtual void putDirect(const Identifier &propertyName, int value, int attr = 0); 0490 virtual void removeDirect(const Identifier &propertyName); 0491 0492 // convenience to add a function property under the function's own built-in name 0493 void putDirectFunction(InternalFunctionImp *, int attr = 0); 0494 0495 void fillGetterPropertySlot(PropertySlot &slot, JSValue **location); 0496 void fillDirectLocationSlot(PropertySlot &slot, JSValue **location); 0497 0498 void defineGetter(ExecState *exec, const Identifier &propertyName, JSObject *getterFunc); 0499 void defineSetter(ExecState *exec, const Identifier &propertyName, JSObject *setterFunc); 0500 0501 virtual bool defineOwnProperty(ExecState *exec, const Identifier &propertyName, PropertyDescriptor &desc, bool shouldThrow); 0502 0503 void preventExtensions(); 0504 bool isExtensible() 0505 { 0506 return _prop.isExtensible(); 0507 } 0508 0509 /** 0510 * Remove all properties from this object. 0511 * This doesn't take DontDelete into account, and isn't in the ECMA spec. 0512 * It's simply a quick way to remove everything stored in the property map. 0513 */ 0514 void clearProperties() 0515 { 0516 _prop.clear(); 0517 } 0518 0519 void saveProperties(SavedProperties &p) const 0520 { 0521 _prop.save(p); 0522 } 0523 void restoreProperties(const SavedProperties &p) 0524 { 0525 _prop.restore(p); 0526 } 0527 0528 virtual bool isActivation() const 0529 { 0530 return false; 0531 } 0532 virtual bool isGlobalObject() const 0533 { 0534 return false; 0535 } 0536 0537 // This is used to keep track of whether scope object have local 0538 // variables introduced by something other than 'var' 0539 bool isLocalInjected() const 0540 { 0541 return _prop.m_objLocalInjected; 0542 } 0543 void setLocalInjected() 0544 { 0545 _prop.m_objLocalInjected = true; 0546 } 0547 0548 protected: 0549 PropertyMap _prop; 0550 private: 0551 0552 const HashEntry *findPropertyHashEntry(const Identifier &propertyName) const; 0553 JSValue *_proto; 0554 #ifdef _WIN32 0555 JSObject(const JSObject &); 0556 JSObject &operator=(const JSObject &); 0557 #endif 0558 }; 0559 0560 /** 0561 * Types of Native Errors available. For custom errors, GeneralError 0562 * should be used. 0563 */ 0564 enum ErrorType { GeneralError = 0, 0565 EvalError = 1, 0566 RangeError = 2, 0567 ReferenceError = 3, 0568 SyntaxError = 4, 0569 TypeError = 5, 0570 URIError = 6 0571 }; 0572 0573 /** 0574 * @short Factory methods for error objects. 0575 */ 0576 class KJS_EXPORT Error 0577 { 0578 public: 0579 /** 0580 * Factory method for error objects. 0581 * 0582 * @param exec The current execution state 0583 * @param errtype Type of error. 0584 * @param message Optional error message. 0585 * @param lineNumber Optional line number. 0586 * @param sourceId Optional source id. 0587 * @param sourceURL Optional source URL. 0588 */ 0589 static JSObject *create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL); 0590 static JSObject *create(ExecState *, ErrorType, const char *message); 0591 0592 /** 0593 * Array of error names corresponding to ErrorType 0594 */ 0595 static const char *const *const errorNames; 0596 }; 0597 0598 KJS_EXPORT JSObject *throwError(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL); 0599 KJS_EXPORT JSObject *throwError(ExecState *, ErrorType, const UString &message); 0600 KJS_EXPORT JSObject *throwError(ExecState *, ErrorType, const char *message); 0601 KJS_EXPORT JSObject *throwError(ExecState *, ErrorType); 0602 0603 inline JSObject::JSObject(JSValue *proto) 0604 : _proto(proto) 0605 { 0606 assert(proto); 0607 } 0608 0609 inline JSObject::JSObject() 0610 : _proto(jsNull()) 0611 {} 0612 0613 inline JSValue *JSObject::prototype() const 0614 { 0615 return _proto; 0616 } 0617 0618 inline void JSObject::setPrototype(JSValue *proto) 0619 { 0620 assert(proto); 0621 _proto = proto; 0622 } 0623 0624 inline bool JSObject::inherits(const ClassInfo *info) const 0625 { 0626 for (const ClassInfo *ci = classInfo(); ci; ci = ci->parentClass) 0627 if (ci == info) { 0628 return true; 0629 } 0630 return false; 0631 } 0632 0633 inline void JSObject::fillDirectLocationSlot(PropertySlot &slot, 0634 JSValue **location) 0635 { 0636 if (_prop.hasGetterSetterProperties() && 0637 JSValue::type(*location) == GetterSetterType) { 0638 fillGetterPropertySlot(slot, location); 0639 } else { 0640 slot.setValueSlot(this, location); 0641 } 0642 } 0643 0644 // this method is here to be after the inline declaration of JSObject::inherits 0645 inline bool JSCell::isObject(const ClassInfo *info) const 0646 { 0647 return isObject() && static_cast<const JSObject *>(this)->inherits(info); 0648 } 0649 0650 // this method is here to be after the inline declaration of JSCell::isObject 0651 inline bool JSValue::isObject(const ClassInfo *c) const 0652 { 0653 return isObject(this, c); 0654 } 0655 0656 inline bool JSValue::isObject(const JSValue *value, const ClassInfo *c) 0657 { 0658 return !JSImmediate::isImmediate(value) && value->asCell()->isObject(c); 0659 } 0660 0661 // It may seem crazy to inline a function this large but it makes a big difference 0662 // since this is function very hot in variable lookup 0663 inline bool JSObject::getPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot) 0664 { 0665 JSObject *object = this; 0666 while (true) { 0667 if (object->getOwnPropertySlot(exec, propertyName, slot)) { 0668 return true; 0669 } 0670 0671 JSValue *proto = object->_proto; 0672 if (!JSValue::isObject(proto)) { 0673 return false; 0674 } 0675 0676 object = static_cast<JSObject *>(proto); 0677 } 0678 } 0679 0680 inline void JSObject::getPropertyNames(ExecState *exec, PropertyNameArray &propertyNames, PropertyMap::PropertyMode mode) 0681 { 0682 for (JSObject *cur = this; cur; cur = JSValue::getObject(cur->_proto)) { 0683 cur->getOwnPropertyNames(exec, propertyNames, mode); 0684 } 0685 } 0686 0687 inline JSValue *JSObject::toPrimitive(ExecState *exec, JSType preferredType) const 0688 { 0689 return defaultValue(exec, preferredType); 0690 } 0691 0692 inline JSValue *JSObject::call(ExecState *exec, JSObject *thisObj, const List &args) 0693 { 0694 return callAsFunction(exec, thisObj, args); 0695 } 0696 0697 } // namespace 0698 0699 #endif // KJS_OBJECT_H