1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/MIRGraph.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1293 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jit/MIRGraph.h" 1.11 + 1.12 +#include "jit/AsmJS.h" 1.13 +#include "jit/BytecodeAnalysis.h" 1.14 +#include "jit/Ion.h" 1.15 +#include "jit/IonSpewer.h" 1.16 +#include "jit/MIR.h" 1.17 +#include "jit/MIRGenerator.h" 1.18 + 1.19 +using namespace js; 1.20 +using namespace js::jit; 1.21 + 1.22 +MIRGenerator::MIRGenerator(CompileCompartment *compartment, const JitCompileOptions &options, 1.23 + TempAllocator *alloc, MIRGraph *graph, CompileInfo *info, 1.24 + const OptimizationInfo *optimizationInfo) 1.25 + : compartment(compartment), 1.26 + info_(info), 1.27 + optimizationInfo_(optimizationInfo), 1.28 + alloc_(alloc), 1.29 + graph_(graph), 1.30 + error_(false), 1.31 + cancelBuild_(false), 1.32 + maxAsmJSStackArgBytes_(0), 1.33 + performsCall_(false), 1.34 + performsAsmJSCall_(false), 1.35 + minAsmJSHeapLength_(AsmJSAllocationGranularity), 1.36 + modifiesFrameArguments_(false), 1.37 + options(options) 1.38 +{ } 1.39 + 1.40 +bool 1.41 +MIRGenerator::abortFmt(const char *message, va_list ap) 1.42 +{ 1.43 + IonSpewVA(IonSpew_Abort, message, ap); 1.44 + error_ = true; 1.45 + return false; 1.46 +} 1.47 + 1.48 +bool 1.49 +MIRGenerator::abort(const char *message, ...) 1.50 +{ 1.51 + va_list ap; 1.52 + va_start(ap, message); 1.53 + abortFmt(message, ap); 1.54 + va_end(ap); 1.55 + return false; 1.56 +} 1.57 + 1.58 +void 1.59 +MIRGraph::addBlock(MBasicBlock *block) 1.60 +{ 1.61 + JS_ASSERT(block); 1.62 + block->setId(blockIdGen_++); 1.63 + blocks_.pushBack(block); 1.64 + numBlocks_++; 1.65 +} 1.66 + 1.67 +void 1.68 +MIRGraph::insertBlockAfter(MBasicBlock *at, MBasicBlock *block) 1.69 +{ 1.70 + block->setId(blockIdGen_++); 1.71 + blocks_.insertAfter(at, block); 1.72 + numBlocks_++; 1.73 +} 1.74 + 1.75 +void 1.76 +MIRGraph::removeBlocksAfter(MBasicBlock *start) 1.77 +{ 1.78 + MBasicBlockIterator iter(begin()); 1.79 + iter++; 1.80 + while (iter != end()) { 1.81 + MBasicBlock *block = *iter; 1.82 + iter++; 1.83 + 1.84 + if (block->id() <= start->id()) 1.85 + continue; 1.86 + 1.87 + // removeBlock will not remove the resumepoints, since 1.88 + // it can be shared with outer blocks. So remove them now. 1.89 + block->discardAllResumePoints(); 1.90 + removeBlock(block); 1.91 + } 1.92 +} 1.93 + 1.94 +void 1.95 +MIRGraph::removeBlock(MBasicBlock *block) 1.96 +{ 1.97 + // Remove a block from the graph. It will also cleanup the block, 1.98 + // except for removing the resumepoints, since multiple blocks can 1.99 + // share the same resumepoints and we cannot distinguish between them. 1.100 + 1.101 + if (block == osrBlock_) 1.102 + osrBlock_ = nullptr; 1.103 + 1.104 + if (returnAccumulator_) { 1.105 + size_t i = 0; 1.106 + while (i < returnAccumulator_->length()) { 1.107 + if ((*returnAccumulator_)[i] == block) 1.108 + returnAccumulator_->erase(returnAccumulator_->begin() + i); 1.109 + else 1.110 + i++; 1.111 + } 1.112 + } 1.113 + 1.114 + block->discardAllInstructions(); 1.115 + 1.116 + // Note: phis are disconnected from the rest of the graph, but are not 1.117 + // removed entirely. If the block being removed is a loop header then 1.118 + // IonBuilder may need to access these phis to more quickly converge on the 1.119 + // possible types in the graph. See IonBuilder::analyzeNewLoopTypes. 1.120 + block->discardAllPhiOperands(); 1.121 + 1.122 + block->markAsDead(); 1.123 + blocks_.remove(block); 1.124 + numBlocks_--; 1.125 +} 1.126 + 1.127 +void 1.128 +MIRGraph::unmarkBlocks() 1.129 +{ 1.130 + for (MBasicBlockIterator i(blocks_.begin()); i != blocks_.end(); i++) 1.131 + i->unmark(); 1.132 +} 1.133 + 1.134 +MDefinition * 1.135 +MIRGraph::forkJoinContext() 1.136 +{ 1.137 + // Search the entry block to find a ForkJoinContext instruction. If we do 1.138 + // not find one, add one after the Start instruction. 1.139 + // 1.140 + // Note: the original design used a field in MIRGraph to cache the 1.141 + // forkJoinContext rather than searching for it again. However, this 1.142 + // could become out of date due to DCE. Given that we do not generally 1.143 + // have to search very far to find the ForkJoinContext instruction if it 1.144 + // exists, and that we don't look for it that often, I opted to simply 1.145 + // eliminate the cache and search anew each time, so that it is that much 1.146 + // easier to keep the IR coherent. - nmatsakis 1.147 + 1.148 + MBasicBlock *entry = entryBlock(); 1.149 + JS_ASSERT(entry->info().executionMode() == ParallelExecution); 1.150 + 1.151 + MInstruction *start = nullptr; 1.152 + for (MInstructionIterator ins(entry->begin()); ins != entry->end(); ins++) { 1.153 + if (ins->isForkJoinContext()) 1.154 + return *ins; 1.155 + else if (ins->isStart()) 1.156 + start = *ins; 1.157 + } 1.158 + JS_ASSERT(start); 1.159 + 1.160 + MForkJoinContext *cx = MForkJoinContext::New(alloc()); 1.161 + entry->insertAfter(start, cx); 1.162 + return cx; 1.163 +} 1.164 + 1.165 +MBasicBlock * 1.166 +MBasicBlock::New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info, 1.167 + MBasicBlock *pred, jsbytecode *entryPc, Kind kind) 1.168 +{ 1.169 + JS_ASSERT(entryPc != nullptr); 1.170 + 1.171 + MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, kind); 1.172 + if (!block->init()) 1.173 + return nullptr; 1.174 + 1.175 + if (!block->inherit(graph.alloc(), analysis, pred, 0)) 1.176 + return nullptr; 1.177 + 1.178 + return block; 1.179 +} 1.180 + 1.181 +MBasicBlock * 1.182 +MBasicBlock::NewPopN(MIRGraph &graph, CompileInfo &info, 1.183 + MBasicBlock *pred, jsbytecode *entryPc, Kind kind, uint32_t popped) 1.184 +{ 1.185 + MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, kind); 1.186 + if (!block->init()) 1.187 + return nullptr; 1.188 + 1.189 + if (!block->inherit(graph.alloc(), nullptr, pred, popped)) 1.190 + return nullptr; 1.191 + 1.192 + return block; 1.193 +} 1.194 + 1.195 +MBasicBlock * 1.196 +MBasicBlock::NewWithResumePoint(MIRGraph &graph, CompileInfo &info, 1.197 + MBasicBlock *pred, jsbytecode *entryPc, 1.198 + MResumePoint *resumePoint) 1.199 +{ 1.200 + MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, NORMAL); 1.201 + 1.202 + resumePoint->block_ = block; 1.203 + block->entryResumePoint_ = resumePoint; 1.204 + 1.205 + if (!block->init()) 1.206 + return nullptr; 1.207 + 1.208 + if (!block->inheritResumePoint(pred)) 1.209 + return nullptr; 1.210 + 1.211 + return block; 1.212 +} 1.213 + 1.214 +MBasicBlock * 1.215 +MBasicBlock::NewPendingLoopHeader(MIRGraph &graph, CompileInfo &info, 1.216 + MBasicBlock *pred, jsbytecode *entryPc, 1.217 + unsigned stackPhiCount) 1.218 +{ 1.219 + JS_ASSERT(entryPc != nullptr); 1.220 + 1.221 + MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, PENDING_LOOP_HEADER); 1.222 + if (!block->init()) 1.223 + return nullptr; 1.224 + 1.225 + if (!block->inherit(graph.alloc(), nullptr, pred, 0, stackPhiCount)) 1.226 + return nullptr; 1.227 + 1.228 + return block; 1.229 +} 1.230 + 1.231 +MBasicBlock * 1.232 +MBasicBlock::NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred) 1.233 +{ 1.234 + return pred->pc() 1.235 + ? MBasicBlock::New(graph, nullptr, info, pred, pred->pc(), SPLIT_EDGE) 1.236 + : MBasicBlock::NewAsmJS(graph, info, pred, SPLIT_EDGE); 1.237 +} 1.238 + 1.239 +MBasicBlock * 1.240 +MBasicBlock::NewAbortPar(MIRGraph &graph, CompileInfo &info, 1.241 + MBasicBlock *pred, jsbytecode *entryPc, 1.242 + MResumePoint *resumePoint) 1.243 +{ 1.244 + MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, entryPc, NORMAL); 1.245 + 1.246 + resumePoint->block_ = block; 1.247 + block->entryResumePoint_ = resumePoint; 1.248 + 1.249 + if (!block->init()) 1.250 + return nullptr; 1.251 + 1.252 + if (!block->addPredecessorWithoutPhis(pred)) 1.253 + return nullptr; 1.254 + 1.255 + block->end(MAbortPar::New(graph.alloc())); 1.256 + return block; 1.257 +} 1.258 + 1.259 +MBasicBlock * 1.260 +MBasicBlock::NewAsmJS(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred, Kind kind) 1.261 +{ 1.262 + MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, /* entryPC = */ nullptr, kind); 1.263 + if (!block->init()) 1.264 + return nullptr; 1.265 + 1.266 + if (pred) { 1.267 + block->stackPosition_ = pred->stackPosition_; 1.268 + 1.269 + if (block->kind_ == PENDING_LOOP_HEADER) { 1.270 + size_t nphis = block->stackPosition_; 1.271 + 1.272 + TempAllocator &alloc = graph.alloc(); 1.273 + MPhi *phis = (MPhi*)alloc.allocateArray<sizeof(MPhi)>(nphis); 1.274 + if (!phis) 1.275 + return nullptr; 1.276 + 1.277 + for (size_t i = 0; i < nphis; i++) { 1.278 + MDefinition *predSlot = pred->getSlot(i); 1.279 + 1.280 + JS_ASSERT(predSlot->type() != MIRType_Value); 1.281 + MPhi *phi = new(phis + i) MPhi(alloc, i, predSlot->type()); 1.282 + 1.283 + JS_ALWAYS_TRUE(phi->reserveLength(2)); 1.284 + phi->addInput(predSlot); 1.285 + 1.286 + block->addPhi(phi); 1.287 + block->setSlot(i, phi); 1.288 + } 1.289 + } else { 1.290 + block->copySlots(pred); 1.291 + } 1.292 + 1.293 + if (!block->predecessors_.append(pred)) 1.294 + return nullptr; 1.295 + } 1.296 + 1.297 + return block; 1.298 +} 1.299 + 1.300 +MBasicBlock::MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind) 1.301 + : unreachable_(false), 1.302 + graph_(graph), 1.303 + info_(info), 1.304 + predecessors_(graph.alloc()), 1.305 + stackPosition_(info_.firstStackSlot()), 1.306 + lastIns_(nullptr), 1.307 + pc_(pc), 1.308 + lir_(nullptr), 1.309 + start_(nullptr), 1.310 + entryResumePoint_(nullptr), 1.311 + successorWithPhis_(nullptr), 1.312 + positionInPhiSuccessor_(0), 1.313 + kind_(kind), 1.314 + loopDepth_(0), 1.315 + mark_(false), 1.316 + immediatelyDominated_(graph.alloc()), 1.317 + immediateDominator_(nullptr), 1.318 + numDominated_(0), 1.319 + trackedPc_(pc) 1.320 +#if defined (JS_ION_PERF) 1.321 + , lineno_(0u), 1.322 + columnIndex_(0u) 1.323 +#endif 1.324 +{ 1.325 +} 1.326 + 1.327 +bool 1.328 +MBasicBlock::init() 1.329 +{ 1.330 + return slots_.init(graph_.alloc(), info_.nslots()); 1.331 +} 1.332 + 1.333 +bool 1.334 +MBasicBlock::increaseSlots(size_t num) 1.335 +{ 1.336 + return slots_.growBy(graph_.alloc(), num); 1.337 +} 1.338 + 1.339 +bool 1.340 +MBasicBlock::ensureHasSlots(size_t num) 1.341 +{ 1.342 + size_t depth = stackDepth() + num; 1.343 + if (depth > nslots()) { 1.344 + if (!increaseSlots(depth - nslots())) 1.345 + return false; 1.346 + } 1.347 + return true; 1.348 +} 1.349 + 1.350 +void 1.351 +MBasicBlock::copySlots(MBasicBlock *from) 1.352 +{ 1.353 + JS_ASSERT(stackPosition_ <= from->stackPosition_); 1.354 + 1.355 + for (uint32_t i = 0; i < stackPosition_; i++) 1.356 + slots_[i] = from->slots_[i]; 1.357 +} 1.358 + 1.359 +bool 1.360 +MBasicBlock::inherit(TempAllocator &alloc, BytecodeAnalysis *analysis, MBasicBlock *pred, 1.361 + uint32_t popped, unsigned stackPhiCount) 1.362 +{ 1.363 + if (pred) { 1.364 + stackPosition_ = pred->stackPosition_; 1.365 + JS_ASSERT(stackPosition_ >= popped); 1.366 + stackPosition_ -= popped; 1.367 + if (kind_ != PENDING_LOOP_HEADER) 1.368 + copySlots(pred); 1.369 + } else { 1.370 + uint32_t stackDepth = analysis->info(pc()).stackDepth; 1.371 + stackPosition_ = info().firstStackSlot() + stackDepth; 1.372 + JS_ASSERT(stackPosition_ >= popped); 1.373 + stackPosition_ -= popped; 1.374 + } 1.375 + 1.376 + JS_ASSERT(info_.nslots() >= stackPosition_); 1.377 + JS_ASSERT(!entryResumePoint_); 1.378 + 1.379 + // Propagate the caller resume point from the inherited block. 1.380 + MResumePoint *callerResumePoint = pred ? pred->callerResumePoint() : nullptr; 1.381 + 1.382 + // Create a resume point using our initial stack state. 1.383 + entryResumePoint_ = new(alloc) MResumePoint(this, pc(), callerResumePoint, MResumePoint::ResumeAt); 1.384 + if (!entryResumePoint_->init(alloc)) 1.385 + return false; 1.386 + 1.387 + if (pred) { 1.388 + if (!predecessors_.append(pred)) 1.389 + return false; 1.390 + 1.391 + if (kind_ == PENDING_LOOP_HEADER) { 1.392 + size_t i = 0; 1.393 + for (i = 0; i < info().firstStackSlot(); i++) { 1.394 + MPhi *phi = MPhi::New(alloc, i); 1.395 + if (!phi->addInputSlow(pred->getSlot(i))) 1.396 + return false; 1.397 + addPhi(phi); 1.398 + setSlot(i, phi); 1.399 + entryResumePoint()->setOperand(i, phi); 1.400 + } 1.401 + 1.402 + JS_ASSERT(stackPhiCount <= stackDepth()); 1.403 + JS_ASSERT(info().firstStackSlot() <= stackDepth() - stackPhiCount); 1.404 + 1.405 + // Avoid creating new phis for stack values that aren't part of the 1.406 + // loop. Note that for loop headers that can OSR, all values on the 1.407 + // stack are part of the loop. 1.408 + for (; i < stackDepth() - stackPhiCount; i++) { 1.409 + MDefinition *val = pred->getSlot(i); 1.410 + setSlot(i, val); 1.411 + entryResumePoint()->setOperand(i, val); 1.412 + } 1.413 + 1.414 + for (; i < stackDepth(); i++) { 1.415 + MPhi *phi = MPhi::New(alloc, i); 1.416 + if (!phi->addInputSlow(pred->getSlot(i))) 1.417 + return false; 1.418 + addPhi(phi); 1.419 + setSlot(i, phi); 1.420 + entryResumePoint()->setOperand(i, phi); 1.421 + } 1.422 + } else { 1.423 + for (size_t i = 0; i < stackDepth(); i++) 1.424 + entryResumePoint()->setOperand(i, getSlot(i)); 1.425 + } 1.426 + } else { 1.427 + /* 1.428 + * Don't leave the operands uninitialized for the caller, as it may not 1.429 + * initialize them later on. 1.430 + */ 1.431 + for (size_t i = 0; i < stackDepth(); i++) 1.432 + entryResumePoint()->clearOperand(i); 1.433 + } 1.434 + 1.435 + return true; 1.436 +} 1.437 + 1.438 +bool 1.439 +MBasicBlock::inheritResumePoint(MBasicBlock *pred) 1.440 +{ 1.441 + // Copy slots from the resume point. 1.442 + stackPosition_ = entryResumePoint_->numOperands(); 1.443 + for (uint32_t i = 0; i < stackPosition_; i++) 1.444 + slots_[i] = entryResumePoint_->getOperand(i); 1.445 + 1.446 + JS_ASSERT(info_.nslots() >= stackPosition_); 1.447 + JS_ASSERT(kind_ != PENDING_LOOP_HEADER); 1.448 + JS_ASSERT(pred != nullptr); 1.449 + 1.450 + if (!predecessors_.append(pred)) 1.451 + return false; 1.452 + 1.453 + return true; 1.454 +} 1.455 + 1.456 +void 1.457 +MBasicBlock::inheritSlots(MBasicBlock *parent) 1.458 +{ 1.459 + stackPosition_ = parent->stackPosition_; 1.460 + copySlots(parent); 1.461 +} 1.462 + 1.463 +bool 1.464 +MBasicBlock::initEntrySlots(TempAllocator &alloc) 1.465 +{ 1.466 + // Create a resume point using our initial stack state. 1.467 + entryResumePoint_ = MResumePoint::New(alloc, this, pc(), callerResumePoint(), 1.468 + MResumePoint::ResumeAt); 1.469 + if (!entryResumePoint_) 1.470 + return false; 1.471 + return true; 1.472 +} 1.473 + 1.474 +MDefinition * 1.475 +MBasicBlock::getSlot(uint32_t index) 1.476 +{ 1.477 + JS_ASSERT(index < stackPosition_); 1.478 + return slots_[index]; 1.479 +} 1.480 + 1.481 +void 1.482 +MBasicBlock::initSlot(uint32_t slot, MDefinition *ins) 1.483 +{ 1.484 + slots_[slot] = ins; 1.485 + if (entryResumePoint()) 1.486 + entryResumePoint()->setOperand(slot, ins); 1.487 +} 1.488 + 1.489 +void 1.490 +MBasicBlock::shimmySlots(int discardDepth) 1.491 +{ 1.492 + // Move all slots above the given depth down by one, 1.493 + // overwriting the MDefinition at discardDepth. 1.494 + 1.495 + JS_ASSERT(discardDepth < 0); 1.496 + JS_ASSERT(stackPosition_ + discardDepth >= info_.firstStackSlot()); 1.497 + 1.498 + for (int i = discardDepth; i < -1; i++) 1.499 + slots_[stackPosition_ + i] = slots_[stackPosition_ + i + 1]; 1.500 + 1.501 + --stackPosition_; 1.502 +} 1.503 + 1.504 +void 1.505 +MBasicBlock::linkOsrValues(MStart *start) 1.506 +{ 1.507 + JS_ASSERT(start->startType() == MStart::StartType_Osr); 1.508 + 1.509 + MResumePoint *res = start->resumePoint(); 1.510 + 1.511 + for (uint32_t i = 0; i < stackDepth(); i++) { 1.512 + MDefinition *def = slots_[i]; 1.513 + if (i == info().scopeChainSlot()) { 1.514 + if (def->isOsrScopeChain()) 1.515 + def->toOsrScopeChain()->setResumePoint(res); 1.516 + } else if (i == info().returnValueSlot()) { 1.517 + if (def->isOsrReturnValue()) 1.518 + def->toOsrReturnValue()->setResumePoint(res); 1.519 + } else if (info().hasArguments() && i == info().argsObjSlot()) { 1.520 + JS_ASSERT(def->isConstant() || def->isOsrArgumentsObject()); 1.521 + JS_ASSERT_IF(def->isConstant(), def->toConstant()->value() == UndefinedValue()); 1.522 + if (def->isOsrArgumentsObject()) 1.523 + def->toOsrArgumentsObject()->setResumePoint(res); 1.524 + } else { 1.525 + JS_ASSERT(def->isOsrValue() || def->isGetArgumentsObjectArg() || def->isConstant() || 1.526 + def->isParameter()); 1.527 + 1.528 + // A constant Undefined can show up here for an argument slot when the function uses 1.529 + // a heavyweight argsobj, but the argument in question is stored on the scope chain. 1.530 + JS_ASSERT_IF(def->isConstant(), def->toConstant()->value() == UndefinedValue()); 1.531 + 1.532 + if (def->isOsrValue()) 1.533 + def->toOsrValue()->setResumePoint(res); 1.534 + else if (def->isGetArgumentsObjectArg()) 1.535 + def->toGetArgumentsObjectArg()->setResumePoint(res); 1.536 + else if (def->isParameter()) 1.537 + def->toParameter()->setResumePoint(res); 1.538 + } 1.539 + } 1.540 +} 1.541 + 1.542 +void 1.543 +MBasicBlock::setSlot(uint32_t slot, MDefinition *ins) 1.544 +{ 1.545 + slots_[slot] = ins; 1.546 +} 1.547 + 1.548 +void 1.549 +MBasicBlock::setVariable(uint32_t index) 1.550 +{ 1.551 + JS_ASSERT(stackPosition_ > info_.firstStackSlot()); 1.552 + setSlot(index, slots_[stackPosition_ - 1]); 1.553 +} 1.554 + 1.555 +void 1.556 +MBasicBlock::setArg(uint32_t arg) 1.557 +{ 1.558 + setVariable(info_.argSlot(arg)); 1.559 +} 1.560 + 1.561 +void 1.562 +MBasicBlock::setLocal(uint32_t local) 1.563 +{ 1.564 + setVariable(info_.localSlot(local)); 1.565 +} 1.566 + 1.567 +void 1.568 +MBasicBlock::setSlot(uint32_t slot) 1.569 +{ 1.570 + setVariable(slot); 1.571 +} 1.572 + 1.573 +void 1.574 +MBasicBlock::rewriteSlot(uint32_t slot, MDefinition *ins) 1.575 +{ 1.576 + setSlot(slot, ins); 1.577 +} 1.578 + 1.579 +void 1.580 +MBasicBlock::rewriteAtDepth(int32_t depth, MDefinition *ins) 1.581 +{ 1.582 + JS_ASSERT(depth < 0); 1.583 + JS_ASSERT(stackPosition_ + depth >= info_.firstStackSlot()); 1.584 + rewriteSlot(stackPosition_ + depth, ins); 1.585 +} 1.586 + 1.587 +void 1.588 +MBasicBlock::push(MDefinition *ins) 1.589 +{ 1.590 + JS_ASSERT(stackPosition_ < nslots()); 1.591 + slots_[stackPosition_++] = ins; 1.592 +} 1.593 + 1.594 +void 1.595 +MBasicBlock::pushVariable(uint32_t slot) 1.596 +{ 1.597 + push(slots_[slot]); 1.598 +} 1.599 + 1.600 +void 1.601 +MBasicBlock::pushArg(uint32_t arg) 1.602 +{ 1.603 + pushVariable(info_.argSlot(arg)); 1.604 +} 1.605 + 1.606 +void 1.607 +MBasicBlock::pushLocal(uint32_t local) 1.608 +{ 1.609 + pushVariable(info_.localSlot(local)); 1.610 +} 1.611 + 1.612 +void 1.613 +MBasicBlock::pushSlot(uint32_t slot) 1.614 +{ 1.615 + pushVariable(slot); 1.616 +} 1.617 + 1.618 +MDefinition * 1.619 +MBasicBlock::pop() 1.620 +{ 1.621 + JS_ASSERT(stackPosition_ > info_.firstStackSlot()); 1.622 + return slots_[--stackPosition_]; 1.623 +} 1.624 + 1.625 +void 1.626 +MBasicBlock::popn(uint32_t n) 1.627 +{ 1.628 + JS_ASSERT(stackPosition_ - n >= info_.firstStackSlot()); 1.629 + JS_ASSERT(stackPosition_ >= stackPosition_ - n); 1.630 + stackPosition_ -= n; 1.631 +} 1.632 + 1.633 +MDefinition * 1.634 +MBasicBlock::scopeChain() 1.635 +{ 1.636 + return getSlot(info().scopeChainSlot()); 1.637 +} 1.638 + 1.639 +MDefinition * 1.640 +MBasicBlock::argumentsObject() 1.641 +{ 1.642 + return getSlot(info().argsObjSlot()); 1.643 +} 1.644 + 1.645 +void 1.646 +MBasicBlock::setScopeChain(MDefinition *scopeObj) 1.647 +{ 1.648 + setSlot(info().scopeChainSlot(), scopeObj); 1.649 +} 1.650 + 1.651 +void 1.652 +MBasicBlock::setArgumentsObject(MDefinition *argsObj) 1.653 +{ 1.654 + setSlot(info().argsObjSlot(), argsObj); 1.655 +} 1.656 + 1.657 +void 1.658 +MBasicBlock::pick(int32_t depth) 1.659 +{ 1.660 + // pick take an element and move it to the top. 1.661 + // pick(-2): 1.662 + // A B C D E 1.663 + // A B D C E [ swapAt(-2) ] 1.664 + // A B D E C [ swapAt(-1) ] 1.665 + for (; depth < 0; depth++) 1.666 + swapAt(depth); 1.667 +} 1.668 + 1.669 +void 1.670 +MBasicBlock::swapAt(int32_t depth) 1.671 +{ 1.672 + uint32_t lhsDepth = stackPosition_ + depth - 1; 1.673 + uint32_t rhsDepth = stackPosition_ + depth; 1.674 + 1.675 + MDefinition *temp = slots_[lhsDepth]; 1.676 + slots_[lhsDepth] = slots_[rhsDepth]; 1.677 + slots_[rhsDepth] = temp; 1.678 +} 1.679 + 1.680 +MDefinition * 1.681 +MBasicBlock::peek(int32_t depth) 1.682 +{ 1.683 + JS_ASSERT(depth < 0); 1.684 + JS_ASSERT(stackPosition_ + depth >= info_.firstStackSlot()); 1.685 + return getSlot(stackPosition_ + depth); 1.686 +} 1.687 + 1.688 +void 1.689 +MBasicBlock::discardLastIns() 1.690 +{ 1.691 + JS_ASSERT(lastIns_); 1.692 + discard(lastIns_); 1.693 + lastIns_ = nullptr; 1.694 +} 1.695 + 1.696 +void 1.697 +MBasicBlock::addFromElsewhere(MInstruction *ins) 1.698 +{ 1.699 + JS_ASSERT(ins->block() != this); 1.700 + 1.701 + // Remove |ins| from its containing block. 1.702 + ins->block()->instructions_.remove(ins); 1.703 + 1.704 + // Add it to this block. 1.705 + add(ins); 1.706 +} 1.707 + 1.708 +void 1.709 +MBasicBlock::moveBefore(MInstruction *at, MInstruction *ins) 1.710 +{ 1.711 + // Remove |ins| from the current block. 1.712 + JS_ASSERT(ins->block() == this); 1.713 + instructions_.remove(ins); 1.714 + 1.715 + // Insert into new block, which may be distinct. 1.716 + // Uses and operands are untouched. 1.717 + at->block()->insertBefore(at, ins); 1.718 +} 1.719 + 1.720 +static inline void 1.721 +AssertSafelyDiscardable(MDefinition *def) 1.722 +{ 1.723 +#ifdef DEBUG 1.724 + // Instructions captured by resume points cannot be safely discarded, since 1.725 + // they are necessary for interpreter frame reconstruction in case of bailout. 1.726 + JS_ASSERT(!def->hasUses()); 1.727 +#endif 1.728 +} 1.729 + 1.730 +void 1.731 +MBasicBlock::discard(MInstruction *ins) 1.732 +{ 1.733 + AssertSafelyDiscardable(ins); 1.734 + for (size_t i = 0, e = ins->numOperands(); i < e; i++) 1.735 + ins->discardOperand(i); 1.736 + 1.737 + instructions_.remove(ins); 1.738 +} 1.739 + 1.740 +MInstructionIterator 1.741 +MBasicBlock::discardAt(MInstructionIterator &iter) 1.742 +{ 1.743 + AssertSafelyDiscardable(*iter); 1.744 + for (size_t i = 0, e = iter->numOperands(); i < e; i++) 1.745 + iter->discardOperand(i); 1.746 + 1.747 + return instructions_.removeAt(iter); 1.748 +} 1.749 + 1.750 +MInstructionReverseIterator 1.751 +MBasicBlock::discardAt(MInstructionReverseIterator &iter) 1.752 +{ 1.753 + AssertSafelyDiscardable(*iter); 1.754 + for (size_t i = 0, e = iter->numOperands(); i < e; i++) 1.755 + iter->discardOperand(i); 1.756 + 1.757 + return instructions_.removeAt(iter); 1.758 +} 1.759 + 1.760 +MDefinitionIterator 1.761 +MBasicBlock::discardDefAt(MDefinitionIterator &old) 1.762 +{ 1.763 + MDefinitionIterator iter(old); 1.764 + 1.765 + if (iter.atPhi()) 1.766 + iter.phiIter_ = iter.block_->discardPhiAt(iter.phiIter_); 1.767 + else 1.768 + iter.iter_ = iter.block_->discardAt(iter.iter_); 1.769 + 1.770 + return iter; 1.771 +} 1.772 + 1.773 +void 1.774 +MBasicBlock::discardAllInstructions() 1.775 +{ 1.776 + for (MInstructionIterator iter = begin(); iter != end(); ) { 1.777 + for (size_t i = 0, e = iter->numOperands(); i < e; i++) 1.778 + iter->discardOperand(i); 1.779 + iter = instructions_.removeAt(iter); 1.780 + } 1.781 + lastIns_ = nullptr; 1.782 +} 1.783 + 1.784 +void 1.785 +MBasicBlock::discardAllPhiOperands() 1.786 +{ 1.787 + for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) { 1.788 + MPhi *phi = *iter; 1.789 + for (size_t i = 0, e = phi->numOperands(); i < e; i++) 1.790 + phi->discardOperand(i); 1.791 + } 1.792 + 1.793 + for (MBasicBlock **pred = predecessors_.begin(); pred != predecessors_.end(); pred++) 1.794 + (*pred)->setSuccessorWithPhis(nullptr, 0); 1.795 +} 1.796 + 1.797 +void 1.798 +MBasicBlock::discardAllPhis() 1.799 +{ 1.800 + discardAllPhiOperands(); 1.801 + phis_.clear(); 1.802 +} 1.803 + 1.804 +void 1.805 +MBasicBlock::discardAllResumePoints(bool discardEntry) 1.806 +{ 1.807 + for (MResumePointIterator iter = resumePointsBegin(); iter != resumePointsEnd(); ) { 1.808 + MResumePoint *rp = *iter; 1.809 + if (rp == entryResumePoint() && !discardEntry) { 1.810 + iter++; 1.811 + } else { 1.812 + rp->discardUses(); 1.813 + iter = resumePoints_.removeAt(iter); 1.814 + } 1.815 + } 1.816 +} 1.817 + 1.818 +void 1.819 +MBasicBlock::insertBefore(MInstruction *at, MInstruction *ins) 1.820 +{ 1.821 + JS_ASSERT(at->block() == this); 1.822 + ins->setBlock(this); 1.823 + graph().allocDefinitionId(ins); 1.824 + instructions_.insertBefore(at, ins); 1.825 + ins->setTrackedPc(at->trackedPc()); 1.826 +} 1.827 + 1.828 +void 1.829 +MBasicBlock::insertAfter(MInstruction *at, MInstruction *ins) 1.830 +{ 1.831 + JS_ASSERT(at->block() == this); 1.832 + ins->setBlock(this); 1.833 + graph().allocDefinitionId(ins); 1.834 + instructions_.insertAfter(at, ins); 1.835 + ins->setTrackedPc(at->trackedPc()); 1.836 +} 1.837 + 1.838 +void 1.839 +MBasicBlock::add(MInstruction *ins) 1.840 +{ 1.841 + JS_ASSERT(!lastIns_); 1.842 + ins->setBlock(this); 1.843 + graph().allocDefinitionId(ins); 1.844 + instructions_.pushBack(ins); 1.845 + ins->setTrackedPc(trackedPc_); 1.846 +} 1.847 + 1.848 +void 1.849 +MBasicBlock::end(MControlInstruction *ins) 1.850 +{ 1.851 + JS_ASSERT(!lastIns_); // Existing control instructions should be removed first. 1.852 + JS_ASSERT(ins); 1.853 + add(ins); 1.854 + lastIns_ = ins; 1.855 +} 1.856 + 1.857 +void 1.858 +MBasicBlock::addPhi(MPhi *phi) 1.859 +{ 1.860 + phis_.pushBack(phi); 1.861 + phi->setBlock(this); 1.862 + graph().allocDefinitionId(phi); 1.863 +} 1.864 + 1.865 +MPhiIterator 1.866 +MBasicBlock::discardPhiAt(MPhiIterator &at) 1.867 +{ 1.868 + JS_ASSERT(!phis_.empty()); 1.869 + 1.870 + for (size_t i = 0, e = at->numOperands(); i < e; i++) 1.871 + at->discardOperand(i); 1.872 + 1.873 + MPhiIterator result = phis_.removeAt(at); 1.874 + 1.875 + if (phis_.empty()) { 1.876 + for (MBasicBlock **pred = predecessors_.begin(); pred != predecessors_.end(); pred++) 1.877 + (*pred)->setSuccessorWithPhis(nullptr, 0); 1.878 + } 1.879 + return result; 1.880 +} 1.881 + 1.882 +bool 1.883 +MBasicBlock::addPredecessor(TempAllocator &alloc, MBasicBlock *pred) 1.884 +{ 1.885 + return addPredecessorPopN(alloc, pred, 0); 1.886 +} 1.887 + 1.888 +bool 1.889 +MBasicBlock::addPredecessorPopN(TempAllocator &alloc, MBasicBlock *pred, uint32_t popped) 1.890 +{ 1.891 + JS_ASSERT(pred); 1.892 + JS_ASSERT(predecessors_.length() > 0); 1.893 + 1.894 + // Predecessors must be finished, and at the correct stack depth. 1.895 + JS_ASSERT(pred->lastIns_); 1.896 + JS_ASSERT(pred->stackPosition_ == stackPosition_ + popped); 1.897 + 1.898 + for (uint32_t i = 0; i < stackPosition_; i++) { 1.899 + MDefinition *mine = getSlot(i); 1.900 + MDefinition *other = pred->getSlot(i); 1.901 + 1.902 + if (mine != other) { 1.903 + // If the current instruction is a phi, and it was created in this 1.904 + // basic block, then we have already placed this phi and should 1.905 + // instead append to its operands. 1.906 + if (mine->isPhi() && mine->block() == this) { 1.907 + JS_ASSERT(predecessors_.length()); 1.908 + if (!mine->toPhi()->addInputSlow(other)) 1.909 + return false; 1.910 + } else { 1.911 + // Otherwise, create a new phi node. 1.912 + MPhi *phi; 1.913 + if (mine->type() == other->type()) 1.914 + phi = MPhi::New(alloc, i, mine->type()); 1.915 + else 1.916 + phi = MPhi::New(alloc, i); 1.917 + addPhi(phi); 1.918 + 1.919 + // Prime the phi for each predecessor, so input(x) comes from 1.920 + // predecessor(x). 1.921 + if (!phi->reserveLength(predecessors_.length() + 1)) 1.922 + return false; 1.923 + 1.924 + for (size_t j = 0; j < predecessors_.length(); j++) { 1.925 + JS_ASSERT(predecessors_[j]->getSlot(i) == mine); 1.926 + phi->addInput(mine); 1.927 + } 1.928 + phi->addInput(other); 1.929 + 1.930 + setSlot(i, phi); 1.931 + if (entryResumePoint()) 1.932 + entryResumePoint()->replaceOperand(i, phi); 1.933 + } 1.934 + } 1.935 + } 1.936 + 1.937 + return predecessors_.append(pred); 1.938 +} 1.939 + 1.940 +bool 1.941 +MBasicBlock::addPredecessorWithoutPhis(MBasicBlock *pred) 1.942 +{ 1.943 + // Predecessors must be finished. 1.944 + JS_ASSERT(pred && pred->lastIns_); 1.945 + return predecessors_.append(pred); 1.946 +} 1.947 + 1.948 +bool 1.949 +MBasicBlock::addImmediatelyDominatedBlock(MBasicBlock *child) 1.950 +{ 1.951 + return immediatelyDominated_.append(child); 1.952 +} 1.953 + 1.954 +void 1.955 +MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end) 1.956 +{ 1.957 +#ifdef DEBUG 1.958 + for (; use != end; use++) { 1.959 + JS_ASSERT_IF(use->consumer()->isDefinition(), 1.960 + use->consumer()->toDefinition()->block()->id() < id()); 1.961 + } 1.962 +#endif 1.963 +} 1.964 + 1.965 +bool 1.966 +MBasicBlock::dominates(const MBasicBlock *other) const 1.967 +{ 1.968 + uint32_t high = domIndex() + numDominated(); 1.969 + uint32_t low = domIndex(); 1.970 + return other->domIndex() >= low && other->domIndex() <= high; 1.971 +} 1.972 + 1.973 +void 1.974 +MBasicBlock::setUnreachable() 1.975 +{ 1.976 + unreachable_ = true; 1.977 + size_t numDom = numImmediatelyDominatedBlocks(); 1.978 + for (size_t d = 0; d < numDom; d++) 1.979 + getImmediatelyDominatedBlock(d)->unreachable_ = true; 1.980 +} 1.981 + 1.982 +AbortReason 1.983 +MBasicBlock::setBackedge(MBasicBlock *pred) 1.984 +{ 1.985 + // Predecessors must be finished, and at the correct stack depth. 1.986 + JS_ASSERT(lastIns_); 1.987 + JS_ASSERT(pred->lastIns_); 1.988 + JS_ASSERT(pred->stackDepth() == entryResumePoint()->stackDepth()); 1.989 + 1.990 + // We must be a pending loop header 1.991 + JS_ASSERT(kind_ == PENDING_LOOP_HEADER); 1.992 + 1.993 + bool hadTypeChange = false; 1.994 + 1.995 + // Add exit definitions to each corresponding phi at the entry. 1.996 + for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++) { 1.997 + MPhi *entryDef = *phi; 1.998 + MDefinition *exitDef = pred->slots_[entryDef->slot()]; 1.999 + 1.1000 + // Assert that we already placed phis for each slot. 1.1001 + JS_ASSERT(entryDef->block() == this); 1.1002 + 1.1003 + if (entryDef == exitDef) { 1.1004 + // If the exit def is the same as the entry def, make a redundant 1.1005 + // phi. Since loop headers have exactly two incoming edges, we 1.1006 + // know that that's just the first input. 1.1007 + // 1.1008 + // Note that we eliminate later rather than now, to avoid any 1.1009 + // weirdness around pending continue edges which might still hold 1.1010 + // onto phis. 1.1011 + exitDef = entryDef->getOperand(0); 1.1012 + } 1.1013 + 1.1014 + bool typeChange = false; 1.1015 + 1.1016 + if (!entryDef->addInputSlow(exitDef, &typeChange)) 1.1017 + return AbortReason_Alloc; 1.1018 + 1.1019 + hadTypeChange |= typeChange; 1.1020 + 1.1021 + JS_ASSERT(entryDef->slot() < pred->stackDepth()); 1.1022 + setSlot(entryDef->slot(), entryDef); 1.1023 + } 1.1024 + 1.1025 + if (hadTypeChange) { 1.1026 + for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++) 1.1027 + phi->removeOperand(phi->numOperands() - 1); 1.1028 + return AbortReason_Disable; 1.1029 + } 1.1030 + 1.1031 + // We are now a loop header proper 1.1032 + kind_ = LOOP_HEADER; 1.1033 + 1.1034 + if (!predecessors_.append(pred)) 1.1035 + return AbortReason_Alloc; 1.1036 + 1.1037 + return AbortReason_NoAbort; 1.1038 +} 1.1039 + 1.1040 +bool 1.1041 +MBasicBlock::setBackedgeAsmJS(MBasicBlock *pred) 1.1042 +{ 1.1043 + // Predecessors must be finished, and at the correct stack depth. 1.1044 + JS_ASSERT(lastIns_); 1.1045 + JS_ASSERT(pred->lastIns_); 1.1046 + JS_ASSERT(stackDepth() == pred->stackDepth()); 1.1047 + 1.1048 + // We must be a pending loop header 1.1049 + JS_ASSERT(kind_ == PENDING_LOOP_HEADER); 1.1050 + 1.1051 + // Add exit definitions to each corresponding phi at the entry. 1.1052 + for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++) { 1.1053 + MPhi *entryDef = *phi; 1.1054 + MDefinition *exitDef = pred->getSlot(entryDef->slot()); 1.1055 + 1.1056 + // Assert that we already placed phis for each slot. 1.1057 + JS_ASSERT(entryDef->block() == this); 1.1058 + 1.1059 + // Assert that the phi already has the correct type. 1.1060 + JS_ASSERT(entryDef->type() == exitDef->type()); 1.1061 + JS_ASSERT(entryDef->type() != MIRType_Value); 1.1062 + 1.1063 + if (entryDef == exitDef) { 1.1064 + // If the exit def is the same as the entry def, make a redundant 1.1065 + // phi. Since loop headers have exactly two incoming edges, we 1.1066 + // know that that's just the first input. 1.1067 + // 1.1068 + // Note that we eliminate later rather than now, to avoid any 1.1069 + // weirdness around pending continue edges which might still hold 1.1070 + // onto phis. 1.1071 + exitDef = entryDef->getOperand(0); 1.1072 + } 1.1073 + 1.1074 + // MBasicBlock::NewAsmJS calls reserveLength(2) for loop header phis. 1.1075 + entryDef->addInput(exitDef); 1.1076 + 1.1077 + JS_ASSERT(entryDef->slot() < pred->stackDepth()); 1.1078 + setSlot(entryDef->slot(), entryDef); 1.1079 + } 1.1080 + 1.1081 + // We are now a loop header proper 1.1082 + kind_ = LOOP_HEADER; 1.1083 + 1.1084 + return predecessors_.append(pred); 1.1085 +} 1.1086 + 1.1087 +void 1.1088 +MBasicBlock::clearLoopHeader() 1.1089 +{ 1.1090 + JS_ASSERT(isLoopHeader()); 1.1091 + kind_ = NORMAL; 1.1092 +} 1.1093 + 1.1094 +size_t 1.1095 +MBasicBlock::numSuccessors() const 1.1096 +{ 1.1097 + JS_ASSERT(lastIns()); 1.1098 + return lastIns()->numSuccessors(); 1.1099 +} 1.1100 + 1.1101 +MBasicBlock * 1.1102 +MBasicBlock::getSuccessor(size_t index) const 1.1103 +{ 1.1104 + JS_ASSERT(lastIns()); 1.1105 + return lastIns()->getSuccessor(index); 1.1106 +} 1.1107 + 1.1108 +size_t 1.1109 +MBasicBlock::getSuccessorIndex(MBasicBlock *block) const 1.1110 +{ 1.1111 + JS_ASSERT(lastIns()); 1.1112 + for (size_t i = 0; i < numSuccessors(); i++) { 1.1113 + if (getSuccessor(i) == block) 1.1114 + return i; 1.1115 + } 1.1116 + MOZ_ASSUME_UNREACHABLE("Invalid successor"); 1.1117 +} 1.1118 + 1.1119 +void 1.1120 +MBasicBlock::replaceSuccessor(size_t pos, MBasicBlock *split) 1.1121 +{ 1.1122 + JS_ASSERT(lastIns()); 1.1123 + 1.1124 + // Note, during split-critical-edges, successors-with-phis is not yet set. 1.1125 + // During PAA, this case is handled before we enter. 1.1126 + JS_ASSERT_IF(successorWithPhis_, successorWithPhis_ != getSuccessor(pos)); 1.1127 + 1.1128 + lastIns()->replaceSuccessor(pos, split); 1.1129 +} 1.1130 + 1.1131 +void 1.1132 +MBasicBlock::replacePredecessor(MBasicBlock *old, MBasicBlock *split) 1.1133 +{ 1.1134 + for (size_t i = 0; i < numPredecessors(); i++) { 1.1135 + if (getPredecessor(i) == old) { 1.1136 + predecessors_[i] = split; 1.1137 + 1.1138 +#ifdef DEBUG 1.1139 + // The same block should not appear twice in the predecessor list. 1.1140 + for (size_t j = i; j < numPredecessors(); j++) 1.1141 + JS_ASSERT(predecessors_[j] != old); 1.1142 +#endif 1.1143 + 1.1144 + return; 1.1145 + } 1.1146 + } 1.1147 + 1.1148 + MOZ_ASSUME_UNREACHABLE("predecessor was not found"); 1.1149 +} 1.1150 + 1.1151 +void 1.1152 +MBasicBlock::clearDominatorInfo() 1.1153 +{ 1.1154 + setImmediateDominator(nullptr); 1.1155 + immediatelyDominated_.clear(); 1.1156 + numDominated_ = 0; 1.1157 +} 1.1158 + 1.1159 +void 1.1160 +MBasicBlock::removePredecessor(MBasicBlock *pred) 1.1161 +{ 1.1162 + JS_ASSERT(numPredecessors() >= 2); 1.1163 + 1.1164 + for (size_t i = 0; i < numPredecessors(); i++) { 1.1165 + if (getPredecessor(i) != pred) 1.1166 + continue; 1.1167 + 1.1168 + // Adjust phis. Note that this can leave redundant phis 1.1169 + // behind. 1.1170 + if (!phisEmpty()) { 1.1171 + JS_ASSERT(pred->successorWithPhis()); 1.1172 + JS_ASSERT(pred->positionInPhiSuccessor() == i); 1.1173 + for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) 1.1174 + iter->removeOperand(i); 1.1175 + for (size_t j = i+1; j < numPredecessors(); j++) 1.1176 + getPredecessor(j)->setSuccessorWithPhis(this, j - 1); 1.1177 + } 1.1178 + 1.1179 + // Remove from pred list. 1.1180 + MBasicBlock **ptr = predecessors_.begin() + i; 1.1181 + predecessors_.erase(ptr); 1.1182 + return; 1.1183 + } 1.1184 + 1.1185 + MOZ_ASSUME_UNREACHABLE("predecessor was not found"); 1.1186 +} 1.1187 + 1.1188 +void 1.1189 +MBasicBlock::inheritPhis(MBasicBlock *header) 1.1190 +{ 1.1191 + for (MPhiIterator iter = header->phisBegin(); iter != header->phisEnd(); iter++) { 1.1192 + MPhi *phi = *iter; 1.1193 + JS_ASSERT(phi->numOperands() == 2); 1.1194 + 1.1195 + // The entry definition is always the leftmost input to the phi. 1.1196 + MDefinition *entryDef = phi->getOperand(0); 1.1197 + MDefinition *exitDef = getSlot(phi->slot()); 1.1198 + 1.1199 + if (entryDef != exitDef) 1.1200 + continue; 1.1201 + 1.1202 + // If the entryDef is the same as exitDef, then we must propagate the 1.1203 + // phi down to this successor. This chance was missed as part of 1.1204 + // setBackedge() because exits are not captured in resume points. 1.1205 + setSlot(phi->slot(), phi); 1.1206 + } 1.1207 +} 1.1208 + 1.1209 +bool 1.1210 +MBasicBlock::specializePhis() 1.1211 +{ 1.1212 + for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) { 1.1213 + MPhi *phi = *iter; 1.1214 + if (!phi->specializeType()) 1.1215 + return false; 1.1216 + } 1.1217 + return true; 1.1218 +} 1.1219 + 1.1220 +void 1.1221 +MBasicBlock::dumpStack(FILE *fp) 1.1222 +{ 1.1223 +#ifdef DEBUG 1.1224 + fprintf(fp, " %-3s %-16s %-6s %-10s\n", "#", "name", "copyOf", "first/next"); 1.1225 + fprintf(fp, "-------------------------------------------\n"); 1.1226 + for (uint32_t i = 0; i < stackPosition_; i++) { 1.1227 + fprintf(fp, " %-3d", i); 1.1228 + fprintf(fp, " %-16p\n", (void *)slots_[i]); 1.1229 + } 1.1230 +#endif 1.1231 +} 1.1232 + 1.1233 +MTest * 1.1234 +MBasicBlock::immediateDominatorBranch(BranchDirection *pdirection) 1.1235 +{ 1.1236 + *pdirection = FALSE_BRANCH; 1.1237 + 1.1238 + if (numPredecessors() != 1) 1.1239 + return nullptr; 1.1240 + 1.1241 + MBasicBlock *dom = immediateDominator(); 1.1242 + if (dom != getPredecessor(0)) 1.1243 + return nullptr; 1.1244 + 1.1245 + // Look for a trailing MTest branching to this block. 1.1246 + MInstruction *ins = dom->lastIns(); 1.1247 + if (ins->isTest()) { 1.1248 + MTest *test = ins->toTest(); 1.1249 + 1.1250 + JS_ASSERT(test->ifTrue() == this || test->ifFalse() == this); 1.1251 + if (test->ifTrue() == this && test->ifFalse() == this) 1.1252 + return nullptr; 1.1253 + 1.1254 + *pdirection = (test->ifTrue() == this) ? TRUE_BRANCH : FALSE_BRANCH; 1.1255 + return test; 1.1256 + } 1.1257 + 1.1258 + return nullptr; 1.1259 +} 1.1260 + 1.1261 +void 1.1262 +MIRGraph::dump(FILE *fp) 1.1263 +{ 1.1264 +#ifdef DEBUG 1.1265 + for (MBasicBlockIterator iter(begin()); iter != end(); iter++) { 1.1266 + fprintf(fp, "block%d:\n", iter->id()); 1.1267 + iter->dump(fp); 1.1268 + fprintf(fp, "\n"); 1.1269 + } 1.1270 +#endif 1.1271 +} 1.1272 + 1.1273 +void 1.1274 +MIRGraph::dump() 1.1275 +{ 1.1276 + dump(stderr); 1.1277 +} 1.1278 + 1.1279 +void 1.1280 +MBasicBlock::dump(FILE *fp) 1.1281 +{ 1.1282 +#ifdef DEBUG 1.1283 + for (MPhiIterator iter(phisBegin()); iter != phisEnd(); iter++) { 1.1284 + iter->dump(fp); 1.1285 + } 1.1286 + for (MInstructionIterator iter(begin()); iter != end(); iter++) { 1.1287 + iter->dump(fp); 1.1288 + } 1.1289 +#endif 1.1290 +} 1.1291 + 1.1292 +void 1.1293 +MBasicBlock::dump() 1.1294 +{ 1.1295 + dump(stderr); 1.1296 +}