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