Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/js/src/jit/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 19 kB image not shown  

Quelle  IonScript.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 jit_IonScript_h
#define jit_IonScript_h

#include "mozilla/MemoryReporting.h"  // MallocSizeOf

#include <stddef.h>  // size_t
#include <stdint.h>  // uint8_t, uint32_t

#include "jstypes.h"

#include "gc/Barrier.h"          // HeapPtr{JitCode,Object}
#include "jit/IonTypes.h"        // IonCompilationId
#include "jit/JitCode.h"         // JitCode
#include "jit/JitOptions.h"      // JitOptions
#include "js/TypeDecls.h"        // jsbytecode
#include "util/TrailingArray.h"  // TrailingArray

namespace js {
namespace jit {

class SnapshotWriter;
class RecoverWriter;
class SafepointWriter;
class CodegenSafepointIndex;
class SafepointIndex;
class OsiIndex;
class IonIC;

// An IonScript attaches Ion-generated information to a JSScript. The header
// structure is followed by several arrays of data. These trailing arrays have a
// layout based on offsets (bytes from 'this') stored in the IonScript header.
//
//    <IonScript itself>
//    --
//    PreBarriered<Value>[] constantTable()
//    uint8_t[]             runtimeData()
//    OsiIndex[]            osiIndex()
//    SafepointIndex[]      safepointIndex()
//    uint32_t[]            icIndex()
//    --
//    uint8_t[]             safepoints()
//    uint8_t[]             snapshots()
//    uint8_t[]             snapshotsRVATable()
//    uint8_t[]             recovers()
//
// Note: These are arranged in order of descending alignment requirements to
// avoid the need for padding. The `runtimeData` uses uint64_t alignement due to
// its use of mozilla::AlignedStorage2.
class alignas(8) IonScript final : public TrailingArray<IonScript> {
 private:
  // Offset (in bytes) from `this` to the start of each trailing array. Each
  // array ends where following one begins. There is no implicit padding (except
  // possible at very end).
  Offset constantTableOffset_ = 0;   // JS::Value aligned
  Offset runtimeDataOffset_ = 0;     // uint64_t aligned
  Offset nurseryObjectsOffset_ = 0;  // pointer aligned
  Offset osiIndexOffset_ = 0;
  Offset safepointIndexOffset_ = 0;
  Offset icIndexOffset_ = 0;
  Offset safepointsOffset_ = 0;
  Offset snapshotsOffset_ = 0;
  Offset rvaTableOffset_ = 0;
  Offset recoversOffset_ = 0;
  Offset allocBytes_ = 0;

  // Code pointer containing the actual method.
  HeapPtr<JitCode*> method_ = nullptr;

  // Entrypoint for OSR, or nullptr.
  jsbytecode* osrPc_ = nullptr;

  // Offset to OSR entrypoint from method_->raw(), or 0.
  uint32_t osrEntryOffset_ = 0;

  // Offset of the invalidation epilogue (which pushes this IonScript
  // and calls the invalidation thunk).
  uint32_t invalidateEpilogueOffset_ = 0;

  // The offset immediately after the IonScript immediate.
  // NOTE: technically a constant delta from
  // |invalidateEpilogueOffset_|, so we could hard-code this
  // per-platform if we want.
  uint32_t invalidateEpilogueDataOffset_ = 0;

  // Number of bailouts that have occurred for reasons that could be
  // fixed if we invalidated and recompiled.
  uint16_t numFixableBailouts_ = 0;

  // Number of bailouts that have occurred for reasons that can't be
  // fixed by recompiling: for example, bailing out to catch an exception.
  uint16_t numUnfixableBailouts_ = 0;

 public:
  enum class LICMState : uint8_t { NeverBailed, Bailed, BailedAndHitFallback };

 private:
  // Tracks the state of LICM bailouts.
  LICMState licmState_ = LICMState::NeverBailed;

  // Flag set if IonScript was compiled with profiling enabled.
  bool hasProfilingInstrumentation_ = false;

  // If true, this IonScript was active on the stack when we discarded JIT code
  // and inactive ICScripts. This means we should use the generic ICScripts for
  // inlined functions when we bail out.
  bool purgedICScripts_ = false;

