js/src/jit/AliasAnalysis.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.

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/AliasAnalysis.h"
michael@0 8
michael@0 9 #include <stdio.h>
michael@0 10
michael@0 11 #include "jit/Ion.h"
michael@0 12 #include "jit/IonBuilder.h"
michael@0 13 #include "jit/IonSpewer.h"
michael@0 14 #include "jit/MIR.h"
michael@0 15 #include "jit/MIRGraph.h"
michael@0 16
michael@0 17 using namespace js;
michael@0 18 using namespace js::jit;
michael@0 19
michael@0 20 using mozilla::Array;
michael@0 21
michael@0 22 namespace js {
michael@0 23 namespace jit {
michael@0 24
michael@0 25 class LoopAliasInfo : public TempObject
michael@0 26 {
michael@0 27 private:
michael@0 28 LoopAliasInfo *outer_;
michael@0 29 MBasicBlock *loopHeader_;
michael@0 30 MDefinitionVector invariantLoads_;
michael@0 31
michael@0 32 public:
michael@0 33 LoopAliasInfo(TempAllocator &alloc, LoopAliasInfo *outer, MBasicBlock *loopHeader)
michael@0 34 : outer_(outer), loopHeader_(loopHeader), invariantLoads_(alloc)
michael@0 35 { }
michael@0 36
michael@0 37 MBasicBlock *loopHeader() const {
michael@0 38 return loopHeader_;
michael@0 39 }
michael@0 40 LoopAliasInfo *outer() const {
michael@0 41 return outer_;
michael@0 42 }
michael@0 43 bool addInvariantLoad(MDefinition *ins) {
michael@0 44 return invariantLoads_.append(ins);
michael@0 45 }
michael@0 46 const MDefinitionVector& invariantLoads() const {
michael@0 47 return invariantLoads_;
michael@0 48 }
michael@0 49 MDefinition *firstInstruction() const {
michael@0 50 return *loopHeader_->begin();
michael@0 51 }
michael@0 52 };
michael@0 53
michael@0 54 } // namespace jit
michael@0 55 } // namespace js
michael@0 56
michael@0 57 namespace {
michael@0 58
michael@0 59 // Iterates over the flags in an AliasSet.
michael@0 60 class AliasSetIterator
michael@0 61 {
michael@0 62 private:
michael@0 63 uint32_t flags;
michael@0 64 unsigned pos;
michael@0 65
michael@0 66 public:
michael@0 67 AliasSetIterator(AliasSet set)
michael@0 68 : flags(set.flags()), pos(0)
michael@0 69 {
michael@0 70 while (flags && (flags & 1) == 0) {
michael@0 71 flags >>= 1;
michael@0 72 pos++;
michael@0 73 }
michael@0 74 }
michael@0 75 AliasSetIterator& operator ++(int) {
michael@0 76 do {
michael@0 77 flags >>= 1;
michael@0 78 pos++;
michael@0 79 } while (flags && (flags & 1) == 0);
michael@0 80 return *this;
michael@0 81 }
michael@0 82 operator bool() const {
michael@0 83 return !!flags;
michael@0 84 }
michael@0 85 unsigned operator *() const {
michael@0 86 JS_ASSERT(pos < AliasSet::NumCategories);
michael@0 87 return pos;
michael@0 88 }
michael@0 89 };
michael@0 90
michael@0 91 } /* anonymous namespace */
michael@0 92
michael@0 93 AliasAnalysis::AliasAnalysis(MIRGenerator *mir, MIRGraph &graph)
michael@0 94 : mir(mir),
michael@0 95 graph_(graph),
michael@0 96 loop_(nullptr)
michael@0 97 {
michael@0 98 }
michael@0 99
michael@0 100 // Whether there might be a path from src to dest, excluding loop backedges. This is
michael@0 101 // approximate and really ought to depend on precomputed reachability information.
michael@0 102 static inline bool
michael@0 103 BlockMightReach(MBasicBlock *src, MBasicBlock *dest)
michael@0 104 {
michael@0 105 while (src->id() <= dest->id()) {
michael@0 106 if (src == dest)
michael@0 107 return true;
michael@0 108 switch (src->numSuccessors()) {
michael@0 109 case 0:
michael@0 110 return false;
michael@0 111 case 1: {
michael@0 112 MBasicBlock *successor = src->getSuccessor(0);
michael@0 113 if (successor->id() <= src->id())
michael@0 114 return true; // Don't iloop.
michael@0 115 src = successor;
michael@0 116 break;
michael@0 117 }
michael@0 118 default:
michael@0 119 return true;
michael@0 120 }
michael@0 121 }
michael@0 122 return false;
michael@0 123 }
michael@0 124
michael@0 125 static void
michael@0 126 IonSpewDependency(MDefinition *load, MDefinition *store, const char *verb, const char *reason)
michael@0 127 {
michael@0 128 if (!IonSpewEnabled(IonSpew_Alias))
michael@0 129 return;
michael@0 130
michael@0 131 fprintf(IonSpewFile, "Load ");
michael@0 132 load->printName(IonSpewFile);
michael@0 133 fprintf(IonSpewFile, " %s on store ", verb);
michael@0 134 store->printName(IonSpewFile);
michael@0 135 fprintf(IonSpewFile, " (%s)\n", reason);
michael@0 136 }
michael@0 137
michael@0 138 static void
michael@0 139 IonSpewAliasInfo(const char *pre, MDefinition *ins, const char *post)
michael@0 140 {
michael@0 141 if (!IonSpewEnabled(IonSpew_Alias))
michael@0 142 return;
michael@0 143
michael@0 144 fprintf(IonSpewFile, "%s ", pre);
michael@0 145 ins->printName(IonSpewFile);
michael@0 146 fprintf(IonSpewFile, " %s\n", post);
michael@0 147 }
michael@0 148
michael@0 149 // This pass annotates every load instruction with the last store instruction
michael@0 150 // on which it depends. The algorithm is optimistic in that it ignores explicit
michael@0 151 // dependencies and only considers loads and stores.
michael@0 152 //
michael@0 153 // Loads inside loops only have an implicit dependency on a store before the
michael@0 154 // loop header if no instruction inside the loop body aliases it. To calculate
michael@0 155 // this efficiently, we maintain a list of maybe-invariant loads and the combined
michael@0 156 // alias set for all stores inside the loop. When we see the loop's backedge, this
michael@0 157 // information is used to mark every load we wrongly assumed to be loop invaraint as
michael@0 158 // having an implicit dependency on the last instruction of the loop header, so that
michael@0 159 // it's never moved before the loop header.
michael@0 160 //
michael@0 161 // The algorithm depends on the invariant that both control instructions and effectful
michael@0 162 // instructions (stores) are never hoisted.
michael@0 163 bool
michael@0 164 AliasAnalysis::analyze()
michael@0 165 {
michael@0 166 Vector<MDefinitionVector, AliasSet::NumCategories, IonAllocPolicy> stores(alloc());
michael@0 167
michael@0 168 // Initialize to the first instruction.
michael@0 169 MDefinition *firstIns = *graph_.begin()->begin();
michael@0 170 for (unsigned i = 0; i < AliasSet::NumCategories; i++) {
michael@0 171 MDefinitionVector defs(alloc());
michael@0 172 if (!defs.append(firstIns))
michael@0 173 return false;
michael@0 174 if (!stores.append(Move(defs)))
michael@0 175 return false;
michael@0 176 }
michael@0 177
michael@0 178 // Type analysis may have inserted new instructions. Since this pass depends
michael@0 179 // on the instruction number ordering, all instructions are renumbered.
michael@0 180 // We start with 1 because some passes use 0 to denote failure.
michael@0 181 uint32_t newId = 1;
michael@0 182
michael@0 183 for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
michael@0 184 if (mir->shouldCancel("Alias Analysis (main loop)"))
michael@0 185 return false;
michael@0 186
michael@0 187 if (block->isLoopHeader()) {
michael@0 188 IonSpew(IonSpew_Alias, "Processing loop header %d", block->id());
michael@0 189 loop_ = new(alloc()) LoopAliasInfo(alloc(), loop_, *block);
michael@0 190 }
michael@0 191
michael@0 192 for (MDefinitionIterator def(*block); def; def++) {
michael@0 193 def->setId(newId++);
michael@0 194
michael@0 195 AliasSet set = def->getAliasSet();
michael@0 196 if (set.isNone())
michael@0 197 continue;
michael@0 198
michael@0 199 if (set.isStore()) {
michael@0 200 for (AliasSetIterator iter(set); iter; iter++) {
michael@0 201 if (!stores[*iter].append(*def))
michael@0 202 return false;
michael@0 203 }
michael@0 204
michael@0 205 if (IonSpewEnabled(IonSpew_Alias)) {
michael@0 206 fprintf(IonSpewFile, "Processing store ");
michael@0 207 def->printName(IonSpewFile);
michael@0 208 fprintf(IonSpewFile, " (flags %x)\n", set.flags());
michael@0 209 }
michael@0 210 } else {
michael@0 211 // Find the most recent store on which this instruction depends.
michael@0 212 MDefinition *lastStore = firstIns;
michael@0 213
michael@0 214 for (AliasSetIterator iter(set); iter; iter++) {
michael@0 215 MDefinitionVector &aliasedStores = stores[*iter];
michael@0 216 for (int i = aliasedStores.length() - 1; i >= 0; i--) {
michael@0 217 MDefinition *store = aliasedStores[i];
michael@0 218 if (def->mightAlias(store) && BlockMightReach(store->block(), *block)) {
michael@0 219 if (lastStore->id() < store->id())
michael@0 220 lastStore = store;
michael@0 221 break;
michael@0 222 }
michael@0 223 }
michael@0 224 }
michael@0 225
michael@0 226 def->setDependency(lastStore);
michael@0 227 IonSpewDependency(*def, lastStore, "depends", "");
michael@0 228
michael@0 229 // If the last store was before the current loop, we assume this load
michael@0 230 // is loop invariant. If a later instruction writes to the same location,
michael@0 231 // we will fix this at the end of the loop.
michael@0 232 if (loop_ && lastStore->id() < loop_->firstInstruction()->id()) {
michael@0 233 if (!loop_->addInvariantLoad(*def))
michael@0 234 return false;
michael@0 235 }
michael@0 236 }
michael@0 237 }
michael@0 238
michael@0 239 // Renumber the last instruction, as the analysis depends on this and the order.
michael@0 240 block->lastIns()->setId(newId++);
michael@0 241
michael@0 242 if (block->isLoopBackedge()) {
michael@0 243 JS_ASSERT(loop_->loopHeader() == block->loopHeaderOfBackedge());
michael@0 244 IonSpew(IonSpew_Alias, "Processing loop backedge %d (header %d)", block->id(),
michael@0 245 loop_->loopHeader()->id());
michael@0 246 LoopAliasInfo *outerLoop = loop_->outer();
michael@0 247 MInstruction *firstLoopIns = *loop_->loopHeader()->begin();
michael@0 248
michael@0 249 const MDefinitionVector &invariant = loop_->invariantLoads();
michael@0 250
michael@0 251 for (unsigned i = 0; i < invariant.length(); i++) {
michael@0 252 MDefinition *ins = invariant[i];
michael@0 253 AliasSet set = ins->getAliasSet();
michael@0 254 JS_ASSERT(set.isLoad());
michael@0 255
michael@0 256 bool hasAlias = false;
michael@0 257 for (AliasSetIterator iter(set); iter; iter++) {
michael@0 258 MDefinitionVector &aliasedStores = stores[*iter];
michael@0 259 for (int i = aliasedStores.length() - 1;; i--) {
michael@0 260 MDefinition *store = aliasedStores[i];
michael@0 261 if (store->id() < firstLoopIns->id())
michael@0 262 break;
michael@0 263 if (ins->mightAlias(store)) {
michael@0 264 hasAlias = true;
michael@0 265 IonSpewDependency(ins, store, "aliases", "store in loop body");
michael@0 266 break;
michael@0 267 }
michael@0 268 }
michael@0 269 if (hasAlias)
michael@0 270 break;
michael@0 271 }
michael@0 272
michael@0 273 if (hasAlias) {
michael@0 274 // This instruction depends on stores inside the loop body. Mark it as having a
michael@0 275 // dependency on the last instruction of the loop header. The last instruction is a
michael@0 276 // control instruction and these are never hoisted.
michael@0 277 MControlInstruction *controlIns = loop_->loopHeader()->lastIns();
michael@0 278 IonSpewDependency(ins, controlIns, "depends", "due to stores in loop body");
michael@0 279 ins->setDependency(controlIns);
michael@0 280 } else {
michael@0 281 IonSpewAliasInfo("Load", ins, "does not depend on any stores in this loop");
michael@0 282
michael@0 283 if (outerLoop && ins->dependency()->id() < outerLoop->firstInstruction()->id()) {
michael@0 284 IonSpewAliasInfo("Load", ins, "may be invariant in outer loop");
michael@0 285 if (!outerLoop->addInvariantLoad(ins))
michael@0 286 return false;
michael@0 287 }
michael@0 288 }
michael@0 289 }
michael@0 290 loop_ = loop_->outer();
michael@0 291 }
michael@0 292 }
michael@0 293
michael@0 294 JS_ASSERT(loop_ == nullptr);
michael@0 295 return true;
michael@0 296 }

mercurial