tor-browser

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

ProxyObject.h (5764B)


      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_ProxyObject_h
      8 #define vm_ProxyObject_h
      9 
     10 #include "js/Proxy.h"
     11 #include "js/shadow/Object.h"  // JS::shadow::Object
     12 #include "vm/JSObject.h"
     13 
     14 namespace js {
     15 
     16 /**
     17 * This is the base class for the various kinds of proxy objects.  It's never
     18 * instantiated.
     19 *
     20 * Proxy objects use their shape primarily to record flags. Property
     21 * information, &c. is all dynamically computed.
     22 *
     23 * There is no class_ member to force specialization of JSObject::is<T>().
     24 * The implementation in JSObject is incorrect for proxies since it doesn't
     25 * take account of the handler type.
     26 */
     27 class ProxyObject : public JSObject {
     28  // GetProxyDataLayout computes the address of this field.
     29  detail::ProxyDataLayout data;
     30 
     31  void static_asserts() {
     32    static_assert(sizeof(ProxyObject) == sizeof(JSObject_Slots0),
     33                  "proxy object size must match GC thing size");
     34    static_assert(offsetof(ProxyObject, data) == detail::ProxyDataOffset,
     35                  "proxy object layout must match shadow interface");
     36    static_assert(offsetof(ProxyObject, data.reservedSlots) ==
     37                      offsetof(JS::shadow::Object, slots),
     38                  "Proxy reservedSlots must overlay native object slots field");
     39  }
     40 
     41 public:
     42  static ProxyObject* New(JSContext* cx, const BaseProxyHandler* handler,
     43                          HandleValue priv, TaggedProto proto_,
     44                          const JSClass* clasp);
     45 
     46  void init(const BaseProxyHandler* handler, HandleValue priv, JSContext* cx);
     47 
     48  // Proxies usually store their ProxyValueArray inline in the object.
     49  // There's one unfortunate exception: when a proxy is swapped with another
     50  // object, and the sizes don't match, we malloc the ProxyValueArray.
     51  void* inlineDataStart() const {
     52    return (void*)(uintptr_t(this) + sizeof(ProxyObject));
     53  }
     54  bool usingInlineValueArray() const {
     55    return data.values() == inlineDataStart();
     56  }
     57  void setInlineValueArray() {
     58    data.reservedSlots =
     59        &reinterpret_cast<detail::ProxyValueArray*>(inlineDataStart())
     60             ->reservedSlots;
     61  }
     62 
     63  // For use from JSObject::swap.
     64  [[nodiscard]] bool prepareForSwap(JSContext* cx,
     65                                    MutableHandleValueVector valuesOut);
     66  [[nodiscard]] bool fixupAfterSwap(JSContext* cx, HandleValueVector values);
     67 
     68  const Value& private_() const { return GetProxyPrivate(this); }
     69  const Value& expando() const { return GetProxyExpando(this); }
     70 
     71  void setExpando(JSObject* expando);
     72 
     73  void setCrossCompartmentPrivate(const Value& priv);
     74  void setSameCompartmentPrivate(const Value& priv);
     75 
     76  JSObject* target() const { return private_().toObjectOrNull(); }
     77 
     78  const BaseProxyHandler* handler() const { return GetProxyHandler(this); }
     79 
     80  void setHandler(const BaseProxyHandler* handler) {
     81    SetProxyHandler(this, handler);
     82  }
     83 
     84  static size_t offsetOfReservedSlots() {
     85    return offsetof(ProxyObject, data.reservedSlots);
     86  }
     87  static size_t offsetOfHandler() {
     88    return offsetof(ProxyObject, data.handler);
     89  }
     90 
     91  size_t numReservedSlots() const { return JSCLASS_RESERVED_SLOTS(getClass()); }
     92  const Value& reservedSlot(size_t n) const {
     93    return GetProxyReservedSlot(this, n);
     94  }
     95 
     96  void setReservedSlot(size_t n, const Value& extra) {
     97    SetProxyReservedSlot(this, n, extra);
     98  }
     99 
    100  gc::AllocKind allocKindForTenure() const;
    101 
    102 private:
    103  GCPtr<Value>* reservedSlotPtr(size_t n) {
    104    return reinterpret_cast<GCPtr<Value>*>(
    105        &detail::GetProxyDataLayout(this)->reservedSlots->slots[n]);
    106  }
    107 
    108  GCPtr<Value>* slotOfPrivate() {
    109    return reinterpret_cast<GCPtr<Value>*>(
    110        &detail::GetProxyDataLayout(this)->values()->privateSlot);
    111  }
    112 
    113  GCPtr<Value>* slotOfExpando() {
    114    return reinterpret_cast<GCPtr<Value>*>(
    115        &detail::GetProxyDataLayout(this)->values()->expandoSlot);
    116  }
    117 
    118  void setPrivate(const Value& priv);
    119 
    120  static bool isValidProxyClass(const JSClass* clasp) {
    121    // Since we can take classes from the outside, make sure that they
    122    // are "sane". They have to quack enough like proxies for us to belive
    123    // they should be treated as such.
    124 
    125    // Proxy classes are not allowed to have call or construct hooks directly.
    126    // Their callability is instead decided by handler()->isCallable().
    127    return clasp->isProxyObject() && clasp->isTrace(ProxyObject::trace) &&
    128           !clasp->getCall() && !clasp->getConstruct();
    129  }
    130 
    131 public:
    132  static unsigned grayLinkReservedSlot(JSObject* obj);
    133 
    134  void renew(const BaseProxyHandler* handler, const Value& priv);
    135 
    136  static void trace(JSTracer* trc, JSObject* obj);
    137 
    138  static void traceEdgeToTarget(JSTracer* trc, ProxyObject* obj);
    139 
    140  void nurseryProxyTenured(ProxyObject* old);
    141 
    142  void nuke();
    143 };
    144 
    145 bool IsDerivedProxyObject(const JSObject* obj,
    146                          const js::BaseProxyHandler* handler);
    147 
    148 }  // namespace js
    149 
    150 template <>
    151 inline bool JSObject::is<js::ProxyObject>() const {
    152  // Note: this method is implemented in terms of the IsProxy() friend API
    153  // functions to ensure the implementations are tied together.
    154  // Note 2: this specialization isn't used for subclasses of ProxyObject
    155  // which must supply their own implementation.
    156  return js::IsProxy(this);
    157 }
    158 
    159 inline bool js::IsDerivedProxyObject(const JSObject* obj,
    160                                     const js::BaseProxyHandler* handler) {
    161  return obj->is<js::ProxyObject>() &&
    162         obj->as<js::ProxyObject>().handler() == handler;
    163 }
    164 
    165 #endif /* vm_ProxyObject_h */