  // Number of bytes this function reserves on the stack for slots spilled by
  // the register allocator.
  uint32_t localSlotsSize_ = 0;

  // Number of bytes used passed in as formal arguments or |this|.
  uint32_t argumentSlotsSize_ = 0;

  // Frame size is the value that can be added to the StackPointer along
  // with the frame prefix to get a valid JitFrameLayout.
  uint32_t frameSize_ = 0;

  // Number of references from invalidation records.
  uint32_t invalidationCount_ = 0;

  // Identifier of the compilation which produced this code.
  IonCompilationId compilationId_;

  // Number of times we tried to enter this script via OSR but failed due to
  // a LOOPENTRY pc other than osrPc_.
  uint32_t osrPcMismatchCounter_ = 0;

#ifdef DEBUG
  // A hash of the ICScripts used in this compilation.
  mozilla::HashNumber icHash_ = 0;
#endif

  // End of fields.

 private:
  // Layout helpers
  Offset constantTableOffset() const { return constantTableOffset_; }
  Offset runtimeDataOffset() const { return runtimeDataOffset_; }
  Offset nurseryObjectsOffset() const { return nurseryObjectsOffset_; }
  Offset osiIndexOffset() const { return osiIndexOffset_; }
  Offset safepointIndexOffset() const { return safepointIndexOffset_; }
  Offset icIndexOffset() const { return icIndexOffset_; }
  Offset safepointsOffset() const { return safepointsOffset_; }
  Offset snapshotsOffset() const { return snapshotsOffset_; }
  Offset rvaTableOffset() const { return rvaTableOffset_; }
  Offset recoversOffset() const { return recoversOffset_; }
  Offset endOffset() const { return allocBytes_; }

  // Hardcode size of incomplete types. These are verified in Ion.cpp.
  static constexpr size_t SizeOf_OsiIndex = 2 * sizeof(uint32_t);
  static constexpr size_t SizeOf_SafepointIndex = 2 * sizeof(uint32_t);

 public:
  //
  // Table of constants referenced in snapshots. (JS::Value alignment)
  //
  PreBarriered<Value>* constants() {
    // Nursery constants are manually barriered in CodeGenerator::link() so a
    // post barrier is not required..
    return offsetToPointer<PreBarriered<Value>>(constantTableOffset());
  }
  size_t numConstants() const {
    return numElements<PreBarriered<Value>>(constantTableOffset(),
                                            runtimeDataOffset());
  }

  //
  // IonIC data structures. (uint64_t alignment)
  //
  uint8_t* runtimeData() {
    return offsetToPointer<uint8_t>(runtimeDataOffset());
  }
  size_t runtimeSize() const {
    return numElements<uint8_t>(runtimeDataOffset(), nurseryObjectsOffset());
  }

  //
  // List of (originally) nursery-allocated objects referenced from JIT code.
  // (JSObject* alignment)
  //
  HeapPtr<JSObject*>* nurseryObjects() {
    return offsetToPointer<HeapPtr<JSObject*>>(nurseryObjectsOffset());
  }
  size_t numNurseryObjects() const {
    return numElements<HeapPtr<JSObject*>>(nurseryObjectsOffset(),
                                           osiIndexOffset());
  }
  void* addressOfNurseryObject(uint32_t index) {
    MOZ_ASSERT(index < numNurseryObjects());
    return &nurseryObjects()[index];
  }

  //
  // Map OSI-point displacement to snapshot.
  //
  OsiIndex* osiIndices() { return offsetToPointer<OsiIndex>(osiIndexOffset()); }
  const OsiIndex* osiIndices() const {
    return offsetToPointer<OsiIndex>(osiIndexOffset());
  }
  size_t numOsiIndices() const {
    return numElements<SizeOf_OsiIndex>(osiIndexOffset(),
                                        safepointIndexOffset());
  }

  //
  // Map code displacement to safepoint / OSI-patch-delta.
  //
  SafepointIndex* safepointIndices() {
    return offsetToPointer<SafepointIndex>(safepointIndexOffset());
  }
  const SafepointIndex* safepointIndices() const {
    return offsetToPointer<SafepointIndex>(safepointIndexOffset());
  }
  size_t numSafepointIndices() const {
    return numElements<SizeOf_SafepointIndex>(safepointIndexOffset(),
                                              icIndexOffset());
  }

