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  *  Copyright (C) 2007 Eric Seidel (eric@webkit.org)
0007  *
0008  *  This library is free software; you can redistribute it and/or
0009  *  modify it under the terms of the GNU Library General Public
0010  *  License as published by the Free Software Foundation; either
0011  *  version 2 of the License, or (at your option) any later version.
0012  *
0013  *  This library is distributed in the hope that it will be useful,
0014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016  *  Library General Public License for more details.
0017  *
0018  *  You should have received a copy of the GNU Library General Public License
0019  *  along with this library; see the file COPYING.LIB.  If not, write to
0020  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021  *  Boston, MA 02110-1301, USA.
0022  *
0023  */
0024 
0025 #include "object.h"
0026 
0027 #include "error_object.h"
0028 #include "lookup.h"
0029 #include "nodes.h"
0030 #include "operations.h"
0031 #include "PropertyNameArray.h"
0032 #include <math.h>
0033 
0034 #include <typeinfo>
0035 
0036 #define JAVASCRIPT_MARK_TRACING 0
0037 
0038 namespace KJS
0039 {
0040 
0041 // ------------------------------ JSObject ------------------------------------
0042 
0043 void JSObject::mark()
0044 {
0045     JSCell::mark();
0046 
0047 #if JAVASCRIPT_MARK_TRACING
0048     static int markStackDepth = 0;
0049     markStackDepth++;
0050     for (int i = 0; i < markStackDepth; i++) {
0051         putchar('-');
0052     }
0053 
0054     printf("%s (%p)\n", className().UTF8String().c_str(), this);
0055 #endif
0056 
0057     JSValue *proto = _proto;
0058     if (!JSValue::marked(proto)) {
0059         JSValue::mark(proto);
0060     }
0061 
0062     _prop.mark();
0063 
0064 #if JAVASCRIPT_MARK_TRACING
0065     markStackDepth--;
0066 #endif
0067 }
0068 
0069 JSType JSObject::type() const
0070 {
0071     return ObjectType;
0072 }
0073 
0074 const ClassInfo *JSObject::classInfo() const
0075 {
0076     return nullptr;
0077 }
0078 
0079 UString JSObject::className() const
0080 {
0081     const ClassInfo *ci = classInfo();
0082     return ci ? ci->className : "Object";
0083 }
0084 
0085 JSValue *JSObject::get(ExecState *exec, const Identifier &propertyName) const
0086 {
0087     PropertySlot slot;
0088 
0089     if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot)) {
0090         JSValue *val = slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
0091         assert(val);
0092         return val;
0093     }
0094 
0095     return jsUndefined();
0096 }
0097 
0098 JSValue *JSObject::get(ExecState *exec, unsigned propertyName) const
0099 {
0100     PropertySlot slot;
0101     if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot)) {
0102         return slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
0103     }
0104 
0105     return jsUndefined();
0106 }
0107 
0108 bool JSObject::getPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot &slot)
0109 {
0110     JSObject *imp = this;
0111 
0112     while (true) {
0113         if (imp->getOwnPropertySlot(exec, propertyName, slot)) {
0114             return true;
0115         }
0116 
0117         JSValue *proto = imp->_proto;
0118         if (!JSValue::isObject(proto)) {
0119             break;
0120         }
0121 
0122         imp = static_cast<JSObject *>(proto);
0123     }
0124 
0125     return false;
0126 }
0127 
0128 bool JSObject::getPropertyDescriptor(ExecState *exec, const Identifier &propertyName, PropertyDescriptor &desc)
0129 {
0130     JSObject *object = this;
0131     while (true) {
0132         if (object->getOwnPropertyDescriptor(exec, propertyName, desc)) {
0133             return true;
0134         }
0135         JSValue *prototype = object->prototype();
0136         if (!JSValue::isObject(prototype)) {
0137             return false;
0138         }
0139         object = JSValue::toObject(prototype, exec);
0140     }
0141 }
0142 
0143 bool JSObject::getOwnPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot &slot)
0144 {
0145     return getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
0146 }
0147 
0148 // Ideally, we would like to inline this, since it's ultra-hot, but with the large VM
0149 // loop, it seems like the code side gets the g++-4.3.x inliner in the paranoid mode, so not only
0150 // does it not inline this, but it also doesn't inline setValueSlot() and hasGetterSetterProperties() (!!!).
0151 bool JSObject::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0152 {
0153     if (JSValue **location = getDirectLocation(propertyName)) {
0154         if (_prop.hasGetterSetterProperties() && JSValue::type(location[0]) == GetterSetterType) {
0155             fillGetterPropertySlot(slot, location);
0156         } else {
0157             slot.setValueSlot(this, location);
0158         }
0159         return true;
0160     }
0161 
0162     // non-standard Netscape extension
0163     if (propertyName == exec->propertyNames().underscoreProto) {
0164         slot.setValueSlot(this, &_proto);
0165         return true;
0166     }
0167 
0168     return false;
0169 }
0170 
0171 bool JSObject::getOwnPropertyDescriptor(ExecState *exec, const Identifier &identifier, PropertyDescriptor &desc)
0172 {
0173     JSValue *jsVal = getDirect(identifier);
0174 
0175     // for classes that do not implement getDirect, like the prototypes,
0176     // we have to check if they still do own the property and use the propertyslot
0177     if (!jsVal) {
0178         PropertySlot slot;
0179         if (getOwnPropertySlot(exec, identifier, slot)) {
0180             jsVal = slot.getValue(exec, this, identifier);
0181         }
0182     }
0183 
0184     if (jsVal) {
0185         unsigned attr = 0;
0186         getPropertyAttributes(identifier, attr);
0187         return desc.setPropertyDescriptorValues(exec, jsVal, attr);
0188     }
0189     return false;
0190 }
0191 
0192 static void throwSetterError(ExecState *exec)
0193 {
0194     throwError(exec, TypeError, "setting a property that has only a getter");
0195 }
0196 
0197 // ECMA 8.6.2.2
0198 void JSObject::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
0199 {
0200     assert(value);
0201 
0202     // non-standard netscape extension
0203     if (propertyName == exec->propertyNames().underscoreProto) {
0204         JSObject *proto = JSValue::getObject(value);
0205         while (proto) {
0206             if (proto == this) {
0207                 throwError(exec, GeneralError, "cyclic __proto__ value");
0208                 return;
0209             }
0210             proto = proto->prototype() ? JSValue::getObject(proto->prototype()) : nullptr;
0211         }
0212 
0213         setPrototype(value);
0214         return;
0215     }
0216 
0217     // putValue() is used for JS assignments. It passes no attribute.
0218     // Assume that a C++ implementation knows what it is doing
0219     // and don't spend time doing a read-only check for it.
0220     bool checkRO = (attr == None || attr == DontDelete);
0221 
0222     if (checkRO) {
0223         // Check for static properties that are ReadOnly; the property map will check the dynamic properties.
0224         // We don't have to worry about setters being read-only as they can't be added with such an attribute.
0225         // We also need to inherit any attributes we have from the entry
0226         const HashEntry *entry = findPropertyHashEntry(propertyName);
0227         if (entry) {
0228             if (entry->attr & ReadOnly) {
0229 #ifdef KJS_VERBOSE
0230                 fprintf(stderr, "WARNING: static property %s is ReadOnly\n", propertyName.ascii());
0231 #endif
0232                 return;
0233             }
0234             attr = entry->attr;
0235         }
0236     }
0237 
0238     // Check if there are any setters or getters in the prototype chain
0239     JSObject *obj = this;
0240     bool hasGettersOrSetters = false;
0241     while (true) {
0242         if (obj->_prop.hasGetterSetterProperties()) {
0243             hasGettersOrSetters = true;
0244             break;
0245         }
0246 
0247         if (!JSValue::isObject(obj->_proto)) {
0248             break;
0249         }
0250 
0251         obj = static_cast<JSObject *>(obj->_proto);
0252     }
0253 
0254     if (hasGettersOrSetters) {
0255         obj = this;
0256         while (true) {
0257             unsigned attributes;
0258             if (JSValue *gs = obj->_prop.get(propertyName, attributes)) {
0259                 if (attributes & GetterSetter) {
0260                     JSObject *setterFunc = static_cast<GetterSetterImp *>(gs)->getSetter();
0261 
0262                     if (!setterFunc) {
0263                         if (false) { //only throw if strict is set
0264                             throwSetterError(exec);
0265                         }
0266                         return;
0267                     }
0268 
0269                     List args;
0270                     args.append(value);
0271 
0272                     setterFunc->call(exec, this, args);
0273                     return;
0274                 } else {
0275                     // If there's an existing property on the object or one of its
0276                     // prototype it should be replaced, so we just break here.
0277                     break;
0278                 }
0279             }
0280 
0281             if (!JSValue::isObject(obj->_proto)) {
0282                 break;
0283             }
0284 
0285             obj = static_cast<JSObject *>(obj->_proto);
0286         }
0287     }
0288 
0289     if (!isExtensible() && !_prop.get(propertyName)) {
0290         return;
0291     }
0292     _prop.put(propertyName, value, attr, checkRO);
0293 }
0294 
0295 void JSObject::put(ExecState *exec, unsigned propertyName,
0296                    JSValue *value, int attr)
0297 {
0298     put(exec, Identifier::from(propertyName), value, attr);
0299 }
0300 
0301 // ECMA 8.6.2.3
0302 bool JSObject::canPut(ExecState *, const Identifier &propertyName) const
0303 {
0304     unsigned attributes;
0305 
0306     // Don't look in the prototype here. We can always put an override
0307     // in the object, even if the prototype has a ReadOnly property.
0308 
0309     if (!getPropertyAttributes(propertyName, attributes)) {
0310         return true;
0311     } else {
0312         return !(attributes & ReadOnly);
0313     }
0314 }
0315 
0316 // ECMA 8.6.2.4
0317 bool JSObject::hasProperty(ExecState *exec, const Identifier &propertyName) const
0318 {
0319     PropertySlot slot;
0320     return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
0321 }
0322 
0323 bool JSObject::hasProperty(ExecState *exec, unsigned propertyName) const
0324 {
0325     PropertySlot slot;
0326     return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
0327 }
0328 
0329 // ECMA 8.6.2.5
0330 bool JSObject::deleteProperty(ExecState * /*exec*/, const Identifier &propertyName)
0331 {
0332     unsigned attributes;
0333     JSValue *v = _prop.get(propertyName, attributes);
0334     if (v) {
0335         if ((attributes & DontDelete)) {
0336             return false;
0337         }
0338         _prop.remove(propertyName);
0339         if (attributes & GetterSetter) {
0340             _prop.setHasGetterSetterProperties(_prop.containsGettersOrSetters());
0341         }
0342         return true;
0343     }
0344 
0345     // Look in the static hashtable of properties
0346     const HashEntry *entry = findPropertyHashEntry(propertyName);
0347     if (entry && entry->attr & DontDelete) {
0348         return false;    // this builtin property can't be deleted
0349     }
0350     return true;
0351 }
0352 
0353 bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
0354 {
0355     return deleteProperty(exec, Identifier::from(propertyName));
0356 }
0357 
0358 static ALWAYS_INLINE JSValue *tryGetAndCallProperty(ExecState *exec, const JSObject *object, const Identifier &propertyName)
0359 {
0360     JSValue *v = object->get(exec, propertyName);
0361     if (JSValue::isObject(v)) {
0362         JSObject *o = static_cast<JSObject *>(v);
0363         if (o->implementsCall()) { // spec says "not primitive type" but ...
0364             JSObject *thisObj = const_cast<JSObject *>(object);
0365             JSValue *def = o->call(exec, thisObj, List::empty());
0366             JSType defType = JSValue::type(def);
0367             ASSERT(defType != GetterSetterType);
0368             if (defType != ObjectType) {
0369                 return def;
0370             }
0371         }
0372     }
0373     return nullptr;
0374 }
0375 
0376 bool JSObject::getPrimitiveNumber(ExecState *exec, double &number, JSValue *&result)
0377 {
0378     result = defaultValue(exec, NumberType);
0379     number = JSValue::toNumber(result, exec);
0380     return !JSValue::isString(result);
0381 }
0382 
0383 // ECMA 8.6.2.6
0384 JSValue *JSObject::defaultValue(ExecState *exec, JSType hint) const
0385 {
0386     const Identifier *firstPropertyName;
0387     const Identifier *secondPropertyName;
0388     /* Prefer String for Date objects */
0389     if ((hint == StringType) || ((hint != NumberType) && (_proto == exec->lexicalInterpreter()->builtinDatePrototype()))) {
0390         firstPropertyName = &exec->propertyNames().toString;
0391         secondPropertyName = &exec->propertyNames().valueOf;
0392     } else {
0393         firstPropertyName = &exec->propertyNames().valueOf;
0394         secondPropertyName = &exec->propertyNames().toString;
0395     }
0396 
0397     JSValue *v;
0398     if ((v = tryGetAndCallProperty(exec, this, *firstPropertyName))) {
0399         return v;
0400     }
0401     if ((v = tryGetAndCallProperty(exec, this, *secondPropertyName))) {
0402         return v;
0403     }
0404 
0405     if (exec->hadException()) {
0406         return exec->exception();
0407     }
0408 
0409     return throwError(exec, TypeError, "No default value");
0410 }
0411 
0412 const HashEntry *JSObject::findPropertyHashEntry(const Identifier &propertyName) const
0413 {
0414     for (const ClassInfo *info = classInfo(); info; info = info->parentClass) {
0415         if (const HashTable *propHashTable = info->propHashTable) {
0416             if (const HashEntry *e = Lookup::findEntry(propHashTable, propertyName)) {
0417                 return e;
0418             }
0419         }
0420     }
0421     return nullptr;
0422 }
0423 
0424 void JSObject::defineGetter(ExecState *, const Identifier &propertyName, JSObject *getterFunc)
0425 {
0426     JSValue *o = getDirect(propertyName);
0427     GetterSetterImp *gs;
0428 
0429     if (o && JSValue::type(o) == GetterSetterType) {
0430         gs = static_cast<GetterSetterImp *>(o);
0431     } else {
0432         gs = new GetterSetterImp;
0433         putDirect(propertyName, gs, GetterSetter);
0434     }
0435 
0436     _prop.setHasGetterSetterProperties(true);
0437     gs->setGetter(getterFunc);
0438 }
0439 
0440 void JSObject::defineSetter(ExecState *, const Identifier &propertyName, JSObject *setterFunc)
0441 {
0442     JSValue *o = getDirect(propertyName);
0443     GetterSetterImp *gs;
0444 
0445     if (o && JSValue::type(o) == GetterSetterType) {
0446         gs = static_cast<GetterSetterImp *>(o);
0447     } else {
0448         gs = new GetterSetterImp;
0449         putDirect(propertyName, gs, GetterSetter);
0450     }
0451 
0452     _prop.setHasGetterSetterProperties(true);
0453     gs->setSetter(setterFunc);
0454 }
0455 
0456 //ECMA Edition 5.1r6 - 8.12.9
0457 bool JSObject::defineOwnProperty(ExecState *exec, const Identifier &propertyName, PropertyDescriptor &desc, bool shouldThrow)
0458 {
0459     PropertyDescriptor current;
0460 
0461     // if Object does not have propertyName as OwnProperty just push it.
0462     if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
0463         if (!isExtensible()) {
0464             if (shouldThrow) {
0465                 throwError(exec, TypeError, "Object is not extensible \'" + propertyName.ustring() + "\'");
0466             }
0467             return false;
0468         }
0469         if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
0470             putDirect(propertyName, desc.value() ? desc.value() : jsUndefined(), desc.attributes());
0471         } else if (desc.isAccessorDescriptor()) {
0472             GetterSetterImp *gs = new GetterSetterImp();
0473             putDirect(propertyName, gs, desc.attributes() | GetterSetter);
0474             _prop.setHasGetterSetterProperties(true);
0475             if (desc.getter() && !JSValue::isUndefined(desc.getter())) {
0476                 gs->setGetter(JSValue::toObject(desc.getter(), exec));
0477             }
0478             if (desc.setter() && !JSValue::isUndefined(desc.setter())) {
0479                 gs->setSetter(JSValue::toObject(desc.setter(), exec));
0480             }
0481         }
0482         return true;
0483     }
0484 
0485     //Step 5
0486     if (desc.isEmpty()) {
0487         return true;
0488     }
0489 
0490     //Step 6
0491     if (desc.equalTo(exec, current)) {
0492         return true;
0493     }
0494 
0495     //Step 7
0496     // Filter out invalid unconfigurable configurations
0497     if (!current.configurable()) {
0498         if (desc.configurable()) {
0499             if (shouldThrow) {
0500                 throwError(exec, TypeError, "can not redefine non-configurable property \'" + propertyName.ustring() + "\'");
0501             }
0502             return false;
0503         }
0504         if (desc.enumerableSet() && desc.enumerable() != current.enumerable()) {
0505             if (shouldThrow) {
0506                 throwError(exec, TypeError, "can not change enumerable attribute of unconfigurable property \'" + propertyName.ustring() + "\'");
0507             }
0508             return false;
0509         }
0510     }
0511 
0512     //Step 8.
0513     if (!desc.isGenericDescriptor()) {
0514         if (current.isDataDescriptor() != desc.isDataDescriptor()) { // Step 9
0515             // DataDescriptor updating to AccessorDescriptor, or the other way.
0516             if (!current.configurable()) {
0517                 if (shouldThrow) {
0518                     throwError(exec, TypeError, "can not change access mechanism for an unconfigurable property \'" + propertyName.ustring() + "\'");
0519                 }
0520                 return false;
0521             }
0522 
0523             deleteProperty(exec, propertyName);
0524 
0525             if (current.isDataDescriptor()) {
0526                 // Updating from DataDescriptor to AccessorDescriptor
0527                 GetterSetterImp *gs = new GetterSetterImp();
0528                 putDirect(propertyName, gs, current.attributesWithOverride(desc) | GetterSetter);
0529                 _prop.setHasGetterSetterProperties(true);
0530 
0531                 if (desc.getter()) {
0532                     if (JSValue::isUndefined(desc.getter())) {
0533                         gs->setGetter(nullptr);
0534                     } else {
0535                         gs->setGetter(JSValue::toObject(desc.getter(), exec));
0536                     }
0537                 }
0538                 if (desc.setter()) {
0539                     if (JSValue::isUndefined(desc.setter())) {
0540                         gs->setSetter(nullptr);
0541                     } else {
0542                         gs->setSetter(JSValue::toObject(desc.setter(), exec));
0543                     }
0544                 }
0545             } else {
0546                 // Updating from AccessorDescriptor to DataDescriptor
0547                 unsigned int newAttr = current.attributesWithOverride(desc);
0548                 if (!desc.writable()) {
0549                     newAttr |= ReadOnly;
0550                 }
0551                 putDirect(propertyName, desc.value() ? desc.value() : jsUndefined(), newAttr);
0552             }
0553             return true;
0554         } else if (current.isDataDescriptor() && desc.isDataDescriptor()) { //Step 10
0555             // Just updating the value here
0556             if (!current.configurable()) {
0557                 if (!current.writable() && desc.writable()) {
0558                     if (shouldThrow) {
0559                         throwError(exec, TypeError, "can not change writable attribute of unconfigurable property \'" + propertyName.ustring() + "\'");
0560                     }
0561                     return false;
0562                 }
0563                 if (!current.writable()) {
0564                     if (desc.value() && !(current.value() && sameValue(exec, current.value(), desc.value()))) {
0565                         if (shouldThrow) {
0566                             throwError(exec, TypeError, "can not change value of a readonly property \'" + propertyName.ustring() + "\'");
0567                         }
0568                         return false;
0569                     }
0570                 }
0571             } else {
0572                 if (!deleteProperty(exec, propertyName)) {
0573                     removeDirect(propertyName);
0574                 }
0575 
0576                 putDirect(propertyName, desc.value() ? desc.value() : current.value(), current.attributesWithOverride(desc));
0577                 return true;
0578             }
0579         } else if (current.isAccessorDescriptor() && desc.isAccessorDescriptor()) { // Step 11
0580             // Filter out unconfigurable combinations
0581             if (!current.configurable()) {
0582                 if (desc.setter() && !sameValue(exec, desc.setter(), current.setter() ? current.setter() : jsUndefined())) {
0583                     if (shouldThrow) {
0584                         throwError(exec, TypeError, "can not change the setter of an unconfigurable property \'" + propertyName.ustring() + "\'");
0585                     }
0586                     return false;
0587                 }
0588                 if (desc.getter() && !sameValue(exec, desc.getter(), current.getter() ? current.getter() : jsUndefined())) {
0589                     if (shouldThrow) {
0590                         throwError(exec, TypeError, "can not change the getter of an unconfigurable property \'" + propertyName.ustring() + "\'");
0591                     }
0592                     return false;
0593                 }
0594             }
0595         }
0596     }
0597 
0598     //Step 12
0599     // Everything is allowed here, updating GetterSetter, storing new value
0600     JSValue *jsval = getDirect(propertyName);
0601     unsigned int newAttr = current.attributesWithOverride(desc);
0602     if (jsval && JSValue::type(jsval) == GetterSetterType) {
0603         GetterSetterImp *gs = static_cast<GetterSetterImp *>(jsval);
0604         if (desc.getter()) {
0605             if (JSValue::isUndefined(desc.getter())) {
0606                 gs->setGetter(nullptr);
0607             } else {
0608                 gs->setGetter(JSValue::toObject(desc.getter(), exec));
0609             }
0610         }
0611         if (desc.setter()) {
0612             if (JSValue::isUndefined(desc.setter())) {
0613                 gs->setSetter(nullptr);
0614             } else {
0615                 gs->setSetter(JSValue::toObject(desc.setter(), exec));
0616             }
0617         }
0618     } else {
0619         jsval = desc.value() ? desc.value() : current.value();
0620     }
0621 
0622     deleteProperty(exec, propertyName);
0623     if (JSValue::type(jsval) == GetterSetterType) {
0624         putDirect(propertyName, jsval, newAttr | GetterSetter);
0625         _prop.setHasGetterSetterProperties(true);
0626     } else {
0627         put(exec, propertyName, jsval, newAttr);
0628     }
0629 
0630     return true; //Step 13
0631 }
0632 
0633 void JSObject::preventExtensions()
0634 {
0635     if (isExtensible()) {
0636         _prop.setExtensible(false);
0637     }
0638 }
0639 
0640 bool JSObject::implementsConstruct() const
0641 {
0642     return false;
0643 }
0644 
0645 JSObject *JSObject::construct(ExecState *, const List & /*args*/)
0646 {
0647     assert(false);
0648     return nullptr;
0649 }
0650 
0651 JSObject *JSObject::construct(ExecState *exec, const List &args, const Identifier & /*functionName*/, const UString & /*sourceURL*/, int /*lineNumber*/)
0652 {
0653     return construct(exec, args);
0654 }
0655 
0656 JSObject *JSObject::valueClone(Interpreter * /*targetCtx*/) const
0657 {
0658     return nullptr;
0659 }
0660 
0661 bool JSObject::isFunctionType() const
0662 {
0663     return implementsCall();
0664 }
0665 
0666 JSValue *JSObject::callAsFunction(ExecState * /*exec*/, JSObject * /*thisObj*/, const List &/*args*/)
0667 {
0668     assert(false);
0669     return nullptr;
0670 }
0671 
0672 bool JSObject::implementsHasInstance() const
0673 {
0674     return false;
0675 }
0676 
0677 bool JSObject::hasInstance(ExecState *exec, JSValue *value)
0678 {
0679     JSValue *proto = get(exec, exec->propertyNames().prototype);
0680     if (!JSValue::isObject(proto)) {
0681         throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
0682         return false;
0683     }
0684 
0685     if (!JSValue::isObject(value)) {
0686         return false;
0687     }
0688 
0689     JSObject *o = static_cast<JSObject *>(value);
0690     while ((o = JSValue::getObject(o->prototype()))) {
0691         if (o == proto) {
0692             return true;
0693         }
0694     }
0695     return false;
0696 }
0697 
0698 bool JSObject::propertyIsEnumerable(ExecState *, const Identifier &propertyName) const
0699 {
0700     unsigned attributes;
0701 
0702     if (!getPropertyAttributes(propertyName, attributes)) {
0703         return false;
0704     } else {
0705         return !(attributes & DontEnum);
0706     }
0707 }
0708 
0709 bool JSObject::getPropertyAttributes(const Identifier &propertyName, unsigned &attributes) const
0710 {
0711     if (_prop.get(propertyName, attributes)) {
0712         return true;
0713     }
0714 
0715     // Look in the static hashtable of properties
0716     const HashEntry *e = findPropertyHashEntry(propertyName);
0717     if (e) {
0718         attributes = e->attr;
0719         return true;
0720     }
0721 
0722     return false;
0723 }
0724 
0725 void JSObject::getOwnPropertyNames(ExecState * /*exec*/, PropertyNameArray &propertyNames, PropertyMap::PropertyMode mode)
0726 {
0727     _prop.getPropertyNames(propertyNames, mode);
0728 
0729     // Add properties from the static hashtable of properties
0730     const ClassInfo *info = classInfo();
0731     while (info) {
0732         if (info->propHashTable) {
0733             int size = info->propHashTable->size;
0734             const HashEntry *e = info->propHashTable->entries;
0735             for (int i = 0; i < size; ++i, ++e) {
0736                 if (e->s && PropertyMap::checkEnumerable(e->attr, mode)) {
0737                     propertyNames.add(e->s);
0738                 }
0739             }
0740         }
0741         info = info->parentClass;
0742     }
0743 }
0744 
0745 bool JSObject::toBoolean(ExecState * /*exec*/) const
0746 {
0747     return true;
0748 }
0749 
0750 double JSObject::toNumber(ExecState *exec) const
0751 {
0752     JSValue *prim = toPrimitive(exec, NumberType);
0753     if (exec->hadException()) { // should be picked up soon in nodes.cpp
0754         return 0.0;
0755     }
0756     return JSValue::toNumber(prim, exec);
0757 }
0758 
0759 UString JSObject::toString(ExecState *exec) const
0760 {
0761     JSValue *prim = toPrimitive(exec, StringType);
0762     if (exec->hadException()) { // should be picked up soon in nodes.cpp
0763         return UString(UString::empty);
0764     }
0765     return JSValue::toString(prim, exec);
0766 }
0767 
0768 JSObject *JSObject::toObject(ExecState * /*exec*/) const
0769 {
0770     return const_cast<JSObject *>(this);
0771 }
0772 
0773 void JSObject::putDirect(const Identifier &propertyName, int value, int attr)
0774 {
0775     _prop.put(propertyName, jsNumber(value), attr);
0776 }
0777 
0778 void JSObject::removeDirect(const Identifier &propertyName)
0779 {
0780     _prop.remove(propertyName);
0781 }
0782 
0783 void JSObject::putDirectFunction(InternalFunctionImp *func, int attr)
0784 {
0785     putDirect(func->functionName(), func, attr);
0786 }
0787 
0788 void JSObject::fillGetterPropertySlot(PropertySlot &slot, JSValue **location)
0789 {
0790     GetterSetterImp *gs = static_cast<GetterSetterImp *>(*location);
0791     JSObject *getterFunc = gs->getGetter();
0792     if (getterFunc) {
0793         slot.setGetterSlot(this, getterFunc);
0794     } else {
0795         slot.setUndefined(this);
0796     }
0797 }
0798 
0799 // ------------------------------ Error ----------------------------------------
0800 
0801 const char *const errorNamesArr[] = {
0802     I18N_NOOP("Error"), // GeneralError
0803     I18N_NOOP("Evaluation error"), // EvalError
0804     I18N_NOOP("Range error"), // RangeError
0805     I18N_NOOP("Reference error"), // ReferenceError
0806     I18N_NOOP("Syntax error"), // SyntaxError
0807     I18N_NOOP("Type error"), // TypeError
0808     I18N_NOOP("URI error"), // URIError
0809 };
0810 
0811 const char *const *const Error::errorNames = errorNamesArr;
0812 
0813 JSObject *Error::create(ExecState *exec, ErrorType errtype, const UString &message,
0814                         int lineno, int sourceId, const UString &sourceURL)
0815 {
0816 #ifdef KJS_VERBOSE
0817     // message could be 0L. Don't enable this on Solaris ;)
0818     fprintf(stderr, "WARNING: KJS %s: %s\n", errorNamesArr[errtype], message.ascii());
0819 #endif
0820 
0821     Interpreter *interp = exec->lexicalInterpreter();
0822     JSObject *cons;
0823     switch (errtype) {
0824     case EvalError:
0825         cons = interp->builtinEvalError();
0826         break;
0827     case RangeError:
0828         cons = interp->builtinRangeError();
0829         break;
0830     case ReferenceError:
0831         cons = interp->builtinReferenceError();
0832         break;
0833     case SyntaxError:
0834         cons = interp->builtinSyntaxError();
0835         break;
0836     case TypeError:
0837         cons = interp->builtinTypeError();
0838         break;
0839     case URIError:
0840         cons = interp->builtinURIError();
0841         break;
0842     default:
0843         cons = interp->builtinError();
0844         break;
0845     }
0846 
0847     List args;
0848     if (message.isEmpty()) {
0849         args.append(jsString(errorNames[errtype]));
0850     } else {
0851         args.append(jsString(message));
0852     }
0853     JSObject *err = static_cast<JSObject *>(cons->construct(exec, args));
0854 
0855     if (lineno != -1) {
0856         err->put(exec, "line", jsNumber(lineno));
0857     }
0858     if (sourceId != -1) {
0859         err->put(exec, "sourceId", jsNumber(sourceId));
0860     }
0861 
0862     if (!sourceURL.isNull()) {
0863         err->put(exec, "sourceURL", jsString(sourceURL));
0864     }
0865 
0866     return err;
0867 
0868     /*
0869     #ifndef NDEBUG
0870       const char *msg = err->get(messagePropertyName)->toString().value().ascii();
0871       if (l >= 0)
0872           fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
0873       else
0874           fprintf(stderr, "KJS: %s. %s\n", estr, msg);
0875     #endif
0876 
0877       return err;
0878     */
0879 }
0880 
0881 JSObject *Error::create(ExecState *exec, ErrorType type, const char *message)
0882 {
0883     return create(exec, type, message, -1, -1, nullptr);
0884 }
0885 
0886 JSObject *throwError(ExecState *exec, ErrorType type)
0887 {
0888     JSObject *error = Error::create(exec, type, UString(), -1, -1, nullptr);
0889     exec->setException(error);
0890     return error;
0891 }
0892 
0893 JSObject *throwError(ExecState *exec, ErrorType type, const UString &message)
0894 {
0895     JSObject *error = Error::create(exec, type, message, -1, -1, nullptr);
0896     exec->setException(error);
0897     return error;
0898 }
0899 
0900 JSObject *throwError(ExecState *exec, ErrorType type, const char *message)
0901 {
0902     JSObject *error = Error::create(exec, type, message, -1, -1, nullptr);
0903     exec->setException(error);
0904     return error;
0905 }
0906 
0907 JSObject *throwError(ExecState *exec, ErrorType type, const UString &message, int line, int sourceId, const UString &sourceURL)
0908 {
0909     JSObject *error = Error::create(exec, type, message, line, sourceId, sourceURL);
0910     exec->setException(error);
0911     return error;
0912 }
0913 
0914 } // namespace KJS