tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }