Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  Realm.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef vm_Realm_h
#define vm_Realm_h

#include "mozilla/Array.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Variant.h"
#include "mozilla/XorShift128PlusRNG.h"

#include <stddef.h>

#include "builtin/Array.h"
#include "ds/IdValuePair.h"
#include "gc/Barrier.h"
#include "js/GCVariant.h"
#include "js/RealmOptions.h"
#include "js/TelemetryTimers.h"
#include "js/UniquePtr.h"
#include "vm/ArrayBufferObject.h"
#include "vm/GuardFuse.h"
#include "vm/InvalidatingFuse.h"
#include "vm/JSContext.h"
#include "vm/PromiseLookup.h"  // js::PromiseLookup
#include "vm/RealmFuses.h"
#include "vm/SavedStacks.h"
#include "wasm/WasmRealm.h"

namespace js {

namespace coverage {
class LCovRealm;
}  // namespace coverage

class AutoRestoreRealmDebugMode;
class Debugger;
class GlobalObject;
class GlobalObjectData;
class GlobalLexicalEnvironmentObject;
class NonSyntacticLexicalEnvironmentObject;
struct IdValuePair;
struct NativeIterator;

/*
 * A single-entry cache for some base-10 double-to-string conversions. This
 * helps date-format-xparb.js.  It also avoids skewing the results for
 * v8-splay.js when measured by the SunSpider harness, where the splay tree
 * initialization (which includes many repeated double-to-string conversions)
 * is erroneously included in the measurement; see bug 562553.
 */

class DtoaCache {
  double dbl;
  int base;
  JSLinearString* str;  // if str==nullptr, dbl and base are not valid

 public:
  DtoaCache() : str(nullptr) {}
  void purge() { str = nullptr; }

  JSLinearString* lookup(int b, double d) {
    return str && b == base && d == dbl ? str : nullptr;
  }

  void cache(int b, double d, JSLinearString* s) {
    base = b;
    dbl = d;
    str = s;
  }

#ifdef JSGC_HASH_TABLE_CHECKS
  void checkCacheAfterMovingGC();
#endif
};

// Cache to speed up the group/shape lookup in ProxyObject::create. A proxy's
// shape is only determined by the Class + proto, so a small cache for this is
// very effective in practice.
class NewProxyCache {
  struct Entry {
    Shape* shape;
  };
  static const size_t NumEntries = 4;
  mozilla::UniquePtr<Entry[], JS::FreePolicy> entries_;

 public:
  MOZ_ALWAYS_INLINE bool lookup(const JSClass* clasp, TaggedProto proto,
                                Shape** shape) const {
    if (!entries_) {
      return false;
    }
    for (size_t i = 0; i < NumEntries; i++) {
      const Entry& entry = entries_[i];
      if (entry.shape && entry.shape->getObjectClass() == clasp &&
          entry.shape->proto() == proto) {
        *shape = entry.shape;
        return true;
      }
    }
    return false;
  }
  void add(Shape* shape) {
    MOZ_ASSERT(shape);
    if (!entries_) {
      entries_.reset(js_pod_calloc<Entry>(NumEntries));
      if (!entries_) {
        return;
      }
    } else {
      for (size_t i = NumEntries - 1; i > 0; i--) {
        entries_[i] = entries_[i - 1];
      }
    }
    entries_[0].shape = shape;
  }
  void purge() { entries_.reset(); }
};

// Cache for NewPlainObjectWithProperties. When the list of properties matches
// a recently created object's shape, we can use this shape directly.
class NewPlainObjectWithPropsCache {
  static const size_t NumEntries = 4;
  mozilla::Array<SharedShape*, NumEntries> entries_;

 public:
  NewPlainObjectWithPropsCache() { purge(); }

  SharedShape* lookup(Handle<IdValueVector> properties) const;
  void add(SharedShape* shape);

  void purge() {
    for (size_t i = 0; i < NumEntries; i++) {
      entries_[i] = nullptr;
    }
  }
};

// Cache for Object.assign's fast path for two plain objects. It's used to
// optimize:
//
//   Object.assign(to, from)
//
// If the |to| object has shape |emptyToShape_| (shape with no properties) and
// the |from| object has shape |fromShape_|, we can use |newToShape_| for |to|
// and copy all (data)) properties from the |from| object.
//
// This is a one-entry cache for now. It has a hit rate of > 90% on both
// Speedometer 2 and Speedometer 3.
class MOZ_NON_TEMPORARY_CLASS PlainObjectAssignCache {
  SharedShape* emptyToShape_ = nullptr;
  SharedShape* fromShape_ = nullptr;
  SharedShape* newToShape_ = nullptr;

#ifdef DEBUG
  void assertValid() const;
#else
  void assertValid() const {}
#endif

