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 +}