js/src/jit/Safepoints.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial