js/src/jit/LIR.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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/LIR.h"
michael@0 8
michael@0 9 #include <ctype.h>
michael@0 10
michael@0 11 #include "jsprf.h"
michael@0 12
michael@0 13 #include "jit/IonSpewer.h"
michael@0 14 #include "jit/MIR.h"
michael@0 15 #include "jit/MIRGenerator.h"
michael@0 16
michael@0 17 using namespace js;
michael@0 18 using namespace js::jit;
michael@0 19
michael@0 20 LIRGraph::LIRGraph(MIRGraph *mir)
michael@0 21 : blocks_(mir->alloc()),
michael@0 22 constantPool_(mir->alloc()),
michael@0 23 constantPoolMap_(mir->alloc()),
michael@0 24 safepoints_(mir->alloc()),
michael@0 25 nonCallSafepoints_(mir->alloc()),
michael@0 26 numVirtualRegisters_(0),
michael@0 27 numInstructions_(1), // First id is 1.
michael@0 28 localSlotCount_(0),
michael@0 29 argumentSlotCount_(0),
michael@0 30 entrySnapshot_(nullptr),
michael@0 31 osrBlock_(nullptr),
michael@0 32 mir_(*mir)
michael@0 33 {
michael@0 34 }
michael@0 35
michael@0 36 bool
michael@0 37 LIRGraph::addConstantToPool(const Value &v, uint32_t *index)
michael@0 38 {
michael@0 39 JS_ASSERT(constantPoolMap_.initialized());
michael@0 40
michael@0 41 ConstantPoolMap::AddPtr p = constantPoolMap_.lookupForAdd(v);
michael@0 42 if (p) {
michael@0 43 *index = p->value();
michael@0 44 return true;
michael@0 45 }
michael@0 46 *index = constantPool_.length();
michael@0 47 return constantPool_.append(v) && constantPoolMap_.add(p, v, *index);
michael@0 48 }
michael@0 49
michael@0 50 bool
michael@0 51 LIRGraph::noteNeedsSafepoint(LInstruction *ins)
michael@0 52 {
michael@0 53 // Instructions with safepoints must be in linear order.
michael@0 54 JS_ASSERT_IF(!safepoints_.empty(), safepoints_.back()->id() < ins->id());
michael@0 55 if (!ins->isCall() && !nonCallSafepoints_.append(ins))
michael@0 56 return false;
michael@0 57 return safepoints_.append(ins);
michael@0 58 }
michael@0 59
michael@0 60 void
michael@0 61 LIRGraph::removeBlock(size_t i)
michael@0 62 {
michael@0 63 blocks_.erase(blocks_.begin() + i);
michael@0 64 }
michael@0 65
michael@0 66 uint32_t
michael@0 67 LBlock::firstId()
michael@0 68 {
michael@0 69 if (phis_.length()) {
michael@0 70 return phis_[0]->id();
michael@0 71 } else {
michael@0 72 for (LInstructionIterator i(instructions_.begin()); i != instructions_.end(); i++) {
michael@0 73 if (i->id())
michael@0 74 return i->id();
michael@0 75 }
michael@0 76 }
michael@0 77 return 0;
michael@0 78 }
michael@0 79 uint32_t
michael@0 80 LBlock::lastId()
michael@0 81 {
michael@0 82 LInstruction *last = *instructions_.rbegin();
michael@0 83 JS_ASSERT(last->id());
michael@0 84 // The last instruction is a control flow instruction which does not have
michael@0 85 // any output.
michael@0 86 JS_ASSERT(last->numDefs() == 0);
michael@0 87 return last->id();
michael@0 88 }
michael@0 89
michael@0 90 LMoveGroup *
michael@0 91 LBlock::getEntryMoveGroup(TempAllocator &alloc)
michael@0 92 {
michael@0 93 if (entryMoveGroup_)
michael@0 94 return entryMoveGroup_;
michael@0 95 entryMoveGroup_ = LMoveGroup::New(alloc);
michael@0 96 if (begin()->isLabel())
michael@0 97 insertAfter(*begin(), entryMoveGroup_);
michael@0 98 else
michael@0 99 insertBefore(*begin(), entryMoveGroup_);
michael@0 100 return entryMoveGroup_;
michael@0 101 }
michael@0 102
michael@0 103 LMoveGroup *
michael@0 104 LBlock::getExitMoveGroup(TempAllocator &alloc)
michael@0 105 {
michael@0 106 if (exitMoveGroup_)
michael@0 107 return exitMoveGroup_;
michael@0 108 exitMoveGroup_ = LMoveGroup::New(alloc);
michael@0 109 insertBefore(*rbegin(), exitMoveGroup_);
michael@0 110 return exitMoveGroup_;
michael@0 111 }
michael@0 112
michael@0 113 static size_t
michael@0 114 TotalOperandCount(MResumePoint *mir)
michael@0 115 {
michael@0 116 size_t accum = mir->numOperands();
michael@0 117 while ((mir = mir->caller()))
michael@0 118 accum += mir->numOperands();
michael@0 119 return accum;
michael@0 120 }
michael@0 121
michael@0 122 LRecoverInfo::LRecoverInfo(TempAllocator &alloc)
michael@0 123 : instructions_(alloc),
michael@0 124 recoverOffset_(INVALID_RECOVER_OFFSET)
michael@0 125 { }
michael@0 126
michael@0 127 LRecoverInfo *
michael@0 128 LRecoverInfo::New(MIRGenerator *gen, MResumePoint *mir)
michael@0 129 {
michael@0 130 LRecoverInfo *recoverInfo = new(gen->alloc()) LRecoverInfo(gen->alloc());
michael@0 131 if (!recoverInfo || !recoverInfo->init(mir))
michael@0 132 return nullptr;
michael@0 133
michael@0 134 IonSpew(IonSpew_Snapshots, "Generating LIR recover info %p from MIR (%p)",
michael@0 135 (void *)recoverInfo, (void *)mir);
michael@0 136
michael@0 137 return recoverInfo;
michael@0 138 }
michael@0 139
michael@0 140 bool
michael@0 141 LRecoverInfo::init(MResumePoint *rp)
michael@0 142 {
michael@0 143 MResumePoint *it = rp;
michael@0 144
michael@0 145 // Sort operations in the order in which we need to restore the stack. This
michael@0 146 // implies that outer frames, as well as operations needed to recover the
michael@0 147 // current frame, are located before the current frame. The inner-most
michael@0 148 // resume point should be the last element in the list.
michael@0 149 do {
michael@0 150 if (!instructions_.append(it))
michael@0 151 return false;
michael@0 152 it = it->caller();
michael@0 153 } while (it);
michael@0 154
michael@0 155 Reverse(instructions_.begin(), instructions_.end());
michael@0 156 MOZ_ASSERT(mir() == rp);
michael@0 157 return true;
michael@0 158 }
michael@0 159
michael@0 160 LSnapshot::LSnapshot(LRecoverInfo *recoverInfo, BailoutKind kind)
michael@0 161 : numSlots_(TotalOperandCount(recoverInfo->mir()) * BOX_PIECES),
michael@0 162 slots_(nullptr),
michael@0 163 recoverInfo_(recoverInfo),
michael@0 164 snapshotOffset_(INVALID_SNAPSHOT_OFFSET),
michael@0 165 bailoutId_(INVALID_BAILOUT_ID),
michael@0 166 bailoutKind_(kind)
michael@0 167 { }
michael@0 168
michael@0 169 bool
michael@0 170 LSnapshot::init(MIRGenerator *gen)
michael@0 171 {
michael@0 172 slots_ = gen->allocate<LAllocation>(numSlots_);
michael@0 173 return !!slots_;
michael@0 174 }
michael@0 175
michael@0 176 LSnapshot *
michael@0 177 LSnapshot::New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind)
michael@0 178 {
michael@0 179 LSnapshot *snapshot = new(gen->alloc()) LSnapshot(recover, kind);
michael@0 180 if (!snapshot || !snapshot->init(gen))
michael@0 181 return nullptr;
michael@0 182
michael@0 183 IonSpew(IonSpew_Snapshots, "Generating LIR snapshot %p from recover (%p)",
michael@0 184 (void *)snapshot, (void *)recover);
michael@0 185
michael@0 186 return snapshot;
michael@0 187 }
michael@0 188
michael@0 189 void
michael@0 190 LSnapshot::rewriteRecoveredInput(LUse input)
michael@0 191 {
michael@0 192 // Mark any operands to this snapshot with the same value as input as being
michael@0 193 // equal to the instruction's result.
michael@0 194 for (size_t i = 0; i < numEntries(); i++) {
michael@0 195 if (getEntry(i)->isUse() && getEntry(i)->toUse()->virtualRegister() == input.virtualRegister())
michael@0 196 setEntry(i, LUse(input.virtualRegister(), LUse::RECOVERED_INPUT));
michael@0 197 }
michael@0 198 }
michael@0 199
michael@0 200 LPhi *
michael@0 201 LPhi::New(MIRGenerator *gen, MPhi *ins)
michael@0 202 {
michael@0 203 LPhi *phi = new (gen->alloc()) LPhi();
michael@0 204 LAllocation *inputs = gen->allocate<LAllocation>(ins->numOperands());
michael@0 205 if (!inputs)
michael@0 206 return nullptr;
michael@0 207
michael@0 208 phi->inputs_ = inputs;
michael@0 209 phi->setMir(ins);
michael@0 210 return phi;
michael@0 211 }
michael@0 212
michael@0 213 void
michael@0 214 LInstruction::printName(FILE *fp, Opcode op)
michael@0 215 {
michael@0 216 static const char * const names[] =
michael@0 217 {
michael@0 218 #define LIROP(x) #x,
michael@0 219 LIR_OPCODE_LIST(LIROP)
michael@0 220 #undef LIROP
michael@0 221 };
michael@0 222 const char *name = names[op];
michael@0 223 size_t len = strlen(name);
michael@0 224 for (size_t i = 0; i < len; i++)
michael@0 225 fprintf(fp, "%c", tolower(name[i]));
michael@0 226 }
michael@0 227
michael@0 228 void
michael@0 229 LInstruction::printName(FILE *fp)
michael@0 230 {
michael@0 231 printName(fp, op());
michael@0 232 }
michael@0 233
michael@0 234 static const char * const TypeChars[] =
michael@0 235 {
michael@0 236 "g", // GENERAL
michael@0 237 "i", // INT32
michael@0 238 "o", // OBJECT
michael@0 239 "s", // SLOTS
michael@0 240 "f", // FLOAT32
michael@0 241 "d", // DOUBLE
michael@0 242 #ifdef JS_NUNBOX32
michael@0 243 "t", // TYPE
michael@0 244 "p" // PAYLOAD
michael@0 245 #elif JS_PUNBOX64
michael@0 246 "x" // BOX
michael@0 247 #endif
michael@0 248 };
michael@0 249
michael@0 250 static void
michael@0 251 PrintDefinition(FILE *fp, const LDefinition &def)
michael@0 252 {
michael@0 253 fprintf(fp, "[%s", TypeChars[def.type()]);
michael@0 254 if (def.virtualRegister())
michael@0 255 fprintf(fp, ":%d", def.virtualRegister());
michael@0 256 if (def.policy() == LDefinition::PRESET) {
michael@0 257 fprintf(fp, " (%s)", def.output()->toString());
michael@0 258 } else if (def.policy() == LDefinition::MUST_REUSE_INPUT) {
michael@0 259 fprintf(fp, " (!)");
michael@0 260 } else if (def.policy() == LDefinition::PASSTHROUGH) {
michael@0 261 fprintf(fp, " (-)");
michael@0 262 }
michael@0 263 fprintf(fp, "]");
michael@0 264 }
michael@0 265
michael@0 266 #ifdef DEBUG
michael@0 267 static void
michael@0 268 PrintUse(char *buf, size_t size, const LUse *use)
michael@0 269 {
michael@0 270 switch (use->policy()) {
michael@0 271 case LUse::REGISTER:
michael@0 272 JS_snprintf(buf, size, "v%d:r", use->virtualRegister());
michael@0 273 break;
michael@0 274 case LUse::FIXED:
michael@0 275 // Unfortunately, we don't know here whether the virtual register is a
michael@0 276 // float or a double. Should we steal a bit in LUse for help? For now,
michael@0 277 // nothing defines any fixed xmm registers.
michael@0 278 JS_snprintf(buf, size, "v%d:%s", use->virtualRegister(),
michael@0 279 Registers::GetName(Registers::Code(use->registerCode())));
michael@0 280 break;
michael@0 281 case LUse::ANY:
michael@0 282 JS_snprintf(buf, size, "v%d:r?", use->virtualRegister());
michael@0 283 break;
michael@0 284 case LUse::KEEPALIVE:
michael@0 285 JS_snprintf(buf, size, "v%d:*", use->virtualRegister());
michael@0 286 break;
michael@0 287 case LUse::RECOVERED_INPUT:
michael@0 288 JS_snprintf(buf, size, "v%d:**", use->virtualRegister());
michael@0 289 break;
michael@0 290 default:
michael@0 291 MOZ_ASSUME_UNREACHABLE("invalid use policy");
michael@0 292 }
michael@0 293 }
michael@0 294
michael@0 295 const char *
michael@0 296 LAllocation::toString() const
michael@0 297 {
michael@0 298 // Not reentrant!
michael@0 299 static char buf[40];
michael@0 300
michael@0 301 switch (kind()) {
michael@0 302 case LAllocation::CONSTANT_VALUE:
michael@0 303 case LAllocation::CONSTANT_INDEX:
michael@0 304 return "c";
michael@0 305 case LAllocation::GPR:
michael@0 306 JS_snprintf(buf, sizeof(buf), "=%s", toGeneralReg()->reg().name());
michael@0 307 return buf;
michael@0 308 case LAllocation::FPU:
michael@0 309 JS_snprintf(buf, sizeof(buf), "=%s", toFloatReg()->reg().name());
michael@0 310 return buf;
michael@0 311 case LAllocation::STACK_SLOT:
michael@0 312 JS_snprintf(buf, sizeof(buf), "stack:%d", toStackSlot()->slot());
michael@0 313 return buf;
michael@0 314 case LAllocation::ARGUMENT_SLOT:
michael@0 315 JS_snprintf(buf, sizeof(buf), "arg:%d", toArgument()->index());
michael@0 316 return buf;
michael@0 317 case LAllocation::USE:
michael@0 318 PrintUse(buf, sizeof(buf), toUse());
michael@0 319 return buf;
michael@0 320 default:
michael@0 321 MOZ_ASSUME_UNREACHABLE("what?");
michael@0 322 }
michael@0 323 }
michael@0 324 #endif // DEBUG
michael@0 325
michael@0 326 void
michael@0 327 LAllocation::dump() const
michael@0 328 {
michael@0 329 fprintf(stderr, "%s\n", toString());
michael@0 330 }
michael@0 331
michael@0 332 void
michael@0 333 LInstruction::printOperands(FILE *fp)
michael@0 334 {
michael@0 335 for (size_t i = 0, e = numOperands(); i < e; i++) {
michael@0 336 fprintf(fp, " (%s)", getOperand(i)->toString());
michael@0 337 if (i != numOperands() - 1)
michael@0 338 fprintf(fp, ",");
michael@0 339 }
michael@0 340 }
michael@0 341
michael@0 342 void
michael@0 343 LInstruction::assignSnapshot(LSnapshot *snapshot)
michael@0 344 {
michael@0 345 JS_ASSERT(!snapshot_);
michael@0 346 snapshot_ = snapshot;
michael@0 347
michael@0 348 #ifdef DEBUG
michael@0 349 if (IonSpewEnabled(IonSpew_Snapshots)) {
michael@0 350 IonSpewHeader(IonSpew_Snapshots);
michael@0 351 fprintf(IonSpewFile, "Assigning snapshot %p to instruction %p (",
michael@0 352 (void *)snapshot, (void *)this);
michael@0 353 printName(IonSpewFile);
michael@0 354 fprintf(IonSpewFile, ")\n");
michael@0 355 }
michael@0 356 #endif
michael@0 357 }
michael@0 358
michael@0 359 void
michael@0 360 LInstruction::dump(FILE *fp)
michael@0 361 {
michael@0 362 fprintf(fp, "{");
michael@0 363 for (size_t i = 0; i < numDefs(); i++) {
michael@0 364 PrintDefinition(fp, *getDef(i));
michael@0 365 if (i != numDefs() - 1)
michael@0 366 fprintf(fp, ", ");
michael@0 367 }
michael@0 368 fprintf(fp, "} <- ");
michael@0 369
michael@0 370 printName(fp);
michael@0 371
michael@0 372
michael@0 373 printInfo(fp);
michael@0 374
michael@0 375 if (numTemps()) {
michael@0 376 fprintf(fp, " t=(");
michael@0 377 for (size_t i = 0; i < numTemps(); i++) {
michael@0 378 PrintDefinition(fp, *getTemp(i));
michael@0 379 if (i != numTemps() - 1)
michael@0 380 fprintf(fp, ", ");
michael@0 381 }
michael@0 382 fprintf(fp, ")");
michael@0 383 }
michael@0 384 fprintf(fp, "\n");
michael@0 385 }
michael@0 386
michael@0 387 void
michael@0 388 LInstruction::dump()
michael@0 389 {
michael@0 390 return dump(stderr);
michael@0 391 }
michael@0 392
michael@0 393 void
michael@0 394 LInstruction::initSafepoint(TempAllocator &alloc)
michael@0 395 {
michael@0 396 JS_ASSERT(!safepoint_);
michael@0 397 safepoint_ = new(alloc) LSafepoint(alloc);
michael@0 398 JS_ASSERT(safepoint_);
michael@0 399 }
michael@0 400
michael@0 401 bool
michael@0 402 LMoveGroup::add(LAllocation *from, LAllocation *to, LDefinition::Type type)
michael@0 403 {
michael@0 404 #ifdef DEBUG
michael@0 405 JS_ASSERT(*from != *to);
michael@0 406 for (size_t i = 0; i < moves_.length(); i++)
michael@0 407 JS_ASSERT(*to != *moves_[i].to());
michael@0 408 #endif
michael@0 409 return moves_.append(LMove(from, to, type));
michael@0 410 }
michael@0 411
michael@0 412 bool
michael@0 413 LMoveGroup::addAfter(LAllocation *from, LAllocation *to, LDefinition::Type type)
michael@0 414 {
michael@0 415 // Transform the operands to this move so that performing the result
michael@0 416 // simultaneously with existing moves in the group will have the same
michael@0 417 // effect as if the original move took place after the existing moves.
michael@0 418
michael@0 419 for (size_t i = 0; i < moves_.length(); i++) {
michael@0 420 if (*moves_[i].to() == *from) {
michael@0 421 from = moves_[i].from();
michael@0 422 break;
michael@0 423 }
michael@0 424 }
michael@0 425
michael@0 426 if (*from == *to)
michael@0 427 return true;
michael@0 428
michael@0 429 for (size_t i = 0; i < moves_.length(); i++) {
michael@0 430 if (*to == *moves_[i].to()) {
michael@0 431 moves_[i] = LMove(from, to, type);
michael@0 432 return true;
michael@0 433 }
michael@0 434 }
michael@0 435
michael@0 436 return add(from, to, type);
michael@0 437 }
michael@0 438
michael@0 439 void
michael@0 440 LMoveGroup::printOperands(FILE *fp)
michael@0 441 {
michael@0 442 for (size_t i = 0; i < numMoves(); i++) {
michael@0 443 const LMove &move = getMove(i);
michael@0 444 // Use two printfs, as LAllocation::toString is not reentrant.
michael@0 445 fprintf(fp, "[%s", move.from()->toString());
michael@0 446 fprintf(fp, " -> %s]", move.to()->toString());
michael@0 447 if (i != numMoves() - 1)
michael@0 448 fprintf(fp, ", ");
michael@0 449 }
michael@0 450 }

mercurial