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 23 kB image not shown  

Quelle  Snapshots.cpp   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/. */


#include "jit/Snapshots.h"

#include "jit/JitSpewer.h"
#ifdef TRACK_SNAPSHOTS
#  include "jit/LIR.h"
#endif
#include "jit/MIR-wasm.h"
#include "jit/MIR.h"
#include "jit/Recover.h"
#include "js/Printer.h"

using namespace js;
using namespace js::jit;

// [SMDOC] IonMonkey Snapshot encoding
//
// Encodings:
//   [ptr] A fixed-size pointer.
//   [vwu] A variable-width unsigned integer.
//   [vws] A variable-width signed integer.
//    [u8] An 8-bit unsigned integer.
//   [u8'] An 8-bit unsigned integer which is potentially extended with packed
//         data.
//   [u8"] Packed data which is stored and packed in the previous [u8'].
//  [vwu*] A list of variable-width unsigned integers.
//   [pld] Payload of Recover Value Allocation:
//         PAYLOAD_NONE:
//           There is no payload.
//
//         PAYLOAD_INDEX:
//           [vwu] Index, such as the constant pool index.
//
//         PAYLOAD_STACK_OFFSET:
//           [vws] Stack offset based on the base of the Ion frame.
//
//         PAYLOAD_GPR:
//            [u8] Code of the general register.
//
//         PAYLOAD_FPU:
//            [u8] Code of the FPU register.
//
//         PAYLOAD_PACKED_TAG:
//           [u8"] Bits 5-7: JSValueType is encoded on the low bits of the Mode
//                           of the RValueAllocation.
//
// Snapshot header:
//
//   [vwu] bits ((n+1)-31]: recover instruction offset
//         bits [0,n): bailout kind (n = SNAPSHOT_BAILOUTKIND_BITS)
//
// Snapshot body, repeated "frame count" times, from oldest frame to newest
// frame. Note that the first frame doesn't have the "parent PC" field.
//
//   [ptr] Debug only: JSScript*
//   [vwu] pc offset
//   [vwu] # of RVA's indexes, including nargs
//  [vwu*] List of indexes to R(ecover)ValueAllocation table. Contains
//         nargs + nfixed + stackDepth items.
//
// Recover value allocations are encoded at the end of the Snapshot buffer, and
// they are padded on ALLOCATION_TABLE_ALIGNMENT.  The encoding of each
// allocation is determined by the RValueAllocation::Layout, which can be
// obtained from the RValueAllocation::Mode with layoutFromMode function.  The
// layout structure list the type of payload which are used to serialized /
// deserialized / dumped the content of the allocations.
//
// R(ecover)ValueAllocation items:
//   [u8'] Mode, which defines the type of the payload as well as the
//         interpretation.
//   [pld] first payload (packed tag, index, stack offset, register, ...)
//   [pld] second payload (register, stack offset, none)
//
//       Modes:
//         CONSTANT [INDEX]
//           Index into the constant pool.
//
//         CST_UNDEFINED []
//           Constant value which correspond to the "undefined" JS value.
//
//         CST_NULL []
//           Constant value which correspond to the "null" JS value.
//
//         DOUBLE_REG [FPU_REG]
//           Double value stored in a FPU register.
//
//         ANY_FLOAT_REG [FPU_REG]
//           Any Float value (float32, simd) stored in a FPU register.
//
//         ANY_FLOAT_STACK [STACK_OFFSET]
//           Any Float value (float32, simd) stored on the stack.
//
//         UNTYPED_REG   [GPR_REG]
//         UNTYPED_STACK [STACK_OFFSET]
//         UNTYPED_REG_REG     [GPR_REG,      GPR_REG]
//         UNTYPED_REG_STACK   [GPR_REG,      STACK_OFFSET]
//         UNTYPED_STACK_REG   [STACK_OFFSET, GPR_REG]
//         UNTYPED_STACK_STACK [STACK_OFFSET, STACK_OFFSET]
//           Value with dynamically known type. On 32 bits architecture, the
//           first register/stack-offset correspond to the holder of the type,
//           and the second correspond to the payload of the JS Value.
//
//         RECOVER_INSTRUCTION [INDEX]
//           Index into the list of recovered instruction results.
//
//         RI_WITH_DEFAULT_CST [INDEX] [INDEX]
//           The first payload is the index into the list of recovered
//           instruction results.  The second payload is the index in the
//           constant pool.
//
//         INTPTR_CST [INDEX]:          (32-bit platform)
//         INTPTR_CST [INDEX] [INDEX]:  (64-bit platform)
//           Unpacked IntPtr value stored in intptr_t. Split into either one or
//           two int32_t values, whose indices into the constant pool is stored
//           in the payloads.
//
//         INTPTR_REG [GPR_REG]:
//           Unpacked IntPtr value stored in intptr_t. Payload is stored in a
//           register.
//
//         INTPTR_STACK [STACK_OFFSET]:
//           Unpacked IntPtr value stored in intptr_t. Payload is stored at an
//           offset on the stack.
//
//         TYPED_REG [PACKED_TAG, GPR_REG]:
//           Value with statically known type, which payload is stored in a
//           register.
//
//         TYPED_STACK [PACKED_TAG, STACK_OFFSET]:
//           Value with statically known type, which payload is stored at an
//           offset on the stack.
//
//         INT64_CST [INDEX] [INDEX]:
//           Unpacked Int64 value stored in int64_t. Split into two int32_t
//           values, whose indices into the constant pool is stored in the
//           payloads.
//
//         INT64_REG    [GPR_REG]:
//         INT64_STACK  [STACK_OFFSET]:
//         INT64_REG_REG      [GPR_REG,      GPR_REG]
//         INT64_REG_STACK    [GPR_REG,      STACK_OFFSET]
//         INT64_STACK_REG    [STACK_OFFSET, GPR_REG]
//         INT64_STACK_STACK  [STACK_OFFSET, STACK_OFFSET]
//           Unpacked Int64 value. On 32 bits architecture, the first
//           register/stack-offset correspond to the low 32-bits, and the
//           second correspond to the high 32-bits.
//

const RValueAllocation::Layout& RValueAllocation::layoutFromMode(Mode mode) {
  switch (mode) {
    case CONSTANT: {
      static const RValueAllocation::Layout layout = {PAYLOAD_INDEX,
                                                      PAYLOAD_NONE, "constant"};
      return layout;
    }

    case CST_UNDEFINED: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_NONE, PAYLOAD_NONE, "undefined"};
      return layout;
    }

    case CST_NULL: {
      static const RValueAllocation::Layout layout = {PAYLOAD_NONE,
                                                      PAYLOAD_NONE, "null"};
      return layout;
    }

    case DOUBLE_REG: {
      static const RValueAllocation::Layout layout = {PAYLOAD_FPU, PAYLOAD_NONE,
                                                      "double"};
      return layout;
    }
    case ANY_FLOAT_REG: {
      static const RValueAllocation::Layout layout = {PAYLOAD_FPU, PAYLOAD_NONE,
                                                      "float register content"};
      return layout;
    }
    case ANY_FLOAT_STACK: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_STACK_OFFSET, PAYLOAD_NONE, "float register content"};
      return layout;
    }
#if defined(JS_NUNBOX32)
    case UNTYPED_REG_REG: {
      static const RValueAllocation::Layout layout = {PAYLOAD_GPR, PAYLOAD_GPR,
                                                      "value"};
      return layout;
    }
    case UNTYPED_REG_STACK: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_GPR, PAYLOAD_STACK_OFFSET, "value"};
      return layout;
    }
    case UNTYPED_STACK_REG: {
      static const RValueAllocation::Layout layout = {PAYLOAD_STACK_OFFSET,
                                                      PAYLOAD_GPR, "value"};
      return layout;
    }
    case UNTYPED_STACK_STACK: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_STACK_OFFSET, PAYLOAD_STACK_OFFSET, "value"};
      return layout;
    }
#elif defined(JS_PUNBOX64)
    case UNTYPED_REG: {
      static const RValueAllocation::Layout layout = {PAYLOAD_GPR, PAYLOAD_NONE,
                                                      "value"};
      return layout;
    }
    case UNTYPED_STACK: {
      static const RValueAllocation::Layout layout = {PAYLOAD_STACK_OFFSET,
                                                      PAYLOAD_NONE, "value"};
      return layout;
    }
#endif
    case RECOVER_INSTRUCTION: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_INDEX, PAYLOAD_NONE, "instruction"};
      return layout;
    }
    case RI_WITH_DEFAULT_CST: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_INDEX, PAYLOAD_INDEX, "instruction with default"};
      return layout;
    }

    case INTPTR_CST: {
#if !defined(JS_64BIT)
      static const RValueAllocation::Layout layout = {
          PAYLOAD_INDEX, PAYLOAD_NONE, "unpacked intptr constant"};
      static_assert(sizeof(int32_t) == sizeof(intptr_t));
#else
      static const RValueAllocation::Layout layout = {
          PAYLOAD_INDEX, PAYLOAD_INDEX, "unpacked intptr constant"};
      static_assert(2 * sizeof(int32_t) == sizeof(intptr_t));
#endif
      return layout;
    }

    case INTPTR_REG: {
      static const RValueAllocation::Layout layout = {PAYLOAD_GPR, PAYLOAD_NONE,
                                                      "unpacked intptr"};
      return layout;
    }

    case INTPTR_STACK: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_STACK_OFFSET, PAYLOAD_NONE, "unpacked intptr"};
      return layout;
    }

    case INT64_CST: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_INDEX, PAYLOAD_INDEX, "unpacked int64 constant"};
      static_assert(2 * sizeof(int32_t) == sizeof(int64_t));
      return layout;
    }

#if defined(JS_NUNBOX32)
    case INT64_REG_REG: {
      static const RValueAllocation::Layout layout = {PAYLOAD_GPR, PAYLOAD_GPR,
                                                      "unpacked int64"};
      return layout;
    }

    case INT64_REG_STACK: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_GPR, PAYLOAD_STACK_OFFSET, "unpacked int64"};
      return layout;
    }

    case INT64_STACK_REG: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_STACK_OFFSET, PAYLOAD_GPR, "unpacked int64"};
      return layout;
    }

    case INT64_STACK_STACK: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_STACK_OFFSET, PAYLOAD_STACK_OFFSET, "unpacked int64"};
      return layout;
    }
#elif defined(JS_PUNBOX64)
    case INT64_REG: {
      static const RValueAllocation::Layout layout = {PAYLOAD_GPR, PAYLOAD_NONE,
                                                      "unpacked int64"};
      return layout;
    }

    case INT64_STACK: {
      static const RValueAllocation::Layout layout = {
          PAYLOAD_STACK_OFFSET, PAYLOAD_NONE, "unpacked int64"};
      return layout;
    }
#endif

    default: {
      static const RValueAllocation::Layout regLayout = {
          PAYLOAD_PACKED_TAG, PAYLOAD_GPR, "typed value"};

      static const RValueAllocation::Layout stackLayout = {
          PAYLOAD_PACKED_TAG, PAYLOAD_STACK_OFFSET, "typed value"};

      if (mode >= TYPED_REG_MIN && mode <= TYPED_REG_MAX) {
        return regLayout;
      }
      if (mode >= TYPED_STACK_MIN && mode <= TYPED_STACK_MAX) {
        return stackLayout;
      }
    }
  }

  MOZ_CRASH_UNSAFE_PRINTF("Unexpected mode: 0x%x", uint32_t(mode));
}

// Pad serialized RValueAllocations by a multiple of X bytes in the allocation
// buffer.  By padding serialized value allocations, we are building an
// indexable table of elements of X bytes, and thus we can safely divide any
// offset within the buffer by X to obtain an index.
//
// By padding, we are loosing space within the allocation buffer, but we
// multiple by X the number of indexes that we can store on one byte in each
// snapshots.
//
// Some value allocations are taking more than X bytes to be encoded, in which
// case we will pad to a multiple of X, and we are wasting indexes. The choice
// of X should be balanced between the wasted padding of serialized value
// allocation, and the saving made in snapshot indexes.
static const size_t ALLOCATION_TABLE_ALIGNMENT = 2; /* bytes */

void RValueAllocation::readPayload(CompactBufferReader& reader,
                                   PayloadType type, uint8_t* mode,
                                   Payload* p) {
  switch (type) {
    case PAYLOAD_NONE:
      break;
    case PAYLOAD_INDEX:
      p->index = reader.readUnsigned();
      break;
    case PAYLOAD_STACK_OFFSET:
      p->stackOffset = reader.readSigned();
      break;
    case PAYLOAD_GPR:
      p->gpr = Register::FromCode(reader.readByte());
      break;
    case PAYLOAD_FPU:
      p->fpu.data = reader.readByte();
      break;
    case PAYLOAD_PACKED_TAG:
      p->type = JSValueType(*mode & PACKED_TAG_MASK);
      *mode = *mode & ~PACKED_TAG_MASK;
      break;
  }
}

RValueAllocation RValueAllocation::read(CompactBufferReader& reader) {
  uint8_t mode = reader.readByte();
  const Layout& layout = layoutFromMode(Mode(mode & MODE_BITS_MASK));
  Payload arg1, arg2;

  readPayload(reader, layout.type1, &mode, &arg1);
  readPayload(reader, layout.type2, &mode, &arg2);
  return RValueAllocation(Mode(mode), arg1, arg2);
}

void RValueAllocation::writePayload(CompactBufferWriter& writer,
                                    PayloadType type, Payload p) {
  switch (type) {
    case PAYLOAD_NONE:
      break;
    case PAYLOAD_INDEX:
      writer.writeUnsigned(p.index);
      break;
    case PAYLOAD_STACK_OFFSET:
      writer.writeSigned(p.stackOffset);
      break;
    case PAYLOAD_GPR:
      static_assert(Registers::Total <= 0x100,
                    "Not enough bytes to encode all registers.");
      writer.writeByte(p.gpr.code());
      break;
    case PAYLOAD_FPU:
      static_assert(FloatRegisters::Total <= 0x100,
                    "Not enough bytes to encode all float registers.");
      writer.writeByte(p.fpu.code());
      break;
    case PAYLOAD_PACKED_TAG: {
      // This code assumes that the PACKED_TAG payload is following the
      // writeByte of the mode.
      if (!writer.oom()) {
        MOZ_ASSERT(writer.length());
        uint8_t* mode = writer.buffer() + (writer.length() - 1);
        MOZ_ASSERT((*mode & PACKED_TAG_MASK) == 0 &&
                   (p.type & ~PACKED_TAG_MASK) == 0);
        *mode = *mode | p.type;
      }
      break;
    }
  }
}

void RValueAllocation::writePadding(CompactBufferWriter& writer) {
  // Write 0x7f in all padding bytes.
  while (writer.length() % ALLOCATION_TABLE_ALIGNMENT) {
    writer.writeByte(0x7f);
  }
}

void RValueAllocation::write(CompactBufferWriter& writer) const {
  const Layout& layout = layoutFromMode(mode());
  MOZ_ASSERT(layout.type2 != PAYLOAD_PACKED_TAG);
  MOZ_ASSERT(writer.length() % ALLOCATION_TABLE_ALIGNMENT == 0);

  writer.writeByte(mode_);
  writePayload(writer, layout.type1, arg1_);
  writePayload(writer, layout.type2, arg2_);
  writePadding(writer);
}

HashNumber RValueAllocation::hash() const {
  HashNumber res = 0;
  res = HashNumber(mode_);
  res = arg1_.index + (res << 6) + (res << 16) - res;
  res = arg2_.index + (res << 6) + (res << 16) - res;
  return res;
}

#ifdef JS_JITSPEW
void RValueAllocation::dumpPayload(GenericPrinter& out, PayloadType type,
                                   Payload p) {
  switch (type) {
    case PAYLOAD_NONE:
      break;
    case PAYLOAD_INDEX:
      out.printf("index %u", p.index);
      break;
    case PAYLOAD_STACK_OFFSET:
      out.printf("stack %d", p.stackOffset);
      break;
    case PAYLOAD_GPR:
      out.printf("reg %s", p.gpr.name());
      break;
    case PAYLOAD_FPU:
      out.printf("reg %s", p.fpu.name());
      break;
    case PAYLOAD_PACKED_TAG:
      out.printf("%s", ValTypeToString(p.type));
      break;
  }
}

void RValueAllocation::dump(GenericPrinter& out) const {
  const Layout& layout = layoutFromMode(mode());
  out.printf("%s", layout.name);

  if (layout.type1 != PAYLOAD_NONE) {
    out.printf(" (");
  }
  dumpPayload(out, layout.type1, arg1_);
  if (layout.type2 != PAYLOAD_NONE) {
    out.printf(", ");
  }
  dumpPayload(out, layout.type2, arg2_);
  if (layout.type1 != PAYLOAD_NONE) {
    out.printf(")");
  }
}
#endif  // JS_JITSPEW

SnapshotReader::SnapshotReader(const uint8_t* snapshots, uint32_t offset,
                               uint32_t RVATableSize, uint32_t listSize)
    : reader_(snapshots + offset, snapshots + listSize),
      allocReader_(snapshots + listSize, snapshots + listSize + RVATableSize),
      allocTable_(snapshots + listSize),
      allocRead_(0) {
  if (!snapshots) {
    return;
  }
  JitSpew(JitSpew_IonSnapshots, "Creating snapshot reader");
  readSnapshotHeader();
}

#define COMPUTE_SHIFT_AFTER_(name) (name##_BITS + name##_SHIFT)
#define COMPUTE_MASK_(name) ((uint32_t(1 << name##_BITS) - 1) << name##_SHIFT)

// Details of snapshot header packing.
static const uint32_t SNAPSHOT_BAILOUTKIND_SHIFT = 0;
static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 6;
static const uint32_t SNAPSHOT_BAILOUTKIND_MASK =
    COMPUTE_MASK_(SNAPSHOT_BAILOUTKIND);

static_assert((1 << SNAPSHOT_BAILOUTKIND_BITS) - 1 >=
                  uint8_t(BailoutKind::Limit),
              "Not enough bits for BailoutKinds");

static const uint32_t SNAPSHOT_ROFFSET_SHIFT =
    COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
static const uint32_t SNAPSHOT_ROFFSET_BITS = 32 - SNAPSHOT_ROFFSET_SHIFT;
static const uint32_t SNAPSHOT_ROFFSET_MASK = COMPUTE_MASK_(SNAPSHOT_ROFFSET);

#undef COMPUTE_MASK_
#undef COMPUTE_SHIFT_AFTER_

void SnapshotReader::readSnapshotHeader() {
  uint32_t bits = reader_.readUnsigned();

  bailoutKind_ = BailoutKind((bits & SNAPSHOT_BAILOUTKIND_MASK) >>
                             SNAPSHOT_BAILOUTKIND_SHIFT);
  recoverOffset_ = (bits & SNAPSHOT_ROFFSET_MASK) >> SNAPSHOT_ROFFSET_SHIFT;

  JitSpew(JitSpew_IonSnapshots, "Read snapshot header with bailout kind %u",
          uint32_t(bailoutKind_));

#ifdef TRACK_SNAPSHOTS
  readTrackSnapshot();
#endif
}

#ifdef TRACK_SNAPSHOTS
void SnapshotReader::readTrackSnapshot() {
  pcOpcode_ = reader_.readUnsigned();
  mirOpcode_ = reader_.readUnsigned();
  mirId_ = reader_.readUnsigned();
  lirOpcode_ = reader_.readUnsigned();
  lirId_ = reader_.readUnsigned();
}

void SnapshotReader::spewBailingFrom() const {
#  ifdef JS_JITSPEW
  if (JitSpewEnabled(JitSpew_IonBailouts)) {
    JitSpewHeader(JitSpew_IonBailouts);
    Fprinter& out = JitSpewPrinter();
    out.printf(" bailing from bytecode: %s, MIR: ", CodeName(JSOp(pcOpcode_)));
    MDefinition::PrintOpcodeName(out, MDefinition::Opcode(mirOpcode_));
    out.printf(" [%u], LIR: ", mirId_);
    LInstruction::printName(out, LInstruction::Opcode(lirOpcode_));
    out.printf(" [%u]", lirId_);
    out.printf("\n");
  }
#  endif
}
#endif

uint32_t SnapshotReader::readAllocationIndex() {
  allocRead_++;
  return reader_.readUnsigned();
}

RValueAllocation SnapshotReader::readAllocation() {
  JitSpew(JitSpew_IonSnapshots, "Reading slot %u", allocRead_);
  uint32_t offset = readAllocationIndex() * ALLOCATION_TABLE_ALIGNMENT;
  allocReader_.seek(allocTable_, offset);
  return RValueAllocation::read(allocReader_);
}

SnapshotWriter::SnapshotWriter()
    // Based on the measurements made in Bug 962555 comment 20, this length
    // should be enough to prevent the reallocation of the hash table for at
    // least half of the compilations.
    : allocMap_(32) {}

RecoverReader::RecoverReader(SnapshotReader& snapshot, const uint8_t* recovers,
                             uint32_t size)
    : reader_(nullptr, nullptr), numInstructions_(0), numInstructionsRead_(0) {
  if (!recovers) {
    return;
  }
  reader_ =
      CompactBufferReader(recovers + snapshot.recoverOffset(), recovers + size);
  readRecoverHeader();
  readInstruction();
}

RecoverReader::RecoverReader(const RecoverReader& rr)
    : reader_(rr.reader_),
      numInstructions_(rr.numInstructions_),
      numInstructionsRead_(rr.numInstructionsRead_) {
  if (reader_.currentPosition()) {
    rr.instruction()->cloneInto(&rawData_);
  }
}

RecoverReader& RecoverReader::operator=(const RecoverReader& rr) {
  reader_ = rr.reader_;
  numInstructions_ = rr.numInstructions_;
  numInstructionsRead_ = rr.numInstructionsRead_;
  if (reader_.currentPosition()) {
    rr.instruction()->cloneInto(&rawData_);
  }
  return *this;
}

void RecoverReader::readRecoverHeader() {
  numInstructions_ = reader_.readUnsigned();
  MOZ_ASSERT(numInstructions_);

  JitSpew(JitSpew_IonSnapshots, "Read recover header with instructionCount %u",
          numInstructions_);
}

void RecoverReader::readInstruction() {
  MOZ_ASSERT(moreInstructions());
  RInstruction::readRecoverData(reader_, &rawData_);
  numInstructionsRead_++;
}

SnapshotOffset SnapshotWriter::startSnapshot(RecoverOffset recoverOffset,
                                             BailoutKind kind) {
  lastStart_ = writer_.length();
  allocWritten_ = 0;

  JitSpew(JitSpew_IonSnapshots,
          "starting snapshot with recover offset %u, bailout kind %u",
          recoverOffset, uint32_t(kind));

  MOZ_ASSERT(uint32_t(kind) < (1 << SNAPSHOT_BAILOUTKIND_BITS));
  MOZ_ASSERT(recoverOffset < (1 << SNAPSHOT_ROFFSET_BITS));
  uint32_t bits = (uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
                  (recoverOffset << SNAPSHOT_ROFFSET_SHIFT);

  writer_.writeUnsigned(bits);
  return lastStart_;
}

#ifdef TRACK_SNAPSHOTS
void SnapshotWriter::trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode,
                                   uint32_t mirId, uint32_t lirOpcode,
                                   uint32_t lirId) {
  writer_.writeUnsigned(pcOpcode);
  writer_.writeUnsigned(mirOpcode);
  writer_.writeUnsigned(mirId);
  writer_.writeUnsigned(lirOpcode);
  writer_.writeUnsigned(lirId);
}
#endif

bool SnapshotWriter::add(const RValueAllocation& alloc) {
  uint32_t offset;
  RValueAllocMap::AddPtr p = allocMap_.lookupForAdd(alloc);
  if (!p) {
    offset = allocWriter_.length();
    alloc.write(allocWriter_);
    if (!allocMap_.add(p, alloc, offset)) {
      allocWriter_.setOOM();
      return false;
    }
  } else {
    offset = p->value();
  }

#ifdef JS_JITSPEW
  if (JitSpewEnabled(JitSpew_IonSnapshots)) {
    JitSpewHeader(JitSpew_IonSnapshots);
    Fprinter& out = JitSpewPrinter();
    out.printf(" slot %u (%u): ", allocWritten_, offset);
    alloc.dump(out);
    out.printf("\n");
  }
#endif

  allocWritten_++;
  writer_.writeUnsigned(offset / ALLOCATION_TABLE_ALIGNMENT);
  return true;
}

void SnapshotWriter::endSnapshot() {
  // Place a sentinel for asserting on the other end.
#ifdef DEBUG
  writer_.writeSigned(-1);
#endif

  JitSpew(JitSpew_IonSnapshots,
          "ending snapshot total size: %u bytes (start %u)",
          uint32_t(writer_.length() - lastStart_), lastStart_);
}

RecoverOffset RecoverWriter::startRecover(uint32_t instructionCount) {
  MOZ_ASSERT(instructionCount);
  instructionCount_ = instructionCount;
  instructionsWritten_ = 0;

  JitSpew(JitSpew_IonSnapshots, "starting recover with %u instruction(s)",
          instructionCount);

  RecoverOffset recoverOffset = writer_.length();
  writer_.writeUnsigned(instructionCount);
  return recoverOffset;
}

void RecoverWriter::writeInstruction(const MNode* rp) {
  if (!rp->writeRecoverData(writer_)) {
    writer_.setOOM();
  }
  instructionsWritten_++;
}

void RecoverWriter::endRecover() {
  MOZ_ASSERT(instructionCount_ == instructionsWritten_);
}

Messung V0.5
C=86 H=99 G=92

¤ Dauer der Verarbeitung: 0.15 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.