1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/Snapshots.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,495 @@ 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 +#ifndef jit_Snapshot_h 1.11 +#define jit_Snapshot_h 1.12 + 1.13 +#include "mozilla/Alignment.h" 1.14 + 1.15 +#include "jsalloc.h" 1.16 +#include "jsbytecode.h" 1.17 + 1.18 +#include "jit/CompactBuffer.h" 1.19 +#include "jit/IonTypes.h" 1.20 +#include "jit/Registers.h" 1.21 + 1.22 +#include "js/HashTable.h" 1.23 + 1.24 +namespace js { 1.25 +namespace jit { 1.26 + 1.27 +class RValueAllocation; 1.28 + 1.29 +// A Recover Value Allocation mirror what is known at compiled time as being the 1.30 +// MIRType and the LAllocation. This is read out of the snapshot to recover the 1.31 +// value which would be there if this frame was an interpreter frame instead of 1.32 +// an Ion frame. 1.33 +// 1.34 +// It is used with the SnapshotIterator to recover a Value from the stack, 1.35 +// spilled registers or the list of constant of the compiled script. 1.36 +// 1.37 +// Unit tests are located in jsapi-tests/testJitRValueAlloc.cpp. 1.38 +class RValueAllocation 1.39 +{ 1.40 + public: 1.41 + 1.42 + // See RValueAllocation encoding in Snapshots.cpp 1.43 + enum Mode 1.44 + { 1.45 + CONSTANT = 0x00, 1.46 + CST_UNDEFINED = 0x01, 1.47 + CST_NULL = 0x02, 1.48 + DOUBLE_REG = 0x03, 1.49 + FLOAT32_REG = 0x04, 1.50 + FLOAT32_STACK = 0x05, 1.51 +#if defined(JS_NUNBOX32) 1.52 + UNTYPED_REG_REG = 0x06, 1.53 + UNTYPED_REG_STACK = 0x07, 1.54 + UNTYPED_STACK_REG = 0x08, 1.55 + UNTYPED_STACK_STACK = 0x09, 1.56 +#elif defined(JS_PUNBOX64) 1.57 + UNTYPED_REG = 0x06, 1.58 + UNTYPED_STACK = 0x07, 1.59 +#endif 1.60 + // The JSValueType is packed in the Mode. 1.61 + TYPED_REG_MIN = 0x10, 1.62 + TYPED_REG_MAX = 0x17, 1.63 + TYPED_REG = TYPED_REG_MIN, 1.64 + 1.65 + // The JSValueType is packed in the Mode. 1.66 + TYPED_STACK_MIN = 0x18, 1.67 + TYPED_STACK_MAX = 0x1f, 1.68 + TYPED_STACK = TYPED_STACK_MIN, 1.69 + 1.70 + INVALID = 0x100, 1.71 + }; 1.72 + 1.73 + // See Payload encoding in Snapshots.cpp 1.74 + enum PayloadType { 1.75 + PAYLOAD_NONE, 1.76 + PAYLOAD_INDEX, 1.77 + PAYLOAD_STACK_OFFSET, 1.78 + PAYLOAD_GPR, 1.79 + PAYLOAD_FPU, 1.80 + PAYLOAD_PACKED_TAG 1.81 + }; 1.82 + 1.83 + struct Layout { 1.84 + PayloadType type1; 1.85 + PayloadType type2; 1.86 + const char *name; 1.87 + }; 1.88 + 1.89 + private: 1.90 + Mode mode_; 1.91 + 1.92 + // Additional information to recover the content of the allocation. 1.93 + union Payload { 1.94 + uint32_t index; 1.95 + int32_t stackOffset; 1.96 + Register gpr; 1.97 + FloatRegister fpu; 1.98 + JSValueType type; 1.99 + }; 1.100 + 1.101 + Payload arg1_; 1.102 + Payload arg2_; 1.103 + 1.104 + static Payload payloadOfIndex(uint32_t index) { 1.105 + Payload p; 1.106 + p.index = index; 1.107 + return p; 1.108 + } 1.109 + static Payload payloadOfStackOffset(int32_t offset) { 1.110 + Payload p; 1.111 + p.stackOffset = offset; 1.112 + return p; 1.113 + } 1.114 + static Payload payloadOfRegister(Register reg) { 1.115 + Payload p; 1.116 + p.gpr = reg; 1.117 + return p; 1.118 + } 1.119 + static Payload payloadOfFloatRegister(FloatRegister reg) { 1.120 + Payload p; 1.121 + p.fpu = reg; 1.122 + return p; 1.123 + } 1.124 + static Payload payloadOfValueType(JSValueType type) { 1.125 + Payload p; 1.126 + p.type = type; 1.127 + return p; 1.128 + } 1.129 + 1.130 + static const Layout &layoutFromMode(Mode mode); 1.131 + 1.132 + static void readPayload(CompactBufferReader &reader, PayloadType t, 1.133 + uint8_t *mode, Payload *p); 1.134 + static void writePayload(CompactBufferWriter &writer, PayloadType t, 1.135 + Payload p); 1.136 + static void writePadding(CompactBufferWriter &writer); 1.137 + static void dumpPayload(FILE *fp, PayloadType t, Payload p); 1.138 + static bool equalPayloads(PayloadType t, Payload lhs, Payload rhs); 1.139 + 1.140 + RValueAllocation(Mode mode, Payload a1, Payload a2) 1.141 + : mode_(mode), 1.142 + arg1_(a1), 1.143 + arg2_(a2) 1.144 + { 1.145 + } 1.146 + 1.147 + RValueAllocation(Mode mode, Payload a1) 1.148 + : mode_(mode), 1.149 + arg1_(a1) 1.150 + { 1.151 + } 1.152 + 1.153 + RValueAllocation(Mode mode) 1.154 + : mode_(mode) 1.155 + { 1.156 + } 1.157 + 1.158 + public: 1.159 + RValueAllocation() 1.160 + : mode_(INVALID) 1.161 + { } 1.162 + 1.163 + // DOUBLE_REG 1.164 + static RValueAllocation Double(const FloatRegister ®) { 1.165 + return RValueAllocation(DOUBLE_REG, payloadOfFloatRegister(reg)); 1.166 + } 1.167 + 1.168 + // FLOAT32_REG or FLOAT32_STACK 1.169 + static RValueAllocation Float32(const FloatRegister ®) { 1.170 + return RValueAllocation(FLOAT32_REG, payloadOfFloatRegister(reg)); 1.171 + } 1.172 + static RValueAllocation Float32(int32_t offset) { 1.173 + return RValueAllocation(FLOAT32_STACK, payloadOfStackOffset(offset)); 1.174 + } 1.175 + 1.176 + // TYPED_REG or TYPED_STACK 1.177 + static RValueAllocation Typed(JSValueType type, const Register ®) { 1.178 + JS_ASSERT(type != JSVAL_TYPE_DOUBLE && 1.179 + type != JSVAL_TYPE_MAGIC && 1.180 + type != JSVAL_TYPE_NULL && 1.181 + type != JSVAL_TYPE_UNDEFINED); 1.182 + return RValueAllocation(TYPED_REG, payloadOfValueType(type), 1.183 + payloadOfRegister(reg)); 1.184 + } 1.185 + static RValueAllocation Typed(JSValueType type, int32_t offset) { 1.186 + JS_ASSERT(type != JSVAL_TYPE_MAGIC && 1.187 + type != JSVAL_TYPE_NULL && 1.188 + type != JSVAL_TYPE_UNDEFINED); 1.189 + return RValueAllocation(TYPED_STACK, payloadOfValueType(type), 1.190 + payloadOfStackOffset(offset)); 1.191 + } 1.192 + 1.193 + // UNTYPED 1.194 +#if defined(JS_NUNBOX32) 1.195 + static RValueAllocation Untyped(const Register &type, const Register &payload) { 1.196 + return RValueAllocation(UNTYPED_REG_REG, 1.197 + payloadOfRegister(type), 1.198 + payloadOfRegister(payload)); 1.199 + } 1.200 + 1.201 + static RValueAllocation Untyped(const Register &type, int32_t payloadStackOffset) { 1.202 + return RValueAllocation(UNTYPED_REG_STACK, 1.203 + payloadOfRegister(type), 1.204 + payloadOfStackOffset(payloadStackOffset)); 1.205 + } 1.206 + 1.207 + static RValueAllocation Untyped(int32_t typeStackOffset, const Register &payload) { 1.208 + return RValueAllocation(UNTYPED_STACK_REG, 1.209 + payloadOfStackOffset(typeStackOffset), 1.210 + payloadOfRegister(payload)); 1.211 + } 1.212 + 1.213 + static RValueAllocation Untyped(int32_t typeStackOffset, int32_t payloadStackOffset) { 1.214 + return RValueAllocation(UNTYPED_STACK_STACK, 1.215 + payloadOfStackOffset(typeStackOffset), 1.216 + payloadOfStackOffset(payloadStackOffset)); 1.217 + } 1.218 + 1.219 +#elif defined(JS_PUNBOX64) 1.220 + static RValueAllocation Untyped(const Register ®) { 1.221 + return RValueAllocation(UNTYPED_REG, payloadOfRegister(reg)); 1.222 + } 1.223 + 1.224 + static RValueAllocation Untyped(int32_t stackOffset) { 1.225 + return RValueAllocation(UNTYPED_STACK, payloadOfStackOffset(stackOffset)); 1.226 + } 1.227 +#endif 1.228 + 1.229 + // common constants. 1.230 + static RValueAllocation Undefined() { 1.231 + return RValueAllocation(CST_UNDEFINED); 1.232 + } 1.233 + static RValueAllocation Null() { 1.234 + return RValueAllocation(CST_NULL); 1.235 + } 1.236 + 1.237 + // CONSTANT's index 1.238 + static RValueAllocation ConstantPool(uint32_t index) { 1.239 + return RValueAllocation(CONSTANT, payloadOfIndex(index)); 1.240 + } 1.241 + 1.242 + void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const; 1.243 + public: 1.244 + static RValueAllocation read(CompactBufferReader &reader); 1.245 + void write(CompactBufferWriter &writer) const; 1.246 + 1.247 + public: 1.248 + Mode mode() const { 1.249 + return mode_; 1.250 + } 1.251 + 1.252 + uint32_t index() const { 1.253 + JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_INDEX); 1.254 + return arg1_.index; 1.255 + } 1.256 + int32_t stackOffset() const { 1.257 + JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_STACK_OFFSET); 1.258 + return arg1_.stackOffset; 1.259 + } 1.260 + Register reg() const { 1.261 + JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_GPR); 1.262 + return arg1_.gpr; 1.263 + } 1.264 + FloatRegister fpuReg() const { 1.265 + JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_FPU); 1.266 + return arg1_.fpu; 1.267 + } 1.268 + JSValueType knownType() const { 1.269 + JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_PACKED_TAG); 1.270 + return arg1_.type; 1.271 + } 1.272 + 1.273 + int32_t stackOffset2() const { 1.274 + JS_ASSERT(layoutFromMode(mode()).type2 == PAYLOAD_STACK_OFFSET); 1.275 + return arg2_.stackOffset; 1.276 + } 1.277 + Register reg2() const { 1.278 + JS_ASSERT(layoutFromMode(mode()).type2 == PAYLOAD_GPR); 1.279 + return arg2_.gpr; 1.280 + } 1.281 + 1.282 + public: 1.283 + void dump(FILE *fp) const; 1.284 + 1.285 + public: 1.286 + bool operator==(const RValueAllocation &rhs) const { 1.287 + if (mode_ != rhs.mode_) 1.288 + return false; 1.289 + 1.290 + const Layout &layout = layoutFromMode(mode()); 1.291 + return equalPayloads(layout.type1, arg1_, rhs.arg1_) && 1.292 + equalPayloads(layout.type2, arg2_, rhs.arg2_); 1.293 + } 1.294 + 1.295 + HashNumber hash() const; 1.296 + 1.297 + struct Hasher 1.298 + { 1.299 + typedef RValueAllocation Key; 1.300 + typedef Key Lookup; 1.301 + static HashNumber hash(const Lookup &v) { 1.302 + return v.hash(); 1.303 + } 1.304 + static bool match(const Key &k, const Lookup &l) { 1.305 + return k == l; 1.306 + } 1.307 + }; 1.308 +}; 1.309 + 1.310 +class RecoverWriter; 1.311 + 1.312 +// Collects snapshots in a contiguous buffer, which is copied into IonScript 1.313 +// memory after code generation. 1.314 +class SnapshotWriter 1.315 +{ 1.316 + CompactBufferWriter writer_; 1.317 + CompactBufferWriter allocWriter_; 1.318 + 1.319 + // Map RValueAllocations to an offset in the allocWriter_ buffer. This is 1.320 + // useful as value allocations are repeated frequently. 1.321 + typedef RValueAllocation RVA; 1.322 + typedef HashMap<RVA, uint32_t, RVA::Hasher, SystemAllocPolicy> RValueAllocMap; 1.323 + RValueAllocMap allocMap_; 1.324 + 1.325 + // This is only used to assert sanity. 1.326 + uint32_t allocWritten_; 1.327 + 1.328 + // Used to report size of the snapshot in the spew messages. 1.329 + SnapshotOffset lastStart_; 1.330 + 1.331 + public: 1.332 + bool init(); 1.333 + 1.334 + SnapshotOffset startSnapshot(RecoverOffset recoverOffset, BailoutKind kind); 1.335 +#ifdef TRACK_SNAPSHOTS 1.336 + void trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId, 1.337 + uint32_t lirOpcode, uint32_t lirId); 1.338 +#endif 1.339 + bool add(const RValueAllocation &slot); 1.340 + 1.341 + uint32_t allocWritten() const { 1.342 + return allocWritten_; 1.343 + } 1.344 + void endSnapshot(); 1.345 + 1.346 + bool oom() const { 1.347 + return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE || 1.348 + allocWriter_.oom() || allocWriter_.length() >= MAX_BUFFER_SIZE; 1.349 + } 1.350 + 1.351 + size_t listSize() const { 1.352 + return writer_.length(); 1.353 + } 1.354 + const uint8_t *listBuffer() const { 1.355 + return writer_.buffer(); 1.356 + } 1.357 + 1.358 + size_t RVATableSize() const { 1.359 + return allocWriter_.length(); 1.360 + } 1.361 + const uint8_t *RVATableBuffer() const { 1.362 + return allocWriter_.buffer(); 1.363 + } 1.364 +}; 1.365 + 1.366 +class MResumePoint; 1.367 + 1.368 +class RecoverWriter 1.369 +{ 1.370 + CompactBufferWriter writer_; 1.371 + 1.372 + uint32_t nframes_; 1.373 + uint32_t framesWritten_; 1.374 + 1.375 + public: 1.376 + SnapshotOffset startRecover(uint32_t frameCount, bool resumeAfter); 1.377 + 1.378 + bool writeFrame(const MResumePoint *rp); 1.379 + 1.380 + void endRecover(); 1.381 + 1.382 + size_t size() const { 1.383 + return writer_.length(); 1.384 + } 1.385 + const uint8_t *buffer() const { 1.386 + return writer_.buffer(); 1.387 + } 1.388 + 1.389 + bool oom() const { 1.390 + return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE; 1.391 + } 1.392 +}; 1.393 + 1.394 +class RecoverReader; 1.395 + 1.396 +// A snapshot reader reads the entries out of the compressed snapshot buffer in 1.397 +// a script. These entries describe the equivalent interpreter frames at a given 1.398 +// position in JIT code. Each entry is an Ion's value allocations, used to 1.399 +// recover the corresponding Value from an Ion frame. 1.400 +class SnapshotReader 1.401 +{ 1.402 + CompactBufferReader reader_; 1.403 + CompactBufferReader allocReader_; 1.404 + const uint8_t* allocTable_; 1.405 + 1.406 + BailoutKind bailoutKind_; 1.407 + uint32_t allocRead_; // Number of slots that have been read. 1.408 + RecoverOffset recoverOffset_; // Offset of the recover instructions. 1.409 + 1.410 +#ifdef TRACK_SNAPSHOTS 1.411 + private: 1.412 + uint32_t pcOpcode_; 1.413 + uint32_t mirOpcode_; 1.414 + uint32_t mirId_; 1.415 + uint32_t lirOpcode_; 1.416 + uint32_t lirId_; 1.417 + 1.418 + public: 1.419 + void readTrackSnapshot(); 1.420 + void spewBailingFrom() const; 1.421 +#endif 1.422 + 1.423 + private: 1.424 + void readSnapshotHeader(); 1.425 + uint32_t readAllocationIndex(); 1.426 + 1.427 + public: 1.428 + SnapshotReader(const uint8_t *snapshots, uint32_t offset, 1.429 + uint32_t RVATableSize, uint32_t listSize); 1.430 + 1.431 + RValueAllocation readAllocation(); 1.432 + void skipAllocation() { 1.433 + readAllocationIndex(); 1.434 + } 1.435 + 1.436 + BailoutKind bailoutKind() const { 1.437 + return bailoutKind_; 1.438 + } 1.439 + RecoverOffset recoverOffset() const { 1.440 + return recoverOffset_; 1.441 + } 1.442 + 1.443 + uint32_t numAllocationsRead() const { 1.444 + return allocRead_; 1.445 + } 1.446 + void resetNumAllocationsRead() { 1.447 + allocRead_ = 0; 1.448 + } 1.449 +}; 1.450 + 1.451 +typedef mozilla::AlignedStorage<4 * sizeof(uint32_t)> RInstructionStorage; 1.452 +class RInstruction; 1.453 + 1.454 +class RecoverReader 1.455 +{ 1.456 + CompactBufferReader reader_; 1.457 + 1.458 + // Number of encoded instructions. 1.459 + uint32_t numInstructions_; 1.460 + 1.461 + // Number of instruction read. 1.462 + uint32_t numInstructionsRead_; 1.463 + 1.464 + // True if we need to resume after the Resume Point instruction of the 1.465 + // innermost frame. 1.466 + bool resumeAfter_; 1.467 + 1.468 + // Space is reserved as part of the RecoverReader to avoid allocations of 1.469 + // data which is needed to decode the current instruction. 1.470 + RInstructionStorage rawData_; 1.471 + 1.472 + private: 1.473 + void readRecoverHeader(); 1.474 + void readInstruction(); 1.475 + 1.476 + public: 1.477 + RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size); 1.478 + 1.479 + bool moreInstructions() const { 1.480 + return numInstructionsRead_ < numInstructions_; 1.481 + } 1.482 + void nextInstruction() { 1.483 + readInstruction(); 1.484 + } 1.485 + 1.486 + const RInstruction *instruction() const { 1.487 + return reinterpret_cast<const RInstruction *>(rawData_.addr()); 1.488 + } 1.489 + 1.490 + bool resumeAfter() const { 1.491 + return resumeAfter_; 1.492 + } 1.493 +}; 1.494 + 1.495 +} 1.496 +} 1.497 + 1.498 +#endif /* jit_Snapshot_h */