 public:
  PlainObjectAssignCache() = default;
  PlainObjectAssignCache(const PlainObjectAssignCache&) = delete;
  void operator=(const PlainObjectAssignCache&) = delete;

  SharedShape* lookup(Shape* emptyToShape, Shape* fromShape) const {
    if (emptyToShape_ == emptyToShape && fromShape_ == fromShape) {
      assertValid();
      return newToShape_;
    }
    return nullptr;
  }
  void fill(SharedShape* emptyToShape, SharedShape* fromShape,
            SharedShape* newToShape) {
    emptyToShape_ = emptyToShape;
    fromShape_ = fromShape;
    newToShape_ = newToShape;
    assertValid();
  }
  void purge() {
    emptyToShape_ = nullptr;
    fromShape_ = nullptr;
    newToShape_ = nullptr;
  }
};

// [SMDOC] Object MetadataBuilder API
//
// We must ensure that all newly allocated JSObjects get their metadata
// set. However, metadata builders may require the new object be in a sane
// state (eg, have its reserved slots initialized so they can get the
// sizeOfExcludingThis of the object). Therefore, for objects of certain
// JSClasses (those marked with JSCLASS_DELAY_METADATA_BUILDER), it is not safe
// for the allocation paths to call the object metadata builder
// immediately. Instead, the JSClass-specific "constructor" C++ function up the
// stack makes a promise that it will ensure that the new object has its
// metadata set after the object is initialized.
//
// The js::AutoSetNewObjectMetadata RAII class provides an ergonomic way for
// constructor functions to do this.
//
// In the presence of internal errors, we do not set the new object's metadata
// (if it was even allocated).

class PropertyIteratorObject;

struct IteratorHashPolicy {
  struct Lookup {
    Shape** shapes;
    size_t numShapes;
    HashNumber shapesHash;

    Lookup(Shape** shapes, size_t numShapes, HashNumber shapesHash)
        : shapes(shapes), numShapes(numShapes), shapesHash(shapesHash) {
      MOZ_ASSERT(numShapes > 0);
    }
  };
  static HashNumber hash(const Lookup& lookup) { return lookup.shapesHash; }
  static bool match(PropertyIteratorObject* obj, const Lookup& lookup);
};

class DebugEnvironments;
class NonSyntacticVariablesObject;
class ObjectWeakMap;
class WithEnvironmentObject;

// ObjectRealm stores various tables and other state associated with particular
// objects in a realm. To make sure the correct ObjectRealm is used for an
// object, use of the ObjectRealm::get(obj) static method is required.
class ObjectRealm {
  // All non-syntactic lexical environments in the realm. These are kept in a
  // map because when loading scripts into a non-syntactic environment, we
  // need to use the same lexical environment to persist lexical bindings.
  js::UniquePtr<js::ObjectWeakMap> nonSyntacticLexicalEnvironments_;

  ObjectRealm(const ObjectRealm&) = delete;
  void operator=(const ObjectRealm&) = delete;

 public:
  // Map from array buffers to views sharing that storage.
  JS::WeakCache<js::InnerViewTable> innerViews;

  // Keep track of the metadata objects which can be associated with each JS
  // object. Both keys and values are in this realm.
  js::UniquePtr<js::ObjectWeakMap> objectMetadataTable;

  using IteratorCache =
      js::HashSet<js::PropertyIteratorObject*, js::IteratorHashPolicy,
                  js::ZoneAllocPolicy>;
  IteratorCache iteratorCache;

  static inline ObjectRealm& get(const JSObject* obj);

  explicit ObjectRealm(JS::Zone* zone);

  void finishRoots();
  void trace(JSTracer* trc);
  void sweepAfterMinorGC(JSTracer* trc);

  void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                              size_t* innerViewsArg,
                              size_t* objectMetadataTablesArg,
                              size_t* nonSyntacticLexicalEnvironmentsArg);

  NonSyntacticLexicalEnvironmentObject*
  getOrCreateNonSyntacticLexicalEnvironment(
      JSContext* cx, Handle<NonSyntacticVariablesObject*> enclosing);

  NonSyntacticLexicalEnvironmentObject*
  getOrCreateNonSyntacticLexicalEnvironment(
      JSContext* cx, Handle<WithEnvironmentObject*> enclosing);

  NonSyntacticLexicalEnvironmentObject*
  getOrCreateNonSyntacticLexicalEnvironment(
      JSContext* cx, Handle<WithEnvironmentObject*> enclosing,
      Handle<NonSyntacticVariablesObject*> key);

 private:
  NonSyntacticLexicalEnvironmentObject*
  getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx,
                                            HandleObject enclosing,
                                            HandleObject key,
                                            HandleObject thisv);

 public:
  NonSyntacticLexicalEnvironmentObject* getNonSyntacticLexicalEnvironment(
      JSObject* key) const;
};

}  // namespace js

class JS::Realm : public JS::shadow::Realm {
  JS::Zone* zone_;
  JSRuntime* runtime_;

  const JS::RealmCreationOptions creationOptions_;
  JS::RealmBehaviors behaviors_;

  friend struct ::JSContext;
  js::WeakHeapPtr<js::GlobalObject*> global_;

  // Note: this is private to enforce use of ObjectRealm::get(obj).
  js::ObjectRealm objects_;
  friend js::ObjectRealm& js::ObjectRealm::get(const JSObject*);

  // See the "Object MetadataBuilder API" comment.
  JSObject* objectPendingMetadata_ = nullptr;
#ifdef DEBUG
  uint32_t numActiveAutoSetNewObjectMetadata_ = 0;
#endif

  // Random number generator for Math.random().
  mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG>
      randomNumberGenerator_;

  // Random number generator for randomHashCodeScrambler().
  mozilla::non_crypto::XorShift128PlusRNG randomKeyGenerator_;

  JSPrincipals* principals_ = nullptr;

  // Bookkeeping information for debug scope objects.
  js::UniquePtr<js::DebugEnvironments> debugEnvs_;

  js::SavedStacks savedStacks_;

  // Used by memory reporters and invalid otherwise.
  JS::RealmStats* realmStats_ = nullptr;

  const js::AllocationMetadataBuilder* allocationMetadataBuilder_ = nullptr;
  void* realmPrivate_ = nullptr;

  // There are two ways to enter a realm:
  //
  // (1) AutoRealm (and JSAutoRealm, JS::EnterRealm)
  // (2) When calling a cross-realm (but same-compartment) function in JIT
  //     code.
  //
  // This field only accounts for (1), to keep the JIT code as simple as
  // possible.
  //
  // An important invariant is that the JIT can only switch to a different
  // realm within the same compartment, so whenever that happens there must
  // always be a same-compartment realm with enterRealmDepthIgnoringJit_ > 0.
  // This lets us set Compartment::hasEnteredRealm without walking the
  // stack.
  unsigned enterRealmDepthIgnoringJit_ = 0;

 public:
  // Various timers for collecting time spent delazifying, jit compiling,
  // executing, etc
  JS::JSTimers timers;

  struct DebuggerVectorEntry {
    // The debugger relies on iterating through the DebuggerVector to know what
    // debuggers to notify about certain actions, which it does using this
    // pointer. We need an explicit Debugger* because the JSObject* from
    // the DebuggerDebuggeeLink to the Debugger is only set some of the time.
    // This `Debugger*` pointer itself could also live on the
    // DebuggerDebuggeeLink itself, but that would then require all of the
    // places that iterate over the realm's DebuggerVector to also traverse
    // the CCW which seems like it would be needlessly complicated.
    js::WeakHeapPtr<js::Debugger*> dbg;

    // This links to the debugger's DebuggerDebuggeeLink object, via a CCW.
    // Tracing this link from the realm allows the debugger to define
    // whether pieces of the debugger should be held live by a given realm.
    js::HeapPtr<JSObject*> debuggerLink;

    DebuggerVectorEntry(js::Debugger* dbg_, JSObject* link);
  };
  using DebuggerVector =
      js::Vector<DebuggerVectorEntry, 0, js::ZoneAllocPolicy>;

 private:
  DebuggerVector debuggers_;

  enum {
    IsDebuggee = 1 << 0,
    DebuggerObservesAllExecution = 1 << 1,
    DebuggerObservesAsmJS = 1 << 2,
    DebuggerObservesCoverage = 1 << 3,
    DebuggerObservesWasm = 1 << 4,
    DebuggerObservesNativeCall = 1 << 5,
  };
  unsigned debugModeBits_ = 0;
  friend class js::AutoRestoreRealmDebugMode;

  bool isSystem_ = false;
  bool allocatedDuringIncrementalGC_;
  bool initializingGlobal_ = true;

