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.

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

mercurial