LCOV - code coverage report
Current view: top level - js/src/jit - Snapshots.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 167 266 62.8 %
Date: 2017-07-14 16:53:18 Functions: 21 30 70.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13