  // Indicates that we are tracing all execution within this realm, i.e.,
  // recording every entrance into exit from each function, among other
  // things. See ExecutionTracer.h for where the bulk of this work
  // happens.
  bool isTracingExecution_ = false;

  js::UniquePtr<js::coverage::LCovRealm> lcovRealm_ = nullptr;

 public:
  // WebAssembly state for the realm.
  js::wasm::Realm wasm;

  js::DtoaCache dtoaCache;
  js::NewProxyCache newProxyCache;
  js::NewPlainObjectWithPropsCache newPlainObjectWithPropsCache;
  js::PlainObjectAssignCache plainObjectAssignCache;
  js::ArraySpeciesLookup arraySpeciesLookup;
  js::PromiseLookup promiseLookup;

  // Last time at which an animation was played for this realm.
  js::MainThreadData<mozilla::TimeStamp> lastAnimationTime;

  /*
   * For generational GC, record whether a write barrier has added this
   * realm's global to the store buffer since the last minor GC.
   *
   * This is used to avoid calling into the VM every time a nursery object is
   * written to a property of the global.
   */

  uint32_t globalWriteBarriered = 0;

  // Counter for shouldCaptureStackForThrow.
  uint16_t numStacksCapturedForThrow_ = 0;

  // Count the number of allocation sites pretenured, for testing purposes.
  uint16_t numAllocSitesPretenured = 0;

#ifdef DEBUG
  bool firedOnNewGlobalObject = false;
#endif

  // True if all incoming wrappers have been nuked. This happens when
  // NukeCrossCompartmentWrappers is called with the NukeAllReferences option.
  // This prevents us from creating new wrappers for the compartment.
  bool nukedIncomingWrappers = false;

  // Enable async stack capturing for this realm even if
  // JS::ContextOptions::asyncStackCaptureDebuggeeOnly_ is true.
  //
  // No-op when JS::ContextOptions::asyncStack_ is false, or
  // JS::ContextOptions::asyncStackCaptureDebuggeeOnly_ is false.
  //
  // This can be used as a lightweight alternative for making the global
  // debuggee, if the async stack capturing is necessary but no other debugging
  // features are used.
  bool isAsyncStackCapturingEnabled = false;

  // Allow to collect more than 50 stack traces for throw even if the global is
  // not a debuggee.
  //
  // Similarly to isAsyncStackCapturingEnabled, this is a lightweight
  // alternative for making the global a debuggee, when no actual debugging
  // features are required.
  bool isUnlimitedStacksCapturingEnabled = false;

 private:
  void updateDebuggerObservesFlag(unsigned flag);

  Realm(const Realm&) = delete;
  void operator=(const Realm&) = delete;

 public:
  Realm(JS::Compartment* comp, const JS::RealmOptions& options);
  ~Realm();

  void init(JSContext* cx, JSPrincipals* principals);
  void destroy(JS::GCContext* gcx);

  void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                              size_t* realmObject, size_t* realmTables,
                              size_t* innerViewsArg,
                              size_t* objectMetadataTablesArg,
                              size_t* savedStacksSet,
                              size_t* nonSyntacticLexicalEnvironmentsArg);

  JS::Zone* zone() { return zone_; }
  const JS::Zone* zone() const { return zone_; }

  JSRuntime* runtimeFromMainThread() const {
    MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
    return runtime_;
  }

  // Note: Unrestricted access to the runtime from an arbitrary thread
  // can easily lead to races. Use this method very carefully.
  JSRuntime* runtimeFromAnyThread() const { return runtime_; }

  const JS::RealmCreationOptions& creationOptions() const {
    return creationOptions_;
  }

  // NOTE: Do not provide accessor for mutable reference.
  // Modifying RealmBehaviors after creating a realm can result in
  // inconsistency.
  const JS::RealmBehaviors& behaviors() const { return behaviors_; }

  void setNonLive() { behaviors_.setNonLive(); }
  void setReduceTimerPrecisionCallerType(JS::RTPCallerTypeToken type) {
    behaviors_.setReduceTimerPrecisionCallerType(type);
  }

  /* Whether to preserve JIT code on non-shrinking GCs. */
  bool preserveJitCode() { return creationOptions_.preserveJitCode(); }

  /* The global object for this realm.
   *
   * Note: the global_ field is null briefly during GC, after the global
   * object is collected; but when that happens the Realm is destroyed during
   * the same GC.)
   *
   * In contrast, JSObject::global() is infallible because marking a JSObject
   * always marks its global as well.
   */

  inline js::GlobalObject* maybeGlobal() const;

  /* An unbarriered getter for use while tracing. */
  js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const {
    return global_.unbarrieredGet();
  }

  /* True if a global exists and it's not being collected. */
  inline bool hasLiveGlobal() const;

  /* True if a global exists and has been successfully initialized. */
  inline bool hasInitializedGlobal() const;

  inline void initGlobal(js::GlobalObject& global);
  void clearInitializingGlobal() { initializingGlobal_ = false; }

  /*
   * This method traces data that is live iff we know that this realm's
   * global is still live.
   */

  void traceGlobalData(JSTracer* trc);

  void traceWeakGlobalEdge(JSTracer* trc);

  /*
   * This method traces Realm-owned GC roots that are considered live
   * regardless of whether the realm's global is still live.
   */

  void traceRoots(JSTracer* trc,
                  js::gc::GCRuntime::TraceOrMarkRuntime traceOrMark);
  /*
   * This method clears out tables of roots in preparation for the final GC.
   */

  void finishRoots();

  void sweepAfterMinorGC(JSTracer* trc);
  void traceWeakDebugEnvironmentEdges(JSTracer* trc);

  void clearScriptCounts();
  void clearScriptLCov();

  void purge();

  void fixupAfterMovingGC(JSTracer* trc);

  void enter() { enterRealmDepthIgnoringJit_++; }
  void leave() {
    MOZ_ASSERT(enterRealmDepthIgnoringJit_ > 0);
    enterRealmDepthIgnoringJit_--;
  }
  bool hasBeenEnteredIgnoringJit() const {
    return enterRealmDepthIgnoringJit_ > 0;
  }
  bool shouldTraceGlobal() const {
    // If we entered this realm in JIT code, there must be a script and
    // function on the stack for this realm, so the global will definitely
    // be traced and it's safe to return false here.
    return hasBeenEnteredIgnoringJit();
  }

  bool hasAllocationMetadataBuilder() const {
    return allocationMetadataBuilder_;
  }
  const js::AllocationMetadataBuilder* getAllocationMetadataBuilder() const {
    return allocationMetadataBuilder_;
  }
  const void* addressOfMetadataBuilder() const {
    return &allocationMetadataBuilder_;
  }
  bool isRecordingAllocations();
  void setAllocationMetadataBuilder(
      const js::AllocationMetadataBuilder* builder);
  void forgetAllocationMetadataBuilder();
  void setNewObjectMetadata(JSContext* cx, JS::HandleObject obj);

  bool hasObjectPendingMetadata() const {
    MOZ_ASSERT_IF(objectPendingMetadata_, hasAllocationMetadataBuilder());
    return objectPendingMetadata_ != nullptr;
  }
  void setObjectPendingMetadata(JSObject* obj) {
    MOZ_ASSERT(numActiveAutoSetNewObjectMetadata_ > 0,
               "Must not use JSCLASS_DELAY_METADATA_BUILDER without "
               "AutoSetNewObjectMetadata");
    MOZ_ASSERT(!objectPendingMetadata_);
    MOZ_ASSERT(obj);
    if (MOZ_UNLIKELY(hasAllocationMetadataBuilder())) {
      objectPendingMetadata_ = obj;
    }
  }
  JSObject* getAndClearObjectPendingMetadata() {
    MOZ_ASSERT(hasAllocationMetadataBuilder());
    JSObject* obj = objectPendingMetadata_;
    objectPendingMetadata_ = nullptr;
    return obj;
  }

#ifdef DEBUG
  void incNumActiveAutoSetNewObjectMetadata() {
    numActiveAutoSetNewObjectMetadata_++;
  }
  void decNumActiveAutoSetNewObjectMetadata() {
    MOZ_ASSERT(numActiveAutoSetNewObjectMetadata_ > 0);
    numActiveAutoSetNewObjectMetadata_--;
  }
