Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #ifndef jit_Snapshot_h
8 #define jit_Snapshot_h
10 #include "mozilla/Alignment.h"
12 #include "jsalloc.h"
13 #include "jsbytecode.h"
15 #include "jit/CompactBuffer.h"
16 #include "jit/IonTypes.h"
17 #include "jit/Registers.h"
19 #include "js/HashTable.h"
21 namespace js {
22 namespace jit {
24 class RValueAllocation;
26 // A Recover Value Allocation mirror what is known at compiled time as being the
27 // MIRType and the LAllocation. This is read out of the snapshot to recover the
28 // value which would be there if this frame was an interpreter frame instead of
29 // an Ion frame.
30 //
31 // It is used with the SnapshotIterator to recover a Value from the stack,
32 // spilled registers or the list of constant of the compiled script.
33 //
34 // Unit tests are located in jsapi-tests/testJitRValueAlloc.cpp.
35 class RValueAllocation
36 {
37 public:
39 // See RValueAllocation encoding in Snapshots.cpp
40 enum Mode
41 {
42 CONSTANT = 0x00,
43 CST_UNDEFINED = 0x01,
44 CST_NULL = 0x02,
45 DOUBLE_REG = 0x03,
46 FLOAT32_REG = 0x04,
47 FLOAT32_STACK = 0x05,
48 #if defined(JS_NUNBOX32)
49 UNTYPED_REG_REG = 0x06,
50 UNTYPED_REG_STACK = 0x07,
51 UNTYPED_STACK_REG = 0x08,
52 UNTYPED_STACK_STACK = 0x09,
53 #elif defined(JS_PUNBOX64)
54 UNTYPED_REG = 0x06,
55 UNTYPED_STACK = 0x07,
56 #endif
57 // The JSValueType is packed in the Mode.
58 TYPED_REG_MIN = 0x10,
59 TYPED_REG_MAX = 0x17,
60 TYPED_REG = TYPED_REG_MIN,
62 // The JSValueType is packed in the Mode.
63 TYPED_STACK_MIN = 0x18,
64 TYPED_STACK_MAX = 0x1f,
65 TYPED_STACK = TYPED_STACK_MIN,
67 INVALID = 0x100,
68 };
70 // See Payload encoding in Snapshots.cpp
71 enum PayloadType {
72 PAYLOAD_NONE,
73 PAYLOAD_INDEX,
74 PAYLOAD_STACK_OFFSET,
75 PAYLOAD_GPR,
76 PAYLOAD_FPU,
77 PAYLOAD_PACKED_TAG
78 };
80 struct Layout {
81 PayloadType type1;
82 PayloadType type2;
83 const char *name;
84 };
86 private:
87 Mode mode_;
89 // Additional information to recover the content of the allocation.
90 union Payload {
91 uint32_t index;
92 int32_t stackOffset;
93 Register gpr;
94 FloatRegister fpu;
95 JSValueType type;
96 };
98 Payload arg1_;
99 Payload arg2_;
101 static Payload payloadOfIndex(uint32_t index) {
102 Payload p;
103 p.index = index;
104 return p;
105 }
106 static Payload payloadOfStackOffset(int32_t offset) {
107 Payload p;
108 p.stackOffset = offset;
109 return p;
110 }
111 static Payload payloadOfRegister(Register reg) {
112 Payload p;
113 p.gpr = reg;
114 return p;
115 }
116 static Payload payloadOfFloatRegister(FloatRegister reg) {
117 Payload p;
118 p.fpu = reg;
119 return p;
120 }
121 static Payload payloadOfValueType(JSValueType type) {
122 Payload p;
123 p.type = type;
124 return p;
125 }
127 static const Layout &layoutFromMode(Mode mode);
129 static void readPayload(CompactBufferReader &reader, PayloadType t,
130 uint8_t *mode, Payload *p);
131 static void writePayload(CompactBufferWriter &writer, PayloadType t,
132 Payload p);
133 static void writePadding(CompactBufferWriter &writer);
134 static void dumpPayload(FILE *fp, PayloadType t, Payload p);
135 static bool equalPayloads(PayloadType t, Payload lhs, Payload rhs);
137 RValueAllocation(Mode mode, Payload a1, Payload a2)
138 : mode_(mode),
139 arg1_(a1),
140 arg2_(a2)
141 {
142 }
144 RValueAllocation(Mode mode, Payload a1)
145 : mode_(mode),
146 arg1_(a1)
147 {
148 }
150 RValueAllocation(Mode mode)
151 : mode_(mode)
152 {
153 }
155 public:
156 RValueAllocation()
157 : mode_(INVALID)
158 { }
160 // DOUBLE_REG
161 static RValueAllocation Double(const FloatRegister ®) {
162 return RValueAllocation(DOUBLE_REG, payloadOfFloatRegister(reg));
163 }
165 // FLOAT32_REG or FLOAT32_STACK
166 static RValueAllocation Float32(const FloatRegister ®) {
167 return RValueAllocation(FLOAT32_REG, payloadOfFloatRegister(reg));
168 }
169 static RValueAllocation Float32(int32_t offset) {
170 return RValueAllocation(FLOAT32_STACK, payloadOfStackOffset(offset));
171 }
173 // TYPED_REG or TYPED_STACK
174 static RValueAllocation Typed(JSValueType type, const Register ®) {
175 JS_ASSERT(type != JSVAL_TYPE_DOUBLE &&
176 type != JSVAL_TYPE_MAGIC &&
177 type != JSVAL_TYPE_NULL &&
178 type != JSVAL_TYPE_UNDEFINED);
179 return RValueAllocation(TYPED_REG, payloadOfValueType(type),
180 payloadOfRegister(reg));
181 }
182 static RValueAllocation Typed(JSValueType type, int32_t offset) {
183 JS_ASSERT(type != JSVAL_TYPE_MAGIC &&
184 type != JSVAL_TYPE_NULL &&
185 type != JSVAL_TYPE_UNDEFINED);
186 return RValueAllocation(TYPED_STACK, payloadOfValueType(type),
187 payloadOfStackOffset(offset));
188 }
190 // UNTYPED
191 #if defined(JS_NUNBOX32)
192 static RValueAllocation Untyped(const Register &type, const Register &payload) {
193 return RValueAllocation(UNTYPED_REG_REG,
194 payloadOfRegister(type),
195 payloadOfRegister(payload));
196 }
198 static RValueAllocation Untyped(const Register &type, int32_t payloadStackOffset) {
199 return RValueAllocation(UNTYPED_REG_STACK,
200 payloadOfRegister(type),
201 payloadOfStackOffset(payloadStackOffset));
202 }
204 static RValueAllocation Untyped(int32_t typeStackOffset, const Register &payload) {
205 return RValueAllocation(UNTYPED_STACK_REG,
206 payloadOfStackOffset(typeStackOffset),
207 payloadOfRegister(payload));
208 }
210 static RValueAllocation Untyped(int32_t typeStackOffset, int32_t payloadStackOffset) {
211 return RValueAllocation(UNTYPED_STACK_STACK,
212 payloadOfStackOffset(typeStackOffset),
213 payloadOfStackOffset(payloadStackOffset));
214 }
216 #elif defined(JS_PUNBOX64)
217 static RValueAllocation Untyped(const Register ®) {
218 return RValueAllocation(UNTYPED_REG, payloadOfRegister(reg));
219 }
221 static RValueAllocation Untyped(int32_t stackOffset) {
222 return RValueAllocation(UNTYPED_STACK, payloadOfStackOffset(stackOffset));
223 }
224 #endif
226 // common constants.
227 static RValueAllocation Undefined() {
228 return RValueAllocation(CST_UNDEFINED);
229 }
230 static RValueAllocation Null() {
231 return RValueAllocation(CST_NULL);
232 }
234 // CONSTANT's index
235 static RValueAllocation ConstantPool(uint32_t index) {
236 return RValueAllocation(CONSTANT, payloadOfIndex(index));
237 }
239 void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
240 public:
241 static RValueAllocation read(CompactBufferReader &reader);
242 void write(CompactBufferWriter &writer) const;
244 public:
245 Mode mode() const {
246 return mode_;
247 }
249 uint32_t index() const {
250 JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_INDEX);
251 return arg1_.index;
252 }
253 int32_t stackOffset() const {
254 JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_STACK_OFFSET);
255 return arg1_.stackOffset;
256 }
257 Register reg() const {
258 JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_GPR);
259 return arg1_.gpr;
260 }
261 FloatRegister fpuReg() const {
262 JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_FPU);
263 return arg1_.fpu;
264 }
265 JSValueType knownType() const {
266 JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_PACKED_TAG);
267 return arg1_.type;
268 }
270 int32_t stackOffset2() const {
271 JS_ASSERT(layoutFromMode(mode()).type2 == PAYLOAD_STACK_OFFSET);
272 return arg2_.stackOffset;
273 }
274 Register reg2() const {
275 JS_ASSERT(layoutFromMode(mode()).type2 == PAYLOAD_GPR);
276 return arg2_.gpr;
277 }
279 public:
280 void dump(FILE *fp) const;
282 public:
283 bool operator==(const RValueAllocation &rhs) const {
284 if (mode_ != rhs.mode_)
285 return false;
287 const Layout &layout = layoutFromMode(mode());
288 return equalPayloads(layout.type1, arg1_, rhs.arg1_) &&
289 equalPayloads(layout.type2, arg2_, rhs.arg2_);
290 }
292 HashNumber hash() const;
294 struct Hasher
295 {
296 typedef RValueAllocation Key;
297 typedef Key Lookup;
298 static HashNumber hash(const Lookup &v) {
299 return v.hash();
300 }
301 static bool match(const Key &k, const Lookup &l) {
302 return k == l;
303 }
304 };
305 };
307 class RecoverWriter;
309 // Collects snapshots in a contiguous buffer, which is copied into IonScript
310 // memory after code generation.
311 class SnapshotWriter
312 {
313 CompactBufferWriter writer_;
314 CompactBufferWriter allocWriter_;
316 // Map RValueAllocations to an offset in the allocWriter_ buffer. This is
317 // useful as value allocations are repeated frequently.
318 typedef RValueAllocation RVA;
319 typedef HashMap<RVA, uint32_t, RVA::Hasher, SystemAllocPolicy> RValueAllocMap;
320 RValueAllocMap allocMap_;
322 // This is only used to assert sanity.
323 uint32_t allocWritten_;
325 // Used to report size of the snapshot in the spew messages.
326 SnapshotOffset lastStart_;
328 public:
329 bool init();
331 SnapshotOffset startSnapshot(RecoverOffset recoverOffset, BailoutKind kind);
332 #ifdef TRACK_SNAPSHOTS
333 void trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
334 uint32_t lirOpcode, uint32_t lirId);
335 #endif
336 bool add(const RValueAllocation &slot);
338 uint32_t allocWritten() const {
339 return allocWritten_;
340 }
341 void endSnapshot();
343 bool oom() const {
344 return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE ||
345 allocWriter_.oom() || allocWriter_.length() >= MAX_BUFFER_SIZE;
346 }
348 size_t listSize() const {
349 return writer_.length();
350 }
351 const uint8_t *listBuffer() const {
352 return writer_.buffer();
353 }
355 size_t RVATableSize() const {
356 return allocWriter_.length();
357 }
358 const uint8_t *RVATableBuffer() const {
359 return allocWriter_.buffer();
360 }
361 };
363 class MResumePoint;
365 class RecoverWriter
366 {
367 CompactBufferWriter writer_;
369 uint32_t nframes_;
370 uint32_t framesWritten_;
372 public:
373 SnapshotOffset startRecover(uint32_t frameCount, bool resumeAfter);
375 bool writeFrame(const MResumePoint *rp);
377 void endRecover();
379 size_t size() const {
380 return writer_.length();
381 }
382 const uint8_t *buffer() const {
383 return writer_.buffer();
384 }
386 bool oom() const {
387 return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
388 }
389 };
391 class RecoverReader;
393 // A snapshot reader reads the entries out of the compressed snapshot buffer in
394 // a script. These entries describe the equivalent interpreter frames at a given
395 // position in JIT code. Each entry is an Ion's value allocations, used to
396 // recover the corresponding Value from an Ion frame.
397 class SnapshotReader
398 {
399 CompactBufferReader reader_;
400 CompactBufferReader allocReader_;
401 const uint8_t* allocTable_;
403 BailoutKind bailoutKind_;
404 uint32_t allocRead_; // Number of slots that have been read.
405 RecoverOffset recoverOffset_; // Offset of the recover instructions.
407 #ifdef TRACK_SNAPSHOTS
408 private:
409 uint32_t pcOpcode_;
410 uint32_t mirOpcode_;
411 uint32_t mirId_;
412 uint32_t lirOpcode_;
413 uint32_t lirId_;
415 public:
416 void readTrackSnapshot();
417 void spewBailingFrom() const;
418 #endif
420 private:
421 void readSnapshotHeader();
422 uint32_t readAllocationIndex();
424 public:
425 SnapshotReader(const uint8_t *snapshots, uint32_t offset,
426 uint32_t RVATableSize, uint32_t listSize);
428 RValueAllocation readAllocation();
429 void skipAllocation() {
430 readAllocationIndex();
431 }
433 BailoutKind bailoutKind() const {
434 return bailoutKind_;
435 }
436 RecoverOffset recoverOffset() const {
437 return recoverOffset_;
438 }
440 uint32_t numAllocationsRead() const {
441 return allocRead_;
442 }
443 void resetNumAllocationsRead() {
444 allocRead_ = 0;
445 }
446 };
448 typedef mozilla::AlignedStorage<4 * sizeof(uint32_t)> RInstructionStorage;
449 class RInstruction;
451 class RecoverReader
452 {
453 CompactBufferReader reader_;
455 // Number of encoded instructions.
456 uint32_t numInstructions_;
458 // Number of instruction read.
459 uint32_t numInstructionsRead_;
461 // True if we need to resume after the Resume Point instruction of the
462 // innermost frame.
463 bool resumeAfter_;
465 // Space is reserved as part of the RecoverReader to avoid allocations of
466 // data which is needed to decode the current instruction.
467 RInstructionStorage rawData_;
469 private:
470 void readRecoverHeader();
471 void readInstruction();
473 public:
474 RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size);
476 bool moreInstructions() const {
477 return numInstructionsRead_ < numInstructions_;
478 }
479 void nextInstruction() {
480 readInstruction();
481 }
483 const RInstruction *instruction() const {
484 return reinterpret_cast<const RInstruction *>(rawData_.addr());
485 }
487 bool resumeAfter() const {
488 return resumeAfter_;
489 }
490 };
492 }
493 }
495 #endif /* jit_Snapshot_h */