File indexing completed on 2024-05-12 15:43:31
0001 // krazy:excludeall=doublequote_chars (UStrings aren't QStrings) 0002 /* 0003 * This file is part of the KDE libraries 0004 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Lesser General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Lesser General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Lesser General Public 0017 * License along with this library; if not, write to the Free Software 0018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0019 * 0020 */ 0021 0022 #include "object_object.h" 0023 0024 #include "operations.h" 0025 #include "function_object.h" 0026 #include "propertydescriptor.h" 0027 #include <stdio.h> 0028 0029 namespace KJS 0030 { 0031 0032 /** 0033 * @internal 0034 * 0035 * Class to implement all methods that are properties of the 0036 * Object object 0037 */ 0038 class ObjectObjectFuncImp : public InternalFunctionImp 0039 { 0040 public: 0041 ObjectObjectFuncImp(ExecState *, FunctionPrototype *, int i, int len, const Identifier &); 0042 0043 JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args) override; 0044 0045 enum { GetOwnPropertyDescriptor, DefineProperty, GetPrototypeOf, 0046 GetOwnPropertyNames, Keys, DefineProperties, Create, IsExtensible, 0047 PreventExtensible, IsSealed, Seal, IsFrozen, Freeze, 0048 //ES6 0049 Is 0050 }; 0051 0052 private: 0053 int id; 0054 }; 0055 0056 // ------------------------------ ObjectPrototype -------------------------------- 0057 0058 ObjectPrototype::ObjectPrototype(ExecState *exec, FunctionPrototype *funcProto) 0059 : JSObject() // [[Prototype]] is null 0060 { 0061 static const Identifier *hasOwnPropertyPropertyName = new Identifier("hasOwnProperty"); 0062 static const Identifier *propertyIsEnumerablePropertyName = new Identifier("propertyIsEnumerable"); 0063 static const Identifier *isPrototypeOfPropertyName = new Identifier("isPrototypeOf"); 0064 static const Identifier *defineGetterPropertyName = new Identifier("__defineGetter__"); 0065 static const Identifier *defineSetterPropertyName = new Identifier("__defineSetter__"); 0066 static const Identifier *lookupGetterPropertyName = new Identifier("__lookupGetter__"); 0067 static const Identifier *lookupSetterPropertyName = new Identifier("__lookupSetter__"); 0068 0069 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::ToString, 0, exec->propertyNames().toString), DontEnum); 0070 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::ToLocaleString, 0, exec->propertyNames().toLocaleString), DontEnum); 0071 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::ValueOf, 0, exec->propertyNames().valueOf), DontEnum); 0072 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::HasOwnProperty, 1, *hasOwnPropertyPropertyName), DontEnum); 0073 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::PropertyIsEnumerable, 1, *propertyIsEnumerablePropertyName), DontEnum); 0074 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::IsPrototypeOf, 1, *isPrototypeOfPropertyName), DontEnum); 0075 0076 // Mozilla extensions 0077 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::DefineGetter, 2, *defineGetterPropertyName), DontEnum); 0078 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::DefineSetter, 2, *defineSetterPropertyName), DontEnum); 0079 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::LookupGetter, 1, *lookupGetterPropertyName), DontEnum); 0080 putDirectFunction(new ObjectProtoFunc(exec, funcProto, ObjectProtoFunc::LookupSetter, 1, *lookupSetterPropertyName), DontEnum); 0081 } 0082 0083 JSObject *ObjectPrototype::self(ExecState *exec) 0084 { 0085 return exec->lexicalInterpreter()->builtinObjectPrototype(); 0086 } 0087 0088 // ------------------------------ ObjectProtoFunc -------------------------------- 0089 0090 ObjectProtoFunc::ObjectProtoFunc(ExecState *exec, FunctionPrototype *funcProto, int i, int len, const Identifier &name) 0091 : InternalFunctionImp(funcProto, name) 0092 , id(i) 0093 { 0094 putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum); 0095 } 0096 0097 // ECMA 15.2.4.2, 15.2.4.4, 15.2.4.5, 15.2.4.7 0098 0099 JSValue *ObjectProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) 0100 { 0101 switch (id) { 0102 case ValueOf: 0103 return thisObj; 0104 case HasOwnProperty: { 0105 PropertySlot slot; 0106 return jsBoolean(thisObj->getOwnPropertySlot(exec, Identifier(JSValue::toString(args[0], exec)), slot)); 0107 } 0108 case IsPrototypeOf: { 0109 if (!JSValue::isObject(args[0])) { 0110 return jsBoolean(false); 0111 } 0112 0113 JSValue *v = static_cast<JSObject *>(args[0])->prototype(); 0114 0115 while (true) { 0116 if (!JSValue::isObject(v)) { 0117 return jsBoolean(false); 0118 } 0119 0120 if (thisObj == static_cast<JSObject *>(v)) 0121 return jsBoolean(true); 0122 0123 v = static_cast<JSObject *>(v)->prototype(); 0124 } 0125 } 0126 case DefineGetter: 0127 case DefineSetter: { 0128 if (!JSValue::isObject(args[1]) || 0129 !static_cast<JSObject *>(args[1])->implementsCall()) { 0130 if (id == DefineGetter) { 0131 return throwError(exec, SyntaxError, "invalid getter usage"); 0132 } else { 0133 return throwError(exec, SyntaxError, "invalid setter usage"); 0134 } 0135 } 0136 0137 if (id == DefineGetter) { 0138 thisObj->defineGetter(exec, Identifier(JSValue::toString(args[0], exec)), static_cast<JSObject *>(args[1])); 0139 } else { 0140 thisObj->defineSetter(exec, Identifier(JSValue::toString(args[0], exec)), static_cast<JSObject *>(args[1])); 0141 } 0142 return jsUndefined(); 0143 } 0144 case LookupGetter: 0145 case LookupSetter: { 0146 Identifier propertyName = Identifier(JSValue::toString(args[0], exec)); 0147 0148 JSObject *obj = thisObj; 0149 while (true) { 0150 JSValue *v = obj->getDirect(propertyName); 0151 0152 if (v) { 0153 if (JSValue::type(v) != GetterSetterType) { 0154 return jsUndefined(); 0155 } 0156 0157 JSObject *funcObj; 0158 0159 if (id == LookupGetter) { 0160 funcObj = static_cast<GetterSetterImp *>(v)->getGetter(); 0161 } else { 0162 funcObj = static_cast<GetterSetterImp *>(v)->getSetter(); 0163 } 0164 0165 if (!funcObj) { 0166 return jsUndefined(); 0167 } else { 0168 return funcObj; 0169 } 0170 } 0171 0172 if (!obj->prototype() || !JSValue::isObject(obj->prototype())) { 0173 return jsUndefined(); 0174 } 0175 0176 obj = static_cast<JSObject *>(obj->prototype()); 0177 } 0178 } 0179 case PropertyIsEnumerable: 0180 return jsBoolean(thisObj->propertyIsEnumerable(exec, Identifier(JSValue::toString(args[0], exec)))); 0181 case ToLocaleString: 0182 return jsString(thisObj->toString(exec)); 0183 case ToString: 0184 default: 0185 return jsString("[object " + thisObj->className() + "]"); 0186 } 0187 } 0188 0189 // ------------------------------ ObjectObjectImp -------------------------------- 0190 0191 ObjectObjectImp::ObjectObjectImp(ExecState *exec, ObjectPrototype *objProto, FunctionPrototype *funcProto) 0192 : InternalFunctionImp(funcProto) 0193 { 0194 static const Identifier *getOwnPropertyDescriptorName = new Identifier("getOwnPropertyDescriptor"); 0195 static const Identifier *createName = new Identifier("create"); 0196 static const Identifier *definePropertyName = new Identifier("defineProperty"); 0197 static const Identifier *definePropertiesName = new Identifier("defineProperties"); 0198 static const Identifier *getPrototypeOf = new Identifier("getPrototypeOf"); 0199 static const Identifier *getOwnPropertyNames = new Identifier("getOwnPropertyNames"); 0200 static const Identifier *sealName = new Identifier("seal"); 0201 static const Identifier *freezeName = new Identifier("freeze"); 0202 static const Identifier *preventExtensionsName = new Identifier("preventExtensions"); 0203 static const Identifier *isSealedName = new Identifier("isSealed"); 0204 static const Identifier *isFrozenName = new Identifier("isFrozen"); 0205 static const Identifier *isExtensibleName = new Identifier("isExtensible"); 0206 static const Identifier *keys = new Identifier("keys"); 0207 static const Identifier* isName = new Identifier("is"); 0208 0209 // ECMA 15.2.3.1 0210 putDirect(exec->propertyNames().prototype, objProto, DontEnum | DontDelete | ReadOnly); 0211 0212 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::GetOwnPropertyDescriptor, 2, *getOwnPropertyDescriptorName), DontEnum); 0213 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Create, 2, *createName), DontEnum); 0214 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::DefineProperty, 3, *definePropertyName), DontEnum); 0215 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::DefineProperties, 2, *definePropertiesName), DontEnum); 0216 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::GetPrototypeOf, 1, *getPrototypeOf), DontEnum); 0217 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::GetOwnPropertyNames, 1, *getOwnPropertyNames), DontEnum); 0218 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Seal, 1, *sealName), DontEnum); 0219 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Freeze, 1, *freezeName), DontEnum); 0220 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::PreventExtensible, 1, *preventExtensionsName), DontEnum); 0221 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::IsSealed, 1, *isSealedName), DontEnum); 0222 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::IsFrozen, 1, *isFrozenName), DontEnum); 0223 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::IsExtensible, 1, *isExtensibleName), DontEnum); 0224 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Keys, 1, *keys), DontEnum); 0225 //ES6 0226 putDirectFunction(new ObjectObjectFuncImp(exec, funcProto, ObjectObjectFuncImp::Is, 2, *isName), DontEnum); 0227 0228 // no. of arguments for constructor 0229 putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum); 0230 } 0231 0232 bool ObjectObjectImp::implementsConstruct() const 0233 { 0234 return true; 0235 } 0236 0237 // ECMA 15.2.2 0238 JSObject *ObjectObjectImp::construct(ExecState *exec, const List &args) 0239 { 0240 JSValue *arg = args[0]; 0241 switch (JSValue::type(arg)) { 0242 case StringType: 0243 case BooleanType: 0244 case NumberType: 0245 case ObjectType: 0246 return JSValue::toObject(arg, exec); 0247 case NullType: 0248 case UndefinedType: 0249 return new JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()); 0250 default: 0251 //### ASSERT_NOT_REACHED(); 0252 return nullptr; 0253 } 0254 } 0255 0256 JSValue *ObjectObjectImp::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args) 0257 { 0258 return construct(exec, args); 0259 } 0260 0261 // ------------------------------ ObjectObjectFuncImp ---------------------------- 0262 0263 ObjectObjectFuncImp::ObjectObjectFuncImp(ExecState *exec, FunctionPrototype *funcProto, int i, int len, const Identifier &name) 0264 : InternalFunctionImp(funcProto, name), id(i) 0265 { 0266 putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum); 0267 } 0268 0269 static JSValue *defineProperties(ExecState *exec, JSObject *object, JSValue *properties) 0270 { 0271 JSObject *props = JSValue::toObject(properties, exec); 0272 if (exec->hadException()) { 0273 return object; 0274 } 0275 PropertyNameArray names; 0276 props->getOwnPropertyNames(exec, names, PropertyMap::ExcludeDontEnumProperties); 0277 int size = names.size(); 0278 Vector<PropertyDescriptor> descriptors; 0279 for (int i = 0; i < size; ++i) { 0280 PropertyDescriptor desc; 0281 if (!desc.setPropertyDescriptorFromObject(exec, props->get(exec, names[i]))) { 0282 return jsUndefined(); 0283 } 0284 descriptors.append(desc); 0285 } 0286 for (int i = 0; i < size; ++i) { 0287 object->defineOwnProperty(exec, names[i], descriptors[i], true); 0288 if (exec->hadException()) { 0289 return jsUndefined(); 0290 } 0291 } 0292 return object; 0293 } 0294 0295 JSValue *ObjectObjectFuncImp::callAsFunction(ExecState *exec, JSObject *, const List &args) 0296 { 0297 switch (id) { 0298 case GetPrototypeOf: { //ECMA Edition 5.1r6 - 15.2.3.2 0299 JSObject *jso = JSValue::getObject(args[0]); 0300 if (!jso) { 0301 return throwError(exec, TypeError, "Not an Object"); 0302 } 0303 return jso->prototype(); 0304 } 0305 case GetOwnPropertyDescriptor: { //ECMA Edition 5.1r6 - 15.2.3.3 0306 JSObject *jso = JSValue::getObject(args[0]); 0307 if (!jso) { 0308 return throwError(exec, TypeError, "Not an Object"); 0309 } 0310 0311 UString name = JSValue::toString(args[1], exec); 0312 PropertyDescriptor desc; 0313 if (!jso->getOwnPropertyDescriptor(exec, Identifier(name), desc)) { 0314 return jsUndefined(); 0315 } 0316 return desc.fromPropertyDescriptor(exec); 0317 } 0318 case GetOwnPropertyNames: //ECMA Edition 5.1r6 - 15.2.3.4 0319 case Keys: { //ECMA Edition 5.1r6 - 15.2.3.14 0320 JSObject *jso = JSValue::getObject(args[0]); 0321 if (!jso) { 0322 return throwError(exec, TypeError, "Not an Object"); 0323 } 0324 0325 JSObject *ret = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty())); 0326 PropertyNameArray propertyNames; 0327 0328 if (id == Keys) { 0329 jso->getOwnPropertyNames(exec, propertyNames, PropertyMap::ExcludeDontEnumProperties); 0330 } else { // id == GetOwnPropertyNames 0331 jso->getOwnPropertyNames(exec, propertyNames, PropertyMap::IncludeDontEnumProperties); 0332 } 0333 PropertyNameArrayIterator propEnd = propertyNames.end(); 0334 unsigned int n = 0; 0335 for (PropertyNameArrayIterator propIter = propertyNames.begin(); propIter != propEnd; ++propIter) { 0336 Identifier name = *propIter; 0337 ret->put(exec, n, jsString(name.ustring()), None); 0338 ++n; 0339 } 0340 ret->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete); 0341 return ret; 0342 } 0343 case Create: { //ECMA Edition 5.1r6 - 15.2.3.5 0344 JSObject *proto = JSValue::getObject(args[0]); 0345 if (!proto && !JSValue::isNull(args[0])) { 0346 return throwError(exec, TypeError, "Not an Object"); 0347 } 0348 0349 JSObject *ret = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinObject()->construct(exec, List::empty())); 0350 if (proto) { 0351 ret->setPrototype(proto); 0352 } else { 0353 ret->setPrototype(jsNull()); 0354 } 0355 if (args.size() >= 2 && !JSValue::isUndefined(args[1])) { 0356 return defineProperties(exec, ret, args[1]); 0357 } 0358 return ret; 0359 } 0360 case DefineProperty: { //ECMA Edition 5.1r6 - 15.2.3.6 0361 JSObject *jso = JSValue::getObject(args[0]); 0362 if (!jso) { 0363 return throwError(exec, TypeError, "Not an Object"); 0364 } 0365 0366 UString name = JSValue::toString(args[1], exec); 0367 PropertyDescriptor desc; 0368 if (!desc.setPropertyDescriptorFromObject(exec, args[2])) { 0369 return jsUndefined(); 0370 } 0371 if (!jso->defineOwnProperty(exec, Identifier(name), desc, true)) { 0372 return jsUndefined(); 0373 } 0374 return jso; 0375 } 0376 case DefineProperties: { //ECMA Edition 5.1r6 - 15.2.3.7 0377 if (!JSValue::isObject(args[0])) { 0378 return throwError(exec, TypeError, "Not an Object"); 0379 } 0380 0381 JSObject *jso = JSValue::getObject(args[0]); 0382 return defineProperties(exec, jso, args[1]); 0383 } 0384 case Seal: { //ECMA Edition 5.1r6 - 15.2.3.8 0385 JSObject *jso = JSValue::getObject(args[0]); 0386 if (!jso) { 0387 return throwError(exec, TypeError, "Not an Object"); 0388 } 0389 0390 PropertyNameArray names; 0391 jso->getOwnPropertyNames(exec, names, PropertyMap::IncludeDontEnumProperties); 0392 int size = names.size(); 0393 0394 PropertyDescriptor desc; 0395 for (int i = 0; i < size; ++i) { 0396 jso->getOwnPropertyDescriptor(exec, names[i], desc); 0397 if (desc.configurable()) { 0398 desc.setConfigureable(false); 0399 if (!jso->defineOwnProperty(exec, names[i], desc, true)) { 0400 return jsUndefined(); 0401 } 0402 } 0403 } 0404 jso->preventExtensions(); 0405 return jso; 0406 } 0407 case Freeze: { //ECMA Edition 5.1r6 - 15.2.3.9 0408 JSObject *jso = JSValue::getObject(args[0]); 0409 if (!jso) { 0410 return throwError(exec, TypeError, "Not an Object"); 0411 } 0412 0413 PropertyNameArray names; 0414 jso->getOwnPropertyNames(exec, names, PropertyMap::IncludeDontEnumProperties); 0415 int size = names.size(); 0416 0417 PropertyDescriptor desc; 0418 for (int i = 0; i < size; ++i) { 0419 jso->getOwnPropertyDescriptor(exec, names[i], desc); 0420 if (desc.isDataDescriptor()) 0421 if (desc.writable()) { 0422 desc.setWritable(false); 0423 } 0424 if (desc.configurable()) { 0425 desc.setConfigureable(false); 0426 } 0427 if (!jso->defineOwnProperty(exec, names[i], desc, true)) { 0428 return jsUndefined(); 0429 } 0430 } 0431 jso->preventExtensions(); 0432 return jso; 0433 } 0434 case PreventExtensible: { //ECMA Edition 5.1r6 - 15.2.3.10 0435 JSObject *jso = JSValue::getObject(args[0]); 0436 if (!jso) { 0437 return throwError(exec, TypeError, "Not an Object"); 0438 } 0439 jso->preventExtensions(); 0440 return jso; 0441 } 0442 case IsSealed: { //ECMA Edition 5.1r6 - 15.2.3.11 0443 JSObject *jso = JSValue::getObject(args[0]); 0444 if (!jso) { 0445 return throwError(exec, TypeError, "Not an Object"); 0446 } 0447 0448 PropertyNameArray names; 0449 jso->getOwnPropertyNames(exec, names, PropertyMap::IncludeDontEnumProperties); 0450 int size = names.size(); 0451 0452 PropertyDescriptor desc; 0453 for (int i = 0; i < size; ++i) { 0454 jso->getOwnPropertyDescriptor(exec, names[i], desc); 0455 if (desc.configurable()) { 0456 return jsBoolean(false); 0457 } 0458 } 0459 return jsBoolean(!jso->isExtensible()); 0460 } 0461 case IsFrozen: { //ECMA Edition 5.1r6 - 15.2.3.12 0462 JSObject *jso = JSValue::getObject(args[0]); 0463 if (!jso) { 0464 return throwError(exec, TypeError, "Not an Object"); 0465 } 0466 0467 PropertyNameArray names; 0468 jso->getOwnPropertyNames(exec, names, PropertyMap::IncludeDontEnumProperties); 0469 int size = names.size(); 0470 0471 PropertyDescriptor desc; 0472 for (int i = 0; i < size; ++i) { 0473 jso->getOwnPropertyDescriptor(exec, names[i], desc); 0474 if (desc.isDataDescriptor()) 0475 if (desc.writable()) { 0476 return jsBoolean(false); 0477 } 0478 if (desc.configurable()) { 0479 return jsBoolean(false); 0480 } 0481 } 0482 return jsBoolean(!jso->isExtensible()); 0483 } 0484 case IsExtensible: { //ECMA Edition 5.1r6 - 15.2.3.13 0485 JSObject *jso = JSValue::getObject(args[0]); 0486 if (!jso) { 0487 return throwError(exec, TypeError, "Not an Object"); 0488 } 0489 return jsBoolean(jso->isExtensible()); 0490 } 0491 case Is: { //ES6 (Draft 08.11.2013) - 19.1.2.10 0492 return jsBoolean(sameValue(exec, args[0], args[1])); 0493 } 0494 default: 0495 return jsUndefined(); 0496 } 0497 } 0498 0499 } // namespace KJS