#endif

  void* realmPrivate() const { return realmPrivate_; }
  void setRealmPrivate(void* p) { realmPrivate_ = p; }

  // This should only be called when it is non-null, i.e. during memory
  // reporting.
  JS::RealmStats& realmStats() {
    // We use MOZ_RELEASE_ASSERT here because in bug 1132502 there was some
    // (inconclusive) evidence that realmStats_ can be nullptr unexpectedly.
    MOZ_RELEASE_ASSERT(realmStats_);
    return *realmStats_;
  }
  void nullRealmStats() {
    MOZ_ASSERT(realmStats_);
    realmStats_ = nullptr;
  }
  void setRealmStats(JS::RealmStats* newStats) {
    MOZ_ASSERT(!realmStats_ && newStats);
    realmStats_ = newStats;
  }

  inline bool marked() const;
  void clearAllocatedDuringGC() { allocatedDuringIncrementalGC_ = false; }

  /*
   * The principals associated with this realm. Note that the same several
   * realms may share the same principals and that a realm may change
   * principals during its lifetime (e.g. in case of lazy parsing).
   */

  JSPrincipals* principals() { return principals_; }
  void setPrincipals(JSPrincipals* principals) { principals_ = principals; }

  bool isSystem() const { return isSystem_; }
  //
  // The Debugger observes execution on a frame-by-frame basis. The
  // invariants of Realm's debug mode bits, JSScript::isDebuggee,
  // InterpreterFrame::isDebuggee, and BaselineFrame::isDebuggee are
  // enumerated below.
  //
  // 1. When a realm's isDebuggee() == true, relazification and lazy
  //    parsing are disabled.
  //
  //    Whether AOT wasm is disabled is togglable by the Debugger API. By
  //    default it is disabled. See debuggerObservesAsmJS below.
  //
  // 2. When a realm's debuggerObservesAllExecution() == true, all of
  //    the realm's scripts are considered debuggee scripts.
  //
  // 3. A script is considered a debuggee script either when, per above, its
  //    realm is observing all execution, or if it has breakpoints set.
  //
  // 4. A debuggee script always pushes a debuggee frame.
  //
  // 5. A debuggee frame calls all slow path Debugger hooks in the
  //    Interpreter and Baseline. A debuggee frame implies that its script's
  //    BaselineScript, if extant, has been compiled with debug hook calls.
  //
  // 6. A debuggee script or a debuggee frame (i.e., during OSR) ensures
  //    that the compiled BaselineScript is compiled with debug hook calls
  //    when attempting to enter Baseline.
  //
  // 7. A debuggee script or a debuggee frame (i.e., during OSR) does not
  //    attempt to enter Ion.
  //
  // Note that a debuggee frame may exist without its script being a
  // debuggee script. e.g., Debugger.Frame.prototype.eval only marks the
  // frame in which it is evaluating as a debuggee frame.
  //

  // True if this realm's global is a debuggee of some Debugger
  // object.
  bool isDebuggee() const { return !!(debugModeBits_ & IsDebuggee); }

  void setIsDebuggee();
  void unsetIsDebuggee();

  bool isTracingExecution() { return isTracingExecution_; }

  void enableExecutionTracing() {
    MOZ_ASSERT(!debuggerObservesCoverage());

    isTracingExecution_ = true;
    setIsDebuggee();
    updateDebuggerObservesAllExecution();
  }

  void disableExecutionTracing() {
    if (!isTracingExecution_) {
      return;
    }

    isTracingExecution_ = false;
    // updateDebuggerObservesAllExecution always wants isDebuggee to be true,
    // so we just have weird ordering here to play nicely with it
    updateDebuggerObservesAllExecution();
    if (!hasDebuggers()) {
      unsetIsDebuggee();
    }
  }

  DebuggerVector& getDebuggers(const JS::AutoRequireNoGC& nogc) {
    return debuggers_;
  };
  bool hasDebuggers() const { return !debuggers_.empty(); }

  // True if this compartment's global is a debuggee of some Debugger
  // object with a live hook that observes all execution; e.g.,
  // onEnterFrame.
  bool debuggerObservesAllExecution() const {
    static const unsigned Mask = IsDebuggee | DebuggerObservesAllExecution;
    return (debugModeBits_ & Mask) == Mask;
  }
  void updateDebuggerObservesAllExecution() {
    updateDebuggerObservesFlag(DebuggerObservesAllExecution);
  }

  // True if this realm's global is a debuggee of some Debugger object
  // whose allowUnobservedAsmJS flag is false.
  bool debuggerObservesAsmJS() const {
    static const unsigned Mask = IsDebuggee | DebuggerObservesAsmJS;
    return (debugModeBits_ & Mask) == Mask;
  }
  void updateDebuggerObservesAsmJS() {
    updateDebuggerObservesFlag(DebuggerObservesAsmJS);
  }

  // True if this realm's global is a debuggee of some Debugger object
  // whose allowUnobservedWasm flag is false.
  //
  // Note that since AOT wasm functions cannot bail out, this flag really
  // means "observe wasm from this point forward". We cannot make
  // already-compiled wasm code observable to Debugger.
  bool debuggerObservesWasm() const {
    static const unsigned Mask = IsDebuggee | DebuggerObservesWasm;
    return (debugModeBits_ & Mask) == Mask;
  }
  void updateDebuggerObservesWasm() {
    updateDebuggerObservesFlag(DebuggerObservesWasm);
  }

  // True if this compartment's global is a debuggee of some Debugger
  // object with a live hook that observes native calls.
  // (has a onNativeCall function registered)
  bool debuggerObservesNativeCall() const {
    static const unsigned Mask = IsDebuggee | DebuggerObservesNativeCall;
    return (debugModeBits_ & Mask) == Mask;
  }
  void updateDebuggerObservesNativeCall() {
    updateDebuggerObservesFlag(DebuggerObservesNativeCall);
  }

  // True if this realm's global is a debuggee of some Debugger object
  // whose collectCoverageInfo flag is true.
  bool debuggerObservesCoverage() const {
    static const unsigned Mask = DebuggerObservesCoverage;
    return (debugModeBits_ & Mask) == Mask;
  }
  void updateDebuggerObservesCoverage();

  // Returns true if the Debugger API is collecting code coverage data for this
  // realm or if the process-wide LCov option is enabled.
  bool collectCoverageForDebug() const;

  // Get or allocate the associated LCovRealm.
  js::coverage::LCovRealm* lcovRealm();

  bool shouldCaptureStackForThrow();

  // Returns the locale for this realm. (Pointer must NOT be freed!)
  const char* getLocale() const;

  // Initializes randomNumberGenerator if needed.
  mozilla::non_crypto::XorShift128PlusRNG& getOrCreateRandomNumberGenerator();

  const mozilla::non_crypto::XorShift128PlusRNG*
  addressOfRandomNumberGenerator() const {
    return randomNumberGenerator_.ptr();
  }

  mozilla::HashCodeScrambler randomHashCodeScrambler();

  js::DebugEnvironments* debugEnvs() { return debugEnvs_.get(); }
  js::UniquePtr<js::DebugEnvironments>& debugEnvsRef() { return debugEnvs_; }

  js::SavedStacks& savedStacks() { return savedStacks_; }

  // Recompute the probability with which this realm should record
  // profiling data (stack traces, allocations log, etc.) about each
  // allocation. We first consult the JS runtime to see if it is recording
  // allocations, and if not then check the probabilities requested by the
  // Debugger instances observing us, if any.
  void chooseAllocationSamplingProbability() {
    savedStacks_.chooseSamplingProbability(this);
  }

  void traceWeakSavedStacks(JSTracer* trc);

  static constexpr size_t offsetOfCompartment() {
    return offsetof(JS::Realm, compartment_);
  }
  static constexpr size_t offsetOfAllocationMetadataBuilder() {
    return offsetof(JS::Realm, allocationMetadataBuilder_);
  }
  static constexpr size_t offsetOfDebugModeBits() {
    return offsetof(JS::Realm, debugModeBits_);
  }
  static constexpr uint32_t debugModeIsDebuggeeBit() { return IsDebuggee; }

  // Note: similar to cx->global(), JIT code can omit the read barrier for the
  // context's active global.
  static constexpr size_t offsetOfActiveGlobal() {
    static_assert(sizeof(global_) == sizeof(uintptr_t),
                  "JIT code assumes field is pointer-sized");
    return offsetof(JS::Realm, global_);
  }

  js::RealmFuses realmFuses;

  // Allocation site used by binding code to provide feedback
  // on allocation heap for DOM allocation functions.
  //
  // See  CallIRGenerator::tryAttachCallNative
  js::gc::AllocSite* localAllocSite = nullptr;

  static size_t offsetOfLocalAllocSite() {
    return offsetof(JS::Realm, localAllocSite);
  }

 private:
  void purgeForOfPicChain();
};