  //
  // Offset into `runtimeData` for each (variable-length) IonIC.
  //
  uint32_t* icIndex() { return offsetToPointer<uint32_t>(icIndexOffset()); }
  size_t numICs() const {
    return numElements<uint32_t>(icIndexOffset(), safepointsOffset());
  }

  //
  // Safepoint table as a CompactBuffer.
  //
  const uint8_t* safepoints() const {
    return offsetToPointer<uint8_t>(safepointsOffset());
  }
  size_t safepointsSize() const {
    return numElements<uint8_t>(safepointsOffset(), snapshotsOffset());
  }

  //
  // Snapshot and RValueAllocation tables as CompactBuffers.
  //
  const uint8_t* snapshots() const {
    return offsetToPointer<uint8_t>(snapshotsOffset());
  }
  size_t snapshotsListSize() const {
    return numElements<uint8_t>(snapshotsOffset(), rvaTableOffset());
  }
  size_t snapshotsRVATableSize() const {
    return numElements<uint8_t>(rvaTableOffset(), recoversOffset());
  }

  //
  // Recover instruction table as a CompactBuffer.
  //
  const uint8_t* recovers() const {
    return offsetToPointer<uint8_t>(recoversOffset());
  }
  size_t recoversSize() const {
    return numElements<uint8_t>(recoversOffset(), endOffset());
  }

 private:
  IonScript(IonCompilationId compilationId, uint32_t localSlotsSize,
            uint32_t argumentSlotsSize, uint32_t frameSize);

 public:
  static IonScript* New(JSContext* cx, IonCompilationId compilationId,
                        uint32_t localSlotsSize, uint32_t argumentSlotsSize,
                        uint32_t frameSize, size_t snapshotsListSize,
                        size_t snapshotsRVATableSize, size_t recoversSize,
                        size_t constants, size_t nurseryObjects,
                        size_t safepointIndices, size_t osiIndices,
                        size_t icEntries, size_t runtimeSize,
                        size_t safepointsSize);

  static void Destroy(JS::GCContext* gcx, IonScript* script);

  void trace(JSTracer* trc);
  void traceWeak(JSTracer* trc);

  static inline size_t offsetOfInvalidationCount() {
    return offsetof(IonScript, invalidationCount_);
  }

 public:
  JitCode* method() const { return method_; }
  void setMethod(JitCode* code) {
    MOZ_ASSERT(!invalidated());
    method_ = code;
  }
  void setOsrPc(jsbytecode* osrPc) { osrPc_ = osrPc; }
  jsbytecode* osrPc() const { return osrPc_; }
  void setOsrEntryOffset(uint32_t offset) {
    MOZ_ASSERT(!osrEntryOffset_);
    osrEntryOffset_ = offset;
  }
  uint32_t osrEntryOffset() const { return osrEntryOffset_; }
  bool containsCodeAddress(uint8_t* addr) const {
    return method()->raw() <= addr &&
           addr <= method()->raw() + method()->instructionsSize();
  }
  bool containsReturnAddress(uint8_t* addr) const {
    // This accounts for an off by one error caused by the return address of a
    // bailout sitting outside the range of the containing function.
    return method()->raw() <= addr &&
           addr <= method()->raw() + method()->instructionsSize();
  }
  void setInvalidationEpilogueOffset(uint32_t offset) {
    MOZ_ASSERT(!invalidateEpilogueOffset_);
    invalidateEpilogueOffset_ = offset;
  }
  uint32_t invalidateEpilogueOffset() const {
    MOZ_ASSERT(invalidateEpilogueOffset_);
    return invalidateEpilogueOffset_;
  }
  void setInvalidationEpilogueDataOffset(uint32_t offset) {
    MOZ_ASSERT(!invalidateEpilogueDataOffset_);
    invalidateEpilogueDataOffset_ = offset;
  }
  uint32_t invalidateEpilogueDataOffset() const {
    MOZ_ASSERT(invalidateEpilogueDataOffset_);
    return invalidateEpilogueDataOffset_;
  }

  uint32_t numFixableBailouts() const { return numFixableBailouts_; }

  void incNumFixableBailouts() { numFixableBailouts_++; }
  void resetNumFixableBailouts() { numFixableBailouts_ = 0; }
  void incNumUnfixableBailouts() { numUnfixableBailouts_++; }

  bool shouldInvalidate() const {
    return numFixableBailouts_ >= JitOptions.frequentBailoutThreshold;
  }
  bool shouldInvalidateAndDisable() const {
    return numUnfixableBailouts_ >= JitOptions.frequentBailoutThreshold * 5;
  }

  LICMState licmState() const { return licmState_; }
  void setHadLICMBailout() {
    if (licmState_ == LICMState::NeverBailed) {
      licmState_ = LICMState::Bailed;
    }
  }
  void noteBaselineFallback() {
    if (licmState_ == LICMState::Bailed) {
      licmState_ = LICMState::BailedAndHitFallback;
    }
  }

  void setHasProfilingInstrumentation() { hasProfilingInstrumentation_ = true; }
  void clearHasProfilingInstrumentation() {
    hasProfilingInstrumentation_ = false;
  }
  bool hasProfilingInstrumentation() const {
    return hasProfilingInstrumentation_;
  }

  bool purgedICScripts() const { return purgedICScripts_; }
  void notePurgedICScripts() { purgedICScripts_ = true; }

  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    return mallocSizeOf(this);
  }
  PreBarriered<Value>& getConstant(size_t index) {
    MOZ_ASSERT(index < numConstants());
    return constants()[index];
  }
  uint32_t localSlotsSize() const { return localSlotsSize_; }
  uint32_t argumentSlotsSize() const { return argumentSlotsSize_; }
  uint32_t frameSize() const { return frameSize_; }
  const SafepointIndex* getSafepointIndex(uint32_t disp) const;
  const SafepointIndex* getSafepointIndex(uint8_t* retAddr) const {
    MOZ_ASSERT(containsCodeAddress(retAddr));
    return getSafepointIndex(retAddr - method()->raw());
  }
  const OsiIndex* getOsiIndex(uint32_t disp) const;
  const OsiIndex* getOsiIndex(uint8_t* retAddr) const;

  IonIC& getICFromIndex(uint32_t index) {
    MOZ_ASSERT(index < numICs());
    uint32_t offset = icIndex()[index];
    return getIC(offset);
  }
  inline IonIC& getIC(uint32_t offset) {
    MOZ_ASSERT(offset < runtimeSize());
    return *reinterpret_cast<IonIC*>(runtimeData() + offset);
  }
  void purgeICs(Zone* zone);
  void copySnapshots(const SnapshotWriter* writer);
  void copyRecovers(const RecoverWriter* writer);
  void copyConstants(const Value* vp);
  void copySafepointIndices(const CodegenSafepointIndex* si);
  void copyOsiIndices(const OsiIndex* oi);
  void copyRuntimeData(const uint8_t* data);
  void copyICEntries(const uint32_t* icEntries);
  void copySafepoints(const SafepointWriter* writer);

  bool invalidated() const { return invalidationCount_ != 0; }

  // Invalidate the current compilation.
  void invalidate(JSContext* cx, JSScript* script, bool resetUses,
                  const char* reason);

  size_t invalidationCount() const { return invalidationCount_; }
  void incrementInvalidationCount() { invalidationCount_++; }
  void decrementInvalidationCount(JS::GCContext* gcx) {
    MOZ_ASSERT(invalidationCount_);
    invalidationCount_--;
    if (!invalidationCount_) {
      Destroy(gcx, this);
    }
  }
  IonCompilationId compilationId() const { return compilationId_; }
  uint32_t incrOsrPcMismatchCounter() { return ++osrPcMismatchCounter_; }
  void resetOsrPcMismatchCounter() { osrPcMismatchCounter_ = 0; }

  size_t allocBytes() const { return allocBytes_; }

  static void preWriteBarrier(Zone* zone, IonScript* ionScript);

#ifdef DEBUG
  mozilla::HashNumber icHash() const { return icHash_; }
  void setICHash(mozilla::HashNumber hash) { icHash_ = hash; }
#endif
};

// Execution information for a basic block which may persist after the
// accompanying IonScript is destroyed, for use during profiling.
struct IonBlockCounts {
 private:
  uint32_t id_;

  // Approximate bytecode in the outer (not inlined) script this block
  // was generated from.
  uint32_t offset_;

  // File and line of the inner script this block was generated from.
  char* description_;

  // ids for successors of this block.
  uint32_t numSuccessors_;
  uint32_t* successors_;

  // Hit count for this block.
  uint64_t hitCount_;

  // Text information about the code generated for this block.
  char* code_;

 public:
  [[nodiscard]] bool init(uint32_t id, uint32_t offset, char* description,
                          uint32_t numSuccessors) {
    id_ = id;
    offset_ = offset;
    description_ = description;
    numSuccessors_ = numSuccessors;
    if (numSuccessors) {
      successors_ = js_pod_calloc<uint32_t>(numSuccessors);
      if (!successors_) {
        return false;
      }
    }
    return true;
  }

  void destroy() {
    js_free(description_);
    js_free(successors_);
    js_free(code_);
  }

  uint32_t id() const { return id_; }

  uint32_t offset() const { return offset_; }

  const char* description() const { return description_; }

  size_t numSuccessors() const { return numSuccessors_; }

  void setSuccessor(size_t i, uint32_t id) {
    MOZ_ASSERT(i < numSuccessors_);
    successors_[i] = id;
  }

  uint32_t successor(size_t i) const {
    MOZ_ASSERT(i < numSuccessors_);
    return successors_[i];
  }

  uint64_t* addressOfHitCount() { return &hitCount_; }

  uint64_t hitCount() const { return hitCount_; }

  void setCode(const char* code) {
    char* ncode = js_pod_malloc<char>(strlen(code) + 1);
    if (ncode) {
      strcpy(ncode, code);
      code_ = ncode;
    }
  }

  const char* code() const { return code_; }

  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    return mallocSizeOf(description_) + mallocSizeOf(successors_) +
           mallocSizeOf(code_);
  }
};

// Execution information for a compiled script which may persist after the
// IonScript is destroyed, for use during profiling.
struct IonScriptCounts {
 private:
  // Any previous invalidated compilation(s) for the script.
  IonScriptCounts* previous_ = nullptr;

  // Information about basic blocks in this script.
  size_t numBlocks_ = 0;
  IonBlockCounts* blocks_ = nullptr;

 public:
  IonScriptCounts() = default;

  ~IonScriptCounts() {
    for (size_t i = 0; i < numBlocks_; i++) {
      blocks_[i].destroy();
    }
    js_free(blocks_);
    // The list can be long in some corner cases (bug 1140084), so
    // unroll the recursion.
    IonScriptCounts* victims = previous_;
    while (victims) {
      IonScriptCounts* victim = victims;
      victims = victim->previous_;
      victim->previous_ = nullptr;
      js_delete(victim);
    }
  }

  [[nodiscard]] bool init(size_t numBlocks) {
    blocks_ = js_pod_calloc<IonBlockCounts>(numBlocks);
    if (!blocks_) {
      return false;
    }

    numBlocks_ = numBlocks;
    return true;
  }

  size_t numBlocks() const { return numBlocks_; }

  IonBlockCounts& block(size_t i) {
    MOZ_ASSERT(i < numBlocks_);
    return blocks_[i];
  }

  void setPrevious(IonScriptCounts* previous) { previous_ = previous; }

  IonScriptCounts* previous() const { return previous_; }

  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    size_t size = 0;
    auto currCounts = this;
    do {
      size += currCounts->sizeOfOneIncludingThis(mallocSizeOf);
      currCounts = currCounts->previous_;
    } while (currCounts);
    return size;
  }

  size_t sizeOfOneIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    size_t size = mallocSizeOf(this) + mallocSizeOf(blocks_);
    for (size_t i = 0; i < numBlocks_; i++) {
      blocks_[i].sizeOfExcludingThis(mallocSizeOf);
    }
    return size;
  }
};

}  // namespace jit
}  // namespace js

namespace JS {

template <>
struct DeletePolicy<js::jit::IonScript> {
  explicit DeletePolicy(JSRuntime* rt) : rt_(rt) {}
  void operator()(const js::jit::IonScript* script);

 private:
  JSRuntime* rt_;
};

}  // namespace JS

#endif /* jit_IonScript_h */

Messung V0.5
C=93 H=99 G=95

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© 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.