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