js/src/jit/Snapshots.cpp

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

mercurial