tor-browser

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

BoundFunctionObject.h (6108B)


      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 #ifndef vm_BoundFunctionObject_h
      8 #define vm_BoundFunctionObject_h
      9 
     10 #include "jstypes.h"
     11 
     12 #include "gc/Policy.h"
     13 #include "vm/ArrayObject.h"
     14 #include "vm/JSObject.h"
     15 
     16 namespace js {
     17 
     18 // Implementation of Bound Function Exotic Objects.
     19 // ES2023 10.4.1
     20 // https://tc39.es/ecma262/#sec-bound-function-exotic-objects
     21 class BoundFunctionObject : public NativeObject {
     22 public:
     23  static const JSClass class_;
     24 
     25  // FlagsSlot uses the low bit for the is-constructor flag and the other bits
     26  // for the number of arguments.
     27  static constexpr size_t IsConstructorFlag = 0b1;
     28  static constexpr size_t NumBoundArgsShift = 1;
     29 
     30  // The maximum number of bound arguments that can be stored inline in
     31  // BoundArg*Slot.
     32  static constexpr size_t MaxInlineBoundArgs = 3;
     33 
     34 private:
     35  enum {
     36    // The [[BoundTargetFunction]] (a callable object).
     37    TargetSlot,
     38 
     39    // The number of arguments + the is-constructor flag, stored as Int32Value.
     40    FlagsSlot,
     41 
     42    // The [[BoundThis]] Value.
     43    BoundThisSlot,
     44 
     45    // The [[BoundArguments]]. If numBoundArgs exceeds MaxInlineBoundArgs,
     46    // BoundArg0Slot will contain an array object that stores the values and the
     47    // other two slots will be unused.
     48    BoundArg0Slot,
     49    BoundArg1Slot,
     50    BoundArg2Slot,
     51 
     52    // Initial slots for the `length` and `name` own data properties. Note that
     53    // these properties are configurable, so these slots can be mutated when the
     54    // object is exposed to JS.
     55    LengthSlot,
     56    NameSlot,
     57 
     58    SlotCount
     59  };
     60 
     61  // The AllocKind should match SlotCount. See assertion in functionBindImpl.
     62  static constexpr gc::AllocKind allocKind = gc::AllocKind::OBJECT8;
     63 
     64  void initFlags(size_t numBoundArgs, bool isConstructor) {
     65    int32_t val = (numBoundArgs << NumBoundArgsShift) | isConstructor;
     66    initReservedSlot(FlagsSlot, Int32Value(val));
     67  }
     68 
     69 public:
     70  size_t numBoundArgs() const {
     71    int32_t v = getReservedSlot(FlagsSlot).toInt32();
     72    MOZ_ASSERT(v >= 0);
     73    return v >> NumBoundArgsShift;
     74  }
     75  bool isConstructor() const {
     76    int32_t v = getReservedSlot(FlagsSlot).toInt32();
     77    return v & IsConstructorFlag;
     78  }
     79 
     80  Value getTargetVal() const { return getReservedSlot(TargetSlot); }
     81  JSObject* getTarget() const { return &getTargetVal().toObject(); }
     82 
     83  Value getBoundThis() const { return getReservedSlot(BoundThisSlot); }
     84 
     85  Value getInlineBoundArg(size_t i) const {
     86    MOZ_ASSERT(i < numBoundArgs());
     87    MOZ_ASSERT(numBoundArgs() <= MaxInlineBoundArgs);
     88    return getReservedSlot(BoundArg0Slot + i);
     89  }
     90  ArrayObject* getBoundArgsArray() const {
     91    MOZ_ASSERT(numBoundArgs() > MaxInlineBoundArgs);
     92    return &getReservedSlot(BoundArg0Slot).toObject().as<ArrayObject>();
     93  }
     94  Value getBoundArg(size_t i) const {
     95    MOZ_ASSERT(i < numBoundArgs());
     96    if (numBoundArgs() <= MaxInlineBoundArgs) {
     97      return getInlineBoundArg(i);
     98    }
     99    return getBoundArgsArray()->getDenseElement(i);
    100  }
    101 
    102  void initLength(double len) {
    103    MOZ_ASSERT(getReservedSlot(LengthSlot).isUndefined());
    104    initReservedSlot(LengthSlot, NumberValue(len));
    105  }
    106  void initName(JSAtom* name) {
    107    MOZ_ASSERT(getReservedSlot(NameSlot).isUndefined());
    108    initReservedSlot(NameSlot, StringValue(name));
    109  }
    110 
    111  // Get the `length` and `name` property values when the object has the
    112  // original shape. See comment for LengthSlot and NameSlot.
    113  Value getLengthForInitialShape() const { return getReservedSlot(LengthSlot); }
    114  Value getNameForInitialShape() const { return getReservedSlot(NameSlot); }
    115 
    116  // The [[Call]] and [[Construct]] hooks.
    117  static bool call(JSContext* cx, unsigned argc, Value* vp);
    118  static bool construct(JSContext* cx, unsigned argc, Value* vp);
    119 
    120  // The JSFunToStringOp implementation for Function.prototype.toString.
    121  static JSString* funToString(JSContext* cx, Handle<JSObject*> obj,
    122                               bool isToSource);
    123 
    124  // Implementation of Function.prototype.bind.
    125  static bool functionBind(JSContext* cx, unsigned argc, Value* vp);
    126 
    127  static SharedShape* assignInitialShape(JSContext* cx,
    128                                         Handle<BoundFunctionObject*> obj);
    129 
    130  static BoundFunctionObject* functionBindImpl(
    131      JSContext* cx, Handle<JSObject*> target, Value* args, uint32_t argc,
    132      Handle<BoundFunctionObject*> maybeBound);
    133 
    134  static BoundFunctionObject* createWithTemplate(
    135      JSContext* cx, Handle<BoundFunctionObject*> templateObj);
    136  static BoundFunctionObject* functionBindSpecializedBaseline(
    137      JSContext* cx, Handle<JSObject*> target, Value* args, uint32_t argc,
    138      Handle<BoundFunctionObject*> templateObj);
    139 
    140  static BoundFunctionObject* createTemplateObject(JSContext* cx);
    141 
    142  bool initTemplateSlotsForSpecializedBind(JSContext* cx, uint32_t numBoundArgs,
    143                                           bool targetIsConstructor,
    144                                           uint32_t targetLength,
    145                                           JSAtom* targetName);
    146 
    147  static constexpr size_t offsetOfTargetSlot() {
    148    return getFixedSlotOffset(TargetSlot);
    149  }
    150  static constexpr size_t offsetOfFlagsSlot() {
    151    return getFixedSlotOffset(FlagsSlot);
    152  }
    153  static constexpr size_t offsetOfBoundThisSlot() {
    154    return getFixedSlotOffset(BoundThisSlot);
    155  }
    156  static constexpr size_t offsetOfFirstInlineBoundArg() {
    157    return getFixedSlotOffset(BoundArg0Slot);
    158  }
    159  static constexpr size_t offsetOfLengthSlot() {
    160    return getFixedSlotOffset(LengthSlot);
    161  }
    162  static constexpr size_t offsetOfNameSlot() {
    163    return getFixedSlotOffset(NameSlot);
    164  }
    165 
    166  static constexpr size_t targetSlot() { return TargetSlot; }
    167  static constexpr size_t boundThisSlot() { return BoundThisSlot; }
    168  static constexpr size_t firstInlineBoundArgSlot() { return BoundArg0Slot; }
    169 };
    170 
    171 };  // namespace js
    172 
    173 #endif /* vm_BoundFunctionObject_h */