inline js::Handle<js::GlobalObject*> JSContext::global() const {
  /*
   * It's safe to use |unbarrieredGet()| here because any realm that is on-stack
   * will be marked automatically, so there's no need for a read barrier on
   * it. Once the realm is popped, the handle is no longer safe to use.
   */

  MOZ_ASSERT(realm_, "Caller needs to enter a realm first");
  return js::Handle<js::GlobalObject*>::fromMarkedLocation(
      realm_->global_.unbarrieredAddress());
}

namespace js {

class MOZ_RAII AssertRealmUnchanged {
 public:
  explicit AssertRealmUnchanged(JSContext* cx)
      : cx(cx), oldRealm(cx->realm()) {}

  ~AssertRealmUnchanged() { MOZ_ASSERT(cx->realm() == oldRealm); }

 protected:
  JSContext* const cx;
  JS::Realm* const oldRealm;
};

// AutoRealm can be used to enter the realm of a JSObject, JSScript or
// ObjectGroup. It must not be used with cross-compartment wrappers, because
// CCWs are not associated with a single realm.
class AutoRealm {
  JSContext* const cx_;
  JS::Realm* const origin_;

 public:
  template <typename T>
  inline AutoRealm(JSContext* cx, const T& target);
  inline ~AutoRealm();

  JSContext* context() const { return cx_; }
  JS::Realm* origin() const { return origin_; }

