js/src/jit/Snapshots.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/Snapshots.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,698 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jit/Snapshots.h"
    1.11 +
    1.12 +#include "jsscript.h"
    1.13 +
    1.14 +#include "jit/CompileInfo.h"
    1.15 +#include "jit/IonSpewer.h"
    1.16 +#ifdef TRACK_SNAPSHOTS
    1.17 +# include "jit/LIR.h"
    1.18 +#endif
    1.19 +#include "jit/MIR.h"
    1.20 +#include "jit/Recover.h"
    1.21 +
    1.22 +using namespace js;
    1.23 +using namespace js::jit;
    1.24 +
    1.25 +// Snapshot header:
    1.26 +//
    1.27 +//   [vwu] bits ((n+1)-31]: frame count
    1.28 +//         bit n+1: resume after
    1.29 +//         bits [0,n): bailout kind (n = SNAPSHOT_BAILOUTKIND_BITS)
    1.30 +//
    1.31 +// Snapshot body, repeated "frame count" times, from oldest frame to newest frame.
    1.32 +// Note that the first frame doesn't have the "parent PC" field.
    1.33 +//
    1.34 +//   [ptr] Debug only: JSScript *
    1.35 +//   [vwu] pc offset
    1.36 +//   [vwu] # of RVA's indexes, including nargs
    1.37 +//  [vwu*] List of indexes to R(ecover)ValueAllocation table. Contains
    1.38 +//         nargs + nfixed + stackDepth items.
    1.39 +//
    1.40 +// Recover value allocations are encoded at the end of the Snapshot buffer, and
    1.41 +// they are padded on ALLOCATION_TABLE_ALIGNMENT.  The encoding of each
    1.42 +// allocation is determined by the RValueAllocation::Layout, which can be
    1.43 +// obtained from the RValueAllocation::Mode with layoutFromMode function.  The
    1.44 +// layout structure list the type of payload which are used to serialized /
    1.45 +// deserialized / dumped the content of the allocations.
    1.46 +//
    1.47 +// R(ecover)ValueAllocation items:
    1.48 +//   [u8'] Mode, which defines the type of the payload as well as the
    1.49 +//         interpretation.
    1.50 +//   [pld] first payload (packed tag, index, stack offset, register, ...)
    1.51 +//   [pld] second payload (register, stack offset, none)
    1.52 +//
    1.53 +//       Modes:
    1.54 +//         CONSTANT [INDEX]
    1.55 +//           Index into the constant pool.
    1.56 +//
    1.57 +//         CST_UNDEFINED []
    1.58 +//           Constant value which correspond to the "undefined" JS value.
    1.59 +//
    1.60 +//         CST_NULL []
    1.61 +//           Constant value which correspond to the "null" JS value.
    1.62 +//
    1.63 +//         DOUBLE_REG [FPU_REG]
    1.64 +//           Double value stored in a FPU register.
    1.65 +//
    1.66 +//         FLOAT32_REG [FPU_REG]
    1.67 +//           Float 32bit value stored in a FPU register.
    1.68 +//
    1.69 +//         FLOAT32_STACK [STACK_OFFSET]
    1.70 +//           Float 32bit value stored on the stack.
    1.71 +//
    1.72 +//         UNTYPED_REG   [GPR_REG]
    1.73 +//         UNTYPED_STACK [STACK_OFFSET]
    1.74 +//         UNTYPED_REG_REG     [GPR_REG,      GPR_REG]
    1.75 +//         UNTYPED_REG_STACK   [GPR_REG,      STACK_OFFSET]
    1.76 +//         UNTYPED_STACK_REG   [STACK_OFFSET, GPR_REG]
    1.77 +//         UNTYPED_STACK_STACK [STACK_OFFSET, STACK_OFFSET]
    1.78 +//           Value with dynamically known type. On 32 bits architecture, the
    1.79 +//           first register/stack-offset correspond to the holder of the type,
    1.80 +//           and the second correspond to the payload of the JS Value.
    1.81 +//
    1.82 +//         TYPED_REG [PACKED_TAG, GPR_REG]:
    1.83 +//           Value with statically known type, which payload is stored in a
    1.84 +//           register.
    1.85 +//
    1.86 +//         TYPED_STACK [PACKED_TAG, STACK_OFFSET]:
    1.87 +//           Value with statically known type, which payload is stored at an
    1.88 +//           offset on the stack.
    1.89 +//
    1.90 +// Encodings:
    1.91 +//   [ptr] A fixed-size pointer.
    1.92 +//   [vwu] A variable-width unsigned integer.
    1.93 +//   [vws] A variable-width signed integer.
    1.94 +//    [u8] An 8-bit unsigned integer.
    1.95 +//   [u8'] An 8-bit unsigned integer which is potentially extended with packed
    1.96 +//         data.
    1.97 +//   [u8"] Packed data which is stored and packed in the previous [u8'].
    1.98 +//  [vwu*] A list of variable-width unsigned integers.
    1.99 +//   [pld] Payload of Recover Value Allocation:
   1.100 +//         PAYLOAD_NONE:
   1.101 +//           There is no payload.
   1.102 +//
   1.103 +//         PAYLOAD_INDEX:
   1.104 +//           [vwu] Index, such as the constant pool index.
   1.105 +//
   1.106 +//         PAYLOAD_STACK_OFFSET:
   1.107 +//           [vws] Stack offset based on the base of the Ion frame.
   1.108 +//
   1.109 +//         PAYLOAD_GPR:
   1.110 +//            [u8] Code of the general register.
   1.111 +//
   1.112 +//         PAYLOAD_FPU:
   1.113 +//            [u8] Code of the FPU register.
   1.114 +//
   1.115 +//         PAYLOAD_PACKED_TAG:
   1.116 +//           [u8"] Bits 5-7: JSValueType is encoded on the low bits of the Mode
   1.117 +//                           of the RValueAllocation.
   1.118 +//
   1.119 +
   1.120 +const RValueAllocation::Layout &
   1.121 +RValueAllocation::layoutFromMode(Mode mode)
   1.122 +{
   1.123 +    switch (mode) {
   1.124 +      case CONSTANT: {
   1.125 +        static const RValueAllocation::Layout layout = {
   1.126 +            PAYLOAD_INDEX,
   1.127 +            PAYLOAD_NONE,
   1.128 +            "constant"
   1.129 +        };
   1.130 +        return layout;
   1.131 +      }
   1.132 +
   1.133 +      case CST_UNDEFINED: {
   1.134 +        static const RValueAllocation::Layout layout = {
   1.135 +            PAYLOAD_NONE,
   1.136 +            PAYLOAD_NONE,
   1.137 +            "undefined"
   1.138 +        };
   1.139 +        return layout;
   1.140 +      }
   1.141 +
   1.142 +      case CST_NULL: {
   1.143 +        static const RValueAllocation::Layout layout = {
   1.144 +            PAYLOAD_NONE,
   1.145 +            PAYLOAD_NONE,
   1.146 +            "null"
   1.147 +        };
   1.148 +        return layout;
   1.149 +      }
   1.150 +
   1.151 +      case DOUBLE_REG: {
   1.152 +        static const RValueAllocation::Layout layout = {
   1.153 +            PAYLOAD_FPU,
   1.154 +            PAYLOAD_NONE,
   1.155 +            "double"
   1.156 +        };
   1.157 +        return layout;
   1.158 +      }
   1.159 +      case FLOAT32_REG: {
   1.160 +        static const RValueAllocation::Layout layout = {
   1.161 +            PAYLOAD_FPU,
   1.162 +            PAYLOAD_NONE,
   1.163 +            "float32"
   1.164 +        };
   1.165 +        return layout;
   1.166 +      }
   1.167 +      case FLOAT32_STACK: {
   1.168 +        static const RValueAllocation::Layout layout = {
   1.169 +            PAYLOAD_STACK_OFFSET,
   1.170 +            PAYLOAD_NONE,
   1.171 +            "float32"
   1.172 +        };
   1.173 +        return layout;
   1.174 +      }
   1.175 +#if defined(JS_NUNBOX32)
   1.176 +      case UNTYPED_REG_REG: {
   1.177 +        static const RValueAllocation::Layout layout = {
   1.178 +            PAYLOAD_GPR,
   1.179 +            PAYLOAD_GPR,
   1.180 +            "value"
   1.181 +        };
   1.182 +        return layout;
   1.183 +      }
   1.184 +      case UNTYPED_REG_STACK: {
   1.185 +        static const RValueAllocation::Layout layout = {
   1.186 +            PAYLOAD_GPR,
   1.187 +            PAYLOAD_STACK_OFFSET,
   1.188 +            "value"
   1.189 +        };
   1.190 +        return layout;
   1.191 +      }
   1.192 +      case UNTYPED_STACK_REG: {
   1.193 +        static const RValueAllocation::Layout layout = {
   1.194 +            PAYLOAD_STACK_OFFSET,
   1.195 +            PAYLOAD_GPR
   1.196 +        };
   1.197 +        return layout;
   1.198 +      }
   1.199 +      case UNTYPED_STACK_STACK: {
   1.200 +        static const RValueAllocation::Layout layout = {
   1.201 +            PAYLOAD_STACK_OFFSET,
   1.202 +            PAYLOAD_STACK_OFFSET,
   1.203 +            "value"
   1.204 +        };
   1.205 +        return layout;
   1.206 +      }
   1.207 +#elif defined(JS_PUNBOX64)
   1.208 +      case UNTYPED_REG: {
   1.209 +        static const RValueAllocation::Layout layout = {
   1.210 +            PAYLOAD_GPR,
   1.211 +            PAYLOAD_NONE,
   1.212 +            "value"
   1.213 +        };
   1.214 +        return layout;
   1.215 +      }
   1.216 +      case UNTYPED_STACK: {
   1.217 +        static const RValueAllocation::Layout layout = {
   1.218 +            PAYLOAD_STACK_OFFSET,
   1.219 +            PAYLOAD_NONE,
   1.220 +            "value"
   1.221 +        };
   1.222 +        return layout;
   1.223 +      }
   1.224 +#endif
   1.225 +      default: {
   1.226 +        static const RValueAllocation::Layout regLayout = {
   1.227 +            PAYLOAD_PACKED_TAG,
   1.228 +            PAYLOAD_GPR,
   1.229 +            "typed value"
   1.230 +        };
   1.231 +
   1.232 +        static const RValueAllocation::Layout stackLayout = {
   1.233 +            PAYLOAD_PACKED_TAG,
   1.234 +            PAYLOAD_STACK_OFFSET,
   1.235 +            "typed value"
   1.236 +        };
   1.237 +
   1.238 +        if (mode >= TYPED_REG_MIN && mode <= TYPED_REG_MAX)
   1.239 +            return regLayout;
   1.240 +        if (mode >= TYPED_STACK_MIN && mode <= TYPED_STACK_MAX)
   1.241 +            return stackLayout;
   1.242 +      }
   1.243 +    }
   1.244 +
   1.245 +    MOZ_ASSUME_UNREACHABLE("Wrong mode type?");
   1.246 +}
   1.247 +
   1.248 +// Pad serialized RValueAllocations by a multiple of X bytes in the allocation
   1.249 +// buffer.  By padding serialized value allocations, we are building an
   1.250 +// indexable table of elements of X bytes, and thus we can safely divide any
   1.251 +// offset within the buffer by X to obtain an index.
   1.252 +//
   1.253 +// By padding, we are loosing space within the allocation buffer, but we
   1.254 +// multiple by X the number of indexes that we can store on one byte in each
   1.255 +// snapshots.
   1.256 +//
   1.257 +// Some value allocations are taking more than X bytes to be encoded, in which
   1.258 +// case we will pad to a multiple of X, and we are wasting indexes. The choice
   1.259 +// of X should be balanced between the wasted padding of serialized value
   1.260 +// allocation, and the saving made in snapshot indexes.
   1.261 +static const size_t ALLOCATION_TABLE_ALIGNMENT = 2; /* bytes */
   1.262 +
   1.263 +void
   1.264 +RValueAllocation::readPayload(CompactBufferReader &reader, PayloadType type,
   1.265 +                              uint8_t *mode, Payload *p)
   1.266 +{
   1.267 +    switch (type) {
   1.268 +      case PAYLOAD_NONE:
   1.269 +        break;
   1.270 +      case PAYLOAD_INDEX:
   1.271 +        p->index = reader.readUnsigned();
   1.272 +        break;
   1.273 +      case PAYLOAD_STACK_OFFSET:
   1.274 +        p->stackOffset = reader.readSigned();
   1.275 +        break;
   1.276 +      case PAYLOAD_GPR:
   1.277 +        p->gpr = Register::FromCode(reader.readByte());
   1.278 +        break;
   1.279 +      case PAYLOAD_FPU:
   1.280 +        p->fpu = FloatRegister::FromCode(reader.readByte());
   1.281 +        break;
   1.282 +      case PAYLOAD_PACKED_TAG:
   1.283 +        p->type = JSValueType(*mode & 0x07);
   1.284 +        *mode = *mode & ~0x07;
   1.285 +        break;
   1.286 +    }
   1.287 +}
   1.288 +
   1.289 +RValueAllocation
   1.290 +RValueAllocation::read(CompactBufferReader &reader)
   1.291 +{
   1.292 +    uint8_t mode = reader.readByte();
   1.293 +    const Layout &layout = layoutFromMode(Mode(mode));
   1.294 +    Payload arg1, arg2;
   1.295 +
   1.296 +    readPayload(reader, layout.type1, &mode, &arg1);
   1.297 +    readPayload(reader, layout.type2, &mode, &arg2);
   1.298 +    return RValueAllocation(Mode(mode), arg1, arg2);
   1.299 +}
   1.300 +
   1.301 +void
   1.302 +RValueAllocation::writePayload(CompactBufferWriter &writer, PayloadType type,
   1.303 +                               Payload p)
   1.304 +{
   1.305 +    switch (type) {
   1.306 +      case PAYLOAD_NONE:
   1.307 +        break;
   1.308 +      case PAYLOAD_INDEX:
   1.309 +        writer.writeUnsigned(p.index);
   1.310 +        break;
   1.311 +      case PAYLOAD_STACK_OFFSET:
   1.312 +        writer.writeSigned(p.stackOffset);
   1.313 +        break;
   1.314 +      case PAYLOAD_GPR:
   1.315 +        static_assert(Registers::Total <= 0x100,
   1.316 +                      "Not enough bytes to encode all registers.");
   1.317 +        writer.writeByte(p.gpr.code());
   1.318 +        break;
   1.319 +      case PAYLOAD_FPU:
   1.320 +        static_assert(FloatRegisters::Total <= 0x100,
   1.321 +                      "Not enough bytes to encode all float registers.");
   1.322 +        writer.writeByte(p.fpu.code());
   1.323 +        break;
   1.324 +      case PAYLOAD_PACKED_TAG: {
   1.325 +        // This code assumes that the PACKED_TAG payload is following the
   1.326 +        // writeByte of the mode.
   1.327 +        MOZ_ASSERT(writer.length());
   1.328 +        uint8_t *mode = writer.buffer() + (writer.length() - 1);
   1.329 +        MOZ_ASSERT((*mode & 0x07) == 0 && (p.type & ~0x07) == 0);
   1.330 +        *mode = *mode | p.type;
   1.331 +        break;
   1.332 +      }
   1.333 +    }
   1.334 +}
   1.335 +
   1.336 +void
   1.337 +RValueAllocation::writePadding(CompactBufferWriter &writer)
   1.338 +{
   1.339 +    // Write 0x7f in all padding bytes.
   1.340 +    while (writer.length() % ALLOCATION_TABLE_ALIGNMENT)
   1.341 +        writer.writeByte(0x7f);
   1.342 +}
   1.343 +
   1.344 +void
   1.345 +RValueAllocation::write(CompactBufferWriter &writer) const
   1.346 +{
   1.347 +    const Layout &layout = layoutFromMode(mode());
   1.348 +    MOZ_ASSERT(layout.type2 != PAYLOAD_PACKED_TAG);
   1.349 +    MOZ_ASSERT(writer.length() % ALLOCATION_TABLE_ALIGNMENT == 0);
   1.350 +
   1.351 +    writer.writeByte(mode_);
   1.352 +    writePayload(writer, layout.type1, arg1_);
   1.353 +    writePayload(writer, layout.type2, arg2_);
   1.354 +    writePadding(writer);
   1.355 +}
   1.356 +
   1.357 +HashNumber
   1.358 +RValueAllocation::hash() const {
   1.359 +    CompactBufferWriter writer;
   1.360 +    write(writer);
   1.361 +
   1.362 +    // We should never oom because the compact buffer writer has 32 inlined
   1.363 +    // bytes, and in the worse case scenario, only encode 12 bytes
   1.364 +    // (12 == mode + signed + signed + pad).
   1.365 +    MOZ_ASSERT(!writer.oom());
   1.366 +    MOZ_ASSERT(writer.length() <= 12);
   1.367 +
   1.368 +    HashNumber res = 0;
   1.369 +    for (size_t i = 0; i < writer.length(); i++) {
   1.370 +        res = ((res << 8) | (res >> (sizeof(res) - 1)));
   1.371 +        res ^= writer.buffer()[i];
   1.372 +    }
   1.373 +    return res;
   1.374 +}
   1.375 +
   1.376 +static const char *
   1.377 +ValTypeToString(JSValueType type)
   1.378 +{
   1.379 +    switch (type) {
   1.380 +      case JSVAL_TYPE_INT32:
   1.381 +        return "int32_t";
   1.382 +      case JSVAL_TYPE_DOUBLE:
   1.383 +        return "double";
   1.384 +      case JSVAL_TYPE_STRING:
   1.385 +        return "string";
   1.386 +      case JSVAL_TYPE_BOOLEAN:
   1.387 +        return "boolean";
   1.388 +      case JSVAL_TYPE_OBJECT:
   1.389 +        return "object";
   1.390 +      case JSVAL_TYPE_MAGIC:
   1.391 +        return "magic";
   1.392 +      default:
   1.393 +        MOZ_ASSUME_UNREACHABLE("no payload");
   1.394 +    }
   1.395 +}
   1.396 +
   1.397 +void
   1.398 +RValueAllocation::dumpPayload(FILE *fp, PayloadType type, Payload p)
   1.399 +{
   1.400 +    switch (type) {
   1.401 +      case PAYLOAD_NONE:
   1.402 +        break;
   1.403 +      case PAYLOAD_INDEX:
   1.404 +        fprintf(fp, "index %u", p.index);
   1.405 +        break;
   1.406 +      case PAYLOAD_STACK_OFFSET:
   1.407 +        fprintf(fp, "stack %d", p.stackOffset);
   1.408 +        break;
   1.409 +      case PAYLOAD_GPR:
   1.410 +        fprintf(fp, "reg %s", p.gpr.name());
   1.411 +        break;
   1.412 +      case PAYLOAD_FPU:
   1.413 +        fprintf(fp, "reg %s", p.fpu.name());
   1.414 +        break;
   1.415 +      case PAYLOAD_PACKED_TAG:
   1.416 +        fprintf(fp, "%s", ValTypeToString(p.type));
   1.417 +        break;
   1.418 +    }
   1.419 +}
   1.420 +
   1.421 +void
   1.422 +RValueAllocation::dump(FILE *fp) const
   1.423 +{
   1.424 +    const Layout &layout = layoutFromMode(mode());
   1.425 +    fprintf(fp, "%s", layout.name);
   1.426 +
   1.427 +    if (layout.type1 != PAYLOAD_NONE)
   1.428 +        fprintf(fp, " (");
   1.429 +    dumpPayload(fp, layout.type1, arg1_);
   1.430 +    if (layout.type2 != PAYLOAD_NONE)
   1.431 +        fprintf(fp, ", ");
   1.432 +    dumpPayload(fp, layout.type2, arg2_);
   1.433 +    if (layout.type1 != PAYLOAD_NONE)
   1.434 +        fprintf(fp, ")");
   1.435 +}
   1.436 +
   1.437 +bool
   1.438 +RValueAllocation::equalPayloads(PayloadType type, Payload lhs, Payload rhs)
   1.439 +{
   1.440 +    switch (type) {
   1.441 +      case PAYLOAD_NONE:
   1.442 +        return true;
   1.443 +      case PAYLOAD_INDEX:
   1.444 +        return lhs.index == rhs.index;
   1.445 +      case PAYLOAD_STACK_OFFSET:
   1.446 +        return lhs.stackOffset == rhs.stackOffset;
   1.447 +      case PAYLOAD_GPR:
   1.448 +        return lhs.gpr == rhs.gpr;
   1.449 +      case PAYLOAD_FPU:
   1.450 +        return lhs.fpu == rhs.fpu;
   1.451 +      case PAYLOAD_PACKED_TAG:
   1.452 +        return lhs.type == rhs.type;
   1.453 +    }
   1.454 +
   1.455 +    return false;
   1.456 +}
   1.457 +
   1.458 +SnapshotReader::SnapshotReader(const uint8_t *snapshots, uint32_t offset,
   1.459 +                               uint32_t RVATableSize, uint32_t listSize)
   1.460 +  : reader_(snapshots + offset, snapshots + listSize),
   1.461 +    allocReader_(snapshots + listSize, snapshots + listSize + RVATableSize),
   1.462 +    allocTable_(snapshots + listSize),
   1.463 +    allocRead_(0)
   1.464 +{
   1.465 +    if (!snapshots)
   1.466 +        return;
   1.467 +    IonSpew(IonSpew_Snapshots, "Creating snapshot reader");
   1.468 +    readSnapshotHeader();
   1.469 +}
   1.470 +
   1.471 +#define COMPUTE_SHIFT_AFTER_(name) (name ## _BITS + name ##_SHIFT)
   1.472 +#define COMPUTE_MASK_(name) ((uint32_t(1 << name ## _BITS) - 1) << name ##_SHIFT)
   1.473 +
   1.474 +// Details of snapshot header packing.
   1.475 +static const uint32_t SNAPSHOT_BAILOUTKIND_SHIFT = 0;
   1.476 +static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 3;
   1.477 +static const uint32_t SNAPSHOT_BAILOUTKIND_MASK = COMPUTE_MASK_(SNAPSHOT_BAILOUTKIND);
   1.478 +
   1.479 +static const uint32_t SNAPSHOT_ROFFSET_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
   1.480 +static const uint32_t SNAPSHOT_ROFFSET_BITS = 32 - SNAPSHOT_ROFFSET_SHIFT;
   1.481 +static const uint32_t SNAPSHOT_ROFFSET_MASK = COMPUTE_MASK_(SNAPSHOT_ROFFSET);
   1.482 +
   1.483 +// Details of recover header packing.
   1.484 +static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
   1.485 +static const uint32_t RECOVER_RESUMEAFTER_BITS = 1;
   1.486 +static const uint32_t RECOVER_RESUMEAFTER_MASK = COMPUTE_MASK_(RECOVER_RESUMEAFTER);
   1.487 +
   1.488 +static const uint32_t RECOVER_RINSCOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
   1.489 +static const uint32_t RECOVER_RINSCOUNT_BITS = 32 - RECOVER_RINSCOUNT_SHIFT;
   1.490 +static const uint32_t RECOVER_RINSCOUNT_MASK = COMPUTE_MASK_(RECOVER_RINSCOUNT);
   1.491 +
   1.492 +#undef COMPUTE_MASK_
   1.493 +#undef COMPUTE_SHIFT_AFTER_
   1.494 +
   1.495 +void
   1.496 +SnapshotReader::readSnapshotHeader()
   1.497 +{
   1.498 +    uint32_t bits = reader_.readUnsigned();
   1.499 +
   1.500 +    bailoutKind_ = BailoutKind((bits & SNAPSHOT_BAILOUTKIND_MASK) >> SNAPSHOT_BAILOUTKIND_SHIFT);
   1.501 +    recoverOffset_ = (bits & SNAPSHOT_ROFFSET_MASK) >> SNAPSHOT_ROFFSET_SHIFT;
   1.502 +
   1.503 +    IonSpew(IonSpew_Snapshots, "Read snapshot header with bailout kind %u",
   1.504 +            bailoutKind_);
   1.505 +
   1.506 +#ifdef TRACK_SNAPSHOTS
   1.507 +    readTrackSnapshot();
   1.508 +#endif
   1.509 +}
   1.510 +
   1.511 +#ifdef TRACK_SNAPSHOTS
   1.512 +void
   1.513 +SnapshotReader::readTrackSnapshot()
   1.514 +{
   1.515 +    pcOpcode_  = reader_.readUnsigned();
   1.516 +    mirOpcode_ = reader_.readUnsigned();
   1.517 +    mirId_     = reader_.readUnsigned();
   1.518 +    lirOpcode_ = reader_.readUnsigned();
   1.519 +    lirId_     = reader_.readUnsigned();
   1.520 +}
   1.521 +
   1.522 +void
   1.523 +SnapshotReader::spewBailingFrom() const
   1.524 +{
   1.525 +    if (IonSpewEnabled(IonSpew_Bailouts)) {
   1.526 +        IonSpewHeader(IonSpew_Bailouts);
   1.527 +        fprintf(IonSpewFile, " bailing from bytecode: %s, MIR: ", js_CodeName[pcOpcode_]);
   1.528 +        MDefinition::PrintOpcodeName(IonSpewFile, MDefinition::Opcode(mirOpcode_));
   1.529 +        fprintf(IonSpewFile, " [%u], LIR: ", mirId_);
   1.530 +        LInstruction::printName(IonSpewFile, LInstruction::Opcode(lirOpcode_));
   1.531 +        fprintf(IonSpewFile, " [%u]", lirId_);
   1.532 +        fprintf(IonSpewFile, "\n");
   1.533 +    }
   1.534 +}
   1.535 +#endif
   1.536 +
   1.537 +uint32_t
   1.538 +SnapshotReader::readAllocationIndex()
   1.539 +{
   1.540 +    allocRead_++;
   1.541 +    return reader_.readUnsigned();
   1.542 +}
   1.543 +
   1.544 +RValueAllocation
   1.545 +SnapshotReader::readAllocation()
   1.546 +{
   1.547 +    IonSpew(IonSpew_Snapshots, "Reading slot %u", allocRead_);
   1.548 +    uint32_t offset = readAllocationIndex() * ALLOCATION_TABLE_ALIGNMENT;
   1.549 +    allocReader_.seek(allocTable_, offset);
   1.550 +    return RValueAllocation::read(allocReader_);
   1.551 +}
   1.552 +
   1.553 +bool
   1.554 +SnapshotWriter::init()
   1.555 +{
   1.556 +    // Based on the measurements made in Bug 962555 comment 20, this should be
   1.557 +    // enough to prevent the reallocation of the hash table for at least half of
   1.558 +    // the compilations.
   1.559 +    return allocMap_.init(32);
   1.560 +}
   1.561 +
   1.562 +RecoverReader::RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size)
   1.563 +  : reader_(nullptr, nullptr),
   1.564 +    numInstructions_(0),
   1.565 +    numInstructionsRead_(0)
   1.566 +{
   1.567 +    if (!recovers)
   1.568 +        return;
   1.569 +    reader_ = CompactBufferReader(recovers + snapshot.recoverOffset(), recovers + size);
   1.570 +    readRecoverHeader();
   1.571 +    readInstruction();
   1.572 +}
   1.573 +
   1.574 +void
   1.575 +RecoverReader::readRecoverHeader()
   1.576 +{
   1.577 +    uint32_t bits = reader_.readUnsigned();
   1.578 +
   1.579 +    numInstructions_ = (bits & RECOVER_RINSCOUNT_MASK) >> RECOVER_RINSCOUNT_SHIFT;
   1.580 +    resumeAfter_ = (bits & RECOVER_RESUMEAFTER_MASK) >> RECOVER_RESUMEAFTER_SHIFT;
   1.581 +    MOZ_ASSERT(numInstructions_);
   1.582 +
   1.583 +    IonSpew(IonSpew_Snapshots, "Read recover header with instructionCount %u (ra: %d)",
   1.584 +            numInstructions_, resumeAfter_);
   1.585 +}
   1.586 +
   1.587 +void
   1.588 +RecoverReader::readInstruction()
   1.589 +{
   1.590 +    MOZ_ASSERT(moreInstructions());
   1.591 +    RInstruction::readRecoverData(reader_, &rawData_);
   1.592 +    numInstructionsRead_++;
   1.593 +}
   1.594 +
   1.595 +SnapshotOffset
   1.596 +SnapshotWriter::startSnapshot(RecoverOffset recoverOffset, BailoutKind kind)
   1.597 +{
   1.598 +    lastStart_ = writer_.length();
   1.599 +    allocWritten_ = 0;
   1.600 +
   1.601 +    IonSpew(IonSpew_Snapshots, "starting snapshot with recover offset %u, bailout kind %u",
   1.602 +            recoverOffset, kind);
   1.603 +
   1.604 +    JS_ASSERT(uint32_t(kind) < (1 << SNAPSHOT_BAILOUTKIND_BITS));
   1.605 +    JS_ASSERT(recoverOffset < (1 << SNAPSHOT_ROFFSET_BITS));
   1.606 +    uint32_t bits =
   1.607 +        (uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
   1.608 +        (recoverOffset << SNAPSHOT_ROFFSET_SHIFT);
   1.609 +
   1.610 +    writer_.writeUnsigned(bits);
   1.611 +    return lastStart_;
   1.612 +}
   1.613 +
   1.614 +#ifdef TRACK_SNAPSHOTS
   1.615 +void
   1.616 +SnapshotWriter::trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
   1.617 +                              uint32_t lirOpcode, uint32_t lirId)
   1.618 +{
   1.619 +    writer_.writeUnsigned(pcOpcode);
   1.620 +    writer_.writeUnsigned(mirOpcode);
   1.621 +    writer_.writeUnsigned(mirId);
   1.622 +    writer_.writeUnsigned(lirOpcode);
   1.623 +    writer_.writeUnsigned(lirId);
   1.624 +}
   1.625 +#endif
   1.626 +
   1.627 +bool
   1.628 +SnapshotWriter::add(const RValueAllocation &alloc)
   1.629 +{
   1.630 +    MOZ_ASSERT(allocMap_.initialized());
   1.631 +
   1.632 +    uint32_t offset;
   1.633 +    RValueAllocMap::AddPtr p = allocMap_.lookupForAdd(alloc);
   1.634 +    if (!p) {
   1.635 +        offset = allocWriter_.length();
   1.636 +        alloc.write(allocWriter_);
   1.637 +        if (!allocMap_.add(p, alloc, offset))
   1.638 +            return false;
   1.639 +    } else {
   1.640 +        offset = p->value();
   1.641 +    }
   1.642 +
   1.643 +    if (IonSpewEnabled(IonSpew_Snapshots)) {
   1.644 +        IonSpewHeader(IonSpew_Snapshots);
   1.645 +        fprintf(IonSpewFile, "    slot %u (%d): ", allocWritten_, offset);
   1.646 +        alloc.dump(IonSpewFile);
   1.647 +        fprintf(IonSpewFile, "\n");
   1.648 +    }
   1.649 +
   1.650 +    allocWritten_++;
   1.651 +    writer_.writeUnsigned(offset / ALLOCATION_TABLE_ALIGNMENT);
   1.652 +    return true;
   1.653 +}
   1.654 +
   1.655 +void
   1.656 +SnapshotWriter::endSnapshot()
   1.657 +{
   1.658 +    // Place a sentinel for asserting on the other end.
   1.659 +#ifdef DEBUG
   1.660 +    writer_.writeSigned(-1);
   1.661 +#endif
   1.662 +
   1.663 +    IonSpew(IonSpew_Snapshots, "ending snapshot total size: %u bytes (start %u)",
   1.664 +            uint32_t(writer_.length() - lastStart_), lastStart_);
   1.665 +}
   1.666 +
   1.667 +RecoverOffset
   1.668 +RecoverWriter::startRecover(uint32_t frameCount, bool resumeAfter)
   1.669 +{
   1.670 +    MOZ_ASSERT(frameCount);
   1.671 +    nframes_ = frameCount;
   1.672 +    framesWritten_ = 0;
   1.673 +
   1.674 +    IonSpew(IonSpew_Snapshots, "starting recover with frameCount %u",
   1.675 +            frameCount);
   1.676 +
   1.677 +    MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK));
   1.678 +    MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_RINSCOUNT_BITS));
   1.679 +    uint32_t bits =
   1.680 +        (uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
   1.681 +        (frameCount << RECOVER_RINSCOUNT_SHIFT);
   1.682 +
   1.683 +    RecoverOffset recoverOffset = writer_.length();
   1.684 +    writer_.writeUnsigned(bits);
   1.685 +    return recoverOffset;
   1.686 +}
   1.687 +
   1.688 +bool
   1.689 +RecoverWriter::writeFrame(const MResumePoint *rp)
   1.690 +{
   1.691 +    if (!rp->writeRecoverData(writer_))
   1.692 +        return false;
   1.693 +    framesWritten_++;
   1.694 +    return true;
   1.695 +}
   1.696 +
   1.697 +void
   1.698 +RecoverWriter::endRecover()
   1.699 +{
   1.700 +    JS_ASSERT(nframes_ == framesWritten_);
   1.701 +}

mercurial