PropertyAndElement.cpp (38888B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "js/PropertyAndElement.h" 8 9 #include "mozilla/Assertions.h" // MOZ_ASSERT 10 11 #include <stddef.h> // size_t 12 #include <stdint.h> // uint32_t 13 14 #include "jsfriendapi.h" // js::GetPropertyKeys, JSITER_OWNONLY 15 #include "jstypes.h" // JS_PUBLIC_API 16 17 #include "js/CallArgs.h" // JSNative 18 #include "js/Class.h" // JS::ObjectOpResult 19 #include "js/Context.h" // AssertHeapIsIdle 20 #include "js/GCVector.h" // JS::GCVector, JS::RootedVector 21 #include "js/Id.h" // JS::PropertyKey, jsid 22 #include "js/PropertyDescriptor.h" // JS::PropertyDescriptor, JSPROP_READONLY 23 #include "js/PropertySpec.h" // JSNativeWrapper 24 #include "js/RootingAPI.h" // JS::Rooted, JS::Handle, JS::MutableHandle 25 #include "js/Value.h" // JS::Value, JS::*Value 26 #include "vm/FunctionPrefixKind.h" // js::FunctionPrefixKind 27 #include "vm/GlobalObject.h" // js::GlobalObject 28 #include "vm/JSAtomUtils.h" // js::Atomize, js::AtomizeChars 29 #include "vm/JSContext.h" // JSContext, CHECK_THREAD 30 #include "vm/JSFunction.h" // js::IdToFunctionName, js::DefineFunction 31 #include "vm/JSObject.h" // JSObject, js::DefineFunctions 32 #include "vm/ObjectOperations.h" // js::DefineProperty, js::DefineDataProperty, js::HasOwnProperty 33 #include "vm/PropertyResult.h" // js::PropertyResult 34 #include "vm/StringType.h" // JSAtom, js::PropertyName 35 36 #include "vm/JSAtomUtils-inl.h" // js::AtomToId, js::IndexToId 37 #include "vm/JSContext-inl.h" // JSContext::check 38 #include "vm/JSObject-inl.h" // js::NewBuiltinClassInstance 39 #include "vm/NativeObject-inl.h" // js::NativeLookupOwnPropertyNoResolve 40 #include "vm/ObjectOperations-inl.h" // js::GetProperty, js::GetElement, js::SetProperty, js::HasProperty, js::DeleteProperty, js::DeleteElement 41 42 using namespace js; 43 44 static bool DefinePropertyByDescriptor(JSContext* cx, JS::Handle<JSObject*> obj, 45 JS::Handle<jsid> id, 46 JS::Handle<JS::PropertyDescriptor> desc, 47 JS::ObjectOpResult& result) { 48 AssertHeapIsIdle(); 49 CHECK_THREAD(cx); 50 cx->check(obj, id, desc); 51 return js::DefineProperty(cx, obj, id, desc, result); 52 } 53 54 JS_PUBLIC_API bool JS_DefinePropertyById( 55 JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 56 JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result) { 57 return ::DefinePropertyByDescriptor(cx, obj, id, desc, result); 58 } 59 60 JS_PUBLIC_API bool JS_DefinePropertyById( 61 JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 62 JS::Handle<JS::PropertyDescriptor> desc) { 63 JS::ObjectOpResult result; 64 return ::DefinePropertyByDescriptor(cx, obj, id, desc, result) && 65 result.checkStrict(cx, obj, id); 66 } 67 68 static bool DefineDataPropertyById(JSContext* cx, JS::Handle<JSObject*> obj, 69 JS::Handle<jsid> id, 70 JS::Handle<JS::Value> value, 71 unsigned attrs) { 72 AssertHeapIsIdle(); 73 CHECK_THREAD(cx); 74 cx->check(obj, id, value); 75 76 return js::DefineDataProperty(cx, obj, id, value, attrs); 77 } 78 79 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, 80 JS::Handle<JSObject*> obj, 81 JS::Handle<jsid> id, 82 JS::Handle<JS::Value> value, 83 unsigned attrs) { 84 return ::DefineDataPropertyById(cx, obj, id, value, attrs); 85 } 86 87 static bool DefineAccessorPropertyById(JSContext* cx, JS::Handle<JSObject*> obj, 88 JS::Handle<jsid> id, 89 JS::Handle<JSObject*> getter, 90 JS::Handle<JSObject*> setter, 91 unsigned attrs) { 92 // JSPROP_READONLY has no meaning when accessors are involved. Ideally we'd 93 // throw if this happens, but we've accepted it for long enough that it's 94 // not worth trying to make callers change their ways. Just flip it off on 95 // its way through the API layer so that we can enforce this internally. 96 attrs &= ~JSPROP_READONLY; 97 98 AssertHeapIsIdle(); 99 CHECK_THREAD(cx); 100 cx->check(obj, id, getter, setter); 101 102 return js::DefineAccessorProperty(cx, obj, id, getter, setter, attrs); 103 } 104 105 static bool DefineAccessorPropertyById(JSContext* cx, JS::Handle<JSObject*> obj, 106 JS::Handle<jsid> id, 107 const JSNativeWrapper& get, 108 const JSNativeWrapper& set, 109 unsigned attrs) { 110 // Getter/setter are both possibly-null JSNatives. Wrap them in JSFunctions. 111 112 // Use unprefixed name with LAZY_ACCESSOR_NAME flag, to avoid calculating 113 // the accessor name, which is less likely to be used. 114 JS::Rooted<JSAtom*> atom(cx, IdToFunctionName(cx, id)); 115 if (!atom) { 116 return false; 117 } 118 119 JS::Rooted<JSFunction*> getter(cx); 120 if (get.op) { 121 getter = NewNativeFunction(cx, get.op, 0, atom, gc::AllocKind::FUNCTION, 122 TenuredObject, 123 FunctionFlags::NATIVE_GETTER_WITH_LAZY_NAME); 124 if (!getter) { 125 return false; 126 } 127 128 if (get.info) { 129 getter->setJitInfo(get.info); 130 } 131 } 132 133 JS::Rooted<JSFunction*> setter(cx); 134 if (set.op) { 135 setter = NewNativeFunction(cx, set.op, 1, atom, gc::AllocKind::FUNCTION, 136 TenuredObject, 137 FunctionFlags::NATIVE_SETTER_WITH_LAZY_NAME); 138 if (!setter) { 139 return false; 140 } 141 142 if (set.info) { 143 setter->setJitInfo(set.info); 144 } 145 } 146 147 return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); 148 } 149 150 /* 151 * Wrapper functions to create wrappers with no corresponding JSJitInfo from API 152 * function arguments. 153 */ 154 static JSNativeWrapper NativeOpWrapper(Native native) { 155 JSNativeWrapper ret; 156 ret.op = native; 157 ret.info = nullptr; 158 return ret; 159 } 160 161 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, 162 JS::Handle<JSObject*> obj, 163 JS::Handle<jsid> id, JSNative getter, 164 JSNative setter, unsigned attrs) { 165 return ::DefineAccessorPropertyById(cx, obj, id, ::NativeOpWrapper(getter), 166 ::NativeOpWrapper(setter), attrs); 167 } 168 169 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, 170 JS::Handle<JSObject*> obj, 171 JS::Handle<jsid> id, 172 JS::Handle<JSObject*> getter, 173 JS::Handle<JSObject*> setter, 174 unsigned attrs) { 175 return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); 176 } 177 178 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, 179 JS::Handle<JSObject*> obj, 180 JS::Handle<jsid> id, 181 JS::Handle<JSObject*> valueArg, 182 unsigned attrs) { 183 JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*valueArg)); 184 return ::DefineDataPropertyById(cx, obj, id, value, attrs); 185 } 186 187 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, 188 JS::Handle<JSObject*> obj, 189 JS::Handle<jsid> id, 190 HandleString valueArg, 191 unsigned attrs) { 192 JS::Rooted<JS::Value> value(cx, JS::StringValue(valueArg)); 193 return ::DefineDataPropertyById(cx, obj, id, value, attrs); 194 } 195 196 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, 197 JS::Handle<JSObject*> obj, 198 JS::Handle<jsid> id, int32_t valueArg, 199 unsigned attrs) { 200 JS::Value value = JS::Int32Value(valueArg); 201 return ::DefineDataPropertyById( 202 cx, obj, id, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 203 } 204 205 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, 206 JS::Handle<JSObject*> obj, 207 JS::Handle<jsid> id, uint32_t valueArg, 208 unsigned attrs) { 209 JS::Value value = JS::NumberValue(valueArg); 210 return ::DefineDataPropertyById( 211 cx, obj, id, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 212 } 213 214 JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, 215 JS::Handle<JSObject*> obj, 216 JS::Handle<jsid> id, double valueArg, 217 unsigned attrs) { 218 JS::Value value = JS::NumberValue(valueArg); 219 return ::DefineDataPropertyById( 220 cx, obj, id, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 221 } 222 223 static bool DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, 224 const char* name, JS::Handle<JS::Value> value, 225 unsigned attrs) { 226 JSAtom* atom = Atomize(cx, name, strlen(name)); 227 if (!atom) { 228 return false; 229 } 230 JS::Rooted<jsid> id(cx, AtomToId(atom)); 231 232 return ::DefineDataPropertyById(cx, obj, id, value, attrs); 233 } 234 235 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 236 const char* name, 237 JS::Handle<JS::Value> value, 238 unsigned attrs) { 239 return ::DefineDataProperty(cx, obj, name, value, attrs); 240 } 241 242 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 243 const char* name, JSNative getter, 244 JSNative setter, unsigned attrs) { 245 JSAtom* atom = Atomize(cx, name, strlen(name)); 246 if (!atom) { 247 return false; 248 } 249 JS::Rooted<jsid> id(cx, AtomToId(atom)); 250 return ::DefineAccessorPropertyById(cx, obj, id, ::NativeOpWrapper(getter), 251 ::NativeOpWrapper(setter), attrs); 252 } 253 254 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 255 const char* name, 256 JS::Handle<JSObject*> getter, 257 JS::Handle<JSObject*> setter, 258 unsigned attrs) { 259 JSAtom* atom = Atomize(cx, name, strlen(name)); 260 if (!atom) { 261 return false; 262 } 263 JS::Rooted<jsid> id(cx, AtomToId(atom)); 264 265 return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); 266 } 267 268 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 269 const char* name, 270 JS::Handle<JSObject*> valueArg, 271 unsigned attrs) { 272 JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*valueArg)); 273 return ::DefineDataProperty(cx, obj, name, value, attrs); 274 } 275 276 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 277 const char* name, HandleString valueArg, 278 unsigned attrs) { 279 JS::Rooted<JS::Value> value(cx, JS::StringValue(valueArg)); 280 return ::DefineDataProperty(cx, obj, name, value, attrs); 281 } 282 283 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 284 const char* name, int32_t valueArg, 285 unsigned attrs) { 286 JS::Value value = JS::Int32Value(valueArg); 287 return ::DefineDataProperty( 288 cx, obj, name, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 289 } 290 291 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 292 const char* name, uint32_t valueArg, 293 unsigned attrs) { 294 JS::Value value = JS::NumberValue(valueArg); 295 return ::DefineDataProperty( 296 cx, obj, name, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 297 } 298 299 JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, 300 const char* name, double valueArg, 301 unsigned attrs) { 302 JS::Value value = JS::NumberValue(valueArg); 303 return ::DefineDataProperty( 304 cx, obj, name, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 305 } 306 307 #define AUTO_NAMELEN(s, n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) 308 309 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 310 const char16_t* name, size_t namelen, 311 JS::Handle<JS::PropertyDescriptor> desc, 312 JS::ObjectOpResult& result) { 313 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 314 if (!atom) { 315 return false; 316 } 317 JS::Rooted<jsid> id(cx, AtomToId(atom)); 318 return ::DefinePropertyByDescriptor(cx, obj, id, desc, result); 319 } 320 321 JS_PUBLIC_API bool JS_DefineUCProperty( 322 JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name, 323 size_t namelen, JS::Handle<JS::PropertyDescriptor> desc) { 324 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 325 if (!atom) { 326 return false; 327 } 328 JS::Rooted<jsid> id(cx, AtomToId(atom)); 329 JS::ObjectOpResult result; 330 return ::DefinePropertyByDescriptor(cx, obj, id, desc, result) && 331 result.checkStrict(cx, obj, id); 332 } 333 334 static bool DefineUCDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, 335 const char16_t* name, size_t namelen, 336 JS::Handle<JS::Value> value, unsigned attrs) { 337 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 338 if (!atom) { 339 return false; 340 } 341 JS::Rooted<jsid> id(cx, AtomToId(atom)); 342 return ::DefineDataPropertyById(cx, obj, id, value, attrs); 343 } 344 345 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 346 const char16_t* name, size_t namelen, 347 JS::Handle<JS::Value> value, 348 unsigned attrs) { 349 return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs); 350 } 351 352 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 353 const char16_t* name, size_t namelen, 354 JS::Handle<JSObject*> getter, 355 JS::Handle<JSObject*> setter, 356 unsigned attrs) { 357 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 358 if (!atom) { 359 return false; 360 } 361 JS::Rooted<jsid> id(cx, AtomToId(atom)); 362 return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); 363 } 364 365 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 366 const char16_t* name, size_t namelen, 367 JS::Handle<JSObject*> valueArg, 368 unsigned attrs) { 369 JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*valueArg)); 370 return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs); 371 } 372 373 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 374 const char16_t* name, size_t namelen, 375 HandleString valueArg, unsigned attrs) { 376 JS::Rooted<JS::Value> value(cx, JS::StringValue(valueArg)); 377 return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs); 378 } 379 380 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 381 const char16_t* name, size_t namelen, 382 int32_t valueArg, unsigned attrs) { 383 JS::Value value = JS::Int32Value(valueArg); 384 return ::DefineUCDataProperty( 385 cx, obj, name, namelen, JS::Handle<JS::Value>::fromMarkedLocation(&value), 386 attrs); 387 } 388 389 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 390 const char16_t* name, size_t namelen, 391 uint32_t valueArg, unsigned attrs) { 392 JS::Value value = JS::NumberValue(valueArg); 393 return ::DefineUCDataProperty( 394 cx, obj, name, namelen, JS::Handle<JS::Value>::fromMarkedLocation(&value), 395 attrs); 396 } 397 398 JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 399 const char16_t* name, size_t namelen, 400 double valueArg, unsigned attrs) { 401 JS::Value value = JS::NumberValue(valueArg); 402 return ::DefineUCDataProperty( 403 cx, obj, name, namelen, JS::Handle<JS::Value>::fromMarkedLocation(&value), 404 attrs); 405 } 406 407 extern bool PropertySpecNameToId(JSContext* cx, JSPropertySpec::Name name, 408 MutableHandleId id); 409 410 static bool DefineSelfHostedProperty(JSContext* cx, JS::Handle<JSObject*> obj, 411 JS::Handle<jsid> id, 412 const char* getterName, 413 const char* setterName, unsigned attrs) { 414 JSAtom* getterNameAtom = Atomize(cx, getterName, strlen(getterName)); 415 if (!getterNameAtom) { 416 return false; 417 } 418 JS::Rooted<PropertyName*> getterNameName(cx, 419 getterNameAtom->asPropertyName()); 420 421 JS::Rooted<JSAtom*> name(cx, IdToFunctionName(cx, id)); 422 if (!name) { 423 return false; 424 } 425 426 JS::Rooted<JS::Value> getterValue(cx); 427 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), getterNameName, 428 name, 0, &getterValue)) { 429 return false; 430 } 431 MOZ_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>()); 432 JS::Rooted<JSFunction*> getterFunc(cx, 433 &getterValue.toObject().as<JSFunction>()); 434 435 JS::Rooted<JSFunction*> setterFunc(cx); 436 if (setterName) { 437 JSAtom* setterNameAtom = Atomize(cx, setterName, strlen(setterName)); 438 if (!setterNameAtom) { 439 return false; 440 } 441 JS::Rooted<PropertyName*> setterNameName(cx, 442 setterNameAtom->asPropertyName()); 443 444 JS::Rooted<JS::Value> setterValue(cx); 445 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), setterNameName, 446 name, 1, &setterValue)) { 447 return false; 448 } 449 MOZ_ASSERT(setterValue.isObject() && 450 setterValue.toObject().is<JSFunction>()); 451 setterFunc = &setterValue.toObject().as<JSFunction>(); 452 } 453 454 return ::DefineAccessorPropertyById(cx, obj, id, getterFunc, setterFunc, 455 attrs); 456 } 457 458 static bool DefineDataElement(JSContext* cx, JS::Handle<JSObject*> obj, 459 uint32_t index, JS::Handle<JS::Value> value, 460 unsigned attrs) { 461 cx->check(obj, value); 462 AssertHeapIsIdle(); 463 CHECK_THREAD(cx); 464 JS::Rooted<jsid> id(cx); 465 if (!IndexToId(cx, index, &id)) { 466 return false; 467 } 468 return ::DefineDataPropertyById(cx, obj, id, value, attrs); 469 } 470 471 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj, 472 uint32_t index, JS::Handle<JS::Value> value, 473 unsigned attrs) { 474 return ::DefineDataElement(cx, obj, index, value, attrs); 475 } 476 477 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj, 478 uint32_t index, 479 JS::Handle<JSObject*> getter, 480 JS::Handle<JSObject*> setter, 481 unsigned attrs) { 482 JS::Rooted<jsid> id(cx); 483 if (!IndexToId(cx, index, &id)) { 484 return false; 485 } 486 return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); 487 } 488 489 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj, 490 uint32_t index, 491 JS::Handle<JSObject*> valueArg, 492 unsigned attrs) { 493 JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*valueArg)); 494 return ::DefineDataElement(cx, obj, index, value, attrs); 495 } 496 497 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj, 498 uint32_t index, HandleString valueArg, 499 unsigned attrs) { 500 JS::Rooted<JS::Value> value(cx, JS::StringValue(valueArg)); 501 return ::DefineDataElement(cx, obj, index, value, attrs); 502 } 503 504 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj, 505 uint32_t index, int32_t valueArg, 506 unsigned attrs) { 507 JS::Value value = JS::Int32Value(valueArg); 508 return ::DefineDataElement( 509 cx, obj, index, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 510 } 511 512 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj, 513 uint32_t index, uint32_t valueArg, 514 unsigned attrs) { 515 JS::Value value = JS::NumberValue(valueArg); 516 return ::DefineDataElement( 517 cx, obj, index, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 518 } 519 520 JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj, 521 uint32_t index, double valueArg, 522 unsigned attrs) { 523 JS::Value value = JS::NumberValue(valueArg); 524 return ::DefineDataElement( 525 cx, obj, index, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs); 526 } 527 528 JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx, JS::Handle<JSObject*> obj, 529 JS::Handle<jsid> id, bool* foundp) { 530 AssertHeapIsIdle(); 531 CHECK_THREAD(cx); 532 cx->check(obj, id); 533 534 return js::HasProperty(cx, obj, id, foundp); 535 } 536 537 JS_PUBLIC_API bool JS_HasProperty(JSContext* cx, JS::Handle<JSObject*> obj, 538 const char* name, bool* foundp) { 539 JSAtom* atom = Atomize(cx, name, strlen(name)); 540 if (!atom) { 541 return false; 542 } 543 JS::Rooted<jsid> id(cx, AtomToId(atom)); 544 return JS_HasPropertyById(cx, obj, id, foundp); 545 } 546 547 JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 548 const char16_t* name, size_t namelen, 549 bool* foundp) { 550 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 551 if (!atom) { 552 return false; 553 } 554 JS::Rooted<jsid> id(cx, AtomToId(atom)); 555 return JS_HasPropertyById(cx, obj, id, foundp); 556 } 557 558 JS_PUBLIC_API bool JS_HasElement(JSContext* cx, JS::Handle<JSObject*> obj, 559 uint32_t index, bool* foundp) { 560 AssertHeapIsIdle(); 561 CHECK_THREAD(cx); 562 JS::Rooted<jsid> id(cx); 563 if (!IndexToId(cx, index, &id)) { 564 return false; 565 } 566 return JS_HasPropertyById(cx, obj, id, foundp); 567 } 568 569 JS_PUBLIC_API bool JS_HasOwnPropertyById(JSContext* cx, 570 JS::Handle<JSObject*> obj, 571 JS::Handle<jsid> id, bool* foundp) { 572 AssertHeapIsIdle(); 573 CHECK_THREAD(cx); 574 cx->check(obj, id); 575 576 return js::HasOwnProperty(cx, obj, id, foundp); 577 } 578 579 JS_PUBLIC_API bool JS_HasOwnProperty(JSContext* cx, JS::Handle<JSObject*> obj, 580 const char* name, bool* foundp) { 581 JSAtom* atom = Atomize(cx, name, strlen(name)); 582 if (!atom) { 583 return false; 584 } 585 JS::Rooted<jsid> id(cx, AtomToId(atom)); 586 return JS_HasOwnPropertyById(cx, obj, id, foundp); 587 } 588 589 JS_PUBLIC_API bool JS_ForwardGetPropertyTo(JSContext* cx, 590 JS::Handle<JSObject*> obj, 591 JS::Handle<jsid> id, 592 JS::Handle<JS::Value> receiver, 593 JS::MutableHandle<JS::Value> vp) { 594 AssertHeapIsIdle(); 595 CHECK_THREAD(cx); 596 cx->check(obj, id, receiver); 597 598 return js::GetProperty(cx, obj, receiver, id, vp); 599 } 600 601 JS_PUBLIC_API bool JS_ForwardGetElementTo(JSContext* cx, 602 JS::Handle<JSObject*> obj, 603 uint32_t index, 604 JS::Handle<JSObject*> receiver, 605 JS::MutableHandle<JS::Value> vp) { 606 AssertHeapIsIdle(); 607 CHECK_THREAD(cx); 608 cx->check(obj); 609 610 return js::GetElement(cx, obj, receiver, index, vp); 611 } 612 613 JS_PUBLIC_API bool JS_GetPropertyById(JSContext* cx, JS::Handle<JSObject*> obj, 614 JS::Handle<jsid> id, 615 JS::MutableHandle<JS::Value> vp) { 616 JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj)); 617 return JS_ForwardGetPropertyTo(cx, obj, id, receiver, vp); 618 } 619 620 JS_PUBLIC_API bool JS_GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 621 const char* name, 622 JS::MutableHandle<JS::Value> vp) { 623 JSAtom* atom = Atomize(cx, name, strlen(name)); 624 if (!atom) { 625 return false; 626 } 627 JS::Rooted<jsid> id(cx, AtomToId(atom)); 628 return JS_GetPropertyById(cx, obj, id, vp); 629 } 630 631 JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 632 const char16_t* name, size_t namelen, 633 JS::MutableHandle<JS::Value> vp) { 634 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 635 if (!atom) { 636 return false; 637 } 638 JS::Rooted<jsid> id(cx, AtomToId(atom)); 639 return JS_GetPropertyById(cx, obj, id, vp); 640 } 641 642 JS_PUBLIC_API bool JS_GetElement(JSContext* cx, JS::Handle<JSObject*> objArg, 643 uint32_t index, 644 JS::MutableHandle<JS::Value> vp) { 645 return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp); 646 } 647 648 JS_PUBLIC_API bool JS_ForwardSetPropertyTo(JSContext* cx, 649 JS::Handle<JSObject*> obj, 650 JS::Handle<jsid> id, 651 JS::Handle<JS::Value> v, 652 JS::Handle<JS::Value> receiver, 653 JS::ObjectOpResult& result) { 654 AssertHeapIsIdle(); 655 CHECK_THREAD(cx); 656 cx->check(obj, id, v, receiver); 657 658 return js::SetProperty(cx, obj, id, v, receiver, result); 659 } 660 661 JS_PUBLIC_API bool JS_SetPropertyById(JSContext* cx, JS::Handle<JSObject*> obj, 662 JS::Handle<jsid> id, 663 JS::Handle<JS::Value> v) { 664 AssertHeapIsIdle(); 665 CHECK_THREAD(cx); 666 cx->check(obj, id, v); 667 668 JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj)); 669 JS::ObjectOpResult ignored; 670 return js::SetProperty(cx, obj, id, v, receiver, ignored); 671 } 672 673 JS_PUBLIC_API bool JS_SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, 674 const char* name, JS::Handle<JS::Value> v) { 675 JSAtom* atom = Atomize(cx, name, strlen(name)); 676 if (!atom) { 677 return false; 678 } 679 JS::Rooted<jsid> id(cx, AtomToId(atom)); 680 return JS_SetPropertyById(cx, obj, id, v); 681 } 682 683 JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 684 const char16_t* name, size_t namelen, 685 JS::Handle<JS::Value> v) { 686 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 687 if (!atom) { 688 return false; 689 } 690 JS::Rooted<jsid> id(cx, AtomToId(atom)); 691 return JS_SetPropertyById(cx, obj, id, v); 692 } 693 694 static bool SetElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index, 695 JS::Handle<JS::Value> v) { 696 AssertHeapIsIdle(); 697 CHECK_THREAD(cx); 698 cx->check(obj, v); 699 700 JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj)); 701 JS::ObjectOpResult ignored; 702 return js::SetElement(cx, obj, index, v, receiver, ignored); 703 } 704 705 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj, 706 uint32_t index, JS::Handle<JS::Value> v) { 707 return ::SetElement(cx, obj, index, v); 708 } 709 710 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj, 711 uint32_t index, JS::Handle<JSObject*> v) { 712 JS::Rooted<JS::Value> value(cx, JS::ObjectOrNullValue(v)); 713 return ::SetElement(cx, obj, index, value); 714 } 715 716 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj, 717 uint32_t index, HandleString v) { 718 JS::Rooted<JS::Value> value(cx, JS::StringValue(v)); 719 return ::SetElement(cx, obj, index, value); 720 } 721 722 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj, 723 uint32_t index, int32_t v) { 724 JS::Rooted<JS::Value> value(cx, JS::NumberValue(v)); 725 return ::SetElement(cx, obj, index, value); 726 } 727 728 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj, 729 uint32_t index, uint32_t v) { 730 JS::Rooted<JS::Value> value(cx, JS::NumberValue(v)); 731 return ::SetElement(cx, obj, index, value); 732 } 733 734 JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj, 735 uint32_t index, double v) { 736 JS::Rooted<JS::Value> value(cx, JS::NumberValue(v)); 737 return ::SetElement(cx, obj, index, value); 738 } 739 740 JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, 741 JS::Handle<JSObject*> obj, 742 JS::Handle<jsid> id, 743 JS::ObjectOpResult& result) { 744 AssertHeapIsIdle(); 745 CHECK_THREAD(cx); 746 cx->check(obj, id); 747 748 return js::DeleteProperty(cx, obj, id, result); 749 } 750 751 JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::Handle<JSObject*> obj, 752 const char* name, 753 JS::ObjectOpResult& result) { 754 CHECK_THREAD(cx); 755 cx->check(obj); 756 757 JSAtom* atom = Atomize(cx, name, strlen(name)); 758 if (!atom) { 759 return false; 760 } 761 JS::Rooted<jsid> id(cx, AtomToId(atom)); 762 return js::DeleteProperty(cx, obj, id, result); 763 } 764 765 JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx, JS::Handle<JSObject*> obj, 766 const char16_t* name, size_t namelen, 767 JS::ObjectOpResult& result) { 768 CHECK_THREAD(cx); 769 cx->check(obj); 770 771 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 772 if (!atom) { 773 return false; 774 } 775 JS::Rooted<jsid> id(cx, AtomToId(atom)); 776 return js::DeleteProperty(cx, obj, id, result); 777 } 778 779 JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::Handle<JSObject*> obj, 780 uint32_t index, 781 JS::ObjectOpResult& result) { 782 AssertHeapIsIdle(); 783 CHECK_THREAD(cx); 784 cx->check(obj); 785 786 return js::DeleteElement(cx, obj, index, result); 787 } 788 789 JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, 790 JS::Handle<JSObject*> obj, 791 JS::Handle<jsid> id) { 792 JS::ObjectOpResult ignored; 793 return JS_DeletePropertyById(cx, obj, id, ignored); 794 } 795 796 JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::Handle<JSObject*> obj, 797 const char* name) { 798 JS::ObjectOpResult ignored; 799 return JS_DeleteProperty(cx, obj, name, ignored); 800 } 801 802 JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::Handle<JSObject*> obj, 803 uint32_t index) { 804 JS::ObjectOpResult ignored; 805 return JS_DeleteElement(cx, obj, index, ignored); 806 } 807 808 JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::Handle<JSObject*> obj, 809 JS::MutableHandle<IdVector> props) { 810 AssertHeapIsIdle(); 811 CHECK_THREAD(cx); 812 cx->check(obj, props); 813 MOZ_ASSERT(props.empty()); 814 815 JS::RootedVector<JS::PropertyKey> ids(cx); 816 if (!js::GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids)) { 817 return false; 818 } 819 820 return props.append(ids.begin(), ids.end()); 821 } 822 823 JS_PUBLIC_API JSObject* JS_DefineObject(JSContext* cx, 824 JS::Handle<JSObject*> obj, 825 const char* name, const JSClass* clasp, 826 unsigned attrs) { 827 AssertHeapIsIdle(); 828 CHECK_THREAD(cx); 829 cx->check(obj); 830 831 JS::Rooted<JSObject*> nobj(cx); 832 if (!clasp) { 833 // Default class is Object. 834 nobj = NewPlainObject(cx); 835 } else { 836 nobj = NewBuiltinClassInstance(cx, clasp); 837 } 838 if (!nobj) { 839 return nullptr; 840 } 841 842 JS::Rooted<JS::Value> nobjValue(cx, JS::ObjectValue(*nobj)); 843 if (!::DefineDataProperty(cx, obj, name, nobjValue, attrs)) { 844 return nullptr; 845 } 846 847 return nobj; 848 } 849 850 JS_PUBLIC_API bool JS_DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj, 851 const JSPropertySpec* ps) { 852 JS::Rooted<jsid> id(cx); 853 854 for (; ps->name; ps++) { 855 if (!PropertySpecNameToId(cx, ps->name, &id)) { 856 return false; 857 } 858 859 if (ShouldIgnorePropertyDefinition(cx, StandardProtoKeyOrNull(obj), id)) { 860 continue; 861 } 862 863 if (ps->isAccessor()) { 864 if (ps->isSelfHosted()) { 865 if (!::DefineSelfHostedProperty( 866 cx, obj, id, ps->u.accessors.getter.selfHosted.funname, 867 ps->u.accessors.setter.selfHosted.funname, ps->attributes())) { 868 return false; 869 } 870 } else { 871 if (!::DefineAccessorPropertyById( 872 cx, obj, id, ps->u.accessors.getter.native, 873 ps->u.accessors.setter.native, ps->attributes())) { 874 return false; 875 } 876 } 877 } else { 878 JS::Rooted<JS::Value> v(cx); 879 if (!ps->getValue(cx, &v)) { 880 return false; 881 } 882 883 if (!::DefineDataPropertyById(cx, obj, id, v, ps->attributes())) { 884 return false; 885 } 886 } 887 } 888 return true; 889 } 890 891 JS_PUBLIC_API bool JS_AlreadyHasOwnPropertyById(JSContext* cx, 892 JS::Handle<JSObject*> obj, 893 JS::Handle<jsid> id, 894 bool* foundp) { 895 AssertHeapIsIdle(); 896 CHECK_THREAD(cx); 897 cx->check(obj, id); 898 899 if (!obj->is<NativeObject>()) { 900 return js::HasOwnProperty(cx, obj, id, foundp); 901 } 902 903 PropertyResult prop; 904 if (!NativeLookupOwnPropertyNoResolve(cx, &obj->as<NativeObject>(), id, 905 &prop)) { 906 return false; 907 } 908 *foundp = prop.isFound(); 909 return true; 910 } 911 912 JS_PUBLIC_API bool JS_AlreadyHasOwnProperty(JSContext* cx, 913 JS::Handle<JSObject*> obj, 914 const char* name, bool* foundp) { 915 JSAtom* atom = Atomize(cx, name, strlen(name)); 916 if (!atom) { 917 return false; 918 } 919 JS::Rooted<jsid> id(cx, AtomToId(atom)); 920 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); 921 } 922 923 JS_PUBLIC_API bool JS_AlreadyHasOwnUCProperty(JSContext* cx, 924 JS::Handle<JSObject*> obj, 925 const char16_t* name, 926 size_t namelen, bool* foundp) { 927 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 928 if (!atom) { 929 return false; 930 } 931 JS::Rooted<jsid> id(cx, AtomToId(atom)); 932 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); 933 } 934 935 JS_PUBLIC_API bool JS_AlreadyHasOwnElement(JSContext* cx, 936 JS::Handle<JSObject*> obj, 937 uint32_t index, bool* foundp) { 938 AssertHeapIsIdle(); 939 CHECK_THREAD(cx); 940 JS::Rooted<jsid> id(cx); 941 if (!IndexToId(cx, index, &id)) { 942 return false; 943 } 944 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); 945 } 946 947 JS_PUBLIC_API bool JS_DefineFunctions(JSContext* cx, JS::Handle<JSObject*> obj, 948 const JSFunctionSpec* fs) { 949 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 950 AssertHeapIsIdle(); 951 CHECK_THREAD(cx); 952 cx->check(obj); 953 954 return js::DefineFunctions(cx, obj, fs); 955 } 956 957 JS_PUBLIC_API JSFunction* JS_DefineFunction(JSContext* cx, 958 JS::Handle<JSObject*> obj, 959 const char* name, JSNative call, 960 unsigned nargs, unsigned attrs) { 961 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 962 AssertHeapIsIdle(); 963 CHECK_THREAD(cx); 964 cx->check(obj); 965 JSAtom* atom = Atomize(cx, name, strlen(name)); 966 if (!atom) { 967 return nullptr; 968 } 969 Rooted<jsid> id(cx, AtomToId(atom)); 970 return js::DefineFunction(cx, obj, id, call, nargs, attrs); 971 } 972 973 JS_PUBLIC_API JSFunction* JS_DefineUCFunction(JSContext* cx, 974 JS::Handle<JSObject*> obj, 975 const char16_t* name, 976 size_t namelen, JSNative call, 977 unsigned nargs, unsigned attrs) { 978 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 979 AssertHeapIsIdle(); 980 CHECK_THREAD(cx); 981 cx->check(obj); 982 JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); 983 if (!atom) { 984 return nullptr; 985 } 986 Rooted<jsid> id(cx, AtomToId(atom)); 987 return js::DefineFunction(cx, obj, id, call, nargs, attrs); 988 } 989 990 JS_PUBLIC_API JSFunction* JS_DefineFunctionById(JSContext* cx, 991 JS::Handle<JSObject*> obj, 992 JS::Handle<jsid> id, 993 JSNative call, unsigned nargs, 994 unsigned attrs) { 995 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 996 AssertHeapIsIdle(); 997 CHECK_THREAD(cx); 998 cx->check(obj, id); 999 return js::DefineFunction(cx, obj, id, call, nargs, attrs); 1000 }