js/src/jit/Snapshots.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     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/. */
     7 #include "jit/Snapshots.h"
     9 #include "jsscript.h"
    11 #include "jit/CompileInfo.h"
    12 #include "jit/IonSpewer.h"
    13 #ifdef TRACK_SNAPSHOTS
    14 # include "jit/LIR.h"
    15 #endif
    16 #include "jit/MIR.h"
    17 #include "jit/Recover.h"
    19 using namespace js;
    20 using namespace js::jit;
    22 // Snapshot header:
    23 //
    24 //   [vwu] bits ((n+1)-31]: frame count
    25 //         bit n+1: resume after
    26 //         bits [0,n): bailout kind (n = SNAPSHOT_BAILOUTKIND_BITS)
    27 //
    28 // Snapshot body, repeated "frame count" times, from oldest frame to newest frame.
    29 // Note that the first frame doesn't have the "parent PC" field.
    30 //
    31 //   [ptr] Debug only: JSScript *
    32 //   [vwu] pc offset
    33 //   [vwu] # of RVA's indexes, including nargs
    34 //  [vwu*] List of indexes to R(ecover)ValueAllocation table. Contains
    35 //         nargs + nfixed + stackDepth items.
    36 //
    37 // Recover value allocations are encoded at the end of the Snapshot buffer, and
    38 // they are padded on ALLOCATION_TABLE_ALIGNMENT.  The encoding of each
    39 // allocation is determined by the RValueAllocation::Layout, which can be
    40 // obtained from the RValueAllocation::Mode with layoutFromMode function.  The
    41 // layout structure list the type of payload which are used to serialized /
    42 // deserialized / dumped the content of the allocations.
    43 //
    44 // R(ecover)ValueAllocation items:
    45 //   [u8'] Mode, which defines the type of the payload as well as the
    46 //         interpretation.
    47 //   [pld] first payload (packed tag, index, stack offset, register, ...)
    48 //   [pld] second payload (register, stack offset, none)
    49 //
    50 //       Modes:
    51 //         CONSTANT [INDEX]
    52 //           Index into the constant pool.
    53 //
    54 //         CST_UNDEFINED []
    55 //           Constant value which correspond to the "undefined" JS value.
    56 //
    57 //         CST_NULL []
    58 //           Constant value which correspond to the "null" JS value.
    59 //
    60 //         DOUBLE_REG [FPU_REG]
    61 //           Double value stored in a FPU register.
    62 //
    63 //         FLOAT32_REG [FPU_REG]
    64 //           Float 32bit value stored in a FPU register.
    65 //
    66 //         FLOAT32_STACK [STACK_OFFSET]
    67 //           Float 32bit value stored on the stack.
    68 //
    69 //         UNTYPED_REG   [GPR_REG]
    70 //         UNTYPED_STACK [STACK_OFFSET]
    71 //         UNTYPED_REG_REG     [GPR_REG,      GPR_REG]
    72 //         UNTYPED_REG_STACK   [GPR_REG,      STACK_OFFSET]
    73 //         UNTYPED_STACK_REG   [STACK_OFFSET, GPR_REG]
    74 //         UNTYPED_STACK_STACK [STACK_OFFSET, STACK_OFFSET]
    75 //           Value with dynamically known type. On 32 bits architecture, the
    76 //           first register/stack-offset correspond to the holder of the type,
    77 //           and the second correspond to the payload of the JS Value.
    78 //
    79 //         TYPED_REG [PACKED_TAG, GPR_REG]:
    80 //           Value with statically known type, which payload is stored in a
    81 //           register.
    82 //
    83 //         TYPED_STACK [PACKED_TAG, STACK_OFFSET]:
    84 //           Value with statically known type, which payload is stored at an
    85 //           offset on the stack.
    86 //
    87 // Encodings:
    88 //   [ptr] A fixed-size pointer.
    89 //   [vwu] A variable-width unsigned integer.
    90 //   [vws] A variable-width signed integer.
    91 //    [u8] An 8-bit unsigned integer.
    92 //   [u8'] An 8-bit unsigned integer which is potentially extended with packed
    93 //         data.
    94 //   [u8"] Packed data which is stored and packed in the previous [u8'].
    95 //  [vwu*] A list of variable-width unsigned integers.
    96 //   [pld] Payload of Recover Value Allocation:
    97 //         PAYLOAD_NONE:
    98 //           There is no payload.
    99 //
   100 //         PAYLOAD_INDEX:
   101 //           [vwu] Index, such as the constant pool index.
   102 //
   103 //         PAYLOAD_STACK_OFFSET:
   104 //           [vws] Stack offset based on the base of the Ion frame.
   105 //
   106 //         PAYLOAD_GPR:
   107 //            [u8] Code of the general register.
   108 //
   109 //         PAYLOAD_FPU:
   110 //            [u8] Code of the FPU register.
   111 //
   112 //         PAYLOAD_PACKED_TAG:
   113 //           [u8"] Bits 5-7: JSValueType is encoded on the low bits of the Mode
   114 //                           of the RValueAllocation.
   115 //
   117 const RValueAllocation::Layout &
   118 RValueAllocation::layoutFromMode(Mode mode)
   119 {
   120     switch (mode) {
   121       case CONSTANT: {
   122         static const RValueAllocation::Layout layout = {
   123             PAYLOAD_INDEX,
   124             PAYLOAD_NONE,
   125             "constant"
   126         };
   127         return layout;
   128       }
   130       case CST_UNDEFINED: {
   131         static const RValueAllocation::Layout layout = {
   132             PAYLOAD_NONE,
   133             PAYLOAD_NONE,
   134             "undefined"
   135         };
   136         return layout;
   137       }
   139       case CST_NULL: {
   140         static const RValueAllocation::Layout layout = {
   141             PAYLOAD_NONE,
   142             PAYLOAD_NONE,
   143             "null"
   144         };
   145         return layout;
   146       }
   148       case DOUBLE_REG: {
   149         static const RValueAllocation::Layout layout = {
   150             PAYLOAD_FPU,
   151             PAYLOAD_NONE,
   152             "double"
   153         };
   154         return layout;
   155       }
   156       case FLOAT32_REG: {
   157         static const RValueAllocation::Layout layout = {
   158             PAYLOAD_FPU,
   159             PAYLOAD_NONE,
   160             "float32"
   161         };
   162         return layout;
   163       }
   164       case FLOAT32_STACK: {
   165         static const RValueAllocation::Layout layout = {
   166             PAYLOAD_STACK_OFFSET,
   167             PAYLOAD_NONE,
   168             "float32"
   169         };
   170         return layout;
   171       }
   172 #if defined(JS_NUNBOX32)
   173       case UNTYPED_REG_REG: {
   174         static const RValueAllocation::Layout layout = {
   175             PAYLOAD_GPR,
   176             PAYLOAD_GPR,
   177             "value"
   178         };
   179         return layout;
   180       }
   181       case UNTYPED_REG_STACK: {
   182         static const RValueAllocation::Layout layout = {
   183             PAYLOAD_GPR,
   184             PAYLOAD_STACK_OFFSET,
   185             "value"
   186         };
   187         return layout;
   188       }
   189       case UNTYPED_STACK_REG: {
   190         static const RValueAllocation::Layout layout = {
   191             PAYLOAD_STACK_OFFSET,
   192             PAYLOAD_GPR
   193         };
   194         return layout;
   195       }
   196       case UNTYPED_STACK_STACK: {
   197         static const RValueAllocation::Layout layout = {
   198             PAYLOAD_STACK_OFFSET,
   199             PAYLOAD_STACK_OFFSET,
   200             "value"
   201         };
   202         return layout;
   203       }
   204 #elif defined(JS_PUNBOX64)
   205       case UNTYPED_REG: {
   206         static const RValueAllocation::Layout layout = {
   207             PAYLOAD_GPR,
   208             PAYLOAD_NONE,
   209             "value"
   210         };
   211         return layout;
   212       }
   213       case UNTYPED_STACK: {
   214         static const RValueAllocation::Layout layout = {
   215             PAYLOAD_STACK_OFFSET,
   216             PAYLOAD_NONE,
   217             "value"
   218         };
   219         return layout;
   220       }
   221 #endif
   222       default: {
   223         static const RValueAllocation::Layout regLayout = {
   224             PAYLOAD_PACKED_TAG,
   225             PAYLOAD_GPR,
   226             "typed value"
   227         };
   229         static const RValueAllocation::Layout stackLayout = {
   230             PAYLOAD_PACKED_TAG,
   231             PAYLOAD_STACK_OFFSET,
   232             "typed value"
   233         };
   235         if (mode >= TYPED_REG_MIN && mode <= TYPED_REG_MAX)
   236             return regLayout;
   237         if (mode >= TYPED_STACK_MIN && mode <= TYPED_STACK_MAX)
   238             return stackLayout;
   239       }
   240     }
   242     MOZ_ASSUME_UNREACHABLE("Wrong mode type?");
   243 }
   245 // Pad serialized RValueAllocations by a multiple of X bytes in the allocation
   246 // buffer.  By padding serialized value allocations, we are building an
   247 // indexable table of elements of X bytes, and thus we can safely divide any
   248 // offset within the buffer by X to obtain an index.
   249 //
   250 // By padding, we are loosing space within the allocation buffer, but we
   251 // multiple by X the number of indexes that we can store on one byte in each
   252 // snapshots.
   253 //
   254 // Some value allocations are taking more than X bytes to be encoded, in which
   255 // case we will pad to a multiple of X, and we are wasting indexes. The choice
   256 // of X should be balanced between the wasted padding of serialized value
   257 // allocation, and the saving made in snapshot indexes.
   258 static const size_t ALLOCATION_TABLE_ALIGNMENT = 2; /* bytes */
   260 void
   261 RValueAllocation::readPayload(CompactBufferReader &reader, PayloadType type,
   262                               uint8_t *mode, Payload *p)
   263 {
   264     switch (type) {
   265       case PAYLOAD_NONE:
   266         break;
   267       case PAYLOAD_INDEX:
   268         p->index = reader.readUnsigned();
   269         break;
   270       case PAYLOAD_STACK_OFFSET:
   271         p->stackOffset = reader.readSigned();
   272         break;
   273       case PAYLOAD_GPR:
   274         p->gpr = Register::FromCode(reader.readByte());
   275         break;
   276       case PAYLOAD_FPU:
   277         p->fpu = FloatRegister::FromCode(reader.readByte());
   278         break;
   279       case PAYLOAD_PACKED_TAG:
   280         p->type = JSValueType(*mode & 0x07);
   281         *mode = *mode & ~0x07;
   282         break;
   283     }
   284 }
   286 RValueAllocation
   287 RValueAllocation::read(CompactBufferReader &reader)
   288 {
   289     uint8_t mode = reader.readByte();
   290     const Layout &layout = layoutFromMode(Mode(mode));
   291     Payload arg1, arg2;
   293     readPayload(reader, layout.type1, &mode, &arg1);
   294     readPayload(reader, layout.type2, &mode, &arg2);
   295     return RValueAllocation(Mode(mode), arg1, arg2);
   296 }
   298 void
   299 RValueAllocation::writePayload(CompactBufferWriter &writer, PayloadType type,
   300                                Payload p)
   301 {
   302     switch (type) {
   303       case PAYLOAD_NONE:
   304         break;
   305       case PAYLOAD_INDEX:
   306         writer.writeUnsigned(p.index);
   307         break;
   308       case PAYLOAD_STACK_OFFSET:
   309         writer.writeSigned(p.stackOffset);
   310         break;
   311       case PAYLOAD_GPR:
   312         static_assert(Registers::Total <= 0x100,
   313                       "Not enough bytes to encode all registers.");
   314         writer.writeByte(p.gpr.code());
   315         break;
   316       case PAYLOAD_FPU:
   317         static_assert(FloatRegisters::Total <= 0x100,
   318                       "Not enough bytes to encode all float registers.");
   319         writer.writeByte(p.fpu.code());
   320         break;
   321       case PAYLOAD_PACKED_TAG: {
   322         // This code assumes that the PACKED_TAG payload is following the
   323         // writeByte of the mode.
   324         MOZ_ASSERT(writer.length());
   325         uint8_t *mode = writer.buffer() + (writer.length() - 1);
   326         MOZ_ASSERT((*mode & 0x07) == 0 && (p.type & ~0x07) == 0);
   327         *mode = *mode | p.type;
   328         break;
   329       }
   330     }
   331 }
   333 void
   334 RValueAllocation::writePadding(CompactBufferWriter &writer)
   335 {
   336     // Write 0x7f in all padding bytes.
   337     while (writer.length() % ALLOCATION_TABLE_ALIGNMENT)
   338         writer.writeByte(0x7f);
   339 }
   341 void
   342 RValueAllocation::write(CompactBufferWriter &writer) const
   343 {
   344     const Layout &layout = layoutFromMode(mode());
   345     MOZ_ASSERT(layout.type2 != PAYLOAD_PACKED_TAG);
   346     MOZ_ASSERT(writer.length() % ALLOCATION_TABLE_ALIGNMENT == 0);
   348     writer.writeByte(mode_);
   349     writePayload(writer, layout.type1, arg1_);
   350     writePayload(writer, layout.type2, arg2_);
   351     writePadding(writer);
   352 }
   354 HashNumber
   355 RValueAllocation::hash() const {
   356     CompactBufferWriter writer;
   357     write(writer);
   359     // We should never oom because the compact buffer writer has 32 inlined
   360     // bytes, and in the worse case scenario, only encode 12 bytes
   361     // (12 == mode + signed + signed + pad).
   362     MOZ_ASSERT(!writer.oom());
   363     MOZ_ASSERT(writer.length() <= 12);
   365     HashNumber res = 0;
   366     for (size_t i = 0; i < writer.length(); i++) {
   367         res = ((res << 8) | (res >> (sizeof(res) - 1)));
   368         res ^= writer.buffer()[i];
   369     }
   370     return res;
   371 }
   373 static const char *
   374 ValTypeToString(JSValueType type)
   375 {
   376     switch (type) {
   377       case JSVAL_TYPE_INT32:
   378         return "int32_t";
   379       case JSVAL_TYPE_DOUBLE:
   380         return "double";
   381       case JSVAL_TYPE_STRING:
   382         return "string";
   383       case JSVAL_TYPE_BOOLEAN:
   384         return "boolean";
   385       case JSVAL_TYPE_OBJECT:
   386         return "object";
   387       case JSVAL_TYPE_MAGIC:
   388         return "magic";
   389       default:
   390         MOZ_ASSUME_UNREACHABLE("no payload");
   391     }
   392 }
   394 void
   395 RValueAllocation::dumpPayload(FILE *fp, PayloadType type, Payload p)
   396 {
   397     switch (type) {
   398       case PAYLOAD_NONE:
   399         break;
   400       case PAYLOAD_INDEX:
   401         fprintf(fp, "index %u", p.index);
   402         break;
   403       case PAYLOAD_STACK_OFFSET:
   404         fprintf(fp, "stack %d", p.stackOffset);
   405         break;
   406       case PAYLOAD_GPR:
   407         fprintf(fp, "reg %s", p.gpr.name());
   408         break;
   409       case PAYLOAD_FPU:
   410         fprintf(fp, "reg %s", p.fpu.name());
   411         break;
   412       case PAYLOAD_PACKED_TAG:
   413         fprintf(fp, "%s", ValTypeToString(p.type));
   414         break;
   415     }
   416 }
   418 void
   419 RValueAllocation::dump(FILE *fp) const
   420 {
   421     const Layout &layout = layoutFromMode(mode());
   422     fprintf(fp, "%s", layout.name);
   424     if (layout.type1 != PAYLOAD_NONE)
   425         fprintf(fp, " (");
   426     dumpPayload(fp, layout.type1, arg1_);
   427     if (layout.type2 != PAYLOAD_NONE)
   428         fprintf(fp, ", ");
   429     dumpPayload(fp, layout.type2, arg2_);
   430     if (layout.type1 != PAYLOAD_NONE)
   431         fprintf(fp, ")");
   432 }
   434 bool
   435 RValueAllocation::equalPayloads(PayloadType type, Payload lhs, Payload rhs)
   436 {
   437     switch (type) {
   438       case PAYLOAD_NONE:
   439         return true;
   440       case PAYLOAD_INDEX:
   441         return lhs.index == rhs.index;
   442       case PAYLOAD_STACK_OFFSET:
   443         return lhs.stackOffset == rhs.stackOffset;
   444       case PAYLOAD_GPR:
   445         return lhs.gpr == rhs.gpr;
   446       case PAYLOAD_FPU:
   447         return lhs.fpu == rhs.fpu;
   448       case PAYLOAD_PACKED_TAG:
   449         return lhs.type == rhs.type;
   450     }
   452     return false;
   453 }
   455 SnapshotReader::SnapshotReader(const uint8_t *snapshots, uint32_t offset,
   456                                uint32_t RVATableSize, uint32_t listSize)
   457   : reader_(snapshots + offset, snapshots + listSize),
   458     allocReader_(snapshots + listSize, snapshots + listSize + RVATableSize),
   459     allocTable_(snapshots + listSize),
   460     allocRead_(0)
   461 {
   462     if (!snapshots)
   463         return;
   464     IonSpew(IonSpew_Snapshots, "Creating snapshot reader");
   465     readSnapshotHeader();
   466 }
   468 #define COMPUTE_SHIFT_AFTER_(name) (name ## _BITS + name ##_SHIFT)
   469 #define COMPUTE_MASK_(name) ((uint32_t(1 << name ## _BITS) - 1) << name ##_SHIFT)
   471 // Details of snapshot header packing.
   472 static const uint32_t SNAPSHOT_BAILOUTKIND_SHIFT = 0;
   473 static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 3;
   474 static const uint32_t SNAPSHOT_BAILOUTKIND_MASK = COMPUTE_MASK_(SNAPSHOT_BAILOUTKIND);
   476 static const uint32_t SNAPSHOT_ROFFSET_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
   477 static const uint32_t SNAPSHOT_ROFFSET_BITS = 32 - SNAPSHOT_ROFFSET_SHIFT;
   478 static const uint32_t SNAPSHOT_ROFFSET_MASK = COMPUTE_MASK_(SNAPSHOT_ROFFSET);
   480 // Details of recover header packing.
   481 static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
   482 static const uint32_t RECOVER_RESUMEAFTER_BITS = 1;
   483 static const uint32_t RECOVER_RESUMEAFTER_MASK = COMPUTE_MASK_(RECOVER_RESUMEAFTER);
   485 static const uint32_t RECOVER_RINSCOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
   486 static const uint32_t RECOVER_RINSCOUNT_BITS = 32 - RECOVER_RINSCOUNT_SHIFT;
   487 static const uint32_t RECOVER_RINSCOUNT_MASK = COMPUTE_MASK_(RECOVER_RINSCOUNT);
   489 #undef COMPUTE_MASK_
   490 #undef COMPUTE_SHIFT_AFTER_
   492 void
   493 SnapshotReader::readSnapshotHeader()
   494 {
   495     uint32_t bits = reader_.readUnsigned();
   497     bailoutKind_ = BailoutKind((bits & SNAPSHOT_BAILOUTKIND_MASK) >> SNAPSHOT_BAILOUTKIND_SHIFT);
   498     recoverOffset_ = (bits & SNAPSHOT_ROFFSET_MASK) >> SNAPSHOT_ROFFSET_SHIFT;
   500     IonSpew(IonSpew_Snapshots, "Read snapshot header with bailout kind %u",
   501             bailoutKind_);
   503 #ifdef TRACK_SNAPSHOTS
   504     readTrackSnapshot();
   505 #endif
   506 }
   508 #ifdef TRACK_SNAPSHOTS
   509 void
   510 SnapshotReader::readTrackSnapshot()
   511 {
   512     pcOpcode_  = reader_.readUnsigned();
   513     mirOpcode_ = reader_.readUnsigned();
   514     mirId_     = reader_.readUnsigned();
   515     lirOpcode_ = reader_.readUnsigned();
   516     lirId_     = reader_.readUnsigned();
   517 }
   519 void
   520 SnapshotReader::spewBailingFrom() const
   521 {
   522     if (IonSpewEnabled(IonSpew_Bailouts)) {
   523         IonSpewHeader(IonSpew_Bailouts);
   524         fprintf(IonSpewFile, " bailing from bytecode: %s, MIR: ", js_CodeName[pcOpcode_]);
   525         MDefinition::PrintOpcodeName(IonSpewFile, MDefinition::Opcode(mirOpcode_));
   526         fprintf(IonSpewFile, " [%u], LIR: ", mirId_);
   527         LInstruction::printName(IonSpewFile, LInstruction::Opcode(lirOpcode_));
   528         fprintf(IonSpewFile, " [%u]", lirId_);
   529         fprintf(IonSpewFile, "\n");
   530     }
   531 }
   532 #endif
   534 uint32_t
   535 SnapshotReader::readAllocationIndex()
   536 {
   537     allocRead_++;
   538     return reader_.readUnsigned();
   539 }
   541 RValueAllocation
   542 SnapshotReader::readAllocation()
   543 {
   544     IonSpew(IonSpew_Snapshots, "Reading slot %u", allocRead_);
   545     uint32_t offset = readAllocationIndex() * ALLOCATION_TABLE_ALIGNMENT;
   546     allocReader_.seek(allocTable_, offset);
   547     return RValueAllocation::read(allocReader_);
   548 }
   550 bool
   551 SnapshotWriter::init()
   552 {
   553     // Based on the measurements made in Bug 962555 comment 20, this should be
   554     // enough to prevent the reallocation of the hash table for at least half of
   555     // the compilations.
   556     return allocMap_.init(32);
   557 }
   559 RecoverReader::RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size)
   560   : reader_(nullptr, nullptr),
   561     numInstructions_(0),
   562     numInstructionsRead_(0)
   563 {
   564     if (!recovers)
   565         return;
   566     reader_ = CompactBufferReader(recovers + snapshot.recoverOffset(), recovers + size);
   567     readRecoverHeader();
   568     readInstruction();
   569 }
   571 void
   572 RecoverReader::readRecoverHeader()
   573 {
   574     uint32_t bits = reader_.readUnsigned();
   576     numInstructions_ = (bits & RECOVER_RINSCOUNT_MASK) >> RECOVER_RINSCOUNT_SHIFT;
   577     resumeAfter_ = (bits & RECOVER_RESUMEAFTER_MASK) >> RECOVER_RESUMEAFTER_SHIFT;
   578     MOZ_ASSERT(numInstructions_);
   580     IonSpew(IonSpew_Snapshots, "Read recover header with instructionCount %u (ra: %d)",
   581             numInstructions_, resumeAfter_);
   582 }
   584 void
   585 RecoverReader::readInstruction()
   586 {
   587     MOZ_ASSERT(moreInstructions());
   588     RInstruction::readRecoverData(reader_, &rawData_);
   589     numInstructionsRead_++;
   590 }
   592 SnapshotOffset
   593 SnapshotWriter::startSnapshot(RecoverOffset recoverOffset, BailoutKind kind)
   594 {
   595     lastStart_ = writer_.length();
   596     allocWritten_ = 0;
   598     IonSpew(IonSpew_Snapshots, "starting snapshot with recover offset %u, bailout kind %u",
   599             recoverOffset, kind);
   601     JS_ASSERT(uint32_t(kind) < (1 << SNAPSHOT_BAILOUTKIND_BITS));
   602     JS_ASSERT(recoverOffset < (1 << SNAPSHOT_ROFFSET_BITS));
   603     uint32_t bits =
   604         (uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
   605         (recoverOffset << SNAPSHOT_ROFFSET_SHIFT);
   607     writer_.writeUnsigned(bits);
   608     return lastStart_;
   609 }
   611 #ifdef TRACK_SNAPSHOTS
   612 void
   613 SnapshotWriter::trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
   614                               uint32_t lirOpcode, uint32_t lirId)
   615 {
   616     writer_.writeUnsigned(pcOpcode);
   617     writer_.writeUnsigned(mirOpcode);
   618     writer_.writeUnsigned(mirId);
   619     writer_.writeUnsigned(lirOpcode);
   620     writer_.writeUnsigned(lirId);
   621 }
   622 #endif
   624 bool
   625 SnapshotWriter::add(const RValueAllocation &alloc)
   626 {
   627     MOZ_ASSERT(allocMap_.initialized());
   629     uint32_t offset;
   630     RValueAllocMap::AddPtr p = allocMap_.lookupForAdd(alloc);
   631     if (!p) {
   632         offset = allocWriter_.length();
   633         alloc.write(allocWriter_);
   634         if (!allocMap_.add(p, alloc, offset))
   635             return false;
   636     } else {
   637         offset = p->value();
   638     }
   640     if (IonSpewEnabled(IonSpew_Snapshots)) {
   641         IonSpewHeader(IonSpew_Snapshots);
   642         fprintf(IonSpewFile, "    slot %u (%d): ", allocWritten_, offset);
   643         alloc.dump(IonSpewFile);
   644         fprintf(IonSpewFile, "\n");
   645     }
   647     allocWritten_++;
   648     writer_.writeUnsigned(offset / ALLOCATION_TABLE_ALIGNMENT);
   649     return true;
   650 }
   652 void
   653 SnapshotWriter::endSnapshot()
   654 {
   655     // Place a sentinel for asserting on the other end.
   656 #ifdef DEBUG
   657     writer_.writeSigned(-1);
   658 #endif
   660     IonSpew(IonSpew_Snapshots, "ending snapshot total size: %u bytes (start %u)",
   661             uint32_t(writer_.length() - lastStart_), lastStart_);
   662 }
   664 RecoverOffset
   665 RecoverWriter::startRecover(uint32_t frameCount, bool resumeAfter)
   666 {
   667     MOZ_ASSERT(frameCount);
   668     nframes_ = frameCount;
   669     framesWritten_ = 0;
   671     IonSpew(IonSpew_Snapshots, "starting recover with frameCount %u",
   672             frameCount);
   674     MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK));
   675     MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_RINSCOUNT_BITS));
   676     uint32_t bits =
   677         (uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
   678         (frameCount << RECOVER_RINSCOUNT_SHIFT);
   680     RecoverOffset recoverOffset = writer_.length();
   681     writer_.writeUnsigned(bits);
   682     return recoverOffset;
   683 }
   685 bool
   686 RecoverWriter::writeFrame(const MResumePoint *rp)
   687 {
   688     if (!rp->writeRecoverData(writer_))
   689         return false;
   690     framesWritten_++;
   691     return true;
   692 }
   694 void
   695 RecoverWriter::endRecover()
   696 {
   697     JS_ASSERT(nframes_ == framesWritten_);
   698 }

mercurial