js/src/jit/MIRGraph.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/MIRGraph.h"
michael@0 8
michael@0 9 #include "jit/AsmJS.h"
michael@0 10 #include "jit/BytecodeAnalysis.h"
michael@0 11 #include "jit/Ion.h"
michael@0 12 #include "jit/IonSpewer.h"
michael@0 13 #include "jit/MIR.h"
michael@0 14 #include "jit/MIRGenerator.h"
michael@0 15
michael@0 16 using namespace js;
michael@0 17 using namespace js::jit;
michael@0 18
michael@0 19 MIRGenerator::MIRGenerator(CompileCompartment *compartment, const JitCompileOptions &options,
michael@0 20 TempAllocator *alloc, MIRGraph *graph, CompileInfo *info,
michael@0 21 const OptimizationInfo *optimizationInfo)
michael@0 22 : compartment(compartment),
michael@0 23 info_(info),
michael@0 24 optimizationInfo_(optimizationInfo),
michael@0 25 alloc_(alloc),
michael@0 26 graph_(graph),
michael@0 27 error_(false),
michael@0 28 cancelBuild_(false),
michael@0 29 maxAsmJSStackArgBytes_(0),
michael@0 30 performsCall_(false),
michael@0 31 performsAsmJSCall_(false),
michael@0 32 minAsmJSHeapLength_(AsmJSAllocationGranularity),
michael@0 33 modifiesFrameArguments_(false),
michael@0 34 options(options)
michael@0 35 { }
michael@0 36
michael@0 37 bool
michael@0 38 MIRGenerator::abortFmt(const char *message, va_list ap)
michael@0 39 {
michael@0 40 IonSpewVA(IonSpew_Abort, message, ap);
michael@0 41 error_ = true;
michael@0 42 return false;
michael@0 43 }
michael@0 44
michael@0 45 bool
michael@0 46 MIRGenerator::abort(const char *message, ...)
michael@0 47 {
michael@0 48 va_list ap;
michael@0 49 va_start(ap, message);
michael@0 50 abortFmt(message, ap);
michael@0 51 va_end(ap);
michael@0 52 return false;
michael@0 53 }
michael@0 54
michael@0 55 void
michael@0 56 MIRGraph::addBlock(MBasicBlock *block)
michael@0 57 {
michael@0 58 JS_ASSERT(block);
michael@0 59 block->setId(blockIdGen_++);
michael@0 60 blocks_.pushBack(block);
michael@0 61 numBlocks_++;
michael@0 62 }
michael@0 63
michael@0 64 void
michael@0 65 MIRGraph::insertBlockAfter(MBasicBlock *at, MBasicBlock *block)
michael@0 66 {
michael@0 67 block->setId(blockIdGen_++);
michael@0 68 blocks_.insertAfter(at, block);
michael@0 69 numBlocks_++;
michael@0 70 }
michael@0 71
michael@0 72 void
michael@0 73 MIRGraph::removeBlocksAfter(MBasicBlock *start)
michael@0 74 {
michael@0 75 MBasicBlockIterator iter(begin());
michael@0 76 iter++;
michael@0 77 while (iter != end()) {
michael@0 78 MBasicBlock *block = *iter;
michael@0 79 iter++;
michael@0 80
michael@0 81 if (block->id() <= start->id())
michael@0 82 continue;
michael@0 83
michael@0 84 // removeBlock will not remove the resumepoints, since
michael@0 85 // it can be shared with outer blocks. So remove them now.
michael@0 86 block->discardAllResumePoints();
michael@0 87 removeBlock(block);
michael@0 88 }
michael@0 89 }
michael@0 90
michael@0 91 void
michael@0 92 MIRGraph::removeBlock(MBasicBlock *block)
michael@0 93 {
michael@0 94 // Remove a block from the graph. It will also cleanup the block,
michael@0 95 // except for removing the resumepoints, since multiple blocks can
michael@0 96 // share the same resumepoints and we cannot distinguish between them.
michael@0 97
michael@0 98 if (block == osrBlock_)
michael@0 99 osrBlock_ = nullptr;
michael@0 100
michael@0 101 if (returnAccumulator_) {
michael@0 102 size_t i = 0;
michael@0 103 while (i < returnAccumulator_->length()) {
michael@0 104 if ((*returnAccumulator_)[i] == block)
michael@0 105 returnAccumulator_->erase(returnAccumulator_->begin() + i);
michael@0 106 else
michael@0 107 i++;
michael@0 108 }
michael@0 109 }
michael@0 110
michael@0 111 block->discardAllInstructions();
michael@0 112
michael@0 113 // Note: phis are disconnected from the rest of the graph, but are not
michael@0 114 // removed entirely. If the block being removed is a loop header then
michael@0 115 // IonBuilder may need to access these phis to more quickly converge on the
michael@0 116 // possible types in the graph. See IonBuilder::analyzeNewLoopTypes.
michael@0 117 block->discardAllPhiOperands();
michael@0 118
michael@0 119 block->markAsDead();
michael@0 120 blocks_.remove(block);
michael@0 121 numBlocks_--;
michael@0 122 }
michael@0 123
michael@0 124 void
michael@0 125 MIRGraph::unmarkBlocks()
michael@0 126 {
michael@0 127 for (MBasicBlockIterator i(blocks_.begin()); i != blocks_.end(); i++)
michael@0 128 i->unmark();
michael@0 129 }
michael@0 130
michael@0 131 MDefinition *
michael@0 132 MIRGraph::forkJoinContext()
michael@0 133 {
michael@0 134 // Search the entry block to find a ForkJoinContext instruction. If we do
michael@0 135 // not find one, add one after the Start instruction.
michael@0 136 //
michael@0 137 // Note: the original design used a field in MIRGraph to cache the
michael@0 138 // forkJoinContext rather than searching for it again. However, this
michael@0 139 // could become out of date due to DCE. Given that we do not generally
michael@0 140 // have to search very far to find the ForkJoinContext instruction if it
michael@0 141 // exists, and that we don't look for it that often, I opted to simply
michael@0 142 // eliminate the cache and search anew each time, so that it is that much
michael@0 143 // easier to keep the IR coherent. - nmatsakis
michael@0 144
michael@0 145 MBasicBlock *entry = entryBlock();
michael@0 146 JS_ASSERT(entry->info().executionMode() == ParallelExecution);
michael@0 147
michael@0 148 MInstruction *start = nullptr;
michael@0 149 for (MInstructionIterator ins(entry->begin()); ins != entry->end(); ins++) {
michael@0 150 if (ins->isForkJoinContext())
michael@0 151 return *ins;
michael@0 152 else if (ins->isStart())
michael@0 153 start = *ins;
michael@0 154 }
michael@0 155 JS_ASSERT(start);
michael@0 156
michael@0 157 MForkJoinContext *cx = MForkJoinContext::New(alloc());
michael@0 158 entry->insertAfter(start, cx);
michael@0 159 return cx;
michael@0 160 }
michael@0 161
michael@0 162 MBasicBlock *
michael@0 163 MBasicBlock::New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info,
michael@0 164 MBasicBlock *pred, jsbytecode *entryPc, Kind kind)
michael@0 165 {
michael@0 166 JS_ASSERT(entryPc != nullptr);
michael@0 167
michael@0 168 MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, kind);
michael@0 169 if (!block->init())
michael@0 170 return nullptr;
michael@0 171
michael@0 172 if (!block->inherit(graph.alloc(), analysis, pred, 0))
michael@0 173 return nullptr;
michael@0 174
michael@0 175 return block;
michael@0 176 }
michael@0 177
michael@0 178 MBasicBlock *
michael@0 179 MBasicBlock::NewPopN(MIRGraph &graph, CompileInfo &info,
michael@0 180 MBasicBlock *pred, jsbytecode *entryPc, Kind kind, uint32_t popped)
michael@0 181 {
michael@0 182 MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, kind);
michael@0 183 if (!block->init())
michael@0 184 return nullptr;
michael@0 185
michael@0 186 if (!block->inherit(graph.alloc(), nullptr, pred, popped))
michael@0 187 return nullptr;
michael@0 188
michael@0 189 return block;
michael@0 190 }
michael@0 191
michael@0 192 MBasicBlock *
michael@0 193 MBasicBlock::NewWithResumePoint(MIRGraph &graph, CompileInfo &info,
michael@0 194 MBasicBlock *pred, jsbytecode *entryPc,
michael@0 195 MResumePoint *resumePoint)
michael@0 196 {
michael@0 197 MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, NORMAL);
michael@0 198
michael@0 199 resumePoint->block_ = block;
michael@0 200 block->entryResumePoint_ = resumePoint;
michael@0 201
michael@0 202 if (!block->init())
michael@0 203 return nullptr;
michael@0 204
michael@0 205 if (!block->inheritResumePoint(pred))
michael@0 206 return nullptr;
michael@0 207
michael@0 208 return block;
michael@0 209 }
michael@0 210
michael@0 211 MBasicBlock *
michael@0 212 MBasicBlock::NewPendingLoopHeader(MIRGraph &graph, CompileInfo &info,
michael@0 213 MBasicBlock *pred, jsbytecode *entryPc,
michael@0 214 unsigned stackPhiCount)
michael@0 215 {
michael@0 216 JS_ASSERT(entryPc != nullptr);
michael@0 217
michael@0 218 MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, PENDING_LOOP_HEADER);
michael@0 219 if (!block->init())
michael@0 220 return nullptr;
michael@0 221
michael@0 222 if (!block->inherit(graph.alloc(), nullptr, pred, 0, stackPhiCount))
michael@0 223 return nullptr;
michael@0 224
michael@0 225 return block;
michael@0 226 }
michael@0 227
michael@0 228 MBasicBlock *
michael@0 229 MBasicBlock::NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred)
michael@0 230 {
michael@0 231 return pred->pc()
michael@0 232 ? MBasicBlock::New(graph, nullptr, info, pred, pred->pc(), SPLIT_EDGE)
michael@0 233 : MBasicBlock::NewAsmJS(graph, info, pred, SPLIT_EDGE);
michael@0 234 }
michael@0 235
michael@0 236 MBasicBlock *
michael@0 237 MBasicBlock::NewAbortPar(MIRGraph &graph, CompileInfo &info,
michael@0 238 MBasicBlock *pred, jsbytecode *entryPc,
michael@0 239 MResumePoint *resumePoint)
michael@0 240 {
michael@0 241 MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, NORMAL);
michael@0 242
michael@0 243 resumePoint->block_ = block;
michael@0 244 block->entryResumePoint_ = resumePoint;
michael@0 245
michael@0 246 if (!block->init())
michael@0 247 return nullptr;
michael@0 248
michael@0 249 if (!block->addPredecessorWithoutPhis(pred))
michael@0 250 return nullptr;
michael@0 251
michael@0 252 block->end(MAbortPar::New(graph.alloc()));
michael@0 253 return block;
michael@0 254 }
michael@0 255
michael@0 256 MBasicBlock *
michael@0 257 MBasicBlock::NewAsmJS(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred, Kind kind)
michael@0 258 {
michael@0 259 MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, /* entryPC = */ nullptr, kind);
michael@0 260 if (!block->init())
michael@0 261 return nullptr;
michael@0 262
michael@0 263 if (pred) {
michael@0 264 block->stackPosition_ = pred->stackPosition_;
michael@0 265
michael@0 266 if (block->kind_ == PENDING_LOOP_HEADER) {
michael@0 267 size_t nphis = block->stackPosition_;
michael@0 268
michael@0 269 TempAllocator &alloc = graph.alloc();
michael@0 270 MPhi *phis = (MPhi*)alloc.allocateArray<sizeof(MPhi)>(nphis);
michael@0 271 if (!phis)
michael@0 272 return nullptr;
michael@0 273
michael@0 274 for (size_t i = 0; i < nphis; i++) {
michael@0 275 MDefinition *predSlot = pred->getSlot(i);
michael@0 276
michael@0 277 JS_ASSERT(predSlot->type() != MIRType_Value);
michael@0 278 MPhi *phi = new(phis + i) MPhi(alloc, i, predSlot->type());
michael@0 279
michael@0 280 JS_ALWAYS_TRUE(phi->reserveLength(2));
michael@0 281 phi->addInput(predSlot);
michael@0 282
michael@0 283 block->addPhi(phi);
michael@0 284 block->setSlot(i, phi);
michael@0 285 }
michael@0 286 } else {
michael@0 287 block->copySlots(pred);
michael@0 288 }
michael@0 289
michael@0 290 if (!block->predecessors_.append(pred))
michael@0 291 return nullptr;
michael@0 292 }
michael@0 293
michael@0 294 return block;
michael@0 295 }
michael@0 296
michael@0 297 MBasicBlock::MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind)
michael@0 298 : unreachable_(false),
michael@0 299 graph_(graph),
michael@0 300 info_(info),
michael@0 301 predecessors_(graph.alloc()),
michael@0 302 stackPosition_(info_.firstStackSlot()),
michael@0 303 lastIns_(nullptr),
michael@0 304 pc_(pc),
michael@0 305 lir_(nullptr),
michael@0 306 start_(nullptr),
michael@0 307 entryResumePoint_(nullptr),
michael@0 308 successorWithPhis_(nullptr),
michael@0 309 positionInPhiSuccessor_(0),
michael@0 310 kind_(kind),
michael@0 311 loopDepth_(0),
michael@0 312 mark_(false),
michael@0 313 immediatelyDominated_(graph.alloc()),
michael@0 314 immediateDominator_(nullptr),
michael@0 315 numDominated_(0),
michael@0 316 trackedPc_(pc)
michael@0 317 #if defined (JS_ION_PERF)
michael@0 318 , lineno_(0u),
michael@0 319 columnIndex_(0u)
michael@0 320 #endif
michael@0 321 {
michael@0 322 }
michael@0 323
michael@0 324 bool
michael@0 325 MBasicBlock::init()
michael@0 326 {
michael@0 327 return slots_.init(graph_.alloc(), info_.nslots());
michael@0 328 }
michael@0 329
michael@0 330 bool
michael@0 331 MBasicBlock::increaseSlots(size_t num)
michael@0 332 {
michael@0 333 return slots_.growBy(graph_.alloc(), num);
michael@0 334 }
michael@0 335
michael@0 336 bool
michael@0 337 MBasicBlock::ensureHasSlots(size_t num)
michael@0 338 {
michael@0 339 size_t depth = stackDepth() + num;
michael@0 340 if (depth > nslots()) {
michael@0 341 if (!increaseSlots(depth - nslots()))
michael@0 342 return false;
michael@0 343 }
michael@0 344 return true;
michael@0 345 }
michael@0 346
michael@0 347 void
michael@0 348 MBasicBlock::copySlots(MBasicBlock *from)
michael@0 349 {
michael@0 350 JS_ASSERT(stackPosition_ <= from->stackPosition_);
michael@0 351
michael@0 352 for (uint32_t i = 0; i < stackPosition_; i++)
michael@0 353 slots_[i] = from->slots_[i];
michael@0 354 }
michael@0 355
michael@0 356 bool
michael@0 357 MBasicBlock::inherit(TempAllocator &alloc, BytecodeAnalysis *analysis, MBasicBlock *pred,
michael@0 358 uint32_t popped, unsigned stackPhiCount)
michael@0 359 {
michael@0 360 if (pred) {
michael@0 361 stackPosition_ = pred->stackPosition_;
michael@0 362 JS_ASSERT(stackPosition_ >= popped);
michael@0 363 stackPosition_ -= popped;
michael@0 364 if (kind_ != PENDING_LOOP_HEADER)
michael@0 365 copySlots(pred);
michael@0 366 } else {
michael@0 367 uint32_t stackDepth = analysis->info(pc()).stackDepth;
michael@0 368 stackPosition_ = info().firstStackSlot() + stackDepth;
michael@0 369 JS_ASSERT(stackPosition_ >= popped);
michael@0 370 stackPosition_ -= popped;
michael@0 371 }
michael@0 372
michael@0 373 JS_ASSERT(info_.nslots() >= stackPosition_);
michael@0 374 JS_ASSERT(!entryResumePoint_);
michael@0 375
michael@0 376 // Propagate the caller resume point from the inherited block.
michael@0 377 MResumePoint *callerResumePoint = pred ? pred->callerResumePoint() : nullptr;
michael@0 378
michael@0 379 // Create a resume point using our initial stack state.
michael@0 380 entryResumePoint_ = new(alloc) MResumePoint(this, pc(), callerResumePoint, MResumePoint::ResumeAt);
michael@0 381 if (!entryResumePoint_->init(alloc))
michael@0 382 return false;
michael@0 383
michael@0 384 if (pred) {
michael@0 385 if (!predecessors_.append(pred))
michael@0 386 return false;
michael@0 387
michael@0 388 if (kind_ == PENDING_LOOP_HEADER) {
michael@0 389 size_t i = 0;
michael@0 390 for (i = 0; i < info().firstStackSlot(); i++) {
michael@0 391 MPhi *phi = MPhi::New(alloc, i);
michael@0 392 if (!phi->addInputSlow(pred->getSlot(i)))
michael@0 393 return false;
michael@0 394 addPhi(phi);
michael@0 395 setSlot(i, phi);
michael@0 396 entryResumePoint()->setOperand(i, phi);
michael@0 397 }
michael@0 398
michael@0 399 JS_ASSERT(stackPhiCount <= stackDepth());
michael@0 400 JS_ASSERT(info().firstStackSlot() <= stackDepth() - stackPhiCount);
michael@0 401
michael@0 402 // Avoid creating new phis for stack values that aren't part of the
michael@0 403 // loop. Note that for loop headers that can OSR, all values on the
michael@0 404 // stack are part of the loop.
michael@0 405 for (; i < stackDepth() - stackPhiCount; i++) {
michael@0 406 MDefinition *val = pred->getSlot(i);
michael@0 407 setSlot(i, val);
michael@0 408 entryResumePoint()->setOperand(i, val);
michael@0 409 }
michael@0 410
michael@0 411 for (; i < stackDepth(); i++) {
michael@0 412 MPhi *phi = MPhi::New(alloc, i);
michael@0 413 if (!phi->addInputSlow(pred->getSlot(i)))
michael@0 414 return false;
michael@0 415 addPhi(phi);
michael@0 416 setSlot(i, phi);
michael@0 417 entryResumePoint()->setOperand(i, phi);
michael@0 418 }
michael@0 419 } else {
michael@0 420 for (size_t i = 0; i < stackDepth(); i++)
michael@0 421 entryResumePoint()->setOperand(i, getSlot(i));
michael@0 422 }
michael@0 423 } else {
michael@0 424 /*
michael@0 425 * Don't leave the operands uninitialized for the caller, as it may not
michael@0 426 * initialize them later on.
michael@0 427 */
michael@0 428 for (size_t i = 0; i < stackDepth(); i++)
michael@0 429 entryResumePoint()->clearOperand(i);
michael@0 430 }
michael@0 431
michael@0 432 return true;
michael@0 433 }
michael@0 434
michael@0 435 bool
michael@0 436 MBasicBlock::inheritResumePoint(MBasicBlock *pred)
michael@0 437 {
michael@0 438 // Copy slots from the resume point.
michael@0 439 stackPosition_ = entryResumePoint_->numOperands();
michael@0 440 for (uint32_t i = 0; i < stackPosition_; i++)
michael@0 441 slots_[i] = entryResumePoint_->getOperand(i);
michael@0 442
michael@0 443 JS_ASSERT(info_.nslots() >= stackPosition_);
michael@0 444 JS_ASSERT(kind_ != PENDING_LOOP_HEADER);
michael@0 445 JS_ASSERT(pred != nullptr);
michael@0 446
michael@0 447 if (!predecessors_.append(pred))
michael@0 448 return false;
michael@0 449
michael@0 450 return true;
michael@0 451 }
michael@0 452
michael@0 453 void
michael@0 454 MBasicBlock::inheritSlots(MBasicBlock *parent)
michael@0 455 {
michael@0 456 stackPosition_ = parent->stackPosition_;
michael@0 457 copySlots(parent);
michael@0 458 }
michael@0 459
michael@0 460 bool
michael@0 461 MBasicBlock::initEntrySlots(TempAllocator &alloc)
michael@0 462 {
michael@0 463 // Create a resume point using our initial stack state.
michael@0 464 entryResumePoint_ = MResumePoint::New(alloc, this, pc(), callerResumePoint(),
michael@0 465 MResumePoint::ResumeAt);
michael@0 466 if (!entryResumePoint_)
michael@0 467 return false;
michael@0 468 return true;
michael@0 469 }
michael@0 470
michael@0 471 MDefinition *
michael@0 472 MBasicBlock::getSlot(uint32_t index)
michael@0 473 {
michael@0 474 JS_ASSERT(index < stackPosition_);
michael@0 475 return slots_[index];
michael@0 476 }
michael@0 477
michael@0 478 void
michael@0 479 MBasicBlock::initSlot(uint32_t slot, MDefinition *ins)
michael@0 480 {
michael@0 481 slots_[slot] = ins;
michael@0 482 if (entryResumePoint())
michael@0 483 entryResumePoint()->setOperand(slot, ins);
michael@0 484 }
michael@0 485
michael@0 486 void
michael@0 487 MBasicBlock::shimmySlots(int discardDepth)
michael@0 488 {
michael@0 489 // Move all slots above the given depth down by one,
michael@0 490 // overwriting the MDefinition at discardDepth.
michael@0 491
michael@0 492 JS_ASSERT(discardDepth < 0);
michael@0 493 JS_ASSERT(stackPosition_ + discardDepth >= info_.firstStackSlot());
michael@0 494
michael@0 495 for (int i = discardDepth; i < -1; i++)
michael@0 496 slots_[stackPosition_ + i] = slots_[stackPosition_ + i + 1];
michael@0 497
michael@0 498 --stackPosition_;
michael@0 499 }
michael@0 500
michael@0 501 void
michael@0 502 MBasicBlock::linkOsrValues(MStart *start)
michael@0 503 {
michael@0 504 JS_ASSERT(start->startType() == MStart::StartType_Osr);
michael@0 505
michael@0 506 MResumePoint *res = start->resumePoint();
michael@0 507
michael@0 508 for (uint32_t i = 0; i < stackDepth(); i++) {
michael@0 509 MDefinition *def = slots_[i];
michael@0 510 if (i == info().scopeChainSlot()) {
michael@0 511 if (def->isOsrScopeChain())
michael@0 512 def->toOsrScopeChain()->setResumePoint(res);
michael@0 513 } else if (i == info().returnValueSlot()) {
michael@0 514 if (def->isOsrReturnValue())
michael@0 515 def->toOsrReturnValue()->setResumePoint(res);
michael@0 516 } else if (info().hasArguments() && i == info().argsObjSlot()) {
michael@0 517 JS_ASSERT(def->isConstant() || def->isOsrArgumentsObject());
michael@0 518 JS_ASSERT_IF(def->isConstant(), def->toConstant()->value() == UndefinedValue());
michael@0 519 if (def->isOsrArgumentsObject())
michael@0 520 def->toOsrArgumentsObject()->setResumePoint(res);
michael@0 521 } else {
michael@0 522 JS_ASSERT(def->isOsrValue() || def->isGetArgumentsObjectArg() || def->isConstant() ||
michael@0 523 def->isParameter());
michael@0 524
michael@0 525 // A constant Undefined can show up here for an argument slot when the function uses
michael@0 526 // a heavyweight argsobj, but the argument in question is stored on the scope chain.
michael@0 527 JS_ASSERT_IF(def->isConstant(), def->toConstant()->value() == UndefinedValue());
michael@0 528
michael@0 529 if (def->isOsrValue())
michael@0 530 def->toOsrValue()->setResumePoint(res);
michael@0 531 else if (def->isGetArgumentsObjectArg())
michael@0 532 def->toGetArgumentsObjectArg()->setResumePoint(res);
michael@0 533 else if (def->isParameter())
michael@0 534 def->toParameter()->setResumePoint(res);
michael@0 535 }
michael@0 536 }
michael@0 537 }
michael@0 538
michael@0 539 void
michael@0 540 MBasicBlock::setSlot(uint32_t slot, MDefinition *ins)
michael@0 541 {
michael@0 542 slots_[slot] = ins;
michael@0 543 }
michael@0 544
michael@0 545 void
michael@0 546 MBasicBlock::setVariable(uint32_t index)
michael@0 547 {
michael@0 548 JS_ASSERT(stackPosition_ > info_.firstStackSlot());
michael@0 549 setSlot(index, slots_[stackPosition_ - 1]);
michael@0 550 }
michael@0 551
michael@0 552 void
michael@0 553 MBasicBlock::setArg(uint32_t arg)
michael@0 554 {
michael@0 555 setVariable(info_.argSlot(arg));
michael@0 556 }
michael@0 557
michael@0 558 void
michael@0 559 MBasicBlock::setLocal(uint32_t local)
michael@0 560 {
michael@0 561 setVariable(info_.localSlot(local));
michael@0 562 }
michael@0 563
michael@0 564 void
michael@0 565 MBasicBlock::setSlot(uint32_t slot)
michael@0 566 {
michael@0 567 setVariable(slot);
michael@0 568 }
michael@0 569
michael@0 570 void
michael@0 571 MBasicBlock::rewriteSlot(uint32_t slot, MDefinition *ins)
michael@0 572 {
michael@0 573 setSlot(slot, ins);
michael@0 574 }
michael@0 575
michael@0 576 void
michael@0 577 MBasicBlock::rewriteAtDepth(int32_t depth, MDefinition *ins)
michael@0 578 {
michael@0 579 JS_ASSERT(depth < 0);
michael@0 580 JS_ASSERT(stackPosition_ + depth >= info_.firstStackSlot());
michael@0 581 rewriteSlot(stackPosition_ + depth, ins);
michael@0 582 }
michael@0 583
michael@0 584 void
michael@0 585 MBasicBlock::push(MDefinition *ins)
michael@0 586 {
michael@0 587 JS_ASSERT(stackPosition_ < nslots());
michael@0 588 slots_[stackPosition_++] = ins;
michael@0 589 }
michael@0 590
michael@0 591 void
michael@0 592 MBasicBlock::pushVariable(uint32_t slot)
michael@0 593 {
michael@0 594 push(slots_[slot]);
michael@0 595 }
michael@0 596
michael@0 597 void
michael@0 598 MBasicBlock::pushArg(uint32_t arg)
michael@0 599 {
michael@0 600 pushVariable(info_.argSlot(arg));
michael@0 601 }
michael@0 602
michael@0 603 void
michael@0 604 MBasicBlock::pushLocal(uint32_t local)
michael@0 605 {
michael@0 606 pushVariable(info_.localSlot(local));
michael@0 607 }
michael@0 608
michael@0 609 void
michael@0 610 MBasicBlock::pushSlot(uint32_t slot)
michael@0 611 {
michael@0 612 pushVariable(slot);
michael@0 613 }
michael@0 614
michael@0 615 MDefinition *
michael@0 616 MBasicBlock::pop()
michael@0 617 {
michael@0 618 JS_ASSERT(stackPosition_ > info_.firstStackSlot());
michael@0 619 return slots_[--stackPosition_];
michael@0 620 }
michael@0 621
michael@0 622 void
michael@0 623 MBasicBlock::popn(uint32_t n)
michael@0 624 {
michael@0 625 JS_ASSERT(stackPosition_ - n >= info_.firstStackSlot());
michael@0 626 JS_ASSERT(stackPosition_ >= stackPosition_ - n);
michael@0 627 stackPosition_ -= n;
michael@0 628 }
michael@0 629
michael@0 630 MDefinition *
michael@0 631 MBasicBlock::scopeChain()
michael@0 632 {
michael@0 633 return getSlot(info().scopeChainSlot());
michael@0 634 }
michael@0 635
michael@0 636 MDefinition *
michael@0 637 MBasicBlock::argumentsObject()
michael@0 638 {
michael@0 639 return getSlot(info().argsObjSlot());
michael@0 640 }
michael@0 641
michael@0 642 void
michael@0 643 MBasicBlock::setScopeChain(MDefinition *scopeObj)
michael@0 644 {
michael@0 645 setSlot(info().scopeChainSlot(), scopeObj);
michael@0 646 }
michael@0 647
michael@0 648 void
michael@0 649 MBasicBlock::setArgumentsObject(MDefinition *argsObj)
michael@0 650 {
michael@0 651 setSlot(info().argsObjSlot(), argsObj);
michael@0 652 }
michael@0 653
michael@0 654 void
michael@0 655 MBasicBlock::pick(int32_t depth)
michael@0 656 {
michael@0 657 // pick take an element and move it to the top.
michael@0 658 // pick(-2):
michael@0 659 // A B C D E
michael@0 660 // A B D C E [ swapAt(-2) ]
michael@0 661 // A B D E C [ swapAt(-1) ]
michael@0 662 for (; depth < 0; depth++)
michael@0 663 swapAt(depth);
michael@0 664 }
michael@0 665
michael@0 666 void
michael@0 667 MBasicBlock::swapAt(int32_t depth)
michael@0 668 {
michael@0 669 uint32_t lhsDepth = stackPosition_ + depth - 1;
michael@0 670 uint32_t rhsDepth = stackPosition_ + depth;
michael@0 671
michael@0 672 MDefinition *temp = slots_[lhsDepth];
michael@0 673 slots_[lhsDepth] = slots_[rhsDepth];
michael@0 674 slots_[rhsDepth] = temp;
michael@0 675 }
michael@0 676
michael@0 677 MDefinition *
michael@0 678 MBasicBlock::peek(int32_t depth)
michael@0 679 {
michael@0 680 JS_ASSERT(depth < 0);
michael@0 681 JS_ASSERT(stackPosition_ + depth >= info_.firstStackSlot());
michael@0 682 return getSlot(stackPosition_ + depth);
michael@0 683 }
michael@0 684
michael@0 685 void
michael@0 686 MBasicBlock::discardLastIns()
michael@0 687 {
michael@0 688 JS_ASSERT(lastIns_);
michael@0 689 discard(lastIns_);
michael@0 690 lastIns_ = nullptr;
michael@0 691 }
michael@0 692
michael@0 693 void
michael@0 694 MBasicBlock::addFromElsewhere(MInstruction *ins)
michael@0 695 {
michael@0 696 JS_ASSERT(ins->block() != this);
michael@0 697
michael@0 698 // Remove |ins| from its containing block.
michael@0 699 ins->block()->instructions_.remove(ins);
michael@0 700
michael@0 701 // Add it to this block.
michael@0 702 add(ins);
michael@0 703 }
michael@0 704
michael@0 705 void
michael@0 706 MBasicBlock::moveBefore(MInstruction *at, MInstruction *ins)
michael@0 707 {
michael@0 708 // Remove |ins| from the current block.
michael@0 709 JS_ASSERT(ins->block() == this);
michael@0 710 instructions_.remove(ins);
michael@0 711
michael@0 712 // Insert into new block, which may be distinct.
michael@0 713 // Uses and operands are untouched.
michael@0 714 at->block()->insertBefore(at, ins);
michael@0 715 }
michael@0 716
michael@0 717 static inline void
michael@0 718 AssertSafelyDiscardable(MDefinition *def)
michael@0 719 {
michael@0 720 #ifdef DEBUG
michael@0 721 // Instructions captured by resume points cannot be safely discarded, since
michael@0 722 // they are necessary for interpreter frame reconstruction in case of bailout.
michael@0 723 JS_ASSERT(!def->hasUses());
michael@0 724 #endif
michael@0 725 }
michael@0 726
michael@0 727 void
michael@0 728 MBasicBlock::discard(MInstruction *ins)
michael@0 729 {
michael@0 730 AssertSafelyDiscardable(ins);
michael@0 731 for (size_t i = 0, e = ins->numOperands(); i < e; i++)
michael@0 732 ins->discardOperand(i);
michael@0 733
michael@0 734 instructions_.remove(ins);
michael@0 735 }
michael@0 736
michael@0 737 MInstructionIterator
michael@0 738 MBasicBlock::discardAt(MInstructionIterator &iter)
michael@0 739 {
michael@0 740 AssertSafelyDiscardable(*iter);
michael@0 741 for (size_t i = 0, e = iter->numOperands(); i < e; i++)
michael@0 742 iter->discardOperand(i);
michael@0 743
michael@0 744 return instructions_.removeAt(iter);
michael@0 745 }
michael@0 746
michael@0 747 MInstructionReverseIterator
michael@0 748 MBasicBlock::discardAt(MInstructionReverseIterator &iter)
michael@0 749 {
michael@0 750 AssertSafelyDiscardable(*iter);
michael@0 751 for (size_t i = 0, e = iter->numOperands(); i < e; i++)
michael@0 752 iter->discardOperand(i);
michael@0 753
michael@0 754 return instructions_.removeAt(iter);
michael@0 755 }
michael@0 756
michael@0 757 MDefinitionIterator
michael@0 758 MBasicBlock::discardDefAt(MDefinitionIterator &old)
michael@0 759 {
michael@0 760 MDefinitionIterator iter(old);
michael@0 761
michael@0 762 if (iter.atPhi())
michael@0 763 iter.phiIter_ = iter.block_->discardPhiAt(iter.phiIter_);
michael@0 764 else
michael@0 765 iter.iter_ = iter.block_->discardAt(iter.iter_);
michael@0 766
michael@0 767 return iter;
michael@0 768 }
michael@0 769
michael@0 770 void
michael@0 771 MBasicBlock::discardAllInstructions()
michael@0 772 {
michael@0 773 for (MInstructionIterator iter = begin(); iter != end(); ) {
michael@0 774 for (size_t i = 0, e = iter->numOperands(); i < e; i++)
michael@0 775 iter->discardOperand(i);
michael@0 776 iter = instructions_.removeAt(iter);
michael@0 777 }
michael@0 778 lastIns_ = nullptr;
michael@0 779 }
michael@0 780
michael@0 781 void
michael@0 782 MBasicBlock::discardAllPhiOperands()
michael@0 783 {
michael@0 784 for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) {
michael@0 785 MPhi *phi = *iter;
michael@0 786 for (size_t i = 0, e = phi->numOperands(); i < e; i++)
michael@0 787 phi->discardOperand(i);
michael@0 788 }
michael@0 789
michael@0 790 for (MBasicBlock **pred = predecessors_.begin(); pred != predecessors_.end(); pred++)
michael@0 791 (*pred)->setSuccessorWithPhis(nullptr, 0);
michael@0 792 }
michael@0 793
michael@0 794 void
michael@0 795 MBasicBlock::discardAllPhis()
michael@0 796 {
michael@0 797 discardAllPhiOperands();
michael@0 798 phis_.clear();
michael@0 799 }
michael@0 800
michael@0 801 void
michael@0 802 MBasicBlock::discardAllResumePoints(bool discardEntry)
michael@0 803 {
michael@0 804 for (MResumePointIterator iter = resumePointsBegin(); iter != resumePointsEnd(); ) {
michael@0 805 MResumePoint *rp = *iter;
michael@0 806 if (rp == entryResumePoint() && !discardEntry) {
michael@0 807 iter++;
michael@0 808 } else {
michael@0 809 rp->discardUses();
michael@0 810 iter = resumePoints_.removeAt(iter);
michael@0 811 }
michael@0 812 }
michael@0 813 }
michael@0 814
michael@0 815 void
michael@0 816 MBasicBlock::insertBefore(MInstruction *at, MInstruction *ins)
michael@0 817 {
michael@0 818 JS_ASSERT(at->block() == this);
michael@0 819 ins->setBlock(this);
michael@0 820 graph().allocDefinitionId(ins);
michael@0 821 instructions_.insertBefore(at, ins);
michael@0 822 ins->setTrackedPc(at->trackedPc());
michael@0 823 }
michael@0 824
michael@0 825 void
michael@0 826 MBasicBlock::insertAfter(MInstruction *at, MInstruction *ins)
michael@0 827 {
michael@0 828 JS_ASSERT(at->block() == this);
michael@0 829 ins->setBlock(this);
michael@0 830 graph().allocDefinitionId(ins);
michael@0 831 instructions_.insertAfter(at, ins);
michael@0 832 ins->setTrackedPc(at->trackedPc());
michael@0 833 }
michael@0 834
michael@0 835 void
michael@0 836 MBasicBlock::add(MInstruction *ins)
michael@0 837 {
michael@0 838 JS_ASSERT(!lastIns_);
michael@0 839 ins->setBlock(this);
michael@0 840 graph().allocDefinitionId(ins);
michael@0 841 instructions_.pushBack(ins);
michael@0 842 ins->setTrackedPc(trackedPc_);
michael@0 843 }
michael@0 844
michael@0 845 void
michael@0 846 MBasicBlock::end(MControlInstruction *ins)
michael@0 847 {
michael@0 848 JS_ASSERT(!lastIns_); // Existing control instructions should be removed first.
michael@0 849 JS_ASSERT(ins);
michael@0 850 add(ins);
michael@0 851 lastIns_ = ins;
michael@0 852 }
michael@0 853
michael@0 854 void
michael@0 855 MBasicBlock::addPhi(MPhi *phi)
michael@0 856 {
michael@0 857 phis_.pushBack(phi);
michael@0 858 phi->setBlock(this);
michael@0 859 graph().allocDefinitionId(phi);
michael@0 860 }
michael@0 861
michael@0 862 MPhiIterator
michael@0 863 MBasicBlock::discardPhiAt(MPhiIterator &at)
michael@0 864 {
michael@0 865 JS_ASSERT(!phis_.empty());
michael@0 866
michael@0 867 for (size_t i = 0, e = at->numOperands(); i < e; i++)
michael@0 868 at->discardOperand(i);
michael@0 869
michael@0 870 MPhiIterator result = phis_.removeAt(at);
michael@0 871
michael@0 872 if (phis_.empty()) {
michael@0 873 for (MBasicBlock **pred = predecessors_.begin(); pred != predecessors_.end(); pred++)
michael@0 874 (*pred)->setSuccessorWithPhis(nullptr, 0);
michael@0 875 }
michael@0 876 return result;
michael@0 877 }
michael@0 878
michael@0 879 bool
michael@0 880 MBasicBlock::addPredecessor(TempAllocator &alloc, MBasicBlock *pred)
michael@0 881 {
michael@0 882 return addPredecessorPopN(alloc, pred, 0);
michael@0 883 }
michael@0 884
michael@0 885 bool
michael@0 886 MBasicBlock::addPredecessorPopN(TempAllocator &alloc, MBasicBlock *pred, uint32_t popped)
michael@0 887 {
michael@0 888 JS_ASSERT(pred);
michael@0 889 JS_ASSERT(predecessors_.length() > 0);
michael@0 890
michael@0 891 // Predecessors must be finished, and at the correct stack depth.
michael@0 892 JS_ASSERT(pred->lastIns_);
michael@0 893 JS_ASSERT(pred->stackPosition_ == stackPosition_ + popped);
michael@0 894
michael@0 895 for (uint32_t i = 0; i < stackPosition_; i++) {
michael@0 896 MDefinition *mine = getSlot(i);
michael@0 897 MDefinition *other = pred->getSlot(i);
michael@0 898
michael@0 899 if (mine != other) {
michael@0 900 // If the current instruction is a phi, and it was created in this
michael@0 901 // basic block, then we have already placed this phi and should
michael@0 902 // instead append to its operands.
michael@0 903 if (mine->isPhi() && mine->block() == this) {
michael@0 904 JS_ASSERT(predecessors_.length());
michael@0 905 if (!mine->toPhi()->addInputSlow(other))
michael@0 906 return false;
michael@0 907 } else {
michael@0 908 // Otherwise, create a new phi node.
michael@0 909 MPhi *phi;
michael@0 910 if (mine->type() == other->type())
michael@0 911 phi = MPhi::New(alloc, i, mine->type());
michael@0 912 else
michael@0 913 phi = MPhi::New(alloc, i);
michael@0 914 addPhi(phi);
michael@0 915
michael@0 916 // Prime the phi for each predecessor, so input(x) comes from
michael@0 917 // predecessor(x).
michael@0 918 if (!phi->reserveLength(predecessors_.length() + 1))
michael@0 919 return false;
michael@0 920
michael@0 921 for (size_t j = 0; j < predecessors_.length(); j++) {
michael@0 922 JS_ASSERT(predecessors_[j]->getSlot(i) == mine);
michael@0 923 phi->addInput(mine);
michael@0 924 }
michael@0 925 phi->addInput(other);
michael@0 926
michael@0 927 setSlot(i, phi);
michael@0 928 if (entryResumePoint())
michael@0 929 entryResumePoint()->replaceOperand(i, phi);
michael@0 930 }
michael@0 931 }
michael@0 932 }
michael@0 933
michael@0 934 return predecessors_.append(pred);
michael@0 935 }
michael@0 936
michael@0 937 bool
michael@0 938 MBasicBlock::addPredecessorWithoutPhis(MBasicBlock *pred)
michael@0 939 {
michael@0 940 // Predecessors must be finished.
michael@0 941 JS_ASSERT(pred && pred->lastIns_);
michael@0 942 return predecessors_.append(pred);
michael@0 943 }
michael@0 944
michael@0 945 bool
michael@0 946 MBasicBlock::addImmediatelyDominatedBlock(MBasicBlock *child)
michael@0 947 {
michael@0 948 return immediatelyDominated_.append(child);
michael@0 949 }
michael@0 950
michael@0 951 void
michael@0 952 MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end)
michael@0 953 {
michael@0 954 #ifdef DEBUG
michael@0 955 for (; use != end; use++) {
michael@0 956 JS_ASSERT_IF(use->consumer()->isDefinition(),
michael@0 957 use->consumer()->toDefinition()->block()->id() < id());
michael@0 958 }
michael@0 959 #endif
michael@0 960 }
michael@0 961
michael@0 962 bool
michael@0 963 MBasicBlock::dominates(const MBasicBlock *other) const
michael@0 964 {
michael@0 965 uint32_t high = domIndex() + numDominated();
michael@0 966 uint32_t low = domIndex();
michael@0 967 return other->domIndex() >= low && other->domIndex() <= high;
michael@0 968 }
michael@0 969
michael@0 970 void
michael@0 971 MBasicBlock::setUnreachable()
michael@0 972 {
michael@0 973 unreachable_ = true;
michael@0 974 size_t numDom = numImmediatelyDominatedBlocks();
michael@0 975 for (size_t d = 0; d < numDom; d++)
michael@0 976 getImmediatelyDominatedBlock(d)->unreachable_ = true;
michael@0 977 }
michael@0 978
michael@0 979 AbortReason
michael@0 980 MBasicBlock::setBackedge(MBasicBlock *pred)
michael@0 981 {
michael@0 982 // Predecessors must be finished, and at the correct stack depth.
michael@0 983 JS_ASSERT(lastIns_);
michael@0 984 JS_ASSERT(pred->lastIns_);
michael@0 985 JS_ASSERT(pred->stackDepth() == entryResumePoint()->stackDepth());
michael@0 986
michael@0 987 // We must be a pending loop header
michael@0 988 JS_ASSERT(kind_ == PENDING_LOOP_HEADER);
michael@0 989
michael@0 990 bool hadTypeChange = false;
michael@0 991
michael@0 992 // Add exit definitions to each corresponding phi at the entry.
michael@0 993 for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++) {
michael@0 994 MPhi *entryDef = *phi;
michael@0 995 MDefinition *exitDef = pred->slots_[entryDef->slot()];
michael@0 996
michael@0 997 // Assert that we already placed phis for each slot.
michael@0 998 JS_ASSERT(entryDef->block() == this);
michael@0 999
michael@0 1000 if (entryDef == exitDef) {
michael@0 1001 // If the exit def is the same as the entry def, make a redundant
michael@0 1002 // phi. Since loop headers have exactly two incoming edges, we
michael@0 1003 // know that that's just the first input.
michael@0 1004 //
michael@0 1005 // Note that we eliminate later rather than now, to avoid any
michael@0 1006 // weirdness around pending continue edges which might still hold
michael@0 1007 // onto phis.
michael@0 1008 exitDef = entryDef->getOperand(0);
michael@0 1009 }
michael@0 1010
michael@0 1011 bool typeChange = false;
michael@0 1012
michael@0 1013 if (!entryDef->addInputSlow(exitDef, &typeChange))
michael@0 1014 return AbortReason_Alloc;
michael@0 1015
michael@0 1016 hadTypeChange |= typeChange;
michael@0 1017
michael@0 1018 JS_ASSERT(entryDef->slot() < pred->stackDepth());
michael@0 1019 setSlot(entryDef->slot(), entryDef);
michael@0 1020 }
michael@0 1021
michael@0 1022 if (hadTypeChange) {
michael@0 1023 for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++)
michael@0 1024 phi->removeOperand(phi->numOperands() - 1);
michael@0 1025 return AbortReason_Disable;
michael@0 1026 }
michael@0 1027
michael@0 1028 // We are now a loop header proper
michael@0 1029 kind_ = LOOP_HEADER;
michael@0 1030
michael@0 1031 if (!predecessors_.append(pred))
michael@0 1032 return AbortReason_Alloc;
michael@0 1033
michael@0 1034 return AbortReason_NoAbort;
michael@0 1035 }
michael@0 1036
michael@0 1037 bool
michael@0 1038 MBasicBlock::setBackedgeAsmJS(MBasicBlock *pred)
michael@0 1039 {
michael@0 1040 // Predecessors must be finished, and at the correct stack depth.
michael@0 1041 JS_ASSERT(lastIns_);
michael@0 1042 JS_ASSERT(pred->lastIns_);
michael@0 1043 JS_ASSERT(stackDepth() == pred->stackDepth());
michael@0 1044
michael@0 1045 // We must be a pending loop header
michael@0 1046 JS_ASSERT(kind_ == PENDING_LOOP_HEADER);
michael@0 1047
michael@0 1048 // Add exit definitions to each corresponding phi at the entry.
michael@0 1049 for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++) {
michael@0 1050 MPhi *entryDef = *phi;
michael@0 1051 MDefinition *exitDef = pred->getSlot(entryDef->slot());
michael@0 1052
michael@0 1053 // Assert that we already placed phis for each slot.
michael@0 1054 JS_ASSERT(entryDef->block() == this);
michael@0 1055
michael@0 1056 // Assert that the phi already has the correct type.
michael@0 1057 JS_ASSERT(entryDef->type() == exitDef->type());
michael@0 1058 JS_ASSERT(entryDef->type() != MIRType_Value);
michael@0 1059
michael@0 1060 if (entryDef == exitDef) {
michael@0 1061 // If the exit def is the same as the entry def, make a redundant
michael@0 1062 // phi. Since loop headers have exactly two incoming edges, we
michael@0 1063 // know that that's just the first input.
michael@0 1064 //
michael@0 1065 // Note that we eliminate later rather than now, to avoid any
michael@0 1066 // weirdness around pending continue edges which might still hold
michael@0 1067 // onto phis.
michael@0 1068 exitDef = entryDef->getOperand(0);
michael@0 1069 }
michael@0 1070
michael@0 1071 // MBasicBlock::NewAsmJS calls reserveLength(2) for loop header phis.
michael@0 1072 entryDef->addInput(exitDef);
michael@0 1073
michael@0 1074 JS_ASSERT(entryDef->slot() < pred->stackDepth());
michael@0 1075 setSlot(entryDef->slot(), entryDef);
michael@0 1076 }
michael@0 1077
michael@0 1078 // We are now a loop header proper
michael@0 1079 kind_ = LOOP_HEADER;
michael@0 1080
michael@0 1081 return predecessors_.append(pred);
michael@0 1082 }
michael@0 1083
michael@0 1084 void
michael@0 1085 MBasicBlock::clearLoopHeader()
michael@0 1086 {
michael@0 1087 JS_ASSERT(isLoopHeader());
michael@0 1088 kind_ = NORMAL;
michael@0 1089 }
michael@0 1090
michael@0 1091 size_t
michael@0 1092 MBasicBlock::numSuccessors() const
michael@0 1093 {
michael@0 1094 JS_ASSERT(lastIns());
michael@0 1095 return lastIns()->numSuccessors();
michael@0 1096 }
michael@0 1097
michael@0 1098 MBasicBlock *
michael@0 1099 MBasicBlock::getSuccessor(size_t index) const
michael@0 1100 {
michael@0 1101 JS_ASSERT(lastIns());
michael@0 1102 return lastIns()->getSuccessor(index);
michael@0 1103 }
michael@0 1104
michael@0 1105 size_t
michael@0 1106 MBasicBlock::getSuccessorIndex(MBasicBlock *block) const
michael@0 1107 {
michael@0 1108 JS_ASSERT(lastIns());
michael@0 1109 for (size_t i = 0; i < numSuccessors(); i++) {
michael@0 1110 if (getSuccessor(i) == block)
michael@0 1111 return i;
michael@0 1112 }
michael@0 1113 MOZ_ASSUME_UNREACHABLE("Invalid successor");
michael@0 1114 }
michael@0 1115
michael@0 1116 void
michael@0 1117 MBasicBlock::replaceSuccessor(size_t pos, MBasicBlock *split)
michael@0 1118 {
michael@0 1119 JS_ASSERT(lastIns());
michael@0 1120
michael@0 1121 // Note, during split-critical-edges, successors-with-phis is not yet set.
michael@0 1122 // During PAA, this case is handled before we enter.
michael@0 1123 JS_ASSERT_IF(successorWithPhis_, successorWithPhis_ != getSuccessor(pos));
michael@0 1124
michael@0 1125 lastIns()->replaceSuccessor(pos, split);
michael@0 1126 }
michael@0 1127
michael@0 1128 void
michael@0 1129 MBasicBlock::replacePredecessor(MBasicBlock *old, MBasicBlock *split)
michael@0 1130 {
michael@0 1131 for (size_t i = 0; i < numPredecessors(); i++) {
michael@0 1132 if (getPredecessor(i) == old) {
michael@0 1133 predecessors_[i] = split;
michael@0 1134
michael@0 1135 #ifdef DEBUG
michael@0 1136 // The same block should not appear twice in the predecessor list.
michael@0 1137 for (size_t j = i; j < numPredecessors(); j++)
michael@0 1138 JS_ASSERT(predecessors_[j] != old);
michael@0 1139 #endif
michael@0 1140
michael@0 1141 return;
michael@0 1142 }
michael@0 1143 }
michael@0 1144
michael@0 1145 MOZ_ASSUME_UNREACHABLE("predecessor was not found");
michael@0 1146 }
michael@0 1147
michael@0 1148 void
michael@0 1149 MBasicBlock::clearDominatorInfo()
michael@0 1150 {
michael@0 1151 setImmediateDominator(nullptr);
michael@0 1152 immediatelyDominated_.clear();
michael@0 1153 numDominated_ = 0;
michael@0 1154 }
michael@0 1155
michael@0 1156 void
michael@0 1157 MBasicBlock::removePredecessor(MBasicBlock *pred)
michael@0 1158 {
michael@0 1159 JS_ASSERT(numPredecessors() >= 2);
michael@0 1160
michael@0 1161 for (size_t i = 0; i < numPredecessors(); i++) {
michael@0 1162 if (getPredecessor(i) != pred)
michael@0 1163 continue;
michael@0 1164
michael@0 1165 // Adjust phis. Note that this can leave redundant phis
michael@0 1166 // behind.
michael@0 1167 if (!phisEmpty()) {
michael@0 1168 JS_ASSERT(pred->successorWithPhis());
michael@0 1169 JS_ASSERT(pred->positionInPhiSuccessor() == i);
michael@0 1170 for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++)
michael@0 1171 iter->removeOperand(i);
michael@0 1172 for (size_t j = i+1; j < numPredecessors(); j++)
michael@0 1173 getPredecessor(j)->setSuccessorWithPhis(this, j - 1);
michael@0 1174 }
michael@0 1175
michael@0 1176 // Remove from pred list.
michael@0 1177 MBasicBlock **ptr = predecessors_.begin() + i;
michael@0 1178 predecessors_.erase(ptr);
michael@0 1179 return;
michael@0 1180 }
michael@0 1181
michael@0 1182 MOZ_ASSUME_UNREACHABLE("predecessor was not found");
michael@0 1183 }
michael@0 1184
michael@0 1185 void
michael@0 1186 MBasicBlock::inheritPhis(MBasicBlock *header)
michael@0 1187 {
michael@0 1188 for (MPhiIterator iter = header->phisBegin(); iter != header->phisEnd(); iter++) {
michael@0 1189 MPhi *phi = *iter;
michael@0 1190 JS_ASSERT(phi->numOperands() == 2);
michael@0 1191
michael@0 1192 // The entry definition is always the leftmost input to the phi.
michael@0 1193 MDefinition *entryDef = phi->getOperand(0);
michael@0 1194 MDefinition *exitDef = getSlot(phi->slot());
michael@0 1195
michael@0 1196 if (entryDef != exitDef)
michael@0 1197 continue;
michael@0 1198
michael@0 1199 // If the entryDef is the same as exitDef, then we must propagate the
michael@0 1200 // phi down to this successor. This chance was missed as part of
michael@0 1201 // setBackedge() because exits are not captured in resume points.
michael@0 1202 setSlot(phi->slot(), phi);
michael@0 1203 }
michael@0 1204 }
michael@0 1205
michael@0 1206 bool
michael@0 1207 MBasicBlock::specializePhis()
michael@0 1208 {
michael@0 1209 for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) {
michael@0 1210 MPhi *phi = *iter;
michael@0 1211 if (!phi->specializeType())
michael@0 1212 return false;
michael@0 1213 }
michael@0 1214 return true;
michael@0 1215 }
michael@0 1216
michael@0 1217 void
michael@0 1218 MBasicBlock::dumpStack(FILE *fp)
michael@0 1219 {
michael@0 1220 #ifdef DEBUG
michael@0 1221 fprintf(fp, " %-3s %-16s %-6s %-10s\n", "#", "name", "copyOf", "first/next");
michael@0 1222 fprintf(fp, "-------------------------------------------\n");
michael@0 1223 for (uint32_t i = 0; i < stackPosition_; i++) {
michael@0 1224 fprintf(fp, " %-3d", i);
michael@0 1225 fprintf(fp, " %-16p\n", (void *)slots_[i]);
michael@0 1226 }
michael@0 1227 #endif
michael@0 1228 }
michael@0 1229
michael@0 1230 MTest *
michael@0 1231 MBasicBlock::immediateDominatorBranch(BranchDirection *pdirection)
michael@0 1232 {
michael@0 1233 *pdirection = FALSE_BRANCH;
michael@0 1234
michael@0 1235 if (numPredecessors() != 1)
michael@0 1236 return nullptr;
michael@0 1237
michael@0 1238 MBasicBlock *dom = immediateDominator();
michael@0 1239 if (dom != getPredecessor(0))
michael@0 1240 return nullptr;
michael@0 1241
michael@0 1242 // Look for a trailing MTest branching to this block.
michael@0 1243 MInstruction *ins = dom->lastIns();
michael@0 1244 if (ins->isTest()) {
michael@0 1245 MTest *test = ins->toTest();
michael@0 1246
michael@0 1247 JS_ASSERT(test->ifTrue() == this || test->ifFalse() == this);
michael@0 1248 if (test->ifTrue() == this && test->ifFalse() == this)
michael@0 1249 return nullptr;
michael@0 1250
michael@0 1251 *pdirection = (test->ifTrue() == this) ? TRUE_BRANCH : FALSE_BRANCH;
michael@0 1252 return test;
michael@0 1253 }
michael@0 1254
michael@0 1255 return nullptr;
michael@0 1256 }
michael@0 1257
michael@0 1258 void
michael@0 1259 MIRGraph::dump(FILE *fp)
michael@0 1260 {
michael@0 1261 #ifdef DEBUG
michael@0 1262 for (MBasicBlockIterator iter(begin()); iter != end(); iter++) {
michael@0 1263 fprintf(fp, "block%d:\n", iter->id());
michael@0 1264 iter->dump(fp);
michael@0 1265 fprintf(fp, "\n");
michael@0 1266 }
michael@0 1267 #endif
michael@0 1268 }
michael@0 1269
michael@0 1270 void
michael@0 1271 MIRGraph::dump()
michael@0 1272 {
michael@0 1273 dump(stderr);
michael@0 1274 }
michael@0 1275
michael@0 1276 void
michael@0 1277 MBasicBlock::dump(FILE *fp)
michael@0 1278 {
michael@0 1279 #ifdef DEBUG
michael@0 1280 for (MPhiIterator iter(phisBegin()); iter != phisEnd(); iter++) {
michael@0 1281 iter->dump(fp);
michael@0 1282 }
michael@0 1283 for (MInstructionIterator iter(begin()); iter != end(); iter++) {
michael@0 1284 iter->dump(fp);
michael@0 1285 }
michael@0 1286 #endif
michael@0 1287 }
michael@0 1288
michael@0 1289 void
michael@0 1290 MBasicBlock::dump()
michael@0 1291 {
michael@0 1292 dump(stderr);
michael@0 1293 }

mercurial