 protected:
  inline AutoRealm(JSContext* cx, JS::Realm* target);

 private:
  AutoRealm(const AutoRealm&) = delete;
  AutoRealm& operator=(const AutoRealm&) = delete;
};

class MOZ_RAII AutoAllocInAtomsZone {
  JSContext* const cx_;
  JS::Realm* const origin_;
  AutoAllocInAtomsZone(const AutoAllocInAtomsZone&) = delete;
  AutoAllocInAtomsZone& operator=(const AutoAllocInAtomsZone&) = delete;

 public:
  inline explicit AutoAllocInAtomsZone(JSContext* cx);
  inline ~AutoAllocInAtomsZone();
};

// During GC we sometimes need to enter a realm when we may have been allocating
// in the the atoms zone. This leaves the atoms zone temporarily. This happens
// in embedding callbacks and when we need to mark object groups as pretenured.
class MOZ_RAII AutoMaybeLeaveAtomsZone {
  JSContext* const cx_;
  bool wasInAtomsZone_;
  AutoMaybeLeaveAtomsZone(const AutoMaybeLeaveAtomsZone&) = delete;
  AutoMaybeLeaveAtomsZone& operator=(const AutoMaybeLeaveAtomsZone&) = delete;

 public:
  inline explicit AutoMaybeLeaveAtomsZone(JSContext* cx);
  inline ~AutoMaybeLeaveAtomsZone();
};

// Enter a realm directly. Only use this where there's no target GC thing
// to pass to AutoRealm or where you need to avoid the assertions in
// JS::Compartment::enterCompartmentOf().
class AutoRealmUnchecked : protected AutoRealm {
 public:
  inline AutoRealmUnchecked(JSContext* cx, JS::Realm* target);
};

// Similar to AutoRealm, but this uses GetFunctionRealm in the spec, and
// handles both bound functions and proxies.
//
// If GetFunctionRealm fails for the following reasons, this does nothing:
//   * `fun` is revoked proxy
//   * unwrapping failed because of a security wrapper
class AutoFunctionOrCurrentRealm {
  mozilla::Maybe<AutoRealmUnchecked> ar_;

 public:
  inline AutoFunctionOrCurrentRealm(JSContext* cx, js::HandleObject fun);
  ~AutoFunctionOrCurrentRealm() = default;

 private:
  AutoFunctionOrCurrentRealm(const AutoFunctionOrCurrentRealm&) = delete;
  AutoFunctionOrCurrentRealm& operator=(const AutoFunctionOrCurrentRealm&) =
      delete;
};

/*
 * Use this to change the behavior of an AutoRealm slightly on error. If
 * the exception happens to be an Error object, copy it to the origin
 * compartment instead of wrapping it.
 */

class ErrorCopier {
  mozilla::Maybe<AutoRealm>& ar;

 public:
  explicit ErrorCopier(mozilla::Maybe<AutoRealm>& ar) : ar(ar) {}
  ~ErrorCopier();
};

// See the "Object MetadataBuilder API" comment.
class MOZ_RAII AutoSetNewObjectMetadata {
  JSContext* cx_;

  AutoSetNewObjectMetadata(const AutoSetNewObjectMetadata& aOther) = delete;
  void operator=(const AutoSetNewObjectMetadata& aOther) = delete;

  void setPendingMetadata();

 public:
  explicit inline AutoSetNewObjectMetadata(JSContext* cx) : cx_(cx) {
#ifdef DEBUG
    MOZ_ASSERT(!cx->realm()->hasObjectPendingMetadata());
    cx_->realm()->incNumActiveAutoSetNewObjectMetadata();
#endif
  }
  inline ~AutoSetNewObjectMetadata() {
#ifdef DEBUG
    cx_->realm()->decNumActiveAutoSetNewObjectMetadata();
#endif
    if (MOZ_UNLIKELY(cx_->realm()->hasAllocationMetadataBuilder())) {
      setPendingMetadata();
    }
  }
};

/* namespace js */

#endif /* vm_Realm_h */

Messung V0.5
C=91 H=99 G=94

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge