tor-browser

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

ArgumentsObject.cpp (38444B)


      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 "vm/ArgumentsObject-inl.h"
      8 
      9 #include "mozilla/Maybe.h"
     10 #include "mozilla/PodOperations.h"
     11 
     12 #include <algorithm>
     13 
     14 #include "gc/GCContext.h"
     15 #include "jit/CalleeToken.h"
     16 #include "jit/JitFrames.h"
     17 #include "util/BitArray.h"
     18 #include "vm/GlobalObject.h"
     19 #include "vm/Stack.h"
     20 
     21 #include "gc/Nursery-inl.h"
     22 #include "vm/FrameIter-inl.h"  // js::FrameIter::unaliasedForEachActual
     23 #include "vm/NativeObject-inl.h"
     24 #include "vm/Stack-inl.h"
     25 
     26 using namespace js;
     27 
     28 /* static */
     29 size_t RareArgumentsData::bytesRequired(size_t numActuals) {
     30  size_t extraBytes = NumWordsForBitArrayOfLength(numActuals) * sizeof(size_t);
     31  return offsetof(RareArgumentsData, deletedBits_) + extraBytes;
     32 }
     33 
     34 /* static */
     35 RareArgumentsData* RareArgumentsData::create(JSContext* cx,
     36                                             ArgumentsObject* obj) {
     37  size_t bytes = RareArgumentsData::bytesRequired(obj->initialLength());
     38 
     39  uint8_t* data = AllocNurseryOrMallocBuffer<uint8_t>(cx, obj, bytes);
     40  if (!data) {
     41    return nullptr;
     42  }
     43 
     44  mozilla::PodZero(data, bytes);
     45 
     46  AddCellMemory(obj, bytes, MemoryUse::RareArgumentsData);
     47 
     48  return new (data) RareArgumentsData();
     49 }
     50 
     51 ArgumentsData::ArgumentsData(uint32_t numArgs) : args(numArgs) {
     52  // |args| must be the last field.
     53  static_assert(offsetof(ArgumentsData, args) + sizeof(args) ==
     54                sizeof(ArgumentsData));
     55 }
     56 
     57 bool ArgumentsObject::createRareData(JSContext* cx) {
     58  MOZ_ASSERT(!data()->rareData);
     59 
     60  RareArgumentsData* rareData = RareArgumentsData::create(cx, this);
     61  if (!rareData) {
     62    return false;
     63  }
     64 
     65  data()->rareData = rareData;
     66  markElementOverridden();
     67  return true;
     68 }
     69 
     70 bool ArgumentsObject::markElementDeleted(JSContext* cx, uint32_t i) {
     71  RareArgumentsData* data = getOrCreateRareData(cx);
     72  if (!data) {
     73    return false;
     74  }
     75 
     76  data->markElementDeleted(initialLength(), i);
     77  return true;
     78 }
     79 
     80 /* static */
     81 void ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame,
     82                                               ArgumentsObject* obj,
     83                                               ArgumentsData* data) {
     84  JSScript* script = frame.script();
     85  if (frame.callee()->needsCallObject() && script->argsObjAliasesFormals()) {
     86    obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj()));
     87    for (PositionalFormalParameterIter fi(script); fi; fi++) {
     88      if (fi.closedOver()) {
     89        data->args.setElement(obj, fi.argumentSlot(),
     90                              MagicEnvSlotValue(fi.location().slot()));
     91        obj->markArgumentForwarded();
     92      }
     93    }
     94  }
     95 }
     96 
     97 /* static */
     98 void ArgumentsObject::MaybeForwardToCallObject(JSFunction* callee,
     99                                               JSObject* callObj,
    100                                               ArgumentsObject* obj,
    101                                               ArgumentsData* data) {
    102  JSScript* script = callee->nonLazyScript();
    103  if (callee->needsCallObject() && script->argsObjAliasesFormals()) {
    104    MOZ_ASSERT(callObj && callObj->is<CallObject>());
    105    obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj));
    106    for (PositionalFormalParameterIter fi(script); fi; fi++) {
    107      if (fi.closedOver()) {
    108        data->args.setElement(obj, fi.argumentSlot(),
    109                              MagicEnvSlotValue(fi.location().slot()));
    110        obj->markArgumentForwarded();
    111      }
    112    }
    113  }
    114 }
    115 
    116 struct CopyFrameArgs {
    117  AbstractFramePtr frame_;
    118 
    119  explicit CopyFrameArgs(AbstractFramePtr frame) : frame_(frame) {}
    120 
    121  void copyActualArgs(ArgumentsObject* owner, GCOwnedArray<Value>& args,
    122                      unsigned numActuals) const {
    123    MOZ_ASSERT_IF(frame_.isInterpreterFrame(),
    124                  !frame_.asInterpreterFrame()->runningInJit());
    125 
    126    // Copy arguments.
    127    Value* src = frame_.argv();
    128    Value* end = src + numActuals;
    129    args.withOwner(owner, [&](auto& args) {
    130      auto* dst = args.begin();
    131      while (src != end) {
    132        (dst++)->init(*src++);
    133      }
    134    });
    135  }
    136 
    137  /*
    138   * If a call object exists and the arguments object aliases formals, the
    139   * call object is the canonical location for formals.
    140   */
    141  void maybeForwardToCallObject(ArgumentsObject* obj, ArgumentsData* data) {
    142    ArgumentsObject::MaybeForwardToCallObject(frame_, obj, data);
    143  }
    144 };
    145 
    146 struct CopyJitFrameArgs {
    147  jit::JitFrameLayout* frame_;
    148  HandleObject callObj_;
    149 
    150  CopyJitFrameArgs(jit::JitFrameLayout* frame, HandleObject callObj)
    151      : frame_(frame), callObj_(callObj) {}
    152 
    153  void copyActualArgs(ArgumentsObject* owner, GCOwnedArray<Value>& args,
    154                      unsigned numActuals) const {
    155    MOZ_ASSERT(frame_->numActualArgs() == numActuals);
    156 
    157    Value* src = frame_->actualArgs();
    158    Value* end = src + numActuals;
    159    args.withOwner(owner, [&](auto& args) {
    160      auto* dst = args.begin();
    161      while (src != end) {
    162        (dst++)->init(*src++);
    163      }
    164    });
    165  }
    166 
    167  /*
    168   * If a call object exists and the arguments object aliases formals, the
    169   * call object is the canonical location for formals.
    170   */
    171  void maybeForwardToCallObject(ArgumentsObject* obj, ArgumentsData* data) {
    172    JSFunction* callee = jit::CalleeTokenToFunction(frame_->calleeToken());
    173    ArgumentsObject::MaybeForwardToCallObject(callee, callObj_, obj, data);
    174  }
    175 };
    176 
    177 struct CopyScriptFrameIterArgs {
    178  ScriptFrameIter& iter_;
    179  RootedValueVector actualArgs_;
    180 
    181  explicit CopyScriptFrameIterArgs(JSContext* cx, ScriptFrameIter& iter)
    182      : iter_(iter), actualArgs_(cx) {}
    183 
    184  // Used to copy arguments to actualArgs_ to simplify copyArgs and
    185  // ArgumentsObject allocation.
    186  [[nodiscard]] bool init(JSContext* cx) {
    187    unsigned numActuals = iter_.numActualArgs();
    188    if (!actualArgs_.reserve(numActuals)) {
    189      return false;
    190    }
    191 
    192    // Append actual arguments.
    193    iter_.unaliasedForEachActual(
    194        cx, [this](const Value& v) { actualArgs_.infallibleAppend(v); });
    195    MOZ_RELEASE_ASSERT(actualArgs_.length() == numActuals);
    196    return true;
    197  }
    198 
    199  void copyActualArgs(ArgumentsObject* owner, GCOwnedArray<Value>& args,
    200                      unsigned numActuals) const {
    201    MOZ_ASSERT(actualArgs_.length() == numActuals);
    202 
    203    args.withOwner(owner, [&](auto& args) {
    204      auto* dst = args.begin();
    205      for (Value v : actualArgs_) {
    206        (dst++)->init(v);
    207      }
    208    });
    209  }
    210 
    211  /*
    212   * Ion frames are copying every argument onto the stack, other locations are
    213   * invalid.
    214   */
    215  void maybeForwardToCallObject(ArgumentsObject* obj, ArgumentsData* data) {
    216    if (!iter_.isIon()) {
    217      ArgumentsObject::MaybeForwardToCallObject(iter_.abstractFramePtr(), obj,
    218                                                data);
    219    }
    220  }
    221 };
    222 
    223 struct CopyInlinedArgs {
    224  HandleValueArray args_;
    225  HandleObject callObj_;
    226  HandleFunction callee_;
    227 
    228  CopyInlinedArgs(HandleValueArray args, HandleObject callObj,
    229                  HandleFunction callee)
    230      : args_(args), callObj_(callObj), callee_(callee) {}
    231 
    232  void copyActualArgs(ArgumentsObject* owner, GCOwnedArray<Value>& args,
    233                      unsigned numActuals) const {
    234    MOZ_ASSERT(numActuals <= args_.length());
    235 
    236    args.withOwner(owner, [&](auto& args) {
    237      auto* dst = args.begin();
    238      for (uint32_t i = 0; i < numActuals; i++) {
    239        (dst++)->init(args_[i]);
    240      }
    241    });
    242  }
    243 
    244  /*
    245   * If a call object exists and the arguments object aliases formals, the
    246   * call object is the canonical location for formals.
    247   */
    248  void maybeForwardToCallObject(ArgumentsObject* obj, ArgumentsData* data) {
    249    ArgumentsObject::MaybeForwardToCallObject(callee_, callObj_, obj, data);
    250  }
    251 };
    252 
    253 ArgumentsObject* ArgumentsObject::createTemplateObject(JSContext* cx,
    254                                                       bool mapped) {
    255  const JSClass* clasp = mapped ? &MappedArgumentsObject::class_
    256                                : &UnmappedArgumentsObject::class_;
    257 
    258  RootedObject proto(cx, &cx->global()->getObjectPrototype());
    259 
    260  constexpr ObjectFlags objectFlags = {ObjectFlag::Indexed};
    261  Rooted<SharedShape*> shape(cx, SharedShape::getInitialShape(
    262                                     cx, clasp, cx->realm(), TaggedProto(proto),
    263                                     FINALIZE_KIND, objectFlags));
    264  if (!shape) {
    265    return nullptr;
    266  }
    267 
    268  AutoSetNewObjectMetadata metadata(cx);
    269  auto* obj = NativeObject::create<ArgumentsObject>(cx, FINALIZE_KIND,
    270                                                    gc::Heap::Tenured, shape);
    271  if (!obj) {
    272    return nullptr;
    273  }
    274 
    275  obj->initFixedSlot(ArgumentsObject::DATA_SLOT, PrivateValue(nullptr));
    276  return obj;
    277 }
    278 
    279 ArgumentsObject* GlobalObject::maybeArgumentsTemplateObject(bool mapped) const {
    280  return mapped ? data().mappedArgumentsTemplate
    281                : data().unmappedArgumentsTemplate;
    282 }
    283 
    284 /* static */
    285 ArgumentsObject* GlobalObject::getOrCreateArgumentsTemplateObject(JSContext* cx,
    286                                                                  bool mapped) {
    287  GlobalObjectData& data = cx->global()->data();
    288  GCPtr<ArgumentsObject*>& obj =
    289      mapped ? data.mappedArgumentsTemplate : data.unmappedArgumentsTemplate;
    290 
    291  ArgumentsObject* templateObj = obj;
    292  if (templateObj) {
    293    return templateObj;
    294  }
    295 
    296  templateObj = ArgumentsObject::createTemplateObject(cx, mapped);
    297  if (!templateObj) {
    298    return nullptr;
    299  }
    300 
    301  obj.init(templateObj);
    302  return templateObj;
    303 }
    304 
    305 template <typename CopyArgs>
    306 /* static */
    307 ArgumentsObject* ArgumentsObject::create(JSContext* cx, HandleFunction callee,
    308                                         unsigned numActuals, CopyArgs& copy) {
    309  // Self-hosted code should use the more efficient ArgumentsLength and
    310  // GetArgument intrinsics instead of `arguments`.
    311  MOZ_ASSERT(!callee->isSelfHostedBuiltin());
    312 
    313  bool mapped = callee->baseScript()->hasMappedArgsObj();
    314  ArgumentsObject* templateObj =
    315      GlobalObject::getOrCreateArgumentsTemplateObject(cx, mapped);
    316  if (!templateObj) {
    317    return nullptr;
    318  }
    319 
    320  Rooted<SharedShape*> shape(cx, templateObj->sharedShape());
    321 
    322  unsigned numFormals = callee->nargs();
    323  unsigned numArgs = std::max(numActuals, numFormals);
    324  unsigned numBytes = ArgumentsData::bytesRequired(numArgs);
    325 
    326  AutoSetNewObjectMetadata metadata(cx);
    327  auto* obj = NativeObject::create<ArgumentsObject>(cx, FINALIZE_KIND,
    328                                                    gc::Heap::Default, shape);
    329  if (!obj) {
    330    return nullptr;
    331  }
    332 
    333  ArgumentsData* data = reinterpret_cast<ArgumentsData*>(
    334      AllocNurseryOrMallocBuffer<uint8_t>(cx, obj, numBytes));
    335  if (!data) {
    336    // Make the object safe for GC.
    337    obj->initFixedSlot(DATA_SLOT, PrivateValue(nullptr));
    338    return nullptr;
    339  }
    340 
    341  new (data) ArgumentsData(numArgs);
    342 
    343  InitReservedSlot(obj, DATA_SLOT, data, numBytes, MemoryUse::ArgumentsData);
    344  obj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee));
    345  obj->initFixedSlot(INITIAL_LENGTH_SLOT,
    346                     Int32Value(numActuals << PACKED_BITS_COUNT));
    347 
    348  // Copy [0, numActuals) into data->args.
    349  copy.copyActualArgs(obj, data->args, numActuals);
    350 
    351  // Fill in missing arguments with |undefined|.
    352  data->args.withOwner(obj, [&](auto& args) {
    353    for (size_t i = numActuals; i < numArgs; i++) {
    354      args[i].init(UndefinedValue());
    355    }
    356  });
    357 
    358  copy.maybeForwardToCallObject(obj, data);
    359 
    360  MOZ_ASSERT(obj->initialLength() == numActuals);
    361  MOZ_ASSERT(!obj->hasOverriddenLength());
    362  return obj;
    363 }
    364 
    365 ArgumentsObject* ArgumentsObject::createExpected(JSContext* cx,
    366                                                 AbstractFramePtr frame) {
    367  MOZ_ASSERT(frame.script()->needsArgsObj());
    368  RootedFunction callee(cx, frame.callee());
    369  CopyFrameArgs copy(frame);
    370  ArgumentsObject* argsobj = create(cx, callee, frame.numActualArgs(), copy);
    371  if (!argsobj) {
    372    return nullptr;
    373  }
    374 
    375  frame.initArgsObj(*argsobj);
    376  return argsobj;
    377 }
    378 
    379 ArgumentsObject* ArgumentsObject::createUnexpected(JSContext* cx,
    380                                                   ScriptFrameIter& iter) {
    381  RootedFunction callee(cx, iter.callee(cx));
    382  CopyScriptFrameIterArgs copy(cx, iter);
    383  if (!copy.init(cx)) {
    384    return nullptr;
    385  }
    386  return create(cx, callee, iter.numActualArgs(), copy);
    387 }
    388 
    389 ArgumentsObject* ArgumentsObject::createUnexpected(JSContext* cx,
    390                                                   AbstractFramePtr frame) {
    391  RootedFunction callee(cx, frame.callee());
    392  CopyFrameArgs copy(frame);
    393  return create(cx, callee, frame.numActualArgs(), copy);
    394 }
    395 
    396 ArgumentsObject* ArgumentsObject::createForIon(JSContext* cx,
    397                                               jit::JitFrameLayout* frame,
    398                                               HandleObject scopeChain) {
    399  jit::CalleeToken token = frame->calleeToken();
    400  MOZ_ASSERT(jit::CalleeTokenIsFunction(token));
    401  RootedFunction callee(cx, jit::CalleeTokenToFunction(token));
    402  RootedObject callObj(
    403      cx, scopeChain->is<CallObject>() ? scopeChain.get() : nullptr);
    404  CopyJitFrameArgs copy(frame, callObj);
    405  return create(cx, callee, frame->numActualArgs(), copy);
    406 }
    407 
    408 /* static */
    409 ArgumentsObject* ArgumentsObject::createFromValueArray(
    410    JSContext* cx, HandleValueArray argsArray, HandleFunction callee,
    411    HandleObject scopeChain, uint32_t numActuals) {
    412  MOZ_ASSERT(numActuals <= MaxInlinedArgs);
    413  RootedObject callObj(
    414      cx, scopeChain->is<CallObject>() ? scopeChain.get() : nullptr);
    415  CopyInlinedArgs copy(argsArray, callObj, callee);
    416  return create(cx, callee, numActuals, copy);
    417 }
    418 
    419 /* static */
    420 ArgumentsObject* ArgumentsObject::createForInlinedIon(JSContext* cx,
    421                                                      Value* args,
    422                                                      HandleFunction callee,
    423                                                      HandleObject scopeChain,
    424                                                      uint32_t numActuals) {
    425  RootedExternalValueArray rootedArgs(cx, numActuals, args);
    426  HandleValueArray argsArray =
    427      HandleValueArray::fromMarkedLocation(numActuals, args);
    428 
    429  return createFromValueArray(cx, argsArray, callee, scopeChain, numActuals);
    430 }
    431 
    432 template <typename CopyArgs>
    433 /* static */
    434 ArgumentsObject* ArgumentsObject::finishPure(
    435    JSContext* cx, ArgumentsObject* obj, JSFunction* callee, JSObject* callObj,
    436    unsigned numActuals, CopyArgs& copy) {
    437  unsigned numFormals = callee->nargs();
    438  unsigned numArgs = std::max(numActuals, numFormals);
    439  unsigned numBytes = ArgumentsData::bytesRequired(numArgs);
    440 
    441  ArgumentsData* data = reinterpret_cast<ArgumentsData*>(
    442      AllocNurseryOrMallocBuffer<uint8_t>(cx, obj, numBytes));
    443  if (!data) {
    444    // Make the object safe for GC. Don't report OOM, the slow path will
    445    // retry the allocation.
    446    cx->recoverFromOutOfMemory();
    447    obj->initFixedSlot(DATA_SLOT, PrivateValue(nullptr));
    448    return nullptr;
    449  }
    450 
    451  new (data) ArgumentsData(numArgs);
    452 
    453  obj->initFixedSlot(INITIAL_LENGTH_SLOT,
    454                     Int32Value(numActuals << PACKED_BITS_COUNT));
    455  obj->initFixedSlot(DATA_SLOT, PrivateValue(data));
    456  AddCellMemory(obj, numBytes, MemoryUse::ArgumentsData);
    457  obj->initFixedSlot(MAYBE_CALL_SLOT, UndefinedValue());
    458  obj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee));
    459 
    460  copy.copyActualArgs(obj, data->args, numActuals);
    461 
    462  // Fill in missing arguments with |undefined|.
    463  data->args.withOwner(obj, [&](auto& args) {
    464    for (size_t i = numActuals; i < numArgs; i++) {
    465      args[i].init(UndefinedValue());
    466    }
    467  });
    468 
    469  if (callObj && callee->needsCallObject()) {
    470    copy.maybeForwardToCallObject(obj, data);
    471  }
    472 
    473  MOZ_ASSERT(obj->initialLength() == numActuals);
    474  MOZ_ASSERT(!obj->hasOverriddenLength());
    475  return obj;
    476 }
    477 
    478 /* static */
    479 ArgumentsObject* ArgumentsObject::finishForIonPure(JSContext* cx,
    480                                                   jit::JitFrameLayout* frame,
    481                                                   JSObject* scopeChain,
    482                                                   ArgumentsObject* obj) {
    483  // JIT code calls this directly (no callVM), because it's faster, so we're
    484  // not allowed to GC in here.
    485  AutoUnsafeCallWithABI unsafe;
    486 
    487  JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken());
    488  RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain : nullptr);
    489  CopyJitFrameArgs copy(frame, callObj);
    490 
    491  unsigned numActuals = frame->numActualArgs();
    492 
    493  return finishPure(cx, obj, callee, callObj, numActuals, copy);
    494 }
    495 
    496 /* static */
    497 ArgumentsObject* ArgumentsObject::finishInlineForIonPure(
    498    JSContext* cx, JSObject* rawCallObj, JSFunction* rawCallee, Value* args,
    499    uint32_t numActuals, ArgumentsObject* obj) {
    500  // JIT code calls this directly (no callVM), because it's faster, so we're
    501  // not allowed to GC in here.
    502  AutoUnsafeCallWithABI unsafe;
    503 
    504  MOZ_ASSERT(numActuals <= MaxInlinedArgs);
    505 
    506  RootedObject callObj(cx, rawCallObj);
    507  RootedFunction callee(cx, rawCallee);
    508  RootedExternalValueArray rootedArgs(cx, numActuals, args);
    509  HandleValueArray argsArray =
    510      HandleValueArray::fromMarkedLocation(numActuals, args);
    511 
    512  CopyInlinedArgs copy(argsArray, callObj, callee);
    513 
    514  return finishPure(cx, obj, callee, callObj, numActuals, copy);
    515 }
    516 
    517 /* static */
    518 bool ArgumentsObject::obj_delProperty(JSContext* cx, HandleObject obj,
    519                                      HandleId id, ObjectOpResult& result) {
    520  ArgumentsObject& argsobj = obj->as<ArgumentsObject>();
    521  if (id.isInt()) {
    522    unsigned arg = unsigned(id.toInt());
    523    if (argsobj.isElement(arg)) {
    524      if (!argsobj.markElementDeleted(cx, arg)) {
    525        return false;
    526      }
    527    }
    528  } else if (id.isAtom(cx->names().length)) {
    529    argsobj.markLengthOverridden();
    530  } else if (id.isAtom(cx->names().callee)) {
    531    argsobj.as<MappedArgumentsObject>().markCalleeOverridden();
    532  } else if (id.isWellKnownSymbol(JS::SymbolCode::iterator)) {
    533    argsobj.markIteratorOverridden();
    534  }
    535  return result.succeed();
    536 }
    537 
    538 /* static */
    539 bool ArgumentsObject::obj_mayResolve(const JSAtomState& names, jsid id,
    540                                     JSObject*) {
    541  // Arguments might resolve indexes, Symbol.iterator, or length/callee.
    542  if (id.isAtom()) {
    543    JSAtom* atom = id.toAtom();
    544    return atom->isIndex() || atom == names.length || atom == names.callee;
    545  }
    546 
    547  return id.isInt() || id.isWellKnownSymbol(JS::SymbolCode::iterator);
    548 }
    549 
    550 bool js::MappedArgGetter(JSContext* cx, HandleObject obj, HandleId id,
    551                         MutableHandleValue vp) {
    552  MappedArgumentsObject& argsobj = obj->as<MappedArgumentsObject>();
    553  if (id.isInt()) {
    554    /*
    555     * arg can exceed the number of arguments if a script changed the
    556     * prototype to point to another Arguments object with a bigger argc.
    557     */
    558    unsigned arg = unsigned(id.toInt());
    559    if (argsobj.isElement(arg)) {
    560      vp.set(argsobj.element(arg));
    561    }
    562  } else if (id.isAtom(cx->names().length)) {
    563    if (!argsobj.hasOverriddenLength()) {
    564      vp.setInt32(argsobj.initialLength());
    565    }
    566  } else {
    567    MOZ_ASSERT(id.isAtom(cx->names().callee));
    568    if (!argsobj.hasOverriddenCallee()) {
    569      vp.setObject(argsobj.callee());
    570    }
    571  }
    572  return true;
    573 }
    574 
    575 bool js::MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id,
    576                         HandleValue v, ObjectOpResult& result) {
    577  Handle<MappedArgumentsObject*> argsobj = obj.as<MappedArgumentsObject>();
    578 
    579  Rooted<mozilla::Maybe<PropertyDescriptor>> desc(cx);
    580  if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc)) {
    581    return false;
    582  }
    583  MOZ_ASSERT(desc.isSome());
    584  MOZ_ASSERT(desc->isDataDescriptor());
    585  MOZ_ASSERT(desc->writable());
    586  MOZ_ASSERT(!desc->resolving());
    587 
    588  if (id.isInt()) {
    589    unsigned arg = unsigned(id.toInt());
    590    if (argsobj->isElement(arg)) {
    591      argsobj->setElement(arg, v);
    592      return result.succeed();
    593    }
    594  } else {
    595    MOZ_ASSERT(id.isAtom(cx->names().length) || id.isAtom(cx->names().callee));
    596  }
    597 
    598  /*
    599   * For simplicity we use delete/define to replace the property with a
    600   * simple data property. Note that we rely on ArgumentsObject::obj_delProperty
    601   * to set the corresponding override-bit.
    602   * Note also that we must define the property instead of setting it in case
    603   * the user has changed the prototype to an object that has a setter for
    604   * this id.
    605   */
    606  Rooted<PropertyDescriptor> desc_(cx, *desc);
    607  desc_.setValue(v);
    608  ObjectOpResult ignored;
    609  return NativeDeleteProperty(cx, argsobj, id, ignored) &&
    610         NativeDefineProperty(cx, argsobj, id, desc_, result);
    611 }
    612 
    613 /* static */
    614 bool ArgumentsObject::getArgumentsIterator(JSContext* cx,
    615                                           MutableHandleValue val) {
    616  Handle<PropertyName*> shName = cx->names().dollar_ArrayValues_;
    617  Rooted<JSAtom*> name(cx, cx->names().values);
    618  return GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, 0,
    619                                             val);
    620 }
    621 
    622 /* static */
    623 bool ArgumentsObject::reifyLength(JSContext* cx, Handle<ArgumentsObject*> obj) {
    624  if (obj->hasOverriddenLength()) {
    625    return true;
    626  }
    627 
    628  RootedId id(cx, NameToId(cx->names().length));
    629  RootedValue val(cx, Int32Value(obj->initialLength()));
    630  if (!NativeDefineDataProperty(cx, obj, id, val, JSPROP_RESOLVING)) {
    631    return false;
    632  }
    633 
    634  obj->markLengthOverridden();
    635  return true;
    636 }
    637 
    638 /* static */
    639 bool ArgumentsObject::reifyIterator(JSContext* cx,
    640                                    Handle<ArgumentsObject*> obj) {
    641  if (obj->hasOverriddenIterator()) {
    642    return true;
    643  }
    644 
    645  RootedId iteratorId(cx, PropertyKey::Symbol(cx->wellKnownSymbols().iterator));
    646  RootedValue val(cx);
    647  if (!ArgumentsObject::getArgumentsIterator(cx, &val)) {
    648    return false;
    649  }
    650  if (!NativeDefineDataProperty(cx, obj, iteratorId, val, JSPROP_RESOLVING)) {
    651    return false;
    652  }
    653 
    654  obj->markIteratorOverridden();
    655  return true;
    656 }
    657 
    658 /* static */
    659 bool MappedArgumentsObject::reifyCallee(JSContext* cx,
    660                                        Handle<MappedArgumentsObject*> obj) {
    661  if (obj->hasOverriddenCallee()) {
    662    return true;
    663  }
    664 
    665  Rooted<PropertyKey> key(cx, NameToId(cx->names().callee));
    666  Rooted<Value> val(cx, ObjectValue(obj->callee()));
    667  if (!NativeDefineDataProperty(cx, obj, key, val, JSPROP_RESOLVING)) {
    668    return false;
    669  }
    670 
    671  obj->markCalleeOverridden();
    672  return true;
    673 }
    674 
    675 static bool ResolveArgumentsProperty(JSContext* cx,
    676                                     Handle<ArgumentsObject*> obj, HandleId id,
    677                                     PropertyFlags flags, bool* resolvedp) {
    678  MOZ_ASSERT(id.isInt() || id.isAtom(cx->names().length) ||
    679             id.isAtom(cx->names().callee));
    680  MOZ_ASSERT(flags.isCustomDataProperty());
    681 
    682  if (!NativeObject::addCustomDataProperty(cx, obj, id, flags)) {
    683    return false;
    684  }
    685 
    686  *resolvedp = true;
    687  return true;
    688 }
    689 
    690 /* static */
    691 bool MappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj,
    692                                        HandleId id, bool* resolvedp) {
    693  auto argsobj = obj.as<MappedArgumentsObject>();
    694 
    695  if (id.isWellKnownSymbol(JS::SymbolCode::iterator)) {
    696    if (argsobj->hasOverriddenIterator()) {
    697      return true;
    698    }
    699 
    700    if (!reifyIterator(cx, argsobj)) {
    701      return false;
    702    }
    703    *resolvedp = true;
    704    return true;
    705  }
    706 
    707  PropertyFlags flags = {PropertyFlag::CustomDataProperty,
    708                         PropertyFlag::Configurable, PropertyFlag::Writable};
    709  if (id.isInt()) {
    710    uint32_t arg = uint32_t(id.toInt());
    711    if (!argsobj->isElement(arg)) {
    712      return true;
    713    }
    714 
    715    flags.setFlag(PropertyFlag::Enumerable);
    716  } else if (id.isAtom(cx->names().length)) {
    717    if (argsobj->hasOverriddenLength()) {
    718      return true;
    719    }
    720  } else {
    721    if (!id.isAtom(cx->names().callee)) {
    722      return true;
    723    }
    724 
    725    if (argsobj->hasOverriddenCallee()) {
    726      return true;
    727    }
    728  }
    729 
    730  return ResolveArgumentsProperty(cx, argsobj, id, flags, resolvedp);
    731 }
    732 
    733 /* static */
    734 bool MappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj) {
    735  auto argsobj = obj.as<MappedArgumentsObject>();
    736 
    737  RootedId id(cx);
    738  bool found;
    739 
    740  // Trigger reflection.
    741  id = NameToId(cx->names().length);
    742  if (!HasOwnProperty(cx, argsobj, id, &found)) {
    743    return false;
    744  }
    745 
    746  id = NameToId(cx->names().callee);
    747  if (!HasOwnProperty(cx, argsobj, id, &found)) {
    748    return false;
    749  }
    750 
    751  id = PropertyKey::Symbol(cx->wellKnownSymbols().iterator);
    752  if (!HasOwnProperty(cx, argsobj, id, &found)) {
    753    return false;
    754  }
    755 
    756  for (unsigned i = 0; i < argsobj->initialLength(); i++) {
    757    id = PropertyKey::Int(i);
    758    if (!HasOwnProperty(cx, argsobj, id, &found)) {
    759      return false;
    760    }
    761  }
    762 
    763  return true;
    764 }
    765 
    766 static bool DefineMappedIndex(JSContext* cx, Handle<MappedArgumentsObject*> obj,
    767                              HandleId id,
    768                              MutableHandle<PropertyDescriptor> desc,
    769                              ObjectOpResult& result) {
    770  // The custom data properties (see MappedArgGetter, MappedArgSetter) have to
    771  // be (re)defined manually because PropertyDescriptor and NativeDefineProperty
    772  // don't support these special properties.
    773  //
    774  // This exists in order to let JS code change the configurable/enumerable
    775  // attributes for these properties.
    776  //
    777  // Note: because this preserves the default mapped-arguments behavior, we
    778  // don't need to mark elements as overridden or deleted.
    779 
    780  MOZ_ASSERT(id.isInt());
    781  MOZ_ASSERT(obj->isElement(id.toInt()));
    782  MOZ_ASSERT(!obj->containsDenseElement(id.toInt()));
    783 
    784  MOZ_ASSERT(!desc.isAccessorDescriptor());
    785 
    786  // Mapped properties aren't used when defining a non-writable property.
    787  MOZ_ASSERT(!desc.hasWritable() || desc.writable());
    788 
    789  // First, resolve the property to simplify the code below.
    790  PropertyResult prop;
    791  if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop)) {
    792    return false;
    793  }
    794 
    795  MOZ_ASSERT(prop.isNativeProperty());
    796 
    797  PropertyInfo propInfo = prop.propertyInfo();
    798  MOZ_ASSERT(propInfo.writable());
    799  MOZ_ASSERT(propInfo.isCustomDataProperty());
    800 
    801  // Change the property's attributes by implementing the relevant parts of
    802  // ValidateAndApplyPropertyDescriptor (ES2021 draft, 10.1.6.3), in particular
    803  // steps 4 and 9.
    804 
    805  // Determine whether the property should be configurable and/or enumerable.
    806  bool configurable = propInfo.configurable();
    807  bool enumerable = propInfo.enumerable();
    808  if (configurable) {
    809    if (desc.hasConfigurable()) {
    810      configurable = desc.configurable();
    811    }
    812    if (desc.hasEnumerable()) {
    813      enumerable = desc.enumerable();
    814    }
    815  } else {
    816    // Property is not configurable so disallow any attribute changes.
    817    if ((desc.hasConfigurable() && desc.configurable()) ||
    818        (desc.hasEnumerable() && enumerable != desc.enumerable())) {
    819      return result.fail(JSMSG_CANT_REDEFINE_PROP);
    820    }
    821  }
    822 
    823  PropertyFlags flags = propInfo.flags();
    824  flags.setFlag(PropertyFlag::Configurable, configurable);
    825  flags.setFlag(PropertyFlag::Enumerable, enumerable);
    826  if (!NativeObject::changeCustomDataPropAttributes(cx, obj, id, flags)) {
    827    return false;
    828  }
    829 
    830  return result.succeed();
    831 }
    832 
    833 // ES 2017 draft 9.4.4.2
    834 /* static */
    835 bool MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj,
    836                                               HandleId id,
    837                                               Handle<PropertyDescriptor> desc,
    838                                               ObjectOpResult& result) {
    839  // Step 1.
    840  auto argsobj = obj.as<MappedArgumentsObject>();
    841 
    842  // Steps 2-3.
    843  bool isMapped = false;
    844  if (id.isInt()) {
    845    unsigned arg = unsigned(id.toInt());
    846    isMapped = argsobj->isElement(arg);
    847  }
    848 
    849  // Step 4.
    850  Rooted<PropertyDescriptor> newArgDesc(cx, desc);
    851 
    852  // Step 5.
    853  bool defineMapped = false;
    854  if (!desc.isAccessorDescriptor() && isMapped) {
    855    // Step 5.a.
    856    if (desc.hasWritable() && !desc.writable()) {
    857      if (!desc.hasValue()) {
    858        RootedValue v(cx, argsobj->element(id.toInt()));
    859        newArgDesc.setValue(v);
    860      }
    861    } else {
    862      // In this case the live mapping is supposed to keep working.
    863      defineMapped = true;
    864    }
    865  }
    866 
    867  // Step 6. NativeDefineProperty will lookup [[Value]] for us.
    868  if (defineMapped) {
    869    if (!DefineMappedIndex(cx, argsobj, id, &newArgDesc, result)) {
    870      return false;
    871    }
    872  } else {
    873    if (!NativeDefineProperty(cx, obj.as<NativeObject>(), id, newArgDesc,
    874                              result)) {
    875      return false;
    876    }
    877  }
    878  // Step 7.
    879  if (!result.ok()) {
    880    return true;
    881  }
    882 
    883  // Step 8.
    884  if (isMapped) {
    885    unsigned arg = unsigned(id.toInt());
    886    if (desc.isAccessorDescriptor()) {
    887      if (!argsobj->markElementDeleted(cx, arg)) {
    888        return false;
    889      }
    890    } else {
    891      if (desc.hasValue()) {
    892        argsobj->setElement(arg, desc.value());
    893      }
    894      if (desc.hasWritable() && !desc.writable()) {
    895        if (!argsobj->markElementDeleted(cx, arg)) {
    896          return false;
    897        }
    898      }
    899    }
    900  }
    901 
    902  // Step 9.
    903  return result.succeed();
    904 }
    905 
    906 bool js::UnmappedArgGetter(JSContext* cx, HandleObject obj, HandleId id,
    907                           MutableHandleValue vp) {
    908  UnmappedArgumentsObject& argsobj = obj->as<UnmappedArgumentsObject>();
    909 
    910  if (id.isInt()) {
    911    /*
    912     * arg can exceed the number of arguments if a script changed the
    913     * prototype to point to another Arguments object with a bigger argc.
    914     */
    915    unsigned arg = unsigned(id.toInt());
    916    if (argsobj.isElement(arg)) {
    917      vp.set(argsobj.element(arg));
    918    }
    919  } else {
    920    MOZ_ASSERT(id.isAtom(cx->names().length));
    921    if (!argsobj.hasOverriddenLength()) {
    922      vp.setInt32(argsobj.initialLength());
    923    }
    924  }
    925  return true;
    926 }
    927 
    928 bool js::UnmappedArgSetter(JSContext* cx, HandleObject obj, HandleId id,
    929                           HandleValue v, ObjectOpResult& result) {
    930  Handle<UnmappedArgumentsObject*> argsobj = obj.as<UnmappedArgumentsObject>();
    931 
    932  Rooted<mozilla::Maybe<PropertyDescriptor>> desc(cx);
    933  if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc)) {
    934    return false;
    935  }
    936  MOZ_ASSERT(desc.isSome());
    937  MOZ_ASSERT(desc->isDataDescriptor());
    938  MOZ_ASSERT(desc->writable());
    939  MOZ_ASSERT(!desc->resolving());
    940 
    941  if (id.isInt()) {
    942    unsigned arg = unsigned(id.toInt());
    943    if (arg < argsobj->initialLength()) {
    944      argsobj->setElement(arg, v);
    945      return result.succeed();
    946    }
    947  } else {
    948    MOZ_ASSERT(id.isAtom(cx->names().length));
    949  }
    950 
    951  /*
    952   * For simplicity we use delete/define to replace the property with a
    953   * simple data property. Note that we rely on ArgumentsObject::obj_delProperty
    954   * to set the corresponding override-bit.
    955   */
    956  Rooted<PropertyDescriptor> desc_(cx, *desc);
    957  desc_.setValue(v);
    958  ObjectOpResult ignored;
    959  return NativeDeleteProperty(cx, argsobj, id, ignored) &&
    960         NativeDefineProperty(cx, argsobj, id, desc_, result);
    961 }
    962 
    963 /* static */
    964 bool UnmappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj,
    965                                          HandleId id, bool* resolvedp) {
    966  auto argsobj = obj.as<UnmappedArgumentsObject>();
    967 
    968  if (id.isWellKnownSymbol(JS::SymbolCode::iterator)) {
    969    if (argsobj->hasOverriddenIterator()) {
    970      return true;
    971    }
    972 
    973    if (!reifyIterator(cx, argsobj)) {
    974      return false;
    975    }
    976    *resolvedp = true;
    977    return true;
    978  }
    979 
    980  if (id.isAtom(cx->names().callee)) {
    981    RootedObject throwTypeError(
    982        cx, GlobalObject::getOrCreateThrowTypeError(cx, cx->global()));
    983    if (!throwTypeError) {
    984      return false;
    985    }
    986 
    987    unsigned attrs = JSPROP_RESOLVING | JSPROP_PERMANENT;
    988    if (!NativeDefineAccessorProperty(cx, argsobj, id, throwTypeError,
    989                                      throwTypeError, attrs)) {
    990      return false;
    991    }
    992 
    993    *resolvedp = true;
    994    return true;
    995  }
    996 
    997  PropertyFlags flags = {PropertyFlag::CustomDataProperty,
    998                         PropertyFlag::Configurable, PropertyFlag::Writable};
    999  if (id.isInt()) {
   1000    uint32_t arg = uint32_t(id.toInt());
   1001    if (!argsobj->isElement(arg)) {
   1002      return true;
   1003    }
   1004 
   1005    flags.setFlag(PropertyFlag::Enumerable);
   1006  } else if (id.isAtom(cx->names().length)) {
   1007    if (argsobj->hasOverriddenLength()) {
   1008      return true;
   1009    }
   1010  } else {
   1011    return true;
   1012  }
   1013 
   1014  return ResolveArgumentsProperty(cx, argsobj, id, flags, resolvedp);
   1015 }
   1016 
   1017 /* static */
   1018 bool UnmappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj) {
   1019  auto argsobj = obj.as<UnmappedArgumentsObject>();
   1020 
   1021  RootedId id(cx);
   1022  bool found;
   1023 
   1024  // Trigger reflection.
   1025  id = NameToId(cx->names().length);
   1026  if (!HasOwnProperty(cx, argsobj, id, &found)) {
   1027    return false;
   1028  }
   1029 
   1030  id = NameToId(cx->names().callee);
   1031  if (!HasOwnProperty(cx, argsobj, id, &found)) {
   1032    return false;
   1033  }
   1034 
   1035  id = PropertyKey::Symbol(cx->wellKnownSymbols().iterator);
   1036  if (!HasOwnProperty(cx, argsobj, id, &found)) {
   1037    return false;
   1038  }
   1039 
   1040  for (unsigned i = 0; i < argsobj->initialLength(); i++) {
   1041    id = PropertyKey::Int(i);
   1042    if (!HasOwnProperty(cx, argsobj, id, &found)) {
   1043      return false;
   1044    }
   1045  }
   1046 
   1047  return true;
   1048 }
   1049 
   1050 void ArgumentsObject::finalize(JS::GCContext* gcx, JSObject* obj) {
   1051  MOZ_ASSERT(!IsInsideNursery(obj));
   1052  ArgumentsObject& argsobj = obj->as<ArgumentsObject>();
   1053  if (argsobj.data()) {
   1054    gcx->free_(&argsobj, argsobj.maybeRareData(),
   1055               RareArgumentsData::bytesRequired(argsobj.initialLength()),
   1056               MemoryUse::RareArgumentsData);
   1057    gcx->free_(&argsobj, argsobj.data(),
   1058               ArgumentsData::bytesRequired(argsobj.data()->numArgs()),
   1059               MemoryUse::ArgumentsData);
   1060  }
   1061 }
   1062 
   1063 void ArgumentsObject::trace(JSTracer* trc, JSObject* obj) {
   1064  ArgumentsObject& argsobj = obj->as<ArgumentsObject>();
   1065  // Template objects have no ArgumentsData.
   1066  if (ArgumentsData* data = argsobj.data()) {
   1067    data->args.trace(trc);
   1068  }
   1069 }
   1070 
   1071 /* static */
   1072 size_t ArgumentsObject::objectMoved(JSObject* dst, JSObject* src) {
   1073  ArgumentsObject* ndst = &dst->as<ArgumentsObject>();
   1074  const ArgumentsObject* nsrc = &src->as<ArgumentsObject>();
   1075  MOZ_ASSERT(ndst->data() == nsrc->data());
   1076 
   1077  if (!IsInsideNursery(src)) {
   1078    return 0;
   1079  }
   1080 
   1081  Nursery& nursery = dst->runtimeFromMainThread()->gc.nursery();
   1082 
   1083  size_t nbytesTotal = 0;
   1084 
   1085  ArgumentsData* data = nsrc->data();
   1086  uint32_t nDataBytes = ArgumentsData::bytesRequired(nsrc->data()->numArgs());
   1087  Nursery::WasBufferMoved result =
   1088      nursery.maybeMoveNurseryOrMallocBufferOnPromotion(
   1089          &data, dst, nDataBytes, MemoryUse::ArgumentsData);
   1090  if (result == Nursery::BufferMoved) {
   1091    ndst->initFixedSlot(DATA_SLOT, PrivateValue(data));
   1092    nbytesTotal += nDataBytes;
   1093  }
   1094 
   1095  if (RareArgumentsData* rareData = nsrc->maybeRareData()) {
   1096    uint32_t nRareBytes =
   1097        RareArgumentsData::bytesRequired(nsrc->initialLength());
   1098    Nursery::WasBufferMoved result =
   1099        nursery.maybeMoveNurseryOrMallocBufferOnPromotion(
   1100            &rareData, dst, nRareBytes, MemoryUse::RareArgumentsData);
   1101    if (result == Nursery::BufferMoved) {
   1102      ndst->data()->rareData = rareData;
   1103      nbytesTotal += nRareBytes;
   1104    }
   1105  }
   1106 
   1107  return nbytesTotal;
   1108 }
   1109 
   1110 /*
   1111 * The classes below collaborate to lazily reflect and synchronize actual
   1112 * argument values, argument count, and callee function object stored in a
   1113 * stack frame with their corresponding property values in the frame's
   1114 * arguments object.
   1115 */
   1116 const JSClassOps MappedArgumentsObject::classOps_ = {
   1117    nullptr,                               // addProperty
   1118    ArgumentsObject::obj_delProperty,      // delProperty
   1119    MappedArgumentsObject::obj_enumerate,  // enumerate
   1120    nullptr,                               // newEnumerate
   1121    MappedArgumentsObject::obj_resolve,    // resolve
   1122    ArgumentsObject::obj_mayResolve,       // mayResolve
   1123    ArgumentsObject::finalize,             // finalize
   1124    nullptr,                               // call
   1125    nullptr,                               // construct
   1126    ArgumentsObject::trace,                // trace
   1127 };
   1128 
   1129 const js::ClassExtension MappedArgumentsObject::classExt_ = {
   1130    ArgumentsObject::objectMoved,  // objectMovedOp
   1131 };
   1132 
   1133 const ObjectOps MappedArgumentsObject::objectOps_ = {
   1134    nullptr,                                    // lookupProperty
   1135    MappedArgumentsObject::obj_defineProperty,  // defineProperty
   1136    nullptr,                                    // hasProperty
   1137    nullptr,                                    // getProperty
   1138    nullptr,                                    // setProperty
   1139    nullptr,                                    // getOwnPropertyDescriptor
   1140    nullptr,                                    // deleteProperty
   1141    nullptr,                                    // getElements
   1142    nullptr,                                    // funToString
   1143 };
   1144 
   1145 const JSClass MappedArgumentsObject::class_ = {
   1146    "Arguments",
   1147    JSCLASS_DELAY_METADATA_BUILDER |
   1148        JSCLASS_HAS_RESERVED_SLOTS(MappedArgumentsObject::RESERVED_SLOTS) |
   1149        JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
   1150        JSCLASS_SKIP_NURSERY_FINALIZE | JSCLASS_BACKGROUND_FINALIZE,
   1151    &MappedArgumentsObject::classOps_,
   1152    nullptr,
   1153    &MappedArgumentsObject::classExt_,
   1154    &MappedArgumentsObject::objectOps_,
   1155 };
   1156 
   1157 /*
   1158 * Unmapped arguments is significantly less magical than mapped arguments, so
   1159 * it is represented by a different class while sharing some functionality.
   1160 */
   1161 const JSClassOps UnmappedArgumentsObject::classOps_ = {
   1162    nullptr,                                 // addProperty
   1163    ArgumentsObject::obj_delProperty,        // delProperty
   1164    UnmappedArgumentsObject::obj_enumerate,  // enumerate
   1165    nullptr,                                 // newEnumerate
   1166    UnmappedArgumentsObject::obj_resolve,    // resolve
   1167    ArgumentsObject::obj_mayResolve,         // mayResolve
   1168    ArgumentsObject::finalize,               // finalize
   1169    nullptr,                                 // call
   1170    nullptr,                                 // construct
   1171    ArgumentsObject::trace,                  // trace
   1172 };
   1173 
   1174 const js::ClassExtension UnmappedArgumentsObject::classExt_ = {
   1175    ArgumentsObject::objectMoved,  // objectMovedOp
   1176 };
   1177 
   1178 const JSClass UnmappedArgumentsObject::class_ = {
   1179    "Arguments",
   1180    JSCLASS_DELAY_METADATA_BUILDER |
   1181        JSCLASS_HAS_RESERVED_SLOTS(UnmappedArgumentsObject::RESERVED_SLOTS) |
   1182        JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
   1183        JSCLASS_SKIP_NURSERY_FINALIZE | JSCLASS_BACKGROUND_FINALIZE,
   1184    &UnmappedArgumentsObject::classOps_,
   1185    nullptr,
   1186    &UnmappedArgumentsObject::classExt_,
   1187 };