js/src/jit/RegisterAllocator.h

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.

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 #ifndef jit_RegisterAllocator_h
michael@0 8 #define jit_RegisterAllocator_h
michael@0 9
michael@0 10 #include "mozilla/Attributes.h"
michael@0 11 #include "mozilla/MathAlgorithms.h"
michael@0 12
michael@0 13 #include "jit/LIR.h"
michael@0 14 #include "jit/MIRGenerator.h"
michael@0 15 #include "jit/MIRGraph.h"
michael@0 16
michael@0 17 // Generic structures and functions for use by register allocators.
michael@0 18
michael@0 19 namespace js {
michael@0 20 namespace jit {
michael@0 21
michael@0 22 class LIRGenerator;
michael@0 23
michael@0 24 // Structure for running a liveness analysis on a finished register allocation.
michael@0 25 // This analysis can be used for two purposes:
michael@0 26 //
michael@0 27 // - Check the integrity of the allocation, i.e. that the reads and writes of
michael@0 28 // physical values preserve the semantics of the original virtual registers.
michael@0 29 //
michael@0 30 // - Populate safepoints with live registers, GC thing and value data, to
michael@0 31 // streamline the process of prototyping new allocators.
michael@0 32 struct AllocationIntegrityState
michael@0 33 {
michael@0 34 explicit AllocationIntegrityState(const LIRGraph &graph)
michael@0 35 : graph(graph)
michael@0 36 {}
michael@0 37
michael@0 38 // Record all virtual registers in the graph. This must be called before
michael@0 39 // register allocation, to pick up the original LUses.
michael@0 40 bool record();
michael@0 41
michael@0 42 // Perform the liveness analysis on the graph, and assert on an invalid
michael@0 43 // allocation. This must be called after register allocation, to pick up
michael@0 44 // all assigned physical values. If populateSafepoints is specified,
michael@0 45 // safepoints will be filled in with liveness information.
michael@0 46 bool check(bool populateSafepoints);
michael@0 47
michael@0 48 private:
michael@0 49
michael@0 50 const LIRGraph &graph;
michael@0 51
michael@0 52 // For all instructions and phis in the graph, keep track of the virtual
michael@0 53 // registers for all inputs and outputs of the nodes. These are overwritten
michael@0 54 // in place during register allocation. This information is kept on the
michael@0 55 // side rather than in the instructions and phis themselves to avoid
michael@0 56 // debug-builds-only bloat in the size of the involved structures.
michael@0 57
michael@0 58 struct InstructionInfo {
michael@0 59 Vector<LAllocation, 2, SystemAllocPolicy> inputs;
michael@0 60 Vector<LDefinition, 0, SystemAllocPolicy> temps;
michael@0 61 Vector<LDefinition, 1, SystemAllocPolicy> outputs;
michael@0 62
michael@0 63 InstructionInfo()
michael@0 64 { }
michael@0 65
michael@0 66 InstructionInfo(const InstructionInfo &o)
michael@0 67 {
michael@0 68 inputs.appendAll(o.inputs);
michael@0 69 temps.appendAll(o.temps);
michael@0 70 outputs.appendAll(o.outputs);
michael@0 71 }
michael@0 72 };
michael@0 73 Vector<InstructionInfo, 0, SystemAllocPolicy> instructions;
michael@0 74
michael@0 75 struct BlockInfo {
michael@0 76 Vector<InstructionInfo, 5, SystemAllocPolicy> phis;
michael@0 77 BlockInfo() {}
michael@0 78 BlockInfo(const BlockInfo &o) {
michael@0 79 phis.appendAll(o.phis);
michael@0 80 }
michael@0 81 };
michael@0 82 Vector<BlockInfo, 0, SystemAllocPolicy> blocks;
michael@0 83
michael@0 84 Vector<LDefinition*, 20, SystemAllocPolicy> virtualRegisters;
michael@0 85
michael@0 86 // Describes a correspondence that should hold at the end of a block.
michael@0 87 // The value which was written to vreg in the original LIR should be
michael@0 88 // physically stored in alloc after the register allocation.
michael@0 89 struct IntegrityItem
michael@0 90 {
michael@0 91 LBlock *block;
michael@0 92 uint32_t vreg;
michael@0 93 LAllocation alloc;
michael@0 94
michael@0 95 // Order of insertion into seen, for sorting.
michael@0 96 uint32_t index;
michael@0 97
michael@0 98 typedef IntegrityItem Lookup;
michael@0 99 static HashNumber hash(const IntegrityItem &item) {
michael@0 100 HashNumber hash = item.alloc.hash();
michael@0 101 hash = mozilla::RotateLeft(hash, 4) ^ item.vreg;
michael@0 102 hash = mozilla::RotateLeft(hash, 4) ^ HashNumber(item.block->mir()->id());
michael@0 103 return hash;
michael@0 104 }
michael@0 105 static bool match(const IntegrityItem &one, const IntegrityItem &two) {
michael@0 106 return one.block == two.block
michael@0 107 && one.vreg == two.vreg
michael@0 108 && one.alloc == two.alloc;
michael@0 109 }
michael@0 110 };
michael@0 111
michael@0 112 // Items still to be processed.
michael@0 113 Vector<IntegrityItem, 10, SystemAllocPolicy> worklist;
michael@0 114
michael@0 115 // Set of all items that have already been processed.
michael@0 116 typedef HashSet<IntegrityItem, IntegrityItem, SystemAllocPolicy> IntegrityItemSet;
michael@0 117 IntegrityItemSet seen;
michael@0 118
michael@0 119 bool checkIntegrity(LBlock *block, LInstruction *ins, uint32_t vreg, LAllocation alloc,
michael@0 120 bool populateSafepoints);
michael@0 121 bool checkSafepointAllocation(LInstruction *ins, uint32_t vreg, LAllocation alloc,
michael@0 122 bool populateSafepoints);
michael@0 123 bool addPredecessor(LBlock *block, uint32_t vreg, LAllocation alloc);
michael@0 124
michael@0 125 void dump();
michael@0 126 };
michael@0 127
michael@0 128 // Represents with better-than-instruction precision a position in the
michael@0 129 // instruction stream.
michael@0 130 //
michael@0 131 // An issue comes up when performing register allocation as to how to represent
michael@0 132 // information such as "this register is only needed for the input of
michael@0 133 // this instruction, it can be clobbered in the output". Just having ranges
michael@0 134 // of instruction IDs is insufficiently expressive to denote all possibilities.
michael@0 135 // This class solves this issue by associating an extra bit with the instruction
michael@0 136 // ID which indicates whether the position is the input half or output half of
michael@0 137 // an instruction.
michael@0 138 class CodePosition
michael@0 139 {
michael@0 140 private:
michael@0 141 MOZ_CONSTEXPR CodePosition(const uint32_t &bits)
michael@0 142 : bits_(bits)
michael@0 143 { }
michael@0 144
michael@0 145 static const unsigned int INSTRUCTION_SHIFT = 1;
michael@0 146 static const unsigned int SUBPOSITION_MASK = 1;
michael@0 147 uint32_t bits_;
michael@0 148
michael@0 149 public:
michael@0 150 static const CodePosition MAX;
michael@0 151 static const CodePosition MIN;
michael@0 152
michael@0 153 // This is the half of the instruction this code position represents, as
michael@0 154 // described in the huge comment above.
michael@0 155 enum SubPosition {
michael@0 156 INPUT,
michael@0 157 OUTPUT
michael@0 158 };
michael@0 159
michael@0 160 MOZ_CONSTEXPR CodePosition() : bits_(0)
michael@0 161 { }
michael@0 162
michael@0 163 CodePosition(uint32_t instruction, SubPosition where) {
michael@0 164 JS_ASSERT(instruction < 0x80000000u);
michael@0 165 JS_ASSERT(((uint32_t)where & SUBPOSITION_MASK) == (uint32_t)where);
michael@0 166 bits_ = (instruction << INSTRUCTION_SHIFT) | (uint32_t)where;
michael@0 167 }
michael@0 168
michael@0 169 uint32_t ins() const {
michael@0 170 return bits_ >> INSTRUCTION_SHIFT;
michael@0 171 }
michael@0 172
michael@0 173 uint32_t pos() const {
michael@0 174 return bits_;
michael@0 175 }
michael@0 176
michael@0 177 SubPosition subpos() const {
michael@0 178 return (SubPosition)(bits_ & SUBPOSITION_MASK);
michael@0 179 }
michael@0 180
michael@0 181 bool operator <(const CodePosition &other) const {
michael@0 182 return bits_ < other.bits_;
michael@0 183 }
michael@0 184
michael@0 185 bool operator <=(const CodePosition &other) const {
michael@0 186 return bits_ <= other.bits_;
michael@0 187 }
michael@0 188
michael@0 189 bool operator !=(const CodePosition &other) const {
michael@0 190 return bits_ != other.bits_;
michael@0 191 }
michael@0 192
michael@0 193 bool operator ==(const CodePosition &other) const {
michael@0 194 return bits_ == other.bits_;
michael@0 195 }
michael@0 196
michael@0 197 bool operator >(const CodePosition &other) const {
michael@0 198 return bits_ > other.bits_;
michael@0 199 }
michael@0 200
michael@0 201 bool operator >=(const CodePosition &other) const {
michael@0 202 return bits_ >= other.bits_;
michael@0 203 }
michael@0 204
michael@0 205 CodePosition previous() const {
michael@0 206 JS_ASSERT(*this != MIN);
michael@0 207 return CodePosition(bits_ - 1);
michael@0 208 }
michael@0 209 CodePosition next() const {
michael@0 210 JS_ASSERT(*this != MAX);
michael@0 211 return CodePosition(bits_ + 1);
michael@0 212 }
michael@0 213 };
michael@0 214
michael@0 215 // Structure to track moves inserted before or after an instruction.
michael@0 216 class InstructionData
michael@0 217 {
michael@0 218 LInstruction *ins_;
michael@0 219 LBlock *block_;
michael@0 220 LMoveGroup *inputMoves_;
michael@0 221 LMoveGroup *movesAfter_;
michael@0 222
michael@0 223 public:
michael@0 224 void init(LInstruction *ins, LBlock *block) {
michael@0 225 JS_ASSERT(!ins_);
michael@0 226 JS_ASSERT(!block_);
michael@0 227 ins_ = ins;
michael@0 228 block_ = block;
michael@0 229 }
michael@0 230 LInstruction *ins() const {
michael@0 231 return ins_;
michael@0 232 }
michael@0 233 LBlock *block() const {
michael@0 234 return block_;
michael@0 235 }
michael@0 236 void setInputMoves(LMoveGroup *moves) {
michael@0 237 inputMoves_ = moves;
michael@0 238 }
michael@0 239 LMoveGroup *inputMoves() const {
michael@0 240 return inputMoves_;
michael@0 241 }
michael@0 242 void setMovesAfter(LMoveGroup *moves) {
michael@0 243 movesAfter_ = moves;
michael@0 244 }
michael@0 245 LMoveGroup *movesAfter() const {
michael@0 246 return movesAfter_;
michael@0 247 }
michael@0 248 };
michael@0 249
michael@0 250 // Structure to track all moves inserted next to instructions in a graph.
michael@0 251 class InstructionDataMap
michael@0 252 {
michael@0 253 InstructionData *insData_;
michael@0 254 uint32_t numIns_;
michael@0 255
michael@0 256 public:
michael@0 257 InstructionDataMap()
michael@0 258 : insData_(nullptr),
michael@0 259 numIns_(0)
michael@0 260 { }
michael@0 261
michael@0 262 bool init(MIRGenerator *gen, uint32_t numInstructions) {
michael@0 263 insData_ = gen->allocate<InstructionData>(numInstructions);
michael@0 264 numIns_ = numInstructions;
michael@0 265 if (!insData_)
michael@0 266 return false;
michael@0 267 memset(insData_, 0, sizeof(InstructionData) * numInstructions);
michael@0 268 return true;
michael@0 269 }
michael@0 270
michael@0 271 InstructionData &operator[](const CodePosition &pos) {
michael@0 272 JS_ASSERT(pos.ins() < numIns_);
michael@0 273 return insData_[pos.ins()];
michael@0 274 }
michael@0 275 InstructionData &operator[](LInstruction *ins) {
michael@0 276 JS_ASSERT(ins->id() < numIns_);
michael@0 277 return insData_[ins->id()];
michael@0 278 }
michael@0 279 InstructionData &operator[](uint32_t ins) {
michael@0 280 JS_ASSERT(ins < numIns_);
michael@0 281 return insData_[ins];
michael@0 282 }
michael@0 283 };
michael@0 284
michael@0 285 // Common superclass for register allocators.
michael@0 286 class RegisterAllocator
michael@0 287 {
michael@0 288 void operator=(const RegisterAllocator &) MOZ_DELETE;
michael@0 289 RegisterAllocator(const RegisterAllocator &) MOZ_DELETE;
michael@0 290
michael@0 291 protected:
michael@0 292 // Context
michael@0 293 MIRGenerator *mir;
michael@0 294 LIRGenerator *lir;
michael@0 295 LIRGraph &graph;
michael@0 296
michael@0 297 // Pool of all registers that should be considered allocateable
michael@0 298 RegisterSet allRegisters_;
michael@0 299
michael@0 300 // Computed data
michael@0 301 InstructionDataMap insData;
michael@0 302
michael@0 303 RegisterAllocator(MIRGenerator *mir, LIRGenerator *lir, LIRGraph &graph)
michael@0 304 : mir(mir),
michael@0 305 lir(lir),
michael@0 306 graph(graph),
michael@0 307 allRegisters_(RegisterSet::All())
michael@0 308 {
michael@0 309 if (FramePointer != InvalidReg && mir->instrumentedProfiling())
michael@0 310 allRegisters_.take(AnyRegister(FramePointer));
michael@0 311 #if defined(JS_CODEGEN_X64)
michael@0 312 if (mir->compilingAsmJS())
michael@0 313 allRegisters_.take(AnyRegister(HeapReg));
michael@0 314 #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
michael@0 315 if (mir->compilingAsmJS()) {
michael@0 316 allRegisters_.take(AnyRegister(HeapReg));
michael@0 317 allRegisters_.take(AnyRegister(GlobalReg));
michael@0 318 allRegisters_.take(AnyRegister(NANReg));
michael@0 319 }
michael@0 320 #endif
michael@0 321 }
michael@0 322
michael@0 323 bool init();
michael@0 324
michael@0 325 TempAllocator &alloc() const {
michael@0 326 return mir->alloc();
michael@0 327 }
michael@0 328
michael@0 329 static CodePosition outputOf(uint32_t pos) {
michael@0 330 return CodePosition(pos, CodePosition::OUTPUT);
michael@0 331 }
michael@0 332 static CodePosition outputOf(const LInstruction *ins) {
michael@0 333 return CodePosition(ins->id(), CodePosition::OUTPUT);
michael@0 334 }
michael@0 335 static CodePosition inputOf(uint32_t pos) {
michael@0 336 return CodePosition(pos, CodePosition::INPUT);
michael@0 337 }
michael@0 338 static CodePosition inputOf(const LInstruction *ins) {
michael@0 339 // Phi nodes "use" their inputs before the beginning of the block.
michael@0 340 JS_ASSERT(!ins->isPhi());
michael@0 341 return CodePosition(ins->id(), CodePosition::INPUT);
michael@0 342 }
michael@0 343
michael@0 344 LMoveGroup *getInputMoveGroup(uint32_t ins);
michael@0 345 LMoveGroup *getMoveGroupAfter(uint32_t ins);
michael@0 346
michael@0 347 LMoveGroup *getInputMoveGroup(CodePosition pos) {
michael@0 348 return getInputMoveGroup(pos.ins());
michael@0 349 }
michael@0 350 LMoveGroup *getMoveGroupAfter(CodePosition pos) {
michael@0 351 return getMoveGroupAfter(pos.ins());
michael@0 352 }
michael@0 353
michael@0 354 CodePosition minimalDefEnd(LInstruction *ins) {
michael@0 355 // Compute the shortest interval that captures vregs defined by ins.
michael@0 356 // Watch for instructions that are followed by an OSI point and/or Nop.
michael@0 357 // If moves are introduced between the instruction and the OSI point then
michael@0 358 // safepoint information for the instruction may be incorrect.
michael@0 359 while (true) {
michael@0 360 LInstruction *next = insData[outputOf(ins).next()].ins();
michael@0 361 if (!next->isNop() && !next->isOsiPoint())
michael@0 362 break;
michael@0 363 ins = next;
michael@0 364 }
michael@0 365
michael@0 366 return outputOf(ins);
michael@0 367 }
michael@0 368 };
michael@0 369
michael@0 370 static inline AnyRegister
michael@0 371 GetFixedRegister(const LDefinition *def, const LUse *use)
michael@0 372 {
michael@0 373 return def->isFloatReg()
michael@0 374 ? AnyRegister(FloatRegister::FromCode(use->registerCode()))
michael@0 375 : AnyRegister(Register::FromCode(use->registerCode()));
michael@0 376 }
michael@0 377
michael@0 378 } // namespace jit
michael@0 379 } // namespace js
michael@0 380
michael@0 381 #endif /* jit_RegisterAllocator_h */

mercurial