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.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * vim: set ts=8 sts=4 et sw=4 tw=99: |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "jit/Safepoints.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "mozilla/MathAlgorithms.h" |
michael@0 | 10 | |
michael@0 | 11 | #include "jit/BitSet.h" |
michael@0 | 12 | #include "jit/IonSpewer.h" |
michael@0 | 13 | #include "jit/LIR.h" |
michael@0 | 14 | |
michael@0 | 15 | using namespace js; |
michael@0 | 16 | using namespace jit; |
michael@0 | 17 | |
michael@0 | 18 | using mozilla::FloorLog2; |
michael@0 | 19 | |
michael@0 | 20 | bool |
michael@0 | 21 | SafepointWriter::init(TempAllocator &alloc, uint32_t slotCount) |
michael@0 | 22 | { |
michael@0 | 23 | frameSlots_ = BitSet::New(alloc, slotCount / sizeof(intptr_t)); |
michael@0 | 24 | if (!frameSlots_) |
michael@0 | 25 | return false; |
michael@0 | 26 | |
michael@0 | 27 | return true; |
michael@0 | 28 | } |
michael@0 | 29 | |
michael@0 | 30 | uint32_t |
michael@0 | 31 | SafepointWriter::startEntry() |
michael@0 | 32 | { |
michael@0 | 33 | IonSpew(IonSpew_Safepoints, "Encoding safepoint (position %d):", stream_.length()); |
michael@0 | 34 | return uint32_t(stream_.length()); |
michael@0 | 35 | } |
michael@0 | 36 | |
michael@0 | 37 | void |
michael@0 | 38 | SafepointWriter::writeOsiCallPointOffset(uint32_t osiCallPointOffset) |
michael@0 | 39 | { |
michael@0 | 40 | stream_.writeUnsigned(osiCallPointOffset); |
michael@0 | 41 | } |
michael@0 | 42 | |
michael@0 | 43 | static void |
michael@0 | 44 | WriteRegisterMask(CompactBufferWriter &stream, uint32_t bits) |
michael@0 | 45 | { |
michael@0 | 46 | if (sizeof(PackedRegisterMask) == 1) |
michael@0 | 47 | stream.writeByte(bits); |
michael@0 | 48 | else |
michael@0 | 49 | stream.writeUnsigned(bits); |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | static int32_t |
michael@0 | 53 | ReadRegisterMask(CompactBufferReader &stream) |
michael@0 | 54 | { |
michael@0 | 55 | if (sizeof(PackedRegisterMask) == 1) |
michael@0 | 56 | return stream.readByte(); |
michael@0 | 57 | return stream.readUnsigned(); |
michael@0 | 58 | } |
michael@0 | 59 | |
michael@0 | 60 | void |
michael@0 | 61 | SafepointWriter::writeGcRegs(LSafepoint *safepoint) |
michael@0 | 62 | { |
michael@0 | 63 | GeneralRegisterSet gc = safepoint->gcRegs(); |
michael@0 | 64 | GeneralRegisterSet spilledGpr = safepoint->liveRegs().gprs(); |
michael@0 | 65 | FloatRegisterSet spilledFloat = safepoint->liveRegs().fpus(); |
michael@0 | 66 | GeneralRegisterSet slots = safepoint->slotsOrElementsRegs(); |
michael@0 | 67 | GeneralRegisterSet valueRegs; |
michael@0 | 68 | |
michael@0 | 69 | WriteRegisterMask(stream_, spilledGpr.bits()); |
michael@0 | 70 | if (!spilledGpr.empty()) { |
michael@0 | 71 | WriteRegisterMask(stream_, gc.bits()); |
michael@0 | 72 | WriteRegisterMask(stream_, slots.bits()); |
michael@0 | 73 | |
michael@0 | 74 | #ifdef JS_PUNBOX64 |
michael@0 | 75 | valueRegs = safepoint->valueRegs(); |
michael@0 | 76 | WriteRegisterMask(stream_, valueRegs.bits()); |
michael@0 | 77 | #endif |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | // GC registers are a subset of the spilled registers. |
michael@0 | 81 | JS_ASSERT((valueRegs.bits() & ~spilledGpr.bits()) == 0); |
michael@0 | 82 | JS_ASSERT((gc.bits() & ~spilledGpr.bits()) == 0); |
michael@0 | 83 | |
michael@0 | 84 | WriteRegisterMask(stream_, spilledFloat.bits()); |
michael@0 | 85 | |
michael@0 | 86 | #ifdef DEBUG |
michael@0 | 87 | if (IonSpewEnabled(IonSpew_Safepoints)) { |
michael@0 | 88 | for (GeneralRegisterForwardIterator iter(spilledGpr); iter.more(); iter++) { |
michael@0 | 89 | const char *type = gc.has(*iter) |
michael@0 | 90 | ? "gc" |
michael@0 | 91 | : slots.has(*iter) |
michael@0 | 92 | ? "slots" |
michael@0 | 93 | : valueRegs.has(*iter) |
michael@0 | 94 | ? "value" |
michael@0 | 95 | : "any"; |
michael@0 | 96 | IonSpew(IonSpew_Safepoints, " %s reg: %s", type, (*iter).name()); |
michael@0 | 97 | } |
michael@0 | 98 | for (FloatRegisterForwardIterator iter(spilledFloat); iter.more(); iter++) |
michael@0 | 99 | IonSpew(IonSpew_Safepoints, " float reg: %s", (*iter).name()); |
michael@0 | 100 | } |
michael@0 | 101 | #endif |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | static void |
michael@0 | 105 | MapSlotsToBitset(BitSet *set, CompactBufferWriter &stream, uint32_t nslots, uint32_t *slots) |
michael@0 | 106 | { |
michael@0 | 107 | set->clear(); |
michael@0 | 108 | |
michael@0 | 109 | for (uint32_t i = 0; i < nslots; i++) { |
michael@0 | 110 | // Slots are represented at a distance from |fp|. We divide by the |
michael@0 | 111 | // pointer size, since we only care about pointer-sized/aligned slots |
michael@0 | 112 | // here. Since the stack grows down, this means slots start at index 1, |
michael@0 | 113 | // so we subtract 1 to pack the bitset. |
michael@0 | 114 | JS_ASSERT(slots[i] % sizeof(intptr_t) == 0); |
michael@0 | 115 | JS_ASSERT(slots[i] / sizeof(intptr_t) > 0); |
michael@0 | 116 | set->insert(slots[i] / sizeof(intptr_t) - 1); |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | size_t count = set->rawLength(); |
michael@0 | 120 | const uint32_t *words = set->raw(); |
michael@0 | 121 | for (size_t i = 0; i < count; i++) |
michael@0 | 122 | stream.writeUnsigned(words[i]); |
michael@0 | 123 | } |
michael@0 | 124 | |
michael@0 | 125 | void |
michael@0 | 126 | SafepointWriter::writeGcSlots(LSafepoint *safepoint) |
michael@0 | 127 | { |
michael@0 | 128 | LSafepoint::SlotList &slots = safepoint->gcSlots(); |
michael@0 | 129 | |
michael@0 | 130 | #ifdef DEBUG |
michael@0 | 131 | for (uint32_t i = 0; i < slots.length(); i++) |
michael@0 | 132 | IonSpew(IonSpew_Safepoints, " gc slot: %d", slots[i]); |
michael@0 | 133 | #endif |
michael@0 | 134 | |
michael@0 | 135 | MapSlotsToBitset(frameSlots_, |
michael@0 | 136 | stream_, |
michael@0 | 137 | slots.length(), |
michael@0 | 138 | slots.begin()); |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | void |
michael@0 | 142 | SafepointWriter::writeSlotsOrElementsSlots(LSafepoint *safepoint) |
michael@0 | 143 | { |
michael@0 | 144 | LSafepoint::SlotList &slots = safepoint->slotsOrElementsSlots(); |
michael@0 | 145 | |
michael@0 | 146 | stream_.writeUnsigned(slots.length()); |
michael@0 | 147 | |
michael@0 | 148 | for (uint32_t i = 0; i < slots.length(); i++) { |
michael@0 | 149 | #ifdef DEBUG |
michael@0 | 150 | IonSpew(IonSpew_Safepoints, " slots/elements slot: %d", slots[i]); |
michael@0 | 151 | #endif |
michael@0 | 152 | stream_.writeUnsigned(slots[i]); |
michael@0 | 153 | } |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | void |
michael@0 | 157 | SafepointWriter::writeValueSlots(LSafepoint *safepoint) |
michael@0 | 158 | { |
michael@0 | 159 | LSafepoint::SlotList &slots = safepoint->valueSlots(); |
michael@0 | 160 | |
michael@0 | 161 | #ifdef DEBUG |
michael@0 | 162 | for (uint32_t i = 0; i < slots.length(); i++) |
michael@0 | 163 | IonSpew(IonSpew_Safepoints, " gc value: %d", slots[i]); |
michael@0 | 164 | #endif |
michael@0 | 165 | |
michael@0 | 166 | MapSlotsToBitset(frameSlots_, stream_, slots.length(), slots.begin()); |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | #if defined(DEBUG) && defined(JS_NUNBOX32) |
michael@0 | 170 | static void |
michael@0 | 171 | DumpNunboxPart(const LAllocation &a) |
michael@0 | 172 | { |
michael@0 | 173 | if (a.isStackSlot()) { |
michael@0 | 174 | fprintf(IonSpewFile, "stack %d", a.toStackSlot()->slot()); |
michael@0 | 175 | } else if (a.isArgument()) { |
michael@0 | 176 | fprintf(IonSpewFile, "arg %d", a.toArgument()->index()); |
michael@0 | 177 | } else { |
michael@0 | 178 | fprintf(IonSpewFile, "reg %s", a.toGeneralReg()->reg().name()); |
michael@0 | 179 | } |
michael@0 | 180 | } |
michael@0 | 181 | #endif // DEBUG |
michael@0 | 182 | |
michael@0 | 183 | // Nunbox part encoding: |
michael@0 | 184 | // |
michael@0 | 185 | // Reg = 000 |
michael@0 | 186 | // Stack = 001 |
michael@0 | 187 | // Arg = 010 |
michael@0 | 188 | // |
michael@0 | 189 | // [vwu] nentries: |
michael@0 | 190 | // uint16_t: tttp ppXX XXXY YYYY |
michael@0 | 191 | // |
michael@0 | 192 | // If ttt = Reg, type is reg XXXXX |
michael@0 | 193 | // If ppp = Reg, payload is reg YYYYY |
michael@0 | 194 | // |
michael@0 | 195 | // If ttt != Reg, type is: |
michael@0 | 196 | // XXXXX if not 11111, otherwise followed by [vwu] |
michael@0 | 197 | // If ppp != Reg, payload is: |
michael@0 | 198 | // YYYYY if not 11111, otherwise followed by [vwu] |
michael@0 | 199 | // |
michael@0 | 200 | enum NunboxPartKind { |
michael@0 | 201 | Part_Reg, |
michael@0 | 202 | Part_Stack, |
michael@0 | 203 | Part_Arg |
michael@0 | 204 | }; |
michael@0 | 205 | |
michael@0 | 206 | static const uint32_t PART_KIND_BITS = 3; |
michael@0 | 207 | static const uint32_t PART_KIND_MASK = (1 << PART_KIND_BITS) - 1; |
michael@0 | 208 | static const uint32_t PART_INFO_BITS = 5; |
michael@0 | 209 | static const uint32_t PART_INFO_MASK = (1 << PART_INFO_BITS) - 1; |
michael@0 | 210 | |
michael@0 | 211 | static const uint32_t MAX_INFO_VALUE = (1 << PART_INFO_BITS) - 1; |
michael@0 | 212 | static const uint32_t TYPE_KIND_SHIFT = 16 - PART_KIND_BITS; |
michael@0 | 213 | static const uint32_t PAYLOAD_KIND_SHIFT = TYPE_KIND_SHIFT - PART_KIND_BITS; |
michael@0 | 214 | static const uint32_t TYPE_INFO_SHIFT = PAYLOAD_KIND_SHIFT - PART_INFO_BITS; |
michael@0 | 215 | static const uint32_t PAYLOAD_INFO_SHIFT = TYPE_INFO_SHIFT - PART_INFO_BITS; |
michael@0 | 216 | |
michael@0 | 217 | JS_STATIC_ASSERT(PAYLOAD_INFO_SHIFT == 0); |
michael@0 | 218 | |
michael@0 | 219 | #ifdef JS_NUNBOX32 |
michael@0 | 220 | static inline NunboxPartKind |
michael@0 | 221 | AllocationToPartKind(const LAllocation &a) |
michael@0 | 222 | { |
michael@0 | 223 | if (a.isRegister()) |
michael@0 | 224 | return Part_Reg; |
michael@0 | 225 | if (a.isStackSlot()) |
michael@0 | 226 | return Part_Stack; |
michael@0 | 227 | JS_ASSERT(a.isArgument()); |
michael@0 | 228 | return Part_Arg; |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | // gcc 4.5 doesn't actually inline CanEncodeInfoInHeader when only |
michael@0 | 232 | // using the "inline" keyword, and miscompiles the function as well |
michael@0 | 233 | // when doing block reordering with branch prediction information. |
michael@0 | 234 | // See bug 799295 comment 71. |
michael@0 | 235 | static MOZ_ALWAYS_INLINE bool |
michael@0 | 236 | CanEncodeInfoInHeader(const LAllocation &a, uint32_t *out) |
michael@0 | 237 | { |
michael@0 | 238 | if (a.isGeneralReg()) { |
michael@0 | 239 | *out = a.toGeneralReg()->reg().code(); |
michael@0 | 240 | return true; |
michael@0 | 241 | } |
michael@0 | 242 | |
michael@0 | 243 | if (a.isStackSlot()) |
michael@0 | 244 | *out = a.toStackSlot()->slot(); |
michael@0 | 245 | else |
michael@0 | 246 | *out = a.toArgument()->index(); |
michael@0 | 247 | |
michael@0 | 248 | return *out < MAX_INFO_VALUE; |
michael@0 | 249 | } |
michael@0 | 250 | |
michael@0 | 251 | void |
michael@0 | 252 | SafepointWriter::writeNunboxParts(LSafepoint *safepoint) |
michael@0 | 253 | { |
michael@0 | 254 | LSafepoint::NunboxList &entries = safepoint->nunboxParts(); |
michael@0 | 255 | |
michael@0 | 256 | # ifdef DEBUG |
michael@0 | 257 | if (IonSpewEnabled(IonSpew_Safepoints)) { |
michael@0 | 258 | for (uint32_t i = 0; i < entries.length(); i++) { |
michael@0 | 259 | SafepointNunboxEntry &entry = entries[i]; |
michael@0 | 260 | if (entry.type.isUse() || entry.payload.isUse()) |
michael@0 | 261 | continue; |
michael@0 | 262 | IonSpewHeader(IonSpew_Safepoints); |
michael@0 | 263 | fprintf(IonSpewFile, " nunbox (type in "); |
michael@0 | 264 | DumpNunboxPart(entry.type); |
michael@0 | 265 | fprintf(IonSpewFile, ", payload in "); |
michael@0 | 266 | DumpNunboxPart(entry.payload); |
michael@0 | 267 | fprintf(IonSpewFile, ")\n"); |
michael@0 | 268 | } |
michael@0 | 269 | } |
michael@0 | 270 | # endif |
michael@0 | 271 | |
michael@0 | 272 | // Safepoints are permitted to have partially filled in entries for nunboxes, |
michael@0 | 273 | // provided that only the type is live and not the payload. Omit these from |
michael@0 | 274 | // the written safepoint. |
michael@0 | 275 | uint32_t partials = safepoint->partialNunboxes(); |
michael@0 | 276 | |
michael@0 | 277 | stream_.writeUnsigned(entries.length() - partials); |
michael@0 | 278 | |
michael@0 | 279 | for (size_t i = 0; i < entries.length(); i++) { |
michael@0 | 280 | SafepointNunboxEntry &entry = entries[i]; |
michael@0 | 281 | |
michael@0 | 282 | if (entry.type.isUse() || entry.payload.isUse()) { |
michael@0 | 283 | partials--; |
michael@0 | 284 | continue; |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | uint16_t header = 0; |
michael@0 | 288 | |
michael@0 | 289 | header |= (AllocationToPartKind(entry.type) << TYPE_KIND_SHIFT); |
michael@0 | 290 | header |= (AllocationToPartKind(entry.payload) << PAYLOAD_KIND_SHIFT); |
michael@0 | 291 | |
michael@0 | 292 | uint32_t typeVal; |
michael@0 | 293 | bool typeExtra = !CanEncodeInfoInHeader(entry.type, &typeVal); |
michael@0 | 294 | if (!typeExtra) |
michael@0 | 295 | header |= (typeVal << TYPE_INFO_SHIFT); |
michael@0 | 296 | else |
michael@0 | 297 | header |= (MAX_INFO_VALUE << TYPE_INFO_SHIFT); |
michael@0 | 298 | |
michael@0 | 299 | uint32_t payloadVal; |
michael@0 | 300 | bool payloadExtra = !CanEncodeInfoInHeader(entry.payload, &payloadVal); |
michael@0 | 301 | if (!payloadExtra) |
michael@0 | 302 | header |= (payloadVal << PAYLOAD_INFO_SHIFT); |
michael@0 | 303 | else |
michael@0 | 304 | header |= (MAX_INFO_VALUE << PAYLOAD_INFO_SHIFT); |
michael@0 | 305 | |
michael@0 | 306 | stream_.writeFixedUint16_t(header); |
michael@0 | 307 | if (typeExtra) |
michael@0 | 308 | stream_.writeUnsigned(typeVal); |
michael@0 | 309 | if (payloadExtra) |
michael@0 | 310 | stream_.writeUnsigned(payloadVal); |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | JS_ASSERT(partials == 0); |
michael@0 | 314 | } |
michael@0 | 315 | #endif |
michael@0 | 316 | |
michael@0 | 317 | void |
michael@0 | 318 | SafepointWriter::encode(LSafepoint *safepoint) |
michael@0 | 319 | { |
michael@0 | 320 | uint32_t safepointOffset = startEntry(); |
michael@0 | 321 | |
michael@0 | 322 | JS_ASSERT(safepoint->osiCallPointOffset()); |
michael@0 | 323 | |
michael@0 | 324 | writeOsiCallPointOffset(safepoint->osiCallPointOffset()); |
michael@0 | 325 | writeGcRegs(safepoint); |
michael@0 | 326 | writeGcSlots(safepoint); |
michael@0 | 327 | writeValueSlots(safepoint); |
michael@0 | 328 | |
michael@0 | 329 | #ifdef JS_NUNBOX32 |
michael@0 | 330 | writeNunboxParts(safepoint); |
michael@0 | 331 | #endif |
michael@0 | 332 | |
michael@0 | 333 | writeSlotsOrElementsSlots(safepoint); |
michael@0 | 334 | |
michael@0 | 335 | endEntry(); |
michael@0 | 336 | safepoint->setOffset(safepointOffset); |
michael@0 | 337 | } |
michael@0 | 338 | |
michael@0 | 339 | void |
michael@0 | 340 | SafepointWriter::endEntry() |
michael@0 | 341 | { |
michael@0 | 342 | IonSpew(IonSpew_Safepoints, " -- entry ended at %d", uint32_t(stream_.length())); |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | SafepointReader::SafepointReader(IonScript *script, const SafepointIndex *si) |
michael@0 | 346 | : stream_(script->safepoints() + si->safepointOffset(), |
michael@0 | 347 | script->safepoints() + script->safepointsSize()), |
michael@0 | 348 | frameSlots_(script->frameSlots() / sizeof(intptr_t)) |
michael@0 | 349 | { |
michael@0 | 350 | osiCallPointOffset_ = stream_.readUnsigned(); |
michael@0 | 351 | |
michael@0 | 352 | // gcSpills is a subset of allGprSpills. |
michael@0 | 353 | allGprSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_)); |
michael@0 | 354 | if (allGprSpills_.empty()) { |
michael@0 | 355 | gcSpills_ = allGprSpills_; |
michael@0 | 356 | valueSpills_ = allGprSpills_; |
michael@0 | 357 | slotsOrElementsSpills_ = allGprSpills_; |
michael@0 | 358 | } else { |
michael@0 | 359 | gcSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_)); |
michael@0 | 360 | slotsOrElementsSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_)); |
michael@0 | 361 | #ifdef JS_PUNBOX64 |
michael@0 | 362 | valueSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_)); |
michael@0 | 363 | #endif |
michael@0 | 364 | } |
michael@0 | 365 | |
michael@0 | 366 | allFloatSpills_ = FloatRegisterSet(ReadRegisterMask(stream_)); |
michael@0 | 367 | |
michael@0 | 368 | advanceFromGcRegs(); |
michael@0 | 369 | } |
michael@0 | 370 | |
michael@0 | 371 | uint32_t |
michael@0 | 372 | SafepointReader::osiReturnPointOffset() const |
michael@0 | 373 | { |
michael@0 | 374 | return osiCallPointOffset_ + Assembler::patchWrite_NearCallSize(); |
michael@0 | 375 | } |
michael@0 | 376 | |
michael@0 | 377 | CodeLocationLabel |
michael@0 | 378 | SafepointReader::InvalidationPatchPoint(IonScript *script, const SafepointIndex *si) |
michael@0 | 379 | { |
michael@0 | 380 | SafepointReader reader(script, si); |
michael@0 | 381 | |
michael@0 | 382 | return CodeLocationLabel(script->method(), reader.osiCallPointOffset()); |
michael@0 | 383 | } |
michael@0 | 384 | |
michael@0 | 385 | void |
michael@0 | 386 | SafepointReader::advanceFromGcRegs() |
michael@0 | 387 | { |
michael@0 | 388 | currentSlotChunk_ = 0; |
michael@0 | 389 | nextSlotChunkNumber_ = 0; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | bool |
michael@0 | 393 | SafepointReader::getSlotFromBitmap(uint32_t *slot) |
michael@0 | 394 | { |
michael@0 | 395 | while (currentSlotChunk_ == 0) { |
michael@0 | 396 | // Are there any more chunks to read? |
michael@0 | 397 | if (nextSlotChunkNumber_ == BitSet::RawLengthForBits(frameSlots_)) |
michael@0 | 398 | return false; |
michael@0 | 399 | |
michael@0 | 400 | // Yes, read the next chunk. |
michael@0 | 401 | currentSlotChunk_ = stream_.readUnsigned(); |
michael@0 | 402 | nextSlotChunkNumber_++; |
michael@0 | 403 | } |
michael@0 | 404 | |
michael@0 | 405 | // The current chunk still has bits in it, so get the next bit, then mask |
michael@0 | 406 | // it out of the slot chunk. |
michael@0 | 407 | uint32_t bit = FloorLog2(currentSlotChunk_); |
michael@0 | 408 | currentSlotChunk_ &= ~(1 << bit); |
michael@0 | 409 | |
michael@0 | 410 | // Return the slot, taking care to add 1 back in since it was subtracted |
michael@0 | 411 | // when added in the original bitset, and re-scale it by the pointer size, |
michael@0 | 412 | // reversing the transformation in MapSlotsToBitset. |
michael@0 | 413 | *slot = (((nextSlotChunkNumber_ - 1) * BitSet::BitsPerWord) + bit + 1) * sizeof(intptr_t); |
michael@0 | 414 | return true; |
michael@0 | 415 | } |
michael@0 | 416 | |
michael@0 | 417 | bool |
michael@0 | 418 | SafepointReader::getGcSlot(uint32_t *slot) |
michael@0 | 419 | { |
michael@0 | 420 | if (getSlotFromBitmap(slot)) |
michael@0 | 421 | return true; |
michael@0 | 422 | advanceFromGcSlots(); |
michael@0 | 423 | return false; |
michael@0 | 424 | } |
michael@0 | 425 | |
michael@0 | 426 | void |
michael@0 | 427 | SafepointReader::advanceFromGcSlots() |
michael@0 | 428 | { |
michael@0 | 429 | // No, reset the counter. |
michael@0 | 430 | currentSlotChunk_ = 0; |
michael@0 | 431 | nextSlotChunkNumber_ = 0; |
michael@0 | 432 | } |
michael@0 | 433 | |
michael@0 | 434 | bool |
michael@0 | 435 | SafepointReader::getValueSlot(uint32_t *slot) |
michael@0 | 436 | { |
michael@0 | 437 | if (getSlotFromBitmap(slot)) |
michael@0 | 438 | return true; |
michael@0 | 439 | advanceFromValueSlots(); |
michael@0 | 440 | return false; |
michael@0 | 441 | } |
michael@0 | 442 | |
michael@0 | 443 | void |
michael@0 | 444 | SafepointReader::advanceFromValueSlots() |
michael@0 | 445 | { |
michael@0 | 446 | #ifdef JS_NUNBOX32 |
michael@0 | 447 | nunboxSlotsRemaining_ = stream_.readUnsigned(); |
michael@0 | 448 | #else |
michael@0 | 449 | nunboxSlotsRemaining_ = 0; |
michael@0 | 450 | advanceFromNunboxSlots(); |
michael@0 | 451 | #endif |
michael@0 | 452 | } |
michael@0 | 453 | |
michael@0 | 454 | static inline LAllocation |
michael@0 | 455 | PartFromStream(CompactBufferReader &stream, NunboxPartKind kind, uint32_t info) |
michael@0 | 456 | { |
michael@0 | 457 | if (kind == Part_Reg) |
michael@0 | 458 | return LGeneralReg(Register::FromCode(info)); |
michael@0 | 459 | |
michael@0 | 460 | if (info == MAX_INFO_VALUE) |
michael@0 | 461 | info = stream.readUnsigned(); |
michael@0 | 462 | |
michael@0 | 463 | if (kind == Part_Stack) |
michael@0 | 464 | return LStackSlot(info); |
michael@0 | 465 | |
michael@0 | 466 | JS_ASSERT(kind == Part_Arg); |
michael@0 | 467 | return LArgument(info); |
michael@0 | 468 | } |
michael@0 | 469 | |
michael@0 | 470 | bool |
michael@0 | 471 | SafepointReader::getNunboxSlot(LAllocation *type, LAllocation *payload) |
michael@0 | 472 | { |
michael@0 | 473 | if (!nunboxSlotsRemaining_--) { |
michael@0 | 474 | advanceFromNunboxSlots(); |
michael@0 | 475 | return false; |
michael@0 | 476 | } |
michael@0 | 477 | |
michael@0 | 478 | uint16_t header = stream_.readFixedUint16_t(); |
michael@0 | 479 | NunboxPartKind typeKind = (NunboxPartKind)((header >> TYPE_KIND_SHIFT) & PART_KIND_MASK); |
michael@0 | 480 | NunboxPartKind payloadKind = (NunboxPartKind)((header >> PAYLOAD_KIND_SHIFT) & PART_KIND_MASK); |
michael@0 | 481 | uint32_t typeInfo = (header >> TYPE_INFO_SHIFT) & PART_INFO_MASK; |
michael@0 | 482 | uint32_t payloadInfo = (header >> PAYLOAD_INFO_SHIFT) & PART_INFO_MASK; |
michael@0 | 483 | |
michael@0 | 484 | *type = PartFromStream(stream_, typeKind, typeInfo); |
michael@0 | 485 | *payload = PartFromStream(stream_, payloadKind, payloadInfo); |
michael@0 | 486 | return true; |
michael@0 | 487 | } |
michael@0 | 488 | |
michael@0 | 489 | void |
michael@0 | 490 | SafepointReader::advanceFromNunboxSlots() |
michael@0 | 491 | { |
michael@0 | 492 | slotsOrElementsSlotsRemaining_ = stream_.readUnsigned(); |
michael@0 | 493 | } |
michael@0 | 494 | |
michael@0 | 495 | bool |
michael@0 | 496 | SafepointReader::getSlotsOrElementsSlot(uint32_t *slot) |
michael@0 | 497 | { |
michael@0 | 498 | if (!slotsOrElementsSlotsRemaining_--) |
michael@0 | 499 | return false; |
michael@0 | 500 | *slot = stream_.readUnsigned(); |
michael@0 | 501 | return true; |
michael@0 | 502 | } |