LCOV - app.info - js/src/methodjit/FrameState.cpp

LCOV - code coverage report
| Current view: | directory - js/src/methodjit - FrameState.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1514 | 1401 | 92.5 %
| Date: | 2012-04-07 | Functions: | 77 | 70 | 90.9 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
          18                 :  * May 28, 2008.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  *   Brendan Eich <brendan@mozilla.org>
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   David Anderson <danderson@mozilla.com>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 : #include "jscntxt.h"
          40                 : #include "FrameState.h"
          41                 : #include "FrameState-inl.h"
          42                 : #include "StubCompiler.h"
          43                 :
          44                 : using namespace js;
          45                 : using namespace js::mjit;
          46                 : using namespace js::analyze;
          47                 :
          48                 : /* Because of Value alignment */
          49                 : JS_STATIC_ASSERT(sizeof(FrameEntry) % 8 == 0);
          50                 :
          51           95862 : FrameState::FrameState(JSContext *cx, mjit::Compiler &cc,
          52                 :                        Assembler &masm, StubCompiler &stubcc)
          53                 :   : cx(cx),
          54                 :     masm(masm), cc(cc), stubcc(stubcc),
          55                 :     a(NULL), entries(NULL), nentries(0), freeRegs(Registers::AvailAnyRegs),
          56           95862 :     loop(NULL), inTryBlock(false)
          57                 : {
          58           95862 : }
          59                 :
          60          191724 : FrameState::~FrameState()
          61                 : {
          62          285455 :     while (a) {
          63           93731 :         ActiveFrame *parent = a->parent;
          64           93731 :         a->script->analysis()->clearAllocations();
          65           93731 :         cx->free_(a);
          66           93731 :         a = parent;
          67                 :     }
          68           95862 :     cx->free_(entries);
          69           95862 : }
          70                 :
          71                 : void
          72            2764 : FrameState::pruneDeadEntries()
          73                 : {
          74            2764 :     unsigned shift = 0;
          75           39410 :     for (unsigned i = 0; i < tracker.nentries; i++) {
          76           36646 :         FrameEntry *fe = tracker[i];
          77           36646 :         if (deadEntry(fe)) {
          78            6619 :             fe->untrack();
          79            6619 :             shift++;
          80           30027 :         } else if (shift) {
          81             990 :             fe->index_ -= shift;
          82             990 :             tracker.entries[fe->index_] = fe;
          83                 :         }
          84                 :     }
          85            2764 :     tracker.nentries -= shift;
          86            2764 : }
          87                 :
          88                 : bool
          89           96663 : FrameState::pushActiveFrame(JSScript *script, uint32_t argc)
          90                 : {
          91           96663 :     if (!a) {
          92           93731 :         this->nentries = analyze::TotalSlots(script) + (script->nslots - script->nfixed) +
          93           93731 :             StackSpace::STACK_JIT_EXTRA - VALUES_PER_STACK_FRAME;
          94                 :         size_t totalBytes = sizeof(FrameEntry) * nentries +       // entries[]
          95                 :                             sizeof(FrameEntry *) * nentries +     // tracker.entries
          96           93731 :                             sizeof(StackEntryExtra) * nentries;   // extraArray
          97           93731 :         uint8_t *cursor = (uint8_t *)OffTheBooks::calloc_(totalBytes);
          98           93731 :         if (!cursor)
          99               0 :             return false;
         100                 :
         101           93731 :         this->entries = (FrameEntry *) cursor;
         102           93731 :         cursor += sizeof(FrameEntry) * nentries;
         103                 :
         104           93731 :         this->tracker.entries = (FrameEntry **)cursor;
         105           93731 :         cursor += sizeof(FrameEntry *) * nentries;
         106                 :
         107           93731 :         this->extraArray = (StackEntryExtra *)cursor;
         108           93731 :         cursor += sizeof(StackEntryExtra) * nentries;
         109                 :
         110           93731 :         JS_ASSERT(reinterpret_cast<uint8_t *>(this->entries) + totalBytes == cursor);
         111                 :
         112                 : #if defined JS_NUNBOX32
         113           93731 :         if (!reifier.init(cx, *this, nentries))
         114               0 :             return false;
         115                 : #endif
         116                 :
         117           93731 :         this->temporaries = this->temporariesTop = this->entries + nentries - TEMPORARY_LIMIT;
         118                 :     }
         119                 :
         120                 :     /* We should have already checked that argc == nargs */
         121           96663 :     JS_ASSERT_IF(a, argc == script->function()->nargs);
         122                 :
         123           96663 :     ActiveFrame *newa = OffTheBooks::new_<ActiveFrame>();
         124           96663 :     if (!newa)
         125               0 :         return false;
         126                 :
         127           96663 :     newa->parent = a;
         128           96663 :     newa->depth = a ? (totalDepth() + VALUES_PER_STACK_FRAME) : 0;
         129                 :
         130           96663 :     newa->script = script;
         131           96663 :     newa->PC = script->code;
         132           96663 :     newa->analysis = script->analysis();
         133                 :
         134                 :     /*
         135                 :      * The callee/this/args in the new frame reuse the same entries as are on
         136                 :      * the stack in the old frame.
         137                 :      */
         138           96663 :     FrameEntry *entriesStart = a ? a->sp - (argc + 2) : entries;
         139           96663 :     newa->callee_ = entriesStart + analyze::CalleeSlot();
         140           96663 :     newa->this_   = entriesStart + analyze::ThisSlot();
         141           96663 :     newa->args    = entriesStart + analyze::ArgSlot(0);
         142           96663 :     newa->locals  = entriesStart + analyze::LocalSlot(script, 0);
         143           96663 :     newa->spBase  = entriesStart + analyze::TotalSlots(script);
         144           96663 :     newa->sp      = newa->spBase;
         145                 :
         146           96663 :     this->a = newa;
         147                 :
         148           96663 :     return true;
         149                 : }
         150                 :
         151                 : void
         152               0 : FrameState::associateReg(FrameEntry *fe, RematInfo::RematType type, AnyRegisterID reg)
         153                 : {
         154               0 :     freeRegs.takeReg(reg);
         155                 :
         156               0 :     if (type == RematInfo::TYPE)
         157               0 :         fe->type.setRegister(reg.reg());
         158               0 :     else if (reg.isReg())
         159               0 :         fe->data.setRegister(reg.reg());
         160                 :     else
         161               0 :         fe->data.setFPRegister(reg.fpreg());
         162               0 :     regstate(reg).associate(fe, type);
         163               0 : }
         164                 :
         165                 : void
         166            2932 : FrameState::popActiveFrame()
         167                 : {
         168            2932 :     a->analysis->clearAllocations();
         169                 :
         170            2932 :     if (a->parent) {
         171                 :         /* Clear registers and copies used by local variables and stack slots. */
         172            6988 :         for (FrameEntry *fe = a->sp - 1; fe >= a->locals; fe--) {
         173            4056 :             if (!fe->isTracked())
         174             395 :                 continue;
         175            3661 :             forgetAllRegs(fe);
         176            3661 :             fe->clear();
         177                 :         }
         178                 :     }
         179                 :
         180            2932 :     ActiveFrame *parent = a->parent;
         181            2932 :     cx->delete_(a);
         182            2932 :     a = parent;
         183            2932 : }
         184                 :
         185                 : void
         186          502569 : FrameState::takeReg(AnyRegisterID reg)
         187                 : {
         188          502569 :     modifyReg(reg);
         189          502569 :     if (freeRegs.hasReg(reg)) {
         190          484649 :         freeRegs.takeReg(reg);
         191          484649 :         JS_ASSERT(!regstate(reg).usedBy());
         192                 :     } else {
         193           17920 :         JS_ASSERT(regstate(reg).fe());
         194           17920 :         evictReg(reg);
         195                 :     }
         196          502569 : }
         197                 :
         198                 : #ifdef DEBUG
         199                 : const char *
         200          154612 : FrameState::entryName(const FrameEntry *fe) const
         201                 : {
         202                 :     static char bufs[4][50];
         203                 :     static unsigned which = 0;
         204          154612 :     which = (which + 1) & 3;
         205          154612 :     char *buf = bufs[which];
         206                 :
         207          154612 :     if (isTemporary(fe)) {
         208            5404 :         JS_snprintf(buf, 50, "temp%d", fe - temporaries);
         209            5404 :         return buf;
         210                 :     }
         211                 :
         212          149208 :     if (fe < a->callee_)
         213            1117 :         return "parent";
         214                 :
         215          148091 :     JS_ASSERT(fe >= a->callee_ && fe < a->sp);
         216                 :
         217          148091 :     if (fe == a->callee_)
         218             129 :         return "callee";
         219          147962 :     if (fe == a->this_)
         220            2125 :         return "'this'";
         221                 :
         222          145837 :     if (isArg(fe))
         223           15151 :         JS_snprintf(buf, 50, "arg%d", fe - a->args);
         224          130686 :     else if (isLocal(fe))
         225           62395 :         JS_snprintf(buf, 50, "local%d", fe - a->locals);
         226                 :     else
         227           68291 :         JS_snprintf(buf, 50, "slot%d", fe - a->spBase);
         228          145837 :     return buf;
         229                 : }
         230                 : #endif
         231                 :
         232                 : void
         233           94321 : FrameState::evictReg(AnyRegisterID reg)
         234                 : {
         235           94321 :     FrameEntry *fe = regstate(reg).fe();
         236                 :
         237           94321 :     JaegerSpew(JSpew_Regalloc, "evicting %s from %s\n", entryName(fe), reg.name());
         238                 :
         239           94321 :     if (regstate(reg).type() == RematInfo::TYPE) {
         240           36119 :         syncType(fe);
         241           36119 :         fe->type.setMemory();
         242           58202 :     } else if (reg.isReg()) {
         243           58190 :         syncData(fe);
         244           58190 :         fe->data.setMemory();
         245                 :     } else {
         246              12 :         syncFe(fe);
         247              12 :         fe->data.setMemory();
         248                 :     }
         249                 :
         250           94321 :     regstate(reg).forget();
         251           94321 : }
         252                 :
         253                 : inline Lifetime *
         254           88700 : FrameState::variableLive(FrameEntry *fe, jsbytecode *pc) const
         255                 : {
         256                 :     /*
         257                 :      * Whether an argument, local or 'this' entry is live at pc. Note: this
         258                 :      * does not account for the 'this' entry when the script is used as a
         259                 :      * constructor, in which case it is live the entire frame.
         260                 :      */
         261           88700 :     JS_ASSERT(cx->typeInferenceEnabled());
         262           88700 :     JS_ASSERT(fe > a->callee_ && fe < a->spBase);
         263                 :
         264           88700 :     uint32_t offset = pc - a->script->code;
         265           88700 :     return a->analysis->liveness(entrySlot(fe)).live(offset);
         266                 : }
         267                 :
         268                 : AnyRegisterID
         269           54168 : FrameState::bestEvictReg(uint32_t mask, bool includePinned) const
         270                 : {
         271           54168 :     JS_ASSERT(cx->typeInferenceEnabled());
         272                 :
         273                 :     /* Must be looking for a specific type of register. */
         274           54168 :     JS_ASSERT((mask & Registers::AvailRegs) != (mask & Registers::AvailFPRegs));
         275                 :
         276           54168 :     AnyRegisterID fallback;
         277           54168 :     uint32_t fallbackOffset = UINT32_MAX;
         278                 :
         279           54168 :     JaegerSpew(JSpew_Regalloc, "picking best register to evict:\n");
         280                 :
         281          857470 :     for (uint32_t i = 0; i < Registers::TotalAnyRegisters; i++) {
         282          804032 :         AnyRegisterID reg = AnyRegisterID::fromRaw(i);
         283                 :
         284                 :         /* Register is not allocatable, don't bother.  */
         285          804032 :         if (!(Registers::maskReg(reg) & mask))
         286          486718 :             continue;
         287                 :
         288                 :         /* Register is not owned by the FrameState. */
         289          317314 :         FrameEntry *fe = includePinned ? regstate(reg).usedBy() : regstate(reg).fe();
         290          317314 :         if (!fe)
         291           70769 :             continue;
         292                 :
         293                 :         /*
         294                 :          * Liveness is not tracked for the callee or for stack slot frame entries.
         295                 :          * The callee is evicted as early as needed, stack slots are evicted as
         296                 :          * late as possible. :XXX: This is unfortunate if the stack slot lives
         297                 :          * a long time (especially if it gets spilled anyways when we hit a branch).
         298                 :          */
         299                 :
         300          246545 :         if (fe == a->callee_) {
         301             129 :             JaegerSpew(JSpew_Regalloc, "result: %s is callee\n", reg.name());
         302             129 :             return reg;
         303                 :         }
         304                 :
         305          246416 :         if (fe >= a->spBase && !isTemporary(fe)) {
         306          214218 :             if (!fallback.isSet()) {
         307           46905 :                 fallback = reg;
         308           46905 :                 fallbackOffset = 0;
         309                 :             }
         310          214218 :             JaegerSpew(JSpew_Regalloc, "    %s is on stack\n", reg.name());
         311          214218 :             continue;
         312                 :         }
         313                 :
         314                 :         /* Prioritize keeping copied entries in registers. */
         315           32198 :         if (fe->isCopied()) {
         316           14820 :             if (!fallback.isSet()) {
         317            4256 :                 fallback = reg;
         318            4256 :                 fallbackOffset = 0;
         319                 :             }
         320           14820 :             JaegerSpew(JSpew_Regalloc, "    %s has copies\n", reg.name());
         321           14820 :             continue;
         322                 :         }
         323                 :
         324           17378 :         if (isTemporary(fe) || (a->parent && fe < a->locals)) {
         325                 :             /*
         326                 :              * All temporaries we currently generate are for loop invariants,
         327                 :              * which we treat as being live everywhere within the loop.
         328                 :              * Additionally, if this is an inlined frame then any entries
         329                 :              * belonging to parents are treated as live everywhere in the call.
         330                 :              */
         331            4668 :             uint32_t offset = a->parent ? a->script->length : loop->backedgeOffset();
         332            4668 :             if (!fallback.isSet() || offset > fallbackOffset) {
         333            1883 :                 fallback = reg;
         334            1883 :                 fallbackOffset = offset;
         335                 :             }
         336            4668 :             JaegerSpew(JSpew_Regalloc, "    %s is a LICM or inline parent entry\n", reg.name());
         337            4668 :             continue;
         338                 :         }
         339                 :
         340                 :         /*
         341                 :          * All entries still in registers should have a lifetime, except 'this'
         342                 :          * in constructors which are not accessed later on.
         343                 :          */
         344           12710 :         Lifetime *lifetime = variableLive(fe, a->PC);
         345                 :
         346           12710 :         if (!lifetime) {
         347              17 :             JS_ASSERT(isConstructorThis(fe));
         348              17 :             fallback = reg;
         349              17 :             fallbackOffset = a->script->length;
         350              17 :             JaegerSpew(JSpew_Regalloc, "    %s is 'this' in a constructor\n", reg.name());
         351              17 :             continue;
         352                 :         }
         353                 :
         354                 :         /*
         355                 :          * Evict variables which are only live in future loop iterations, and are
         356                 :          * not carried around the loop in a register.
         357                 :          */
         358           12693 :         if (lifetime->loopTail && (!loop || !loop->carriesLoopReg(fe))) {
         359                 :             JaegerSpew(JSpew_Regalloc, "result: %s (%s) only live in later iterations\n",
         360             601 :                        entryName(fe), reg.name());
         361             601 :             return reg;
         362                 :         }
         363                 :
         364           12092 :         JaegerSpew(JSpew_Regalloc, "    %s (%s): %u\n", entryName(fe), reg.name(), lifetime->end);
         365                 :
         366                 :         /*
         367                 :          * The best live register to evict is the one that will be live for the
         368                 :          * longest time. This may need tweaking for variables that are used in
         369                 :          * many places throughout their lifetime. Note that we don't pay attention
         370                 :          * to whether the register is synced or not --- it is more efficient to
         371                 :          * have things in registers when they're needed than to emit some extra
         372                 :          * writes for things that won't be used again for a while.
         373                 :          */
         374                 :
         375           12092 :         if (!fallback.isSet() || lifetime->end > fallbackOffset) {
         376            7929 :             fallback = reg;
         377            7929 :             fallbackOffset = lifetime->end;
         378                 :         }
         379                 :     }
         380                 :
         381           53438 :     JS_ASSERT(fallback.isSet());
         382                 :
         383           53438 :     JaegerSpew(JSpew_Regalloc, "result %s\n", fallback.name());
         384           53438 :     return fallback;
         385                 : }
         386                 :
         387                 : void
         388           67369 : FrameState::evictDeadEntries(bool includePinned)
         389                 : {
         390         1077904 :     for (uint32_t i = 0; i < Registers::TotalAnyRegisters; i++) {
         391         1010535 :         AnyRegisterID reg = AnyRegisterID::fromRaw(i);
         392                 :
         393                 :         /* Follow along with the same filters as bestEvictReg. */
         394                 :
         395         1010535 :         if (!(Registers::maskReg(reg) & Registers::AvailAnyRegs))
         396          134738 :             continue;
         397                 :
         398          875797 :         FrameEntry *fe = includePinned ? regstate(reg).usedBy() : regstate(reg).fe();
         399          875797 :         if (!fe)
         400          587302 :             continue;
         401                 :
         402          334608 :         if (fe == a->callee_ || isConstructorThis(fe) ||
         403           46113 :             fe >= a->spBase || fe->isCopied() || (a->parent && fe < a->locals)) {
         404          268839 :             continue;
         405                 :         }
         406                 :
         407           19656 :         Lifetime *lifetime = variableLive(fe, a->PC);
         408           19656 :         if (lifetime)
         409           17622 :             continue;
         410                 :
         411                 :         /*
         412                 :          * If we are about to fake sync for an entry with known type, reset
         413                 :          * that type. We don't want to regard it as correctly synced later.
         414                 :          */
         415            2034 :         if (!fe->type.synced() && fe->isTypeKnown())
         416             226 :             fe->type.setMemory();
         417                 :
         418                 :         /*
         419                 :          * Mark the entry as synced to avoid emitting a store, we don't need
         420                 :          * to keep this value around.
         421                 :          */
         422            2034 :         fakeSync(fe);
         423            2034 :         if (regstate(reg).type() == RematInfo::DATA)
         424            1491 :             fe->data.setMemory();
         425                 :         else
         426             543 :             fe->type.setMemory();
         427            2034 :         forgetReg(reg);
         428                 :     }
         429           67369 : }
         430                 :
         431                 : AnyRegisterID
         432           89751 : FrameState::evictSomeReg(uint32_t mask)
         433                 : {
         434           89751 :     JS_ASSERT(!freeRegs.hasRegInMask(mask));
         435                 :
         436           89751 :     if (cx->typeInferenceEnabled()) {
         437           54120 :         evictDeadEntries(false);
         438                 :
         439           54120 :         if (freeRegs.hasRegInMask(mask)) {
         440                 :             /* There was a register in use by a dead local variable. */
         441            1102 :             AnyRegisterID reg = freeRegs.takeAnyReg(mask);
         442            1102 :             modifyReg(reg);
         443            1102 :             return reg;
         444                 :         }
         445                 :
         446           53018 :         AnyRegisterID reg = bestEvictReg(mask, false);
         447           53018 :         evictReg(reg);
         448           53018 :         return reg;
         449                 :     }
         450                 :
         451                 :     /* With inference disabled, only general purpose registers are managed. */
         452           35631 :     JS_ASSERT((mask & ~Registers::AvailRegs) == 0);
         453                 :
         454           35631 :     MaybeRegisterID fallback;
         455                 :
         456          251186 :     for (uint32_t i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
         457          227803 :         RegisterID reg = RegisterID(i);
         458                 :
         459                 :         /* Register is not allocatable, don't bother.  */
         460          227803 :         if (!(Registers::maskReg(reg) & mask))
         461           53250 :             continue;
         462                 :
         463                 :         /* Register is not owned by the FrameState. */
         464          174553 :         FrameEntry *fe = regstate(reg).fe();
         465          174553 :         if (!fe)
         466           32283 :             continue;
         467                 :
         468                 :         /* Try to find a candidate... that doesn't need spilling. */
         469          142270 :         fallback = reg;
         470                 :
         471          142270 :         if (regstate(reg).type() == RematInfo::TYPE && fe->type.synced()) {
         472            6776 :             fe->type.setMemory();
         473            6776 :             regstate(reg).forget();
         474            6776 :             return reg;
         475                 :         }
         476          135494 :         if (regstate(reg).type() == RematInfo::DATA && fe->data.synced()) {
         477            5472 :             fe->data.setMemory();
         478            5472 :             regstate(reg).forget();
         479            5472 :             return reg;
         480                 :         }
         481                 :     }
         482                 :
         483           23383 :     evictReg(fallback.reg());
         484           23383 :     return fallback.reg();
         485                 : }
         486                 :
         487                 : void
         488          604151 : FrameState::resetInternalState()
         489                 : {
         490         1989827 :     for (uint32_t i = 0; i < tracker.nentries; i++)
         491         1385676 :         tracker[i]->untrack();
         492                 :
         493          604151 :     tracker.reset();
         494          604151 :     freeRegs = Registers(Registers::AvailAnyRegs);
         495          604151 : }
         496                 :
         497                 : void
         498          102477 : FrameState::discardFrame()
         499                 : {
         500          102477 :     resetInternalState();
         501          102477 :     PodArrayZero(regstate_);
         502          102477 : }
         503                 :
         504                 : FrameEntry *
         505             155 : FrameState::snapshotState()
         506                 : {
         507                 :     /* Everything can be recovered from a copy of the frame entries. */
         508             155 :     FrameEntry *snapshot = cx->array_new<FrameEntry>(nentries);
         509             155 :     if (!snapshot)
         510               0 :         return NULL;
         511             155 :     PodCopy(snapshot, entries, nentries);
         512             155 :     return snapshot;
         513                 : }
         514                 :
         515                 : void
         516             323 : FrameState::restoreFromSnapshot(FrameEntry *snapshot)
         517                 : {
         518             323 :     discardFrame();
         519             323 :     PodCopy(entries, snapshot, nentries);
         520                 :
         521           85329 :     for (unsigned i = 0; i < nentries; i++) {
         522           85006 :         FrameEntry *fe = entries + i;
         523           85006 :         if (!fe->isTracked())
         524           83158 :             continue;
         525            1848 :         tracker.entries[fe->index_] = fe;
         526            1848 :         tracker.nentries = Max(tracker.nentries, fe->index_ + 1);
         527            1848 :         if (fe->isCopy())
         528             518 :             continue;
         529            1330 :         if (fe->type.inRegister()) {
         530              24 :             freeRegs.takeReg(fe->type.reg());
         531              24 :             regstate(fe->type.reg()).associate(fe, RematInfo::TYPE);
         532                 :         }
         533            1330 :         if (fe->data.inRegister()) {
         534            1048 :             freeRegs.takeReg(fe->data.reg());
         535            1048 :             regstate(fe->data.reg()).associate(fe, RematInfo::DATA);
         536                 :         }
         537            1330 :         if (fe->data.inFPRegister()) {
         538               0 :             freeRegs.takeReg(fe->data.fpreg());
         539               0 :             regstate(fe->data.fpreg()).associate(fe, RematInfo::DATA);
         540                 :         }
         541                 :     }
         542             323 : }
         543                 :
         544                 : void
         545          204022 : FrameState::forgetEverything()
         546                 : {
         547          204022 :     resetInternalState();
         548                 :
         549                 : #ifdef DEBUG
         550         3264352 :     for (uint32_t i = 0; i < Registers::TotalAnyRegisters; i++) {
         551         3060330 :         AnyRegisterID reg = AnyRegisterID::fromRaw(i);
         552         3060330 :         JS_ASSERT(!regstate(reg).usedBy());
         553                 :     }
         554                 : #endif
         555          204022 : }
         556                 :
         557                 : #ifdef DEBUG
         558                 : void
         559               0 : FrameState::dumpAllocation(RegisterAllocation *alloc)
         560                 : {
         561               0 :     JS_ASSERT(cx->typeInferenceEnabled());
         562               0 :     for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
         563               0 :         AnyRegisterID reg = AnyRegisterID::fromRaw(i);
         564               0 :         if (alloc->assigned(reg)) {
         565               0 :             printf(" (%s: %s%s)", reg.name(), entryName(entries + alloc->index(reg)),
         566               0 :                    alloc->synced(reg) ? "" : " unsynced");
         567                 :         }
         568                 :     }
         569               0 :     printf("\n");
         570               0 : }
         571                 : #endif
         572                 :
         573                 : RegisterAllocation *
         574          147124 : FrameState::computeAllocation(jsbytecode *target)
         575                 : {
         576          147124 :     JS_ASSERT(cx->typeInferenceEnabled());
         577          147124 :     RegisterAllocation *alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
         578          147124 :     if (!alloc) {
         579               0 :         js_ReportOutOfMemory(cx);
         580               0 :         return NULL;
         581                 :     }
         582                 :
         583                 :     /*
         584                 :      * State must be synced at exception and switch targets, at traps and when
         585                 :      * crossing between compilation chunks.
         586                 :      */
         587          435265 :     if (a->analysis->getCode(target).safePoint ||
         588          288141 :         (!a->parent && !cc.bytecodeInChunk(target))) {
         589                 : #ifdef DEBUG
         590            1161 :         if (IsJaegerSpewChannelActive(JSpew_Regalloc)) {
         591               0 :             JaegerSpew(JSpew_Regalloc, "allocation at %u:", unsigned(target - a->script->code));
         592               0 :             dumpAllocation(alloc);
         593                 :         }
         594                 : #endif
         595            1161 :         return alloc;
         596                 :     }
         597                 :
         598                 :     /*
         599                 :      * The allocation to use at the target consists of all parent, temporary
         600                 :      * and non-stack entries currently in registers which are live at target.
         601                 :      */
         602          145963 :     Registers regs = Registers::AvailAnyRegs;
         603         2189445 :     while (!regs.empty()) {
         604         1897519 :         AnyRegisterID reg = regs.takeAnyReg();
         605         1897519 :         if (freeRegs.hasReg(reg) || regstate(reg).type() == RematInfo::TYPE)
         606         1806646 :             continue;
         607           90873 :         FrameEntry *fe = regstate(reg).fe();
         608          285627 :         if (fe < a->callee_ ||
         609           88356 :             isConstructorThis(fe) ||
         610           52891 :             (fe > a->callee_ && fe < a->spBase && variableLive(fe, target)) ||
         611           53507 :             (isTemporary(fe) && (a->parent || uint32_t(target - a->script->code) <= loop->backedgeOffset()))) {
         612                 :             /*
         613                 :              * For entries currently in floating point registers, check they
         614                 :              * are known to be doubles at the target. We don't need to do this
         615                 :              * for entries in normal registers, as fixDoubleTypes must have been
         616                 :              * called to convert them to floats.
         617                 :              */
         618           38845 :             if (!reg.isReg() && !isTemporary(fe) && fe >= a->callee_ && fe < a->spBase) {
         619             486 :                 if (!a->analysis->trackSlot(entrySlot(fe)))
         620               0 :                     continue;
         621             486 :                 bool nonDoubleTarget = false;
         622             486 :                 const SlotValue *newv = a->analysis->newValues(target);
         623            1651 :                 while (newv && newv->slot) {
         624            2003 :                     if (newv->value.kind() == SSAValue::PHI &&
         625             662 :                         newv->value.phiOffset() == uint32_t(target - a->script->code) &&
         626             662 :                         newv->slot == entrySlot(fe)) {
         627             123 :                         types::TypeSet *types = a->analysis->getValueTypes(newv->value);
         628             123 :                         if (types->getKnownTypeTag(cx) != JSVAL_TYPE_DOUBLE)
         629               0 :                             nonDoubleTarget = true;
         630                 :                     }
         631             679 :                     newv++;
         632                 :                 }
         633             486 :                 if (nonDoubleTarget)
         634               0 :                     continue;
         635                 :             }
         636           38845 :             alloc->set(reg, fe - entries, fe->data.synced());
         637                 :         }
         638                 :     }
         639                 :
         640                 : #ifdef DEBUG
         641          145963 :     if (IsJaegerSpewChannelActive(JSpew_Regalloc)) {
         642               0 :         JaegerSpew(JSpew_Regalloc, "allocation at %u:", unsigned(target - a->script->code));
         643               0 :         dumpAllocation(alloc);
         644                 :     }
         645                 : #endif
         646                 :
         647          145963 :     return alloc;
         648                 : }
         649                 :
         650                 : void
         651            2896 : FrameState::relocateReg(AnyRegisterID reg, RegisterAllocation *alloc, Uses uses)
         652                 : {
         653            2896 :     JS_ASSERT(cx->typeInferenceEnabled());
         654                 :
         655                 :     /*
         656                 :      * The reg needs to be freed to make room for a variable carried across
         657                 :      * a branch. Either evict its entry, or try to move it to a different
         658                 :      * register if it is needed to test the branch condition. :XXX: could also
         659                 :      * watch for variables which are carried across the branch but are in a
         660                 :      * the register for a different carried entry, we just spill these for now.
         661                 :      */
         662            2896 :     JS_ASSERT(!freeRegs.hasReg(reg));
         663                 :
         664            5218 :     for (unsigned i = 0; i < uses.nuses; i++) {
         665            3955 :         FrameEntry *fe = peek(-1 - i);
         666            3955 :         if (fe->isCopy())
         667            1959 :             fe = fe->copyOf();
         668            3955 :         if (reg.isReg() && fe->data.inRegister() && fe->data.reg() == reg.reg()) {
         669            1633 :             pinReg(reg);
         670            1633 :             RegisterID nreg = allocReg();
         671            1633 :             unpinReg(reg);
         672                 :
         673            1633 :             JaegerSpew(JSpew_Regalloc, "relocating %s\n", reg.name());
         674                 :
         675            1633 :             masm.move(reg.reg(), nreg);
         676            1633 :             regstate(reg).forget();
         677            1633 :             regstate(nreg).associate(fe, RematInfo::DATA);
         678            1633 :             fe->data.setRegister(nreg);
         679            1633 :             freeRegs.putReg(reg);
         680            1633 :             return;
         681                 :         }
         682                 :     }
         683                 :
         684            1263 :     JaegerSpew(JSpew_Regalloc, "could not relocate %s\n", reg.name());
         685                 :
         686            1263 :     takeReg(reg);
         687            1263 :     freeRegs.putReg(reg);
         688                 : }
         689                 :
         690                 : bool
         691          328280 : FrameState::syncForBranch(jsbytecode *target, Uses uses)
         692                 : {
         693                 :     /* There should be no unowned or pinned registers. */
         694                 : #ifdef DEBUG
         695          328280 :     Registers checkRegs(Registers::AvailAnyRegs);
         696         4924200 :     while (!checkRegs.empty()) {
         697         4267640 :         AnyRegisterID reg = checkRegs.takeAnyReg();
         698         4267640 :         JS_ASSERT_IF(!freeRegs.hasReg(reg), regstate(reg).fe());
         699                 :     }
         700                 : #endif
         701                 :
         702          328280 :     if (!cx->typeInferenceEnabled()) {
         703          127261 :         syncAndForgetEverything();
         704          127261 :         return true;
         705                 :     }
         706                 :
         707          201019 :     RegisterAllocation *&alloc = a->analysis->getAllocation(target);
         708          201019 :     if (!alloc) {
         709          146780 :         alloc = computeAllocation(target);
         710          146780 :         if (!alloc)
         711               0 :             return false;
         712                 :     }
         713                 :
         714          201019 :     syncForAllocation(alloc, false, uses);
         715                 :
         716          201019 :     return true;
         717                 : }
         718                 :
         719                 : void
         720          201812 : FrameState::syncForAllocation(RegisterAllocation *alloc, bool inlineReturn, Uses uses)
         721                 : {
         722                 :     /*
         723                 :      * First pass. Sync all entries which will not be carried in a register,
         724                 :      * and uncopy everything except values popped by the branch or before the
         725                 :      * call returns.
         726                 :      */
         727                 :
         728          201812 :     FrameEntry *topEntry = NULL;
         729          201812 :     if (inlineReturn)
         730             793 :         topEntry = a->parent->sp - (GET_ARGC(a->parent->PC) + 2);
         731                 :
         732          975111 :     for (uint32_t i = tracker.nentries - 1; i < tracker.nentries; i--) {
         733          773299 :         FrameEntry *fe = tracker[i];
         734                 :
         735          773299 :         if (deadEntry(fe, uses.nuses))
         736          464427 :             continue;
         737          308872 :         if (inlineReturn && fe >= topEntry && !isTemporary(fe)) {
         738                 :             /*
         739                 :              * The return value has already been stored, so there is no need to
         740                 :              * keep any of the entries for this frame or for values popped once
         741                 :              * the call returns intact. Forcibly evict any registers for these,
         742                 :              * so that we don't emit sync code for them if we need a register
         743                 :              * in syncFe below.
         744                 :              */
         745            1775 :             forgetAllRegs(fe);
         746            1775 :             fe->resetSynced();
         747            1775 :             continue;
         748                 :         }
         749                 :
         750                 :         /* Force syncs for locals which are dead at the current PC. */
         751          307097 :         if (isLocal(fe) && !fe->copied && !a->analysis->slotEscapes(entrySlot(fe))) {
         752           87084 :             Lifetime *lifetime = a->analysis->liveness(entrySlot(fe)).live(a->PC - a->script->code);
         753           87084 :             if (!lifetime)
         754           38420 :                 fakeSync(fe);
         755                 :         }
         756                 :
         757                 :         /* If returning from a script, fake syncs for dead locals in the immediate parent. */
         758          307573 :         if (inlineReturn && fe >= a->parent->locals &&
         759                 :             fe - a->parent->locals < a->parent->script->nfixed &&
         760             476 :             !a->parent->analysis->slotEscapes(frameSlot(a->parent, fe))) {
         761             476 :             const LifetimeVariable &var = a->parent->analysis->liveness(frameSlot(a->parent, fe));
         762             476 :             Lifetime *lifetime = var.live(a->parent->PC - a->parent->script->code);
         763             476 :             if (!lifetime)
         764              47 :                 fakeSync(fe);
         765                 :         }
         766                 :
         767          307097 :         if (!fe->isCopy() && alloc->hasAnyReg(fe - entries)) {
         768                 :             /* Types are always synced, except for known doubles. */
         769           51861 :             if (!fe->isType(JSVAL_TYPE_DOUBLE))
         770           51262 :                 syncType(fe);
         771                 :         } else {
         772          255236 :             syncFe(fe);
         773          255236 :             if (fe->isCopy())
         774            3822 :                 fe->resetSynced();
         775                 :         }
         776                 :     }
         777                 :
         778                 :     /*
         779                 :      * Second pass. Move entries carried in registers to the right register
         780                 :      * provided no value used in the branch is evicted. After this pass,
         781                 :      * everything will either be in the right register or will be in memory.
         782                 :      */
         783                 :
         784          201812 :     Registers regs = Registers(Registers::AvailAnyRegs);
         785         3027180 :     while (!regs.empty()) {
         786         2623556 :         AnyRegisterID reg = regs.takeAnyReg();
         787         2623556 :         if (!alloc->assigned(reg))
         788         2568464 :             continue;
         789           55092 :         FrameEntry *fe = getOrTrack(alloc->index(reg));
         790           55092 :         JS_ASSERT(!fe->isCopy());
         791                 :
         792           55092 :         JS_ASSERT_IF(!fe->isType(JSVAL_TYPE_DOUBLE), fe->type.synced());
         793           55092 :         if (!fe->data.synced() && alloc->synced(reg))
         794            3983 :             syncFe(fe);
         795                 :
         796           55092 :         if (fe->dataInRegister(reg))
         797           46933 :             continue;
         798                 :
         799            8159 :         if (!freeRegs.hasReg(reg))
         800            2896 :             relocateReg(reg, alloc, uses);
         801                 :
         802            8159 :         if (reg.isReg()) {
         803            8059 :             RegisterID nreg = reg.reg();
         804            8059 :             if (fe->isType(JSVAL_TYPE_DOUBLE)) {
         805               0 :                 JS_ASSERT(!a->analysis->trackSlot(entrySlot(fe)));
         806               0 :                 syncFe(fe);
         807               0 :                 forgetAllRegs(fe);
         808               0 :                 fe->type.setMemory();
         809               0 :                 fe->data.setMemory();
         810                 :             }
         811            8059 :             if (fe->data.inMemory()) {
         812            4969 :                 masm.loadPayload(addressOf(fe), nreg);
         813            3090 :             } else if (fe->isConstant()) {
         814               7 :                 masm.loadValuePayload(fe->getValue(), nreg);
         815                 :             } else {
         816            3083 :                 JS_ASSERT(fe->data.inRegister() && fe->data.reg() != nreg);
         817            3083 :                 masm.move(fe->data.reg(), nreg);
         818            3083 :                 freeRegs.putReg(fe->data.reg());
         819            3083 :                 regstate(fe->data.reg()).forget();
         820                 :             }
         821            8059 :             fe->data.setRegister(nreg);
         822                 :         } else {
         823             100 :             FPRegisterID nreg = reg.fpreg();
         824             100 :             JS_ASSERT(!fe->isNotType(JSVAL_TYPE_DOUBLE));
         825             100 :             if (!fe->isTypeKnown())
         826              88 :                 learnType(fe, JSVAL_TYPE_DOUBLE, false);
         827             100 :             if (fe->data.inMemory()) {
         828              90 :                 masm.loadDouble(addressOf(fe), nreg);
         829              10 :             } else if (fe->isConstant()) {
         830               2 :                 masm.slowLoadConstantDouble(fe->getValue().toDouble(), nreg);
         831                 :             } else {
         832               8 :                 JS_ASSERT(fe->data.inFPRegister() && fe->data.fpreg() != nreg);
         833               8 :                 masm.moveDouble(fe->data.fpreg(), nreg);
         834               8 :                 freeRegs.putReg(fe->data.fpreg());
         835               8 :                 regstate(fe->data.fpreg()).forget();
         836                 :             }
         837             100 :             fe->data.setFPRegister(nreg);
         838                 :         }
         839                 :
         840            8159 :         freeRegs.takeReg(reg);
         841            8159 :         regstate(reg).associate(fe, RematInfo::DATA);
         842                 :     }
         843          201812 : }
         844                 :
         845                 : bool
         846          297652 : FrameState::discardForJoin(RegisterAllocation *&alloc, uint32_t stackDepth)
         847                 : {
         848          297652 :     if (!cx->typeInferenceEnabled()) {
         849          106611 :         resetInternalState();
         850          106611 :         PodArrayZero(regstate_);
         851          106611 :         a->sp = a->spBase + stackDepth;
         852          106611 :         return true;
         853                 :     }
         854                 :
         855          191041 :     if (!alloc) {
         856                 :         /*
         857                 :          * This shows up for loop entries which are not reachable from the
         858                 :          * loop head, and for exception, switch target and trap safe points.
         859                 :          */
         860            3957 :         alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
         861            3957 :         if (!alloc) {
         862               0 :             js_ReportOutOfMemory(cx);
         863               0 :             return false;
         864                 :         }
         865                 :     }
         866                 :
         867          191041 :     resetInternalState();
         868          191041 :     PodArrayZero(regstate_);
         869                 :
         870          191041 :     Registers regs(Registers::AvailAnyRegs);
         871         2865615 :     while (!regs.empty()) {
         872         2483533 :         AnyRegisterID reg = regs.takeAnyReg();
         873         2483533 :         if (!alloc->assigned(reg))
         874         2444735 :             continue;
         875           38798 :         FrameEntry *fe = getOrTrack(alloc->index(reg));
         876                 :
         877           38798 :         freeRegs.takeReg(reg);
         878                 :
         879                 :         /*
         880                 :          * We can't look at the type of the fe as we haven't restored analysis types yet,
         881                 :          * but if this is an FP reg it will be set to double type.
         882                 :          */
         883           38798 :         if (reg.isReg()) {
         884           38289 :             fe->data.setRegister(reg.reg());
         885                 :         } else {
         886             509 :             fe->setType(JSVAL_TYPE_DOUBLE);
         887             509 :             fe->data.setFPRegister(reg.fpreg());
         888                 :         }
         889                 :
         890           38798 :         regstate(reg).associate(fe, RematInfo::DATA);
         891           38798 :         if (!alloc->synced(reg)) {
         892           16511 :             fe->data.unsync();
         893           16511 :             if (!reg.isReg())
         894             269 :                 fe->type.unsync();
         895                 :         }
         896                 :     }
         897                 :
         898          191041 :     a->sp = a->spBase + stackDepth;
         899                 :
         900          310120 :     for (unsigned i = 0; i < stackDepth; i++)
         901          119079 :         extraArray[a->spBase + i - entries].reset();
         902                 :
         903          191041 :     return true;
         904                 : }
         905                 :
         906                 : bool
         907          289883 : FrameState::consistentRegisters(jsbytecode *target)
         908                 : {
         909          289883 :     if (!cx->typeInferenceEnabled()) {
         910           63273 :         JS_ASSERT(freeRegs.freeMask == Registers::AvailAnyRegs);
         911           63273 :         return true;
         912                 :     }
         913                 :
         914                 :     /*
         915                 :      * Before calling this, either the entire state should have been synced or
         916                 :      * syncForBranch should have been called. These will ensure that any FE
         917                 :      * which is not consistent with the target's register state has already
         918                 :      * been synced, and no stores will need to be issued by prepareForJump.
         919                 :      */
         920          226610 :     RegisterAllocation *alloc = a->analysis->getAllocation(target);
         921          226610 :     JS_ASSERT(alloc);
         922                 :
         923          226610 :     Registers regs(Registers::AvailAnyRegs);
         924          226610 :     while (!regs.empty()) {
         925         2920552 :         AnyRegisterID reg = regs.takeAnyReg();
         926         2920552 :         if (alloc->assigned(reg)) {
         927           61145 :             FrameEntry *needed = getOrTrack(alloc->index(reg));
         928           61145 :             if (!freeRegs.hasReg(reg)) {
         929           54343 :                 FrameEntry *fe = regstate(reg).fe();
         930           54343 :                 if (fe != needed)
         931              14 :                     return false;
         932                 :             } else {
         933            6802 :                 return false;
         934                 :             }
         935                 :         }
         936                 :     }
         937                 :
         938          219794 :     return true;
         939                 : }
         940                 :
         941                 : void
         942           83298 : FrameState::prepareForJump(jsbytecode *target, Assembler &masm, bool synced)
         943                 : {
         944           83298 :     if (!cx->typeInferenceEnabled())
         945               0 :         return;
         946                 :
         947           83298 :     JS_ASSERT_IF(!synced, !consistentRegisters(target));
         948                 :
         949           83298 :     RegisterAllocation *alloc = a->analysis->getAllocation(target);
         950           83298 :     JS_ASSERT(alloc);
         951                 :
         952           83298 :     Registers regs = 0;
         953                 :
         954           83298 :     regs = Registers(Registers::AvailAnyRegs);
         955         1249470 :     while (!regs.empty()) {
         956         1082874 :         AnyRegisterID reg = regs.takeAnyReg();
         957         1082874 :         if (!alloc->assigned(reg))
         958         1020677 :             continue;
         959                 :
         960           62197 :         const FrameEntry *fe = getOrTrack(alloc->index(reg));
         961           62197 :         if (synced || !fe->backing()->dataInRegister(reg)) {
         962           62154 :             JS_ASSERT_IF(!synced, fe->data.synced());
         963           62154 :             if (reg.isReg())
         964           61628 :                 masm.loadPayload(addressOf(fe), reg.reg());
         965                 :             else
         966             526 :                 masm.loadDouble(addressOf(fe), reg.fpreg());
         967                 :         }
         968                 :     }
         969                 : }
         970                 :
         971                 : void
         972          235574 : FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
         973                 : {
         974          235574 :     if (fe->isConstant()) {
         975           84088 :         masm.storeValue(fe->getValue(), address);
         976           84088 :         return;
         977                 :     }
         978                 :
         979          151486 :     if (fe->isCopy())
         980            2682 :         fe = fe->copyOf();
         981                 :
         982          151486 :     JS_ASSERT(!freeRegs.hasReg(address.base));
         983                 :
         984                 :     /* If loading from memory, ensure destination differs. */
         985          260570 :     JS_ASSERT_IF((fe->type.inMemory() || fe->data.inMemory()),
         986                 :                  addressOf(fe).base != address.base ||
         987          260570 :                  addressOf(fe).offset != address.offset);
         988                 :
         989          151486 :     if (fe->data.inFPRegister()) {
         990            2430 :         masm.storeDouble(fe->data.fpreg(), address);
         991            2430 :         return;
         992                 :     }
         993                 :
         994          149056 :     if (fe->isType(JSVAL_TYPE_DOUBLE)) {
         995             101 :         JS_ASSERT(fe->data.inMemory());
         996             101 :         masm.loadDouble(addressOf(fe), Registers::FPConversionTemp);
         997             101 :         masm.storeDouble(Registers::FPConversionTemp, address);
         998             101 :         return;
         999                 :     }
        1000                 :
        1001                 :     /* Don't clobber the address's register. */
        1002          148955 :     bool pinAddressReg = !!regstate(address.base).fe();
        1003          148955 :     if (pinAddressReg)
        1004            1358 :         pinReg(address.base);
        1005                 :
        1006                 : #if defined JS_PUNBOX64
        1007                 :     if (fe->type.inMemory() && fe->data.inMemory()) {
        1008                 :         /* Future optimization: track that the Value is in a register. */
        1009                 :         RegisterID vreg = Registers::ValueReg;
        1010                 :         masm.loadPtr(addressOf(fe), vreg);
        1011                 :         masm.storePtr(vreg, address);
        1012                 :         if (pinAddressReg)
        1013                 :             unpinReg(address.base);
        1014                 :         return;
        1015                 :     }
        1016                 :
        1017                 :     JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
        1018                 :
        1019                 :     /*
        1020                 :      * If dreg is obtained via allocReg(), then calling
        1021                 :      * pinReg() trips an assertion. But in all other cases,
        1022                 :      * calling pinReg() is necessary in the fe->type.inMemory() path.
        1023                 :      * Remember whether pinReg() can be safely called.
        1024                 :      */
        1025                 :     bool canPinDreg = true;
        1026                 :     bool wasInRegister = fe->data.inRegister();
        1027                 :
        1028                 :     /* Get a register for the payload. */
        1029                 :     MaybeRegisterID dreg;
        1030                 :     if (fe->data.inRegister()) {
        1031                 :         dreg = fe->data.reg();
        1032                 :     } else {
        1033                 :         JS_ASSERT(fe->data.inMemory());
        1034                 :         if (popped) {
        1035                 :             dreg = allocReg();
        1036                 :             masm.loadPayload(addressOf(fe), dreg.reg());
        1037                 :             canPinDreg = false;
        1038                 :         } else {
        1039                 :             dreg = allocAndLoadReg(fe, false, RematInfo::DATA).reg();
        1040                 :             fe->data.setRegister(dreg.reg());
        1041                 :         }
        1042                 :     }
        1043                 :
        1044                 :     /* Store the Value. */
        1045                 :     if (fe->type.inRegister()) {
        1046                 :         masm.storeValueFromComponents(fe->type.reg(), dreg.reg(), address);
        1047                 :     } else if (fe->isTypeKnown()) {
        1048                 :         masm.storeValueFromComponents(ImmType(fe->getKnownType()), dreg.reg(), address);
        1049                 :     } else {
        1050                 :         JS_ASSERT(fe->type.inMemory());
        1051                 :         if (canPinDreg)
        1052                 :             pinReg(dreg.reg());
        1053                 :
        1054                 :         RegisterID treg;
        1055                 :         if (popped) {
        1056                 :             treg = allocReg();
        1057                 :             masm.loadTypeTag(addressOf(fe), treg);
        1058                 :         } else {
        1059                 :             treg = allocAndLoadReg(fe, false, RematInfo::TYPE).reg();
        1060                 :         }
        1061                 :         masm.storeValueFromComponents(treg, dreg.reg(), address);
        1062                 :
        1063                 :         if (popped)
        1064                 :             freeReg(treg);
        1065                 :         else
        1066                 :             fe->type.setRegister(treg);
        1067                 :
        1068                 :         if (canPinDreg)
        1069                 :             unpinReg(dreg.reg());
        1070                 :     }
        1071                 :
        1072                 :     /* If register is untracked, free it. */
        1073                 :     if (!wasInRegister && popped)
        1074                 :         freeReg(dreg.reg());
        1075                 :
        1076                 : #elif defined JS_NUNBOX32
        1077                 :
        1078          148955 :     if (fe->data.inRegister()) {
        1079          120929 :         masm.storePayload(fe->data.reg(), address);
        1080                 :     } else {
        1081           28026 :         JS_ASSERT(fe->data.inMemory());
        1082                 :         RegisterID reg;
        1083           28026 :         if (popped) {
        1084           25947 :             reg = allocReg();
        1085           25947 :             masm.loadPayload(addressOf(fe), reg);
        1086                 :         } else {
        1087            2079 :             reg = allocAndLoadReg(fe, false, RematInfo::DATA).reg();
        1088                 :         }
        1089           28026 :         masm.storePayload(reg, address);
        1090           28026 :         if (popped)
        1091           25947 :             freeReg(reg);
        1092                 :         else
        1093            2079 :             fe->data.setRegister(reg);
        1094                 :     }
        1095                 :
        1096          148955 :     if (fe->isTypeKnown()) {
        1097           67542 :         masm.storeTypeTag(ImmType(fe->getKnownType()), address);
        1098           81413 :     } else if (fe->type.inRegister()) {
        1099           38891 :         masm.storeTypeTag(fe->type.reg(), address);
        1100                 :     } else {
        1101           42522 :         JS_ASSERT(fe->type.inMemory());
        1102                 :         RegisterID reg;
        1103           42522 :         if (popped) {
        1104           41376 :             reg = allocReg();
        1105           41376 :             masm.loadTypeTag(addressOf(fe), reg);
        1106                 :         } else {
        1107            1146 :             reg = allocAndLoadReg(fe, false, RematInfo::TYPE).reg();
        1108                 :         }
        1109           42522 :         masm.storeTypeTag(reg, address);
        1110           42522 :         if (popped)
        1111           41376 :             freeReg(reg);
        1112                 :         else
        1113            1146 :             fe->type.setRegister(reg);
        1114                 :     }
        1115                 : #endif
        1116          148955 :     if (pinAddressReg)
        1117            1358 :         unpinReg(address.base);
        1118                 : }
        1119                 :
        1120                 : void
        1121             492 : FrameState::loadThisForReturn(RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
        1122                 : {
        1123             492 :     return loadForReturn(getThis(), typeReg, dataReg, tempReg);
        1124                 : }
        1125                 :
        1126           10573 : void FrameState::loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
        1127                 : {
        1128           10573 :     JS_ASSERT(dataReg != typeReg && dataReg != tempReg && typeReg != tempReg);
        1129                 :
        1130           10573 :     if (fe->isConstant()) {
        1131            2281 :         masm.loadValueAsComponents(fe->getValue(), typeReg, dataReg);
        1132            2281 :         return;
        1133                 :     }
        1134                 :
        1135            8292 :     if (fe->isType(JSVAL_TYPE_DOUBLE)) {
        1136             335 :         FPRegisterID fpreg = tempFPRegForData(fe);
        1137             335 :         masm.breakDouble(fpreg, typeReg, dataReg);
        1138             335 :         return;
        1139                 :     }
        1140                 :
        1141            7957 :     if (fe->isCopy())
        1142            1909 :         fe = fe->copyOf();
        1143                 :
        1144            7957 :     MaybeRegisterID maybeType = maybePinType(fe);
        1145            7957 :     MaybeRegisterID maybeData = maybePinData(fe);
        1146                 :
        1147            7957 :     if (fe->isTypeKnown()) {
        1148                 :         // If the data is in memory, or in the wrong reg, load/move it.
        1149            3232 :         if (!maybeData.isSet())
        1150            1045 :             masm.loadPayload(addressOf(fe), dataReg);
        1151            2187 :         else if (maybeData.reg() != dataReg)
        1152            1317 :             masm.move(maybeData.reg(), dataReg);
        1153            3232 :         masm.move(ImmType(fe->getKnownType()), typeReg);
        1154            3232 :         return;
        1155                 :     }
        1156                 :
        1157                 :     // If both halves of the value are in memory, make this easier and load
        1158                 :     // both pieces into their respective registers.
        1159            4725 :     if (fe->type.inMemory() && fe->data.inMemory()) {
        1160            1636 :         masm.loadValueAsComponents(addressOf(fe), typeReg, dataReg);
        1161            1636 :         return;
        1162                 :     }
        1163                 :
        1164                 :     // Now, we should be guaranteed that at least one part is in a register.
        1165            3089 :     JS_ASSERT(maybeType.isSet() || maybeData.isSet());
        1166                 :
        1167                 :     // Make sure we have two registers while making sure not clobber either half.
        1168                 :     // Here we are allowed to mess up the FrameState invariants, because this
        1169                 :     // is specialized code for a path that is about to discard the entire frame.
        1170            3089 :     if (!maybeType.isSet()) {
        1171             277 :         JS_ASSERT(maybeData.isSet());
        1172             277 :         if (maybeData.reg() != typeReg)
        1173             251 :             maybeType = typeReg;
        1174                 :         else
        1175              26 :             maybeType = tempReg;
        1176             277 :         masm.loadTypeTag(addressOf(fe), maybeType.reg());
        1177            2812 :     } else if (!maybeData.isSet()) {
        1178               3 :         JS_ASSERT(maybeType.isSet());
        1179               3 :         if (maybeType.reg() != dataReg)
        1180               2 :             maybeData = dataReg;
        1181                 :         else
        1182               1 :             maybeData = tempReg;
        1183               3 :         masm.loadPayload(addressOf(fe), maybeData.reg());
        1184                 :     }
        1185                 :
        1186            3089 :     RegisterID type = maybeType.reg();
        1187            3089 :     RegisterID data = maybeData.reg();
        1188                 :
        1189            3089 :     if (data == typeReg && type == dataReg) {
        1190             213 :         masm.move(type, tempReg);
        1191             213 :         masm.move(data, dataReg);
        1192             213 :         masm.move(tempReg, typeReg);
        1193            2876 :     } else if (data != dataReg) {
        1194             583 :         if (type == typeReg) {
        1195             251 :             masm.move(data, dataReg);
        1196             332 :         } else if (type != dataReg) {
        1197             298 :             masm.move(data, dataReg);
        1198             298 :             if (type != typeReg)
        1199             298 :                 masm.move(type, typeReg);
        1200                 :         } else {
        1201              34 :             JS_ASSERT(data != typeReg);
        1202              34 :             masm.move(type, typeReg);
        1203              34 :             masm.move(data, dataReg);
        1204                 :         }
        1205            2293 :     } else if (type != typeReg) {
        1206              79 :         masm.move(type, typeReg);
        1207                 :     }
        1208                 : }
        1209                 :
        1210                 : #ifdef DEBUG
        1211                 : void
        1212         8145898 : FrameState::assertValidRegisterState() const
        1213                 : {
        1214         8145898 :     Registers checkedFreeRegs(Registers::AvailAnyRegs);
        1215                 :
        1216                 :     /* Check that copied and copy info balance out. */
        1217         8145898 :     int32_t copyCount = 0;
        1218                 :
        1219       425283296 :     for (uint32_t i = 0; i < tracker.nentries; i++) {
        1220       417137398 :         FrameEntry *fe = tracker[i];
        1221       417137398 :         if (deadEntry(fe))
        1222        10378200 :             continue;
        1223                 :
        1224       406759198 :         JS_ASSERT(i == fe->trackerIndex());
        1225                 :
        1226       406759198 :         if (fe->isCopy()) {
        1227         1439849 :             JS_ASSERT_IF(!fe->copyOf()->temporary, fe > fe->copyOf());
        1228         1439849 :             JS_ASSERT(fe->trackerIndex() > fe->copyOf()->trackerIndex());
        1229         1439849 :             JS_ASSERT(!deadEntry(fe->copyOf()));
        1230         1439849 :             JS_ASSERT(fe->copyOf()->isCopied());
        1231         1439849 :             JS_ASSERT(!fe->isCopied());
        1232         1439849 :             copyCount--;
        1233         1439849 :             continue;
        1234                 :         }
        1235                 :
        1236       405319349 :         copyCount += fe->copied;
        1237                 :
        1238       405319349 :         if (fe->type.inRegister()) {
        1239         3326115 :             checkedFreeRegs.takeReg(fe->type.reg());
        1240         3326115 :             JS_ASSERT(regstate(fe->type.reg()).fe() == fe);
        1241         3326115 :             JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
        1242                 :         }
        1243       405319349 :         if (fe->data.inRegister()) {
        1244         7643149 :             checkedFreeRegs.takeReg(fe->data.reg());
        1245         7643149 :             JS_ASSERT(regstate(fe->data.reg()).fe() == fe);
        1246         7643149 :             JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
        1247                 :         }
        1248       405319349 :         if (fe->data.inFPRegister()) {
        1249          130279 :             JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
        1250          130279 :             checkedFreeRegs.takeReg(fe->data.fpreg());
        1251          130279 :             JS_ASSERT(regstate(fe->data.fpreg()).fe() == fe);
        1252                 :         }
        1253                 :     }
        1254                 :
        1255         8145898 :     JS_ASSERT(copyCount == 0);
        1256         8145898 :     JS_ASSERT(checkedFreeRegs == freeRegs);
        1257                 :
        1258        73313082 :     for (uint32_t i = 0; i < Registers::TotalRegisters; i++) {
        1259        65167184 :         AnyRegisterID reg = (RegisterID) i;
        1260        65167184 :         JS_ASSERT(!regstate(reg).isPinned());
        1261        65167184 :         JS_ASSERT_IF(regstate(reg).fe(), !freeRegs.hasReg(reg));
        1262        65167184 :         JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).fe()->isTracked());
        1263                 :     }
        1264                 :
        1265        65167184 :     for (uint32_t i = 0; i < Registers::TotalFPRegisters; i++) {
        1266        57021286 :         AnyRegisterID reg = (FPRegisterID) i;
        1267        57021286 :         JS_ASSERT(!regstate(reg).isPinned());
        1268        57021286 :         JS_ASSERT_IF(regstate(reg).fe(), !freeRegs.hasReg(reg));
        1269        57021286 :         JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).fe()->isTracked());
        1270        57021286 :         JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).type() == RematInfo::DATA);
        1271                 :     }
        1272         8145898 : }
        1273                 : #endif
        1274                 :
        1275                 : #if defined JS_NUNBOX32
        1276                 : void
        1277           75565 : FrameState::syncFancy(Assembler &masm, Registers avail, int trackerIndex) const
        1278                 : {
        1279           75565 :     reifier.reset(&masm, avail, a->sp, entries);
        1280                 :
        1281          512547 :     for (; trackerIndex >= 0; trackerIndex--) {
        1282          436982 :         FrameEntry *fe = tracker[trackerIndex];
        1283          436982 :         if (fe >= a->sp)
        1284           11457 :             continue;
        1285                 :
        1286          425525 :         reifier.sync(fe);
        1287                 :     }
        1288           75565 : }
        1289                 :
        1290                 : #endif
        1291                 : void
        1292         2107379 : FrameState::sync(Assembler &masm, Uses uses) const
        1293                 : {
        1294         2107379 :     if (!entries)
        1295               0 :         return;
        1296                 :
        1297                 :     /* Sync all registers up-front. */
        1298         2107379 :     Registers allRegs(Registers::AvailAnyRegs);
        1299        31610685 :     while (!allRegs.empty()) {
        1300        27395927 :         AnyRegisterID reg = allRegs.takeAnyReg();
        1301        27395927 :         FrameEntry *fe = regstate(reg).usedBy();
        1302        27395927 :         if (!fe)
        1303        22008955 :             continue;
        1304                 :
        1305         5386972 :         JS_ASSERT(fe->isTracked());
        1306                 :
        1307                 : #if defined JS_PUNBOX64
        1308                 :         /* Sync entire FE to prevent loads. */
        1309                 :         ensureFeSynced(fe, masm);
        1310                 :
        1311                 :         /* Take the other register in the pair, if one exists. */
        1312                 :         if (regstate(reg).type() == RematInfo::DATA && fe->type.inRegister())
        1313                 :             allRegs.takeReg(fe->type.reg());
        1314                 :         else if (regstate(reg).type() == RematInfo::TYPE && fe->data.inRegister())
        1315                 :             allRegs.takeReg(fe->data.reg());
        1316                 : #elif defined JS_NUNBOX32
        1317                 :         /* Sync register if unsynced. */
        1318         5386972 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
        1319           27733 :             ensureFeSynced(fe, masm);
        1320         5359239 :         } else if (regstate(reg).type() == RematInfo::DATA) {
        1321         3174394 :             JS_ASSERT(fe->data.reg() == reg.reg());
        1322         3174394 :             ensureDataSynced(fe, masm);
        1323                 :         } else {
        1324         2184845 :             JS_ASSERT(fe->type.reg() == reg.reg());
        1325         2184845 :             ensureTypeSynced(fe, masm);
        1326                 :         }
        1327                 : #endif
        1328                 :     }
        1329                 :
        1330                 :     /*
        1331                 :      * Keep track of free registers using a bitmask. If we have to drop into
        1332                 :      * syncFancy(), then this mask will help avoid eviction.
        1333                 :      */
        1334         2107379 :     Registers avail(freeRegs.freeMask & Registers::AvailRegs);
        1335         2107379 :     Registers temp(Registers::TempAnyRegs);
        1336                 :
        1337         2107379 :     unsigned nentries = tracker.nentries;
        1338        10025827 :     for (int trackerIndex = nentries - 1; trackerIndex >= 0; trackerIndex--) {
        1339         7994013 :         JS_ASSERT(tracker.nentries == nentries);
        1340         7994013 :         FrameEntry *fe = tracker[trackerIndex];
        1341         7994013 :         if (fe >= a->sp)
        1342         1918725 :             continue;
        1343                 :
        1344         6075288 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
        1345                 :             /* Copies of in-memory doubles can be synced without spilling. */
        1346           40068 :             if (fe->isCopy() || !fe->data.inFPRegister())
        1347           12689 :                 ensureFeSynced(fe, masm);
        1348           40068 :             continue;
        1349                 :         }
        1350                 :
        1351         6035220 :         if (!fe->isCopy()) {
        1352         5693580 :             if (fe->data.inRegister() && !regstate(fe->data.reg()).isPinned())
        1353         3010762 :                 avail.putReg(fe->data.reg());
        1354         5693580 :             if (fe->type.inRegister() && !regstate(fe->type.reg()).isPinned())
        1355         2103295 :                 avail.putReg(fe->type.reg());
        1356                 :         } else {
        1357          341640 :             FrameEntry *backing = fe->copyOf();
        1358          341640 :             JS_ASSERT(!backing->isConstant() && !fe->isConstant());
        1359                 :
        1360                 : #if defined JS_PUNBOX64
        1361                 :             if ((!fe->type.synced() && backing->type.inMemory()) ||
        1362                 :                 (!fe->data.synced() && backing->data.inMemory())) {
        1363                 :
        1364                 :                 RegisterID syncReg = Registers::ValueReg;
        1365                 :
        1366                 :                 /* Load the entire Value into syncReg. */
        1367                 :                 if (backing->type.synced() && backing->data.synced()) {
        1368                 :                     masm.loadValue(addressOf(backing), syncReg);
        1369                 :                 } else if (backing->type.inMemory()) {
        1370                 :                     masm.loadTypeTag(addressOf(backing), syncReg);
        1371                 :                     masm.orPtr(backing->data.reg(), syncReg);
        1372                 :                 } else {
        1373                 :                     JS_ASSERT(backing->data.inMemory());
        1374                 :                     masm.loadPayload(addressOf(backing), syncReg);
        1375                 :                     if (backing->isTypeKnown())
        1376                 :                         masm.orPtr(ImmType(backing->getKnownType()), syncReg);
        1377                 :                     else
        1378                 :                         masm.orPtr(backing->type.reg(), syncReg);
        1379                 :                 }
        1380                 :
        1381                 :                 masm.storeValue(syncReg, addressOf(fe));
        1382                 :                 continue;
        1383                 :             }
        1384                 : #elif defined JS_NUNBOX32
        1385                 :             /* Fall back to a slower sync algorithm if load required. */
        1386          960424 :             if ((!fe->type.synced() && backing->type.inMemory()) ||
        1387          618784 :                 (!fe->data.synced() && backing->data.inMemory())) {
        1388           75565 :                 syncFancy(masm, avail, trackerIndex);
        1389           75565 :                 return;
        1390                 :             }
        1391                 : #endif
        1392                 :         }
        1393                 :
        1394         5959655 :         bool copy = fe->isCopy();
        1395                 :
        1396                 :         /* If a part still needs syncing, it is either a copy or constant. */
        1397                 : #if defined JS_PUNBOX64
        1398                 :         /* All register-backed FEs have been entirely synced up-front. */
        1399                 :         if (copy || (!fe->type.inRegister() && !fe->data.inRegister()))
        1400                 :             ensureFeSynced(fe, masm);
        1401                 : #elif defined JS_NUNBOX32
        1402                 :         /* All components held in registers have been already synced. */
        1403         5959655 :         if (copy || !fe->data.inRegister())
        1404         2869668 :             ensureDataSynced(fe, masm);
        1405         5959655 :         if (copy || !fe->type.inRegister())
        1406         3836483 :             ensureTypeSynced(fe, masm);
        1407                 : #endif
        1408                 :     }
        1409                 : }
        1410                 :
        1411                 : void
        1412          896614 : FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore)
        1413                 : {
        1414          896614 :     if (loop) {
        1415                 :         /*
        1416                 :          * Drop any remaining loop registers so we don't do any more after-the-fact
        1417                 :          * allocation of the initial register state.
        1418                 :          */
        1419          117050 :         loop->clearLoopRegisters();
        1420                 :     }
        1421                 :
        1422                 :     /* Sync all kill-registers up-front. */
        1423          896614 :     Registers search(kill.freeMask & ~freeRegs.freeMask);
        1424         2521606 :     while (!search.empty()) {
        1425          728378 :         AnyRegisterID reg = search.takeAnyReg();
        1426          728378 :         FrameEntry *fe = regstate(reg).usedBy();
        1427          728378 :         if (!fe || deadEntry(fe, ignore.nuses))
        1428           98229 :             continue;
        1429                 :
        1430          630149 :         JS_ASSERT(fe->isTracked());
        1431                 :
        1432                 : #if defined JS_PUNBOX64
        1433                 :         /* Don't use syncFe(), since that may clobber more registers. */
        1434                 :         ensureFeSynced(fe, masm);
        1435                 :
        1436                 :         if (!fe->type.synced())
        1437                 :             fe->type.sync();
        1438                 :         if (!fe->data.synced())
        1439                 :             fe->data.sync();
        1440                 :
        1441                 :         /* Take the other register in the pair, if one exists. */
        1442                 :         if (regstate(reg).type() == RematInfo::DATA) {
        1443                 :             if (!fe->isType(JSVAL_TYPE_DOUBLE)) {
        1444                 :                 JS_ASSERT(fe->data.reg() == reg.reg());
        1445                 :                 if (fe->type.inRegister() && search.hasReg(fe->type.reg()))
        1446                 :                     search.takeReg(fe->type.reg());
        1447                 :             }
        1448                 :         } else {
        1449                 :             JS_ASSERT(fe->type.reg() == reg.reg());
        1450                 :             if (fe->data.inRegister() && search.hasReg(fe->data.reg()))
        1451                 :                 search.takeReg(fe->data.reg());
        1452                 :         }
        1453                 : #elif defined JS_NUNBOX32
        1454                 :         /* Sync this register. */
        1455          630149 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
        1456            7084 :             syncFe(fe);
        1457          623065 :         } else if (regstate(reg).type() == RematInfo::DATA) {
        1458          401674 :             JS_ASSERT(fe->data.reg() == reg.reg());
        1459          401674 :             syncData(fe);
        1460                 :         } else {
        1461          221391 :             JS_ASSERT(fe->type.reg() == reg.reg());
        1462          221391 :             syncType(fe);
        1463                 :         }
        1464                 : #endif
        1465                 :     }
        1466                 :
        1467                 :
        1468          896614 :     unsigned nentries = tracker.nentries;
        1469         4357107 :     for (int trackerIndex = nentries - 1; trackerIndex >= 0; trackerIndex--) {
        1470         3460493 :         JS_ASSERT(tracker.nentries == nentries);
        1471         3460493 :         FrameEntry *fe = tracker[trackerIndex];
        1472                 :
        1473         3460493 :         if (fe >= a->sp || deadEntry(fe, ignore.nuses))
        1474          888575 :             continue;
        1475                 :
        1476         2571918 :         syncFe(fe);
        1477                 :
        1478         2571918 :         if (fe->isCopy())
        1479           87894 :             continue;
        1480                 :
        1481                 :         /* Forget registers. */
        1482         2484024 :         if (fe->data.inRegister() && !regstate(fe->data.reg()).isPinned()) {
        1483          408038 :             forgetReg(fe->data.reg());
        1484          408038 :             fe->data.setMemory();
        1485                 :         }
        1486         2484024 :         if (fe->data.inFPRegister() && !regstate(fe->data.fpreg()).isPinned()) {
        1487            5800 :             forgetReg(fe->data.fpreg());
        1488            5800 :             fe->data.setMemory();
        1489                 :         }
        1490         2484024 :         if (fe->type.inRegister() && !regstate(fe->type.reg()).isPinned()) {
        1491          234407 :             forgetReg(fe->type.reg());
        1492          234407 :             fe->type.setMemory();
        1493                 :         }
        1494                 :     }
        1495                 :
        1496                 :     /*
        1497                 :      * Anything still alive at this point is guaranteed to be synced. However,
        1498                 :      * it is necessary to evict temporary registers.
        1499                 :      */
        1500          896614 :     search = Registers(kill.freeMask & ~freeRegs.freeMask);
        1501         2047499 :     while (!search.empty()) {
        1502          254271 :         AnyRegisterID reg = search.takeAnyReg();
        1503          254271 :         FrameEntry *fe = regstate(reg).usedBy();
        1504          254271 :         if (!fe || deadEntry(fe, ignore.nuses))
        1505           98229 :             continue;
        1506                 :
        1507          156042 :         JS_ASSERT(fe->isTracked());
        1508                 :
        1509          156042 :         if (regstate(reg).type() == RematInfo::DATA) {
        1510          100152 :             JS_ASSERT_IF(reg.isFPReg(), fe->data.fpreg() == reg.fpreg());
        1511          100152 :             JS_ASSERT_IF(!reg.isFPReg(), fe->data.reg() == reg.reg());
        1512          100152 :             JS_ASSERT(fe->data.synced());
        1513          100152 :             fe->data.setMemory();
        1514                 :         } else {
        1515           55890 :             JS_ASSERT(fe->type.reg() == reg.reg());
        1516           55890 :             JS_ASSERT(fe->type.synced());
        1517           55890 :             fe->type.setMemory();
        1518                 :         }
        1519                 :
        1520          156042 :         forgetReg(reg);
        1521                 :     }
        1522          896614 : }
        1523                 :
        1524                 : void
        1525         1605194 : FrameState::merge(Assembler &masm, Changes changes) const
        1526                 : {
        1527                 :     /*
        1528                 :      * Note: this should only be called by StubCompiler::rejoin, which will notify
        1529                 :      * this FrameState about the jump to patch up in case a new loop register is
        1530                 :      * allocated later.
        1531                 :      */
        1532                 :
        1533                 :     /*
        1534                 :      * For any changed values we are merging back which we consider to be doubles,
        1535                 :      * ensure they actually are doubles.  They must be doubles or ints, but we
        1536                 :      * do not require stub paths to always generate a double when needed.
        1537                 :      * :FIXME: we check this on OOL stub calls, but not inline stub calls.
        1538                 :      */
        1539         1605194 :     if (cx->typeInferenceEnabled()) {
        1540         1088678 :         for (unsigned i = 0; i < changes.nchanges; i++) {
        1541          380915 :             FrameEntry *fe = a->sp - 1 - i;
        1542          380915 :             if (fe->isTracked() && fe->isType(JSVAL_TYPE_DOUBLE))
        1543           19458 :                 masm.ensureInMemoryDouble(addressOf(fe));
        1544                 :         }
        1545                 :     }
        1546                 :
        1547         1605194 :     uint32_t mask = Registers::AvailAnyRegs & ~freeRegs.freeMask;
        1548         1605194 :     Registers search(mask);
        1549                 :
        1550         5701386 :     while (!search.empty(mask)) {
        1551         2490998 :         AnyRegisterID reg = search.peekReg(mask);
        1552         2490998 :         FrameEntry *fe = regstate(reg).usedBy();
        1553                 :
        1554         2490998 :         if (!fe) {
        1555            7306 :             search.takeReg(reg);
        1556            7306 :             continue;
        1557                 :         }
        1558                 :
        1559         2483692 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
        1560           41997 :             JS_ASSERT(fe->data.fpreg() == reg.fpreg());
        1561           41997 :             search.takeReg(fe->data.fpreg());
        1562           41997 :             masm.loadDouble(addressOf(fe), fe->data.fpreg());
        1563         2441695 :         } else if (fe->data.inRegister() && fe->type.inRegister()) {
        1564         1081765 :             search.takeReg(fe->data.reg());
        1565         1081765 :             search.takeReg(fe->type.reg());
        1566         1081765 :             masm.loadValueAsComponents(addressOf(fe), fe->type.reg(), fe->data.reg());
        1567                 :         } else {
        1568         1359930 :             if (fe->data.inRegister()) {
        1569         1329271 :                 search.takeReg(fe->data.reg());
        1570         1329271 :                 masm.loadPayload(addressOf(fe), fe->data.reg());
        1571                 :             }
        1572         1359930 :             if (fe->type.inRegister()) {
        1573           30659 :                 search.takeReg(fe->type.reg());
        1574           30659 :                 masm.loadTypeTag(addressOf(fe), fe->type.reg());
        1575                 :             }
        1576                 :         }
        1577                 :     }
        1578         1605194 : }
        1579                 :
        1580                 : JSC::MacroAssembler::RegisterID
        1581          187127 : FrameState::copyDataIntoReg(FrameEntry *fe)
        1582                 : {
        1583          187127 :     return copyDataIntoReg(this->masm, fe);
        1584                 : }
        1585                 :
        1586                 : void
        1587            1000 : FrameState::copyDataIntoReg(FrameEntry *fe, RegisterID hint)
        1588                 : {
        1589            1000 :     JS_ASSERT(!fe->isConstant());
        1590            1000 :     JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
        1591                 :
        1592            1000 :     if (fe->isCopy())
        1593             325 :         fe = fe->copyOf();
        1594                 :
        1595            1000 :     if (!fe->data.inRegister())
        1596             245 :         tempRegForData(fe);
        1597                 :
        1598            1000 :     RegisterID reg = fe->data.reg();
        1599            1000 :     if (reg == hint) {
        1600              85 :         if (freeRegs.empty(Registers::AvailRegs)) {
        1601              71 :             ensureDataSynced(fe, masm);
        1602              71 :             fe->data.setMemory();
        1603                 :         } else {
        1604              14 :             reg = allocReg();
        1605              14 :             masm.move(hint, reg);
        1606              14 :             fe->data.setRegister(reg);
        1607              14 :             regstate(reg).associate(regstate(hint).fe(), RematInfo::DATA);
        1608                 :         }
        1609              85 :         regstate(hint).forget();
        1610                 :     } else {
        1611             915 :         pinReg(reg);
        1612             915 :         takeReg(hint);
        1613             915 :         unpinReg(reg);
        1614             915 :         masm.move(reg, hint);
        1615                 :     }
        1616                 :
        1617            1000 :     modifyReg(hint);
        1618            1000 : }
        1619                 :
        1620                 : JSC::MacroAssembler::RegisterID
        1621          189493 : FrameState::copyDataIntoReg(Assembler &masm, FrameEntry *fe)
        1622                 : {
        1623          189493 :     JS_ASSERT(!fe->isConstant());
        1624                 :
        1625          189493 :     if (fe->isCopy())
        1626           67038 :         fe = fe->copyOf();
        1627                 :
        1628          189493 :     if (fe->data.inRegister()) {
        1629          142585 :         RegisterID reg = fe->data.reg();
        1630          142585 :         if (freeRegs.empty(Registers::AvailRegs)) {
        1631           12316 :             ensureDataSynced(fe, masm);
        1632           12316 :             fe->data.setMemory();
        1633           12316 :             regstate(reg).forget();
        1634           12316 :             modifyReg(reg);
        1635                 :         } else {
        1636          130269 :             RegisterID newReg = allocReg();
        1637          130269 :             masm.move(reg, newReg);
        1638          130269 :             reg = newReg;
        1639                 :         }
        1640          142585 :         return reg;
        1641                 :     }
        1642                 :
        1643           46908 :     RegisterID reg = allocReg();
        1644                 :
        1645           46908 :     if (!freeRegs.empty(Registers::AvailRegs))
        1646           41294 :         masm.move(tempRegForData(fe), reg);
        1647                 :     else
        1648            5614 :         masm.loadPayload(addressOf(fe),reg);
        1649                 :
        1650           46908 :     return reg;
        1651                 : }
        1652                 :
        1653                 : JSC::MacroAssembler::RegisterID
        1654            8505 : FrameState::copyTypeIntoReg(FrameEntry *fe)
        1655                 : {
        1656            8505 :     if (fe->isCopy())
        1657            2035 :         fe = fe->copyOf();
        1658                 :
        1659            8505 :     JS_ASSERT(!fe->type.isConstant());
        1660                 :
        1661            8505 :     if (fe->type.inRegister()) {
        1662            6019 :         RegisterID reg = fe->type.reg();
        1663            6019 :         if (freeRegs.empty(Registers::AvailRegs)) {
        1664            4062 :             ensureTypeSynced(fe, masm);
        1665            4062 :             fe->type.setMemory();
        1666            4062 :             regstate(reg).forget();
        1667            4062 :             modifyReg(reg);
        1668                 :         } else {
        1669            1957 :             RegisterID newReg = allocReg();
        1670            1957 :             masm.move(reg, newReg);
        1671            1957 :             reg = newReg;
        1672                 :         }
        1673            6019 :         return reg;
        1674                 :     }
        1675                 :
        1676            2486 :     RegisterID reg = allocReg();
        1677                 :
        1678            2486 :     if (!freeRegs.empty(Registers::AvailRegs))
        1679             872 :         masm.move(tempRegForType(fe), reg);
        1680                 :     else
        1681            1614 :         masm.loadTypeTag(addressOf(fe), reg);
        1682                 :
        1683            2486 :     return reg;
        1684                 : }
        1685                 :
        1686                 : JSC::MacroAssembler::RegisterID
        1687               0 : FrameState::copyInt32ConstantIntoReg(FrameEntry *fe)
        1688                 : {
        1689               0 :     return copyInt32ConstantIntoReg(masm, fe);
        1690                 : }
        1691                 :
        1692                 : JSC::MacroAssembler::RegisterID
        1693               0 : FrameState::copyInt32ConstantIntoReg(Assembler &masm, FrameEntry *fe)
        1694                 : {
        1695               0 :     JS_ASSERT(fe->data.isConstant());
        1696                 :
        1697               0 :     if (fe->isCopy())
        1698               0 :         fe = fe->copyOf();
        1699                 :
        1700               0 :     RegisterID reg = allocReg();
        1701               0 :     masm.move(Imm32(fe->getValue().toInt32()), reg);
        1702               0 :     return reg;
        1703                 : }
        1704                 :
        1705                 : JSC::MacroAssembler::RegisterID
        1706             647 : FrameState::ownRegForType(FrameEntry *fe)
        1707                 : {
        1708             647 :     JS_ASSERT(!fe->isTypeKnown());
        1709                 :
        1710                 :     RegisterID reg;
        1711             647 :     if (fe->isCopy()) {
        1712                 :         /* For now, just do an extra move. The reg must be mutable. */
        1713             195 :         FrameEntry *backing = fe->copyOf();
        1714             195 :         if (!backing->type.inRegister()) {
        1715             107 :             JS_ASSERT(backing->type.inMemory());
        1716             107 :             tempRegForType(backing);
        1717                 :         }
        1718                 :
        1719             195 :         if (freeRegs.empty(Registers::AvailRegs)) {
        1720                 :             /* For now... just steal the register that already exists. */
        1721               9 :             ensureTypeSynced(backing, masm);
        1722               9 :             reg = backing->type.reg();
        1723               9 :             backing->type.setMemory();
        1724               9 :             regstate(reg).forget();
        1725               9 :             modifyReg(reg);
        1726                 :         } else {
        1727             186 :             reg = allocReg();
        1728             186 :             masm.move(backing->type.reg(), reg);
        1729                 :         }
        1730             195 :         return reg;
        1731                 :     }
        1732                 :
        1733             452 :     if (fe->type.inRegister()) {
        1734             450 :         reg = fe->type.reg();
        1735                 :
        1736                 :         /* Remove ownership of this register. */
        1737             450 :         JS_ASSERT(regstate(reg).fe() == fe);
        1738             450 :         JS_ASSERT(regstate(reg).type() == RematInfo::TYPE);
        1739             450 :         regstate(reg).forget();
        1740             450 :         fe->type.setMemory();
        1741             450 :         modifyReg(reg);
        1742                 :     } else {
        1743               2 :         JS_ASSERT(fe->type.inMemory());
        1744               2 :         reg = allocReg();
        1745               2 :         masm.loadTypeTag(addressOf(fe), reg);
        1746                 :     }
        1747             452 :     return reg;
        1748                 : }
        1749                 :
        1750                 : JSC::MacroAssembler::RegisterID
        1751           46433 : FrameState::ownRegForData(FrameEntry *fe)
        1752                 : {
        1753           46433 :     JS_ASSERT(!fe->isConstant());
        1754           46433 :     JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
        1755                 :
        1756                 :     RegisterID reg;
        1757           46433 :     if (fe->isCopy()) {
        1758                 :         /* For now, just do an extra move. The reg must be mutable. */
        1759            3921 :         FrameEntry *backing = fe->copyOf();
        1760            3921 :         if (!backing->data.inRegister()) {
        1761            1412 :             JS_ASSERT(backing->data.inMemory());
        1762            1412 :             tempRegForData(backing);
        1763                 :         }
        1764                 :
        1765            3921 :         if (freeRegs.empty(Registers::AvailRegs)) {
        1766                 :             /* For now... just steal the register that already exists. */
        1767            1382 :             ensureDataSynced(backing, masm);
        1768            1382 :             reg = backing->data.reg();
        1769            1382 :             backing->data.setMemory();
        1770            1382 :             regstate(reg).forget();
        1771            1382 :             modifyReg(reg);
        1772                 :         } else {
        1773            2539 :             reg = allocReg();
        1774            2539 :             masm.move(backing->data.reg(), reg);
        1775                 :         }
        1776            3921 :         return reg;
        1777                 :     }
        1778                 :
        1779           42512 :     if (fe->isCopied())
        1780               0 :         uncopy(fe);
        1781                 :
        1782           42512 :     if (fe->data.inRegister()) {
        1783           42124 :         reg = fe->data.reg();
        1784                 :         /* Remove ownership of this register. */
        1785           42124 :         JS_ASSERT(regstate(reg).fe() == fe);
        1786           42124 :         JS_ASSERT(regstate(reg).type() == RematInfo::DATA);
        1787           42124 :         regstate(reg).forget();
        1788           42124 :         fe->data.setMemory();
        1789           42124 :         modifyReg(reg);
        1790                 :     } else {
        1791             388 :         JS_ASSERT(fe->data.inMemory());
        1792             388 :         reg = allocReg();
        1793             388 :         masm.loadPayload(addressOf(fe), reg);
        1794                 :     }
        1795           42512 :     return reg;
        1796                 : }
        1797                 :
        1798                 : void
        1799           16843 : FrameState::discardFe(FrameEntry *fe)
        1800                 : {
        1801           16843 :     forgetEntry(fe);
        1802           16843 :     fe->type.setMemory();
        1803           16843 :     fe->data.setMemory();
        1804           16843 :     fe->clear();
        1805           16843 : }
        1806                 :
        1807                 : void
        1808            8364 : FrameState::pushDouble(FPRegisterID fpreg)
        1809                 : {
        1810            8364 :     FrameEntry *fe = rawPush();
        1811            8364 :     fe->resetUnsynced();
        1812            8364 :     fe->setType(JSVAL_TYPE_DOUBLE);
        1813            8364 :     fe->data.setFPRegister(fpreg);
        1814            8364 :     regstate(fpreg).associate(fe, RematInfo::DATA);
        1815            8364 : }
        1816                 :
        1817                 : void
        1818               0 : FrameState::pushDouble(Address address)
        1819                 : {
        1820               0 :     FPRegisterID fpreg = allocFPReg();
        1821               0 :     masm.loadDouble(address, fpreg);
        1822               0 :     pushDouble(fpreg);
        1823               0 : }
        1824                 :
        1825                 : void
        1826            1498 : FrameState::ensureDouble(FrameEntry *fe)
        1827                 : {
        1828            1498 :     if (fe->isType(JSVAL_TYPE_DOUBLE))
        1829            1054 :         return;
        1830                 :
        1831             444 :     if (fe->isConstant()) {
        1832              89 :         JS_ASSERT(fe->getValue().isInt32());
        1833              89 :         Value newValue = DoubleValue(double(fe->getValue().toInt32()));
        1834              89 :         fe->setConstant(newValue);
        1835              89 :         return;
        1836                 :     }
        1837                 :
        1838             355 :     FrameEntry *backing = fe;
        1839             355 :     if (fe->isCopy()) {
        1840                 :         /* Forget this entry is a copy.  We are converting this entry, not the backing. */
        1841              12 :         backing = fe->copyOf();
        1842              12 :         fe->clear();
        1843             343 :     } else if (fe->isCopied()) {
        1844                 :         /* Sync and forget any copies of this entry. */
        1845              36 :         for (uint32_t i = fe->trackerIndex() + 1; i < tracker.nentries; i++) {
        1846              20 :             FrameEntry *nfe = tracker[i];
        1847              20 :             if (!deadEntry(nfe) && nfe->isCopy() && nfe->copyOf() == fe) {
        1848              16 :                 syncFe(nfe);
        1849              16 :                 nfe->resetSynced();
        1850                 :             }
        1851                 :         }
        1852                 :     }
        1853                 :
        1854             355 :     FPRegisterID fpreg = allocFPReg();
        1855                 :
        1856             355 :     if (backing->isType(JSVAL_TYPE_INT32)) {
        1857              26 :         RegisterID data = tempRegForData(backing);
        1858              26 :         masm.convertInt32ToDouble(data, fpreg);
        1859                 :     } else {
        1860             329 :         syncFe(backing);
        1861             329 :         masm.moveInt32OrDouble(addressOf(backing), fpreg);
        1862                 :     }
        1863                 :
        1864             355 :     if (fe == backing)
        1865             343 :         forgetAllRegs(fe);
        1866             355 :     fe->resetUnsynced();
        1867             355 :     fe->setType(JSVAL_TYPE_DOUBLE);
        1868             355 :     fe->data.setFPRegister(fpreg);
        1869             355 :     regstate(fpreg).associate(fe, RematInfo::DATA);
        1870                 :
        1871             355 :     fe->data.unsync();
        1872             355 :     fe->type.unsync();
        1873                 : }
        1874                 :
        1875                 : void
        1876               4 : FrameState::ensureInteger(FrameEntry *fe)
        1877                 : {
        1878                 :     /*
        1879                 :      * This method is used to revert a previous ensureDouble call made for a
        1880                 :      * branch. The entry is definitely a double, and has had no copies made.
        1881                 :      */
        1882                 :
        1883               4 :     if (fe->isConstant()) {
        1884               1 :         Value newValue = Int32Value(int32_t(fe->getValue().toDouble()));
        1885               1 :         fe->setConstant(newValue);
        1886               1 :         return;
        1887                 :     }
        1888                 :
        1889               3 :     JS_ASSERT(!fe->isCopy() && !fe->isCopied());
        1890               3 :     JS_ASSERT_IF(fe->isTypeKnown(), fe->isType(JSVAL_TYPE_DOUBLE));
        1891                 :
        1892               3 :     if (!fe->isType(JSVAL_TYPE_DOUBLE)) {
        1893                 :         /*
        1894                 :          * A normal register may have been allocated after calling
        1895                 :          * syncAndForgetEverything.
        1896                 :          */
        1897               0 :         if (fe->data.inRegister()) {
        1898               0 :             syncFe(fe);
        1899               0 :             forgetReg(fe->data.reg());
        1900               0 :             fe->data.setMemory();
        1901                 :         }
        1902               0 :         learnType(fe, JSVAL_TYPE_DOUBLE, false);
        1903                 :     }
        1904                 :
        1905               3 :     RegisterID reg = allocReg();
        1906               3 :     FPRegisterID fpreg = tempFPRegForData(fe);
        1907               3 :     Jump j = masm.branchTruncateDoubleToInt32(fpreg, reg);
        1908               3 :     j.linkTo(masm.label(), &masm);
        1909                 :
        1910               3 :     forgetAllRegs(fe);
        1911               3 :     fe->resetUnsynced();
        1912               3 :     fe->setType(JSVAL_TYPE_INT32);
        1913               3 :     fe->data.setRegister(reg);
        1914               3 :     regstate(reg).associate(fe, RematInfo::DATA);
        1915                 :
        1916               3 :     fe->data.unsync();
        1917               3 :     fe->type.unsync();
        1918                 : }
        1919                 :
        1920                 : void
        1921               0 : FrameState::ensureInMemoryDoubles(Assembler &masm)
        1922                 : {
        1923               0 :     JS_ASSERT(!a->parent);
        1924               0 :     for (uint32_t i = 0; i < tracker.nentries; i++) {
        1925               0 :         FrameEntry *fe = tracker[i];
        1926               0 :         if (!deadEntry(fe) && fe->isType(JSVAL_TYPE_DOUBLE) &&
        1927               0 :             !fe->isCopy() && !fe->isConstant()) {
        1928               0 :             masm.ensureInMemoryDouble(addressOf(fe));
        1929                 :         }
        1930                 :     }
        1931               0 : }
        1932                 :
        1933                 : void
        1934          511040 : FrameState::pushCopyOf(FrameEntry *backing)
        1935                 : {
        1936          511040 :     JS_ASSERT(backing->isTracked());
        1937          511040 :     FrameEntry *fe = rawPush();
        1938          511040 :     fe->resetUnsynced();
        1939          511040 :     if (backing->isConstant()) {
        1940           82426 :         fe->setConstant(backing->getValue());
        1941                 :     } else {
        1942          428614 :         if (backing->isCopy())
        1943           28969 :             backing = backing->copyOf();
        1944          428614 :         fe->setCopyOf(backing);
        1945                 :
        1946                 :         /* Maintain tracker ordering guarantees for copies. */
        1947          428614 :         JS_ASSERT(backing->isCopied());
        1948          428614 :         if (fe->trackerIndex() < backing->trackerIndex())
        1949           46410 :             swapInTracker(fe, backing);
        1950                 :     }
        1951          511040 : }
        1952                 :
        1953                 : FrameEntry *
        1954              50 : FrameState::walkTrackerForUncopy(FrameEntry *original)
        1955                 : {
        1956              50 :     uint32_t firstCopy = InvalidIndex;
        1957              50 :     FrameEntry *bestFe = NULL;
        1958              50 :     uint32_t ncopies = 0;
        1959             204 :     for (uint32_t i = original->trackerIndex() + 1; i < tracker.nentries; i++) {
        1960             154 :         FrameEntry *fe = tracker[i];
        1961             154 :         if (deadEntry(fe))
        1962              15 :             continue;
        1963             139 :         if (fe->isCopy() && fe->copyOf() == original) {
        1964              50 :             if (firstCopy == InvalidIndex) {
        1965              50 :                 firstCopy = i;
        1966              50 :                 bestFe = fe;
        1967               0 :             } else if (fe < bestFe) {
        1968               0 :                 bestFe = fe;
        1969                 :             }
        1970              50 :             ncopies++;
        1971                 :         }
        1972                 :     }
        1973                 :
        1974              50 :     if (!ncopies) {
        1975               0 :         JS_ASSERT(firstCopy == InvalidIndex);
        1976               0 :         JS_ASSERT(!bestFe);
        1977               0 :         return NULL;
        1978                 :     }
        1979                 :
        1980              50 :     JS_ASSERT(firstCopy != InvalidIndex);
        1981              50 :     JS_ASSERT(bestFe);
        1982              50 :     JS_ASSERT_IF(!isTemporary(original), bestFe > original);
        1983                 :
        1984                 :     /* Mark all extra copies as copies of the new backing index. */
        1985              50 :     bestFe->setCopyOf(NULL);
        1986              50 :     if (ncopies > 1) {
        1987               0 :         for (uint32_t i = firstCopy; i < tracker.nentries; i++) {
        1988               0 :             FrameEntry *other = tracker[i];
        1989               0 :             if (deadEntry(other) || other == bestFe)
        1990               0 :                 continue;
        1991                 :
        1992                 :             /* The original must be tracked before copies. */
        1993               0 :             JS_ASSERT(other != original);
        1994                 :
        1995               0 :             if (!other->isCopy() || other->copyOf() != original)
        1996               0 :                 continue;
        1997                 :
        1998               0 :             other->setCopyOf(bestFe);
        1999                 :
        2000                 :             /*
        2001                 :              * This is safe even though we're mutating during iteration. There
        2002                 :              * are two cases. The first is that both indexes are <= i, and :.
        2003                 :              * will never be observed. The other case is we're placing the
        2004                 :              * other FE such that it will be observed later. Luckily, copyOf()
        2005                 :              * will return != original, so nothing will happen.
        2006                 :              */
        2007               0 :             if (other->trackerIndex() < bestFe->trackerIndex())
        2008               0 :                 swapInTracker(bestFe, other);
        2009                 :         }
        2010                 :     }
        2011                 :
        2012              50 :     return bestFe;
        2013                 : }
        2014                 :
        2015                 : FrameEntry *
        2016           57566 : FrameState::walkFrameForUncopy(FrameEntry *original)
        2017                 : {
        2018           57566 :     FrameEntry *bestFe = NULL;
        2019           57566 :     uint32_t ncopies = 0;
        2020                 :
        2021                 :     /* It's only necessary to visit as many FEs are being tracked. */
        2022           57566 :     uint32_t maxvisits = tracker.nentries;
        2023                 :
        2024          233196 :     for (FrameEntry *fe = original + 1; fe < a->sp && maxvisits; fe++) {
        2025          175630 :         if (!fe->isTracked())
        2026             749 :             continue;
        2027                 :
        2028          174881 :         maxvisits--;
        2029                 :
        2030          174881 :         if (fe->isCopy() && fe->copyOf() == original) {
        2031           57569 :             if (!bestFe) {
        2032           57566 :                 bestFe = fe;
        2033           57566 :                 bestFe->setCopyOf(NULL);
        2034                 :             } else {
        2035               3 :                 fe->setCopyOf(bestFe);
        2036               3 :                 if (fe->trackerIndex() < bestFe->trackerIndex())
        2037               0 :                     swapInTracker(bestFe, fe);
        2038                 :             }
        2039           57569 :             ncopies++;
        2040                 :         }
        2041                 :     }
        2042                 :
        2043           57566 :     return bestFe;
        2044                 : }
        2045                 :
        2046                 : FrameEntry *
        2047           57616 : FrameState::uncopy(FrameEntry *original)
        2048                 : {
        2049           57616 :     JS_ASSERT(original->isCopied());
        2050                 :
        2051                 :     /*
        2052                 :      * Copies have three critical invariants:
        2053                 :      *  1) The backing store precedes all copies in the tracker.
        2054                 :      *  2) The backing store precedes all copies in the FrameState.
        2055                 :      *  3) The backing store of a copy cannot be popped from the stack
        2056                 :      *     while the copy is still live.
        2057                 :      *
        2058                 :      * Maintaining this invariant iteratively is kind of hard, so we choose
        2059                 :      * the "lowest" copy in the frame up-front.
        2060                 :      *
        2061                 :      * For example, if the stack is:
        2062                 :      *    [A, B, C, D]
        2063                 :      * And the tracker has:
        2064                 :      *    [A, D, C, B]
        2065                 :      *
        2066                 :      * If B, C, and D are copies of A - we will walk the tracker to the end
        2067                 :      * and select B, not D (see bug 583684).
        2068                 :      *
        2069                 :      * Note: |tracker.nentries <= (nslots + nargs)|. However, this walk is
        2070                 :      * sub-optimal if |tracker.nentries - original->trackerIndex() > sp - original|.
        2071                 :      * With large scripts this may be a problem worth investigating. Note that
        2072                 :      * the tracker is walked twice, so we multiply by 2 for pessimism.
        2073                 :      */
        2074                 :     FrameEntry *fe;
        2075           57616 :     if ((tracker.nentries - original->trackerIndex()) * 2 > uint32_t(a->sp - original))
        2076           57566 :         fe = walkFrameForUncopy(original);
        2077                 :     else
        2078              50 :         fe = walkTrackerForUncopy(original);
        2079           57616 :     JS_ASSERT(fe);
        2080                 :
        2081                 :     /*
        2082                 :      * Switch the new backing store to the old backing store. During
        2083                 :      * this process we also necessarily make sure the copy can be
        2084                 :      * synced.
        2085                 :      */
        2086           57616 :     if (!original->isTypeKnown()) {
        2087                 :         /*
        2088                 :          * If the copy is unsynced, and the original is in memory,
        2089                 :          * give the original a register. We do this below too; it's
        2090                 :          * okay if it's spilled.
        2091                 :          */
        2092           32019 :         if (original->type.inMemory() && !fe->type.synced())
        2093             161 :             tempRegForType(original);
        2094           32019 :         fe->type.inherit(original->type);
        2095           32019 :         if (fe->type.inRegister())
        2096           32007 :             regstate(fe->type.reg()).reassociate(fe);
        2097                 :     } else {
        2098           25597 :         fe->setType(original->getKnownType());
        2099                 :     }
        2100           57616 :     if (original->isType(JSVAL_TYPE_DOUBLE)) {
        2101             100 :         if (original->data.inMemory() && !fe->data.synced())
        2102               0 :             tempFPRegForData(original);
        2103             100 :         fe->data.inherit(original->data);
        2104             100 :         if (fe->data.inFPRegister())
        2105             100 :             regstate(fe->data.fpreg()).reassociate(fe);
        2106                 :     } else {
        2107           57516 :         if (fe->type.inRegister())
        2108           32007 :             pinReg(fe->type.reg());
        2109           57516 :         if (original->data.inMemory() && !fe->data.synced())
        2110            2793 :             tempRegForData(original);
        2111           57516 :         if (fe->type.inRegister())
        2112           32007 :             unpinReg(fe->type.reg());
        2113           57516 :         fe->data.inherit(original->data);
        2114           57516 :         if (fe->data.inRegister())
        2115           57479 :             regstate(fe->data.reg()).reassociate(fe);
        2116                 :     }
        2117                 :
        2118           57616 :     return fe;
        2119                 : }
        2120                 :
        2121                 : bool
        2122           11961 : FrameState::hasOnlyCopy(FrameEntry *backing, FrameEntry *fe)
        2123                 : {
        2124           11961 :     JS_ASSERT(backing->isCopied() && fe->copyOf() == backing);
        2125                 :
        2126           66348 :     for (uint32_t i = backing->trackerIndex() + 1; i < tracker.nentries; i++) {
        2127           54752 :         FrameEntry *nfe = tracker[i];
        2128           54752 :         if (nfe != fe && !deadEntry(nfe) && nfe->isCopy() && nfe->copyOf() == backing)
        2129             365 :             return false;
        2130                 :     }
        2131                 :
        2132           11596 :     return true;
        2133                 : }
        2134                 :
        2135                 : void
        2136           12302 : FrameState::separateBinaryEntries(FrameEntry *lhs, FrameEntry *rhs)
        2137                 : {
        2138           12302 :     JS_ASSERT(lhs == a->sp - 2 && rhs == a->sp - 1);
        2139           12302 :     if (rhs->isCopy() && rhs->copyOf() == lhs) {
        2140               0 :         syncAndForgetFe(rhs);
        2141               0 :         syncAndForgetFe(lhs);
        2142               0 :         uncopy(lhs);
        2143                 :     }
        2144           12302 : }
        2145                 :
        2146                 : void
        2147          198605 : FrameState::storeLocal(uint32_t n, bool popGuaranteed)
        2148                 : {
        2149          198605 :     FrameEntry *local = getLocal(n);
        2150                 :
        2151          198605 :     if (a->analysis->slotEscapes(entrySlot(local))) {
        2152          107882 :         JS_ASSERT(local->data.inMemory());
        2153          107882 :         storeTo(peek(-1), addressOf(local), popGuaranteed);
        2154          107882 :         return;
        2155                 :     }
        2156                 :
        2157           90723 :     storeTop(local);
        2158                 :
        2159           90723 :     if (loop)
        2160           18571 :         local->lastLoop = loop->headOffset();
        2161                 :
        2162           90723 :     if (inTryBlock)
        2163             482 :         syncFe(local);
        2164                 : }
        2165                 :
        2166                 : void
        2167            2299 : FrameState::storeArg(uint32_t n, bool popGuaranteed)
        2168                 : {
        2169                 :     // Note that args are always immediately synced, because they can be
        2170                 :     // aliased (but not written to) via f.arguments.
        2171            2299 :     FrameEntry *arg = getArg(n);
        2172                 :
        2173            2299 :     if (a->analysis->slotEscapes(entrySlot(arg))) {
        2174            1333 :         JS_ASSERT(arg->data.inMemory());
        2175            1333 :         storeTo(peek(-1), addressOf(arg), popGuaranteed);
        2176            1333 :         return;
        2177                 :     }
        2178                 :
        2179             966 :     storeTop(arg);
        2180                 :
        2181             966 :     if (loop)
        2182             373 :         arg->lastLoop = loop->headOffset();
        2183                 :
        2184             966 :     syncFe(arg);
        2185                 : }
        2186                 :
        2187                 : void
        2188         1390559 : FrameState::forgetEntry(FrameEntry *fe)
        2189                 : {
        2190         1390559 :     if (fe->isCopied()) {
        2191           57614 :         uncopy(fe);
        2192           57614 :         fe->resetUnsynced();
        2193                 :     } else {
        2194         1332945 :         forgetAllRegs(fe);
        2195                 :     }
        2196                 :
        2197         1390559 :     extraArray[fe - entries].reset();
        2198         1390559 : }
        2199                 :
        2200                 : void
        2201          408446 : FrameState::storeTop(FrameEntry *target)
        2202                 : {
        2203          408446 :     JS_ASSERT(!isTemporary(target));
        2204                 :
        2205                 :     /* Detect something like (x = x) which is a no-op. */
        2206          408446 :     FrameEntry *top = peek(-1);
        2207          408446 :     if (top->isCopy() && top->copyOf() == target) {
        2208               8 :         JS_ASSERT(target->isCopied());
        2209               8 :         return;
        2210                 :     }
        2211                 :
        2212                 :     /*
        2213                 :      * If this is overwriting a known non-double type with another value of the
        2214                 :      * same type, then make sure we keep the type marked as synced after doing
        2215                 :      * the copy.
        2216                 :      */
        2217          408438 :     bool wasSynced = target->type.synced();
        2218          408438 :     JSValueType oldType = target->isTypeKnown() ? target->getKnownType() : JSVAL_TYPE_UNKNOWN;
        2219          408438 :     bool trySyncType = wasSynced && oldType != JSVAL_TYPE_UNKNOWN && oldType != JSVAL_TYPE_DOUBLE;
        2220                 :
        2221                 :     /* Completely invalidate the local variable. */
        2222          408438 :     forgetEntry(target);
        2223          408438 :     target->resetUnsynced();
        2224                 :
        2225                 :     /* Constants are easy to propagate. */
        2226          408438 :     if (top->isConstant()) {
        2227          126255 :         target->clear();
        2228          126255 :         target->setConstant(top->getValue());
        2229          126255 :         if (trySyncType && target->isType(oldType))
        2230             119 :             target->type.sync();
        2231          126255 :         return;
        2232                 :     }
        2233                 :
        2234                 :     /*
        2235                 :      * When dealing with copies, there are three important invariants:
        2236                 :      *
        2237                 :      * 1) The backing store precedes all copies in the tracker.
        2238                 :      * 2) The backing store precedes all copies in the FrameState.
        2239                 :      * 2) The backing store of a local is never a stack slot, UNLESS the local
        2240                 :      *    variable itself is a stack slot (blocks) that precedes the stack
        2241                 :      *    slot.
        2242                 :      *
        2243                 :      * If the top is a copy, and the second condition holds true, the local
        2244                 :      * can be rewritten as a copy of the original backing slot. If the first
        2245                 :      * condition does not hold, force it to hold by swapping in-place.
        2246                 :      */
        2247          282183 :     FrameEntry *backing = top;
        2248          282183 :     if (top->isCopy()) {
        2249           92428 :         backing = top->copyOf();
        2250           92428 :         JS_ASSERT(backing->trackerIndex() < top->trackerIndex());
        2251                 :
        2252           92428 :         if (backing < target || isTemporary(backing)) {
        2253                 :             /* local.idx < backing.idx means local cannot be a copy yet */
        2254           29883 :             if (target->trackerIndex() < backing->trackerIndex())
        2255            1543 :                 swapInTracker(backing, target);
        2256           29883 :             target->setCopyOf(backing);
        2257           29883 :             if (trySyncType && target->isType(oldType))
        2258              37 :                 target->type.sync();
        2259           29883 :             return;
        2260                 :         }
        2261                 :
        2262                 :         /*
        2263                 :          * If control flow lands here, then there was a bytecode sequence like
        2264                 :          *
        2265                 :          *  ENTERBLOCK 2
        2266                 :          *  GETLOCAL 1
        2267                 :          *  SETLOCAL 0
        2268                 :          *
        2269                 :          * The problem is slot N can't be backed by M if M could be popped
        2270                 :          * before N. We want a guarantee that when we pop M, even if it was
        2271                 :          * copied, it has no outstanding copies.
        2272                 :          *
        2273                 :          * Because of |let| expressions, it's kind of hard to really know
        2274                 :          * whether a region on the stack will be popped all at once. Bleh!
        2275                 :          *
        2276                 :          * This should be rare except in browser code (and maybe even then),
        2277                 :          * but even so there's a quick workaround. We take all copies of the
        2278                 :          * backing fe, and redirect them to be copies of the destination.
        2279                 :          */
        2280          218256 :         for (uint32_t i = backing->trackerIndex() + 1; i < tracker.nentries; i++) {
        2281          155711 :             FrameEntry *fe = tracker[i];
        2282          155711 :             if (deadEntry(fe))
        2283           11871 :                 continue;
        2284          143840 :             if (fe->isCopy() && fe->copyOf() == backing)
        2285           62564 :                 fe->setCopyOf(target);
        2286                 :         }
        2287                 :     }
        2288                 :
        2289                 :     /*
        2290                 :      * This is valid from the top->isCopy() path because we're guaranteed a
        2291                 :      * consistent ordering - all copies of |backing| are tracked after
        2292                 :      * |backing|. Transitively, only one swap is needed.
        2293                 :      */
        2294          252300 :     if (backing->trackerIndex() < target->trackerIndex())
        2295           18770 :         swapInTracker(backing, target);
        2296                 :
        2297          252300 :     if (backing->isType(JSVAL_TYPE_DOUBLE)) {
        2298            2916 :         FPRegisterID fpreg = tempFPRegForData(backing);
        2299            2916 :         target->setType(JSVAL_TYPE_DOUBLE);
        2300            2916 :         target->data.setFPRegister(fpreg);
        2301            2916 :         regstate(fpreg).reassociate(target);
        2302                 :     } else {
        2303                 :         /*
        2304                 :          * Move the backing store down - we spill registers here, but we could be
        2305                 :          * smarter and re-use the type reg. If we need registers for both the type
        2306                 :          * and data in the backing, make sure we keep the other components pinned.
        2307                 :          * There is nothing else to keep us from evicting the backing's registers.
        2308                 :          */
        2309          249384 :         if (backing->type.inRegister())
        2310           94889 :             pinReg(backing->type.reg());
        2311          249384 :         RegisterID reg = tempRegForData(backing);
        2312          249384 :         if (backing->type.inRegister())
        2313           94889 :             unpinReg(backing->type.reg());
        2314          249384 :         target->data.setRegister(reg);
        2315          249384 :         regstate(reg).reassociate(target);
        2316                 :
        2317          249384 :         if (backing->isTypeKnown()) {
        2318          135129 :             target->setType(backing->getKnownType());
        2319                 :         } else {
        2320          114255 :             pinReg(reg);
        2321          114255 :             RegisterID typeReg = tempRegForType(backing);
        2322          114255 :             unpinReg(reg);
        2323          114255 :             target->type.setRegister(typeReg);
        2324          114255 :             regstate(typeReg).reassociate(target);
        2325                 :         }
        2326                 :     }
        2327                 :
        2328          252300 :     backing->setCopyOf(target);
        2329          252300 :     JS_ASSERT(top->copyOf() == target);
        2330                 :
        2331          252300 :     if (trySyncType && target->isType(oldType))
        2332           61032 :         target->type.sync();
        2333                 : }
        2334                 :
        2335                 : void
        2336          132213 : FrameState::shimmy(uint32_t n)
        2337                 : {
        2338          132213 :     JS_ASSERT(a->sp - n >= a->spBase);
        2339          132213 :     int32_t depth = 0 - int32_t(n);
        2340          132213 :     storeTop(peek(depth - 1));
        2341          132213 :     popn(n);
        2342          132213 : }
        2343                 :
        2344                 : void
        2345          184544 : FrameState::shift(int32_t n)
        2346                 : {
        2347          184544 :     JS_ASSERT(n < 0);
        2348          184544 :     JS_ASSERT(a->sp + n - 1 >= a->spBase);
        2349          184544 :     storeTop(peek(n - 1));
        2350          184544 :     pop();
        2351          184544 : }
        2352                 :
        2353                 : void
        2354               0 : FrameState::swap()
        2355                 : {
        2356                 :     // A B
        2357                 :
        2358               0 :     dupAt(-2);
        2359                 :     // A B A
        2360                 :
        2361               0 :     dupAt(-2);
        2362                 :     // A B A B
        2363                 :
        2364               0 :     shift(-3);
        2365                 :     // B B A
        2366                 :
        2367               0 :     shimmy(1);
        2368                 :     // B A
        2369               0 : }
        2370                 :
        2371                 : void
        2372             395 : FrameState::forgetKnownDouble(FrameEntry *fe)
        2373                 : {
        2374                 :     /*
        2375                 :      * Forget all information indicating fe is a double, so we can use GPRs for its
        2376                 :      * contents.  We currently need to do this in order to use the entry in MICs/PICs
        2377                 :      * or to construct its ValueRemat. :FIXME: this needs to get fixed.
        2378                 :      */
        2379             395 :     JS_ASSERT(!fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE));
        2380                 :
        2381             395 :     RegisterID typeReg = allocReg();
        2382             395 :     RegisterID dataReg = allocReg();
        2383                 :
        2384                 :     /* Copy into a different FP register, as breakDouble can modify fpreg. */
        2385             395 :     FPRegisterID fpreg = allocFPReg();
        2386             395 :     masm.moveDouble(tempFPRegForData(fe), fpreg);
        2387             395 :     masm.breakDouble(fpreg, typeReg, dataReg);
        2388                 :
        2389             395 :     forgetAllRegs(fe);
        2390             395 :     fe->resetUnsynced();
        2391             395 :     fe->clear();
        2392                 :
        2393             395 :     regstate(typeReg).associate(fe, RematInfo::TYPE);
        2394             395 :     regstate(dataReg).associate(fe, RematInfo::DATA);
        2395             395 :     fe->type.setRegister(typeReg);
        2396             395 :     fe->data.setRegister(dataReg);
        2397             395 :     freeReg(fpreg);
        2398             395 : }
        2399                 :
        2400                 : void
        2401           81564 : FrameState::pinEntry(FrameEntry *fe, ValueRemat &vr, bool breakDouble)
        2402                 : {
        2403           81564 :     if (breakDouble && !fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE))
        2404             386 :         forgetKnownDouble(fe);
        2405                 :
        2406           81564 :     if (fe->isConstant()) {
        2407           16286 :         vr = ValueRemat::FromConstant(fe->getValue());
        2408           65278 :     } else if (fe->isType(JSVAL_TYPE_DOUBLE)) {
        2409            1385 :         FPRegisterID fpreg = tempFPRegForData(fe);
        2410            1385 :         pinReg(fpreg);
        2411            1385 :         vr = ValueRemat::FromFPRegister(fpreg);
        2412                 :     } else {
        2413                 :         // Pin the type register so it can't spill.
        2414           63893 :         MaybeRegisterID maybePinnedType = maybePinType(fe);
        2415                 :
        2416                 :         // Get and pin the data register.
        2417           63893 :         RegisterID dataReg = tempRegForData(fe);
        2418           63893 :         pinReg(dataReg);
        2419                 :
        2420           63893 :         if (fe->isTypeKnown()) {
        2421           39260 :             vr = ValueRemat::FromKnownType(fe->getKnownType(), dataReg);
        2422                 :         } else {
        2423                 :             // The type might not be loaded yet, so unpin for simplicity.
        2424           24633 :             maybeUnpinReg(maybePinnedType);
        2425                 :
        2426           24633 :             vr = ValueRemat::FromRegisters(tempRegForType(fe), dataReg);
        2427           24633 :             pinReg(vr.typeReg());
        2428                 :         }
        2429                 :     }
        2430                 :
        2431                 :     // Set these bits last, since allocation could have caused a sync.
        2432           81564 :     vr.isDataSynced = fe->data.synced();
        2433           81564 :     vr.isTypeSynced = fe->type.synced();
        2434           81564 : }
        2435                 :
        2436                 : void
        2437           70852 : FrameState::unpinEntry(const ValueRemat &vr)
        2438                 : {
        2439           70852 :     if (vr.isFPRegister()) {
        2440            1385 :         unpinReg(vr.fpReg());
        2441           69467 :     } else if (!vr.isConstant()) {
        2442           56061 :         if (!vr.isTypeKnown())
        2443           20011 :             unpinReg(vr.typeReg());
        2444           56061 :         unpinReg(vr.dataReg());
        2445                 :     }
        2446           70852 : }
        2447                 :
        2448                 : void
        2449           10712 : FrameState::ensureValueSynced(Assembler &masm, FrameEntry *fe, const ValueRemat &vr)
        2450                 : {
        2451                 : #if defined JS_PUNBOX64
        2452                 :     if (!vr.isDataSynced || !vr.isTypeSynced)
        2453                 :         masm.storeValue(vr, addressOf(fe));
        2454                 : #elif defined JS_NUNBOX32
        2455           10712 :     if (vr.isConstant() || vr.isFPRegister()) {
        2456            2880 :         if (!vr.isDataSynced || !vr.isTypeSynced)
        2457            2869 :             masm.storeValue(vr.value(), addressOf(fe));
        2458                 :     } else {
        2459            7832 :         if (!vr.isDataSynced)
        2460            7603 :             masm.storePayload(vr.dataReg(), addressOf(fe));
        2461            7832 :         if (!vr.isTypeSynced) {
        2462            7554 :             if (vr.isTypeKnown())
        2463            3194 :                 masm.storeTypeTag(ImmType(vr.knownType()), addressOf(fe));
        2464                 :             else
        2465            4360 :                 masm.storeTypeTag(vr.typeReg(), addressOf(fe));
        2466                 :         }
        2467                 :     }
        2468                 : #endif
        2469           10712 : }
        2470                 :
        2471                 : static inline bool
        2472         1558320 : AllocHelper(RematInfo &info, MaybeRegisterID &maybe)
        2473                 : {
        2474         1558320 :     if (info.inRegister()) {
        2475         1057833 :         maybe = info.reg();
        2476         1057833 :         return true;
        2477                 :     }
        2478          500487 :     return false;
        2479                 : }
        2480                 :
        2481                 : void
        2482              82 : FrameState::allocForSameBinary(FrameEntry *fe, JSOp op, BinaryAlloc &alloc)
        2483                 : {
        2484              82 :     alloc.rhsNeedsRemat = false;
        2485                 :
        2486              82 :     if (!fe->isTypeKnown()) {
        2487              54 :         alloc.lhsType = tempRegForType(fe);
        2488              54 :         pinReg(alloc.lhsType.reg());
        2489                 :     }
        2490                 :
        2491              82 :     alloc.lhsData = tempRegForData(fe);
        2492                 :
        2493              82 :     if (!freeRegs.empty(Registers::AvailRegs)) {
        2494              62 :         alloc.result = allocReg();
        2495              62 :         masm.move(alloc.lhsData.reg(), alloc.result);
        2496              62 :         alloc.lhsNeedsRemat = false;
        2497                 :     } else {
        2498              20 :         alloc.result = alloc.lhsData.reg();
        2499              20 :         takeReg(alloc.result);
        2500              20 :         alloc.lhsNeedsRemat = true;
        2501                 :     }
        2502                 :
        2503              82 :     if (alloc.lhsType.isSet())
        2504              54 :         unpinReg(alloc.lhsType.reg());
        2505                 :
        2506              82 :     alloc.lhsFP = alloc.rhsFP = allocFPReg();
        2507              82 : }
        2508                 :
        2509                 : void
        2510           93030 : FrameState::ensureFullRegs(FrameEntry *fe, MaybeRegisterID *type, MaybeRegisterID *data)
        2511                 : {
        2512           93030 :     fe = fe->isCopy() ? fe->copyOf() : fe;
        2513                 :
        2514           93030 :     JS_ASSERT(!data->isSet() && !type->isSet());
        2515           93030 :     if (!fe->type.inMemory()) {
        2516           76013 :         if (fe->type.inRegister())
        2517           38058 :             *type = fe->type.reg();
        2518           76013 :         if (fe->data.isConstant())
        2519               0 :             return;
        2520           76013 :         if (fe->data.inRegister()) {
        2521           72870 :             *data = fe->data.reg();
        2522           72870 :             return;
        2523                 :         }
        2524            3143 :         if (fe->type.inRegister())
        2525             296 :             pinReg(fe->type.reg());
        2526            3143 :         *data = tempRegForData(fe);
        2527            3143 :         if (fe->type.inRegister())
        2528             296 :             unpinReg(fe->type.reg());
        2529           17017 :     } else if (!fe->data.inMemory()) {
        2530             482 :         if (fe->data.inRegister())
        2531             482 :             *data = fe->data.reg();
        2532             482 :         if (fe->type.isConstant())
        2533               0 :             return;
        2534             482 :         if (fe->type.inRegister()) {
        2535               0 :             *type = fe->type.reg();
        2536               0 :             return;
        2537                 :         }
        2538             482 :         if (fe->data.inRegister())
        2539             482 :             pinReg(fe->data.reg());
        2540             482 :         *type = tempRegForType(fe);
        2541             482 :         if (fe->data.inRegister())
        2542             482 :             unpinReg(fe->data.reg());
        2543                 :     } else {
        2544           16535 :         *data = tempRegForData(fe);
        2545           16535 :         pinReg(data->reg());
        2546           16535 :         *type = tempRegForType(fe);
        2547           16535 :         unpinReg(data->reg());
        2548                 :     }
        2549                 : }
        2550                 :
        2551                 : inline bool
        2552           53077 : FrameState::binaryEntryLive(FrameEntry *fe) const
        2553                 : {
        2554                 :     /*
        2555                 :      * Compute whether fe is live after the binary operation performed at the current
        2556                 :      * bytecode. This is similar to variableLive except that it returns false for the
        2557                 :      * top two stack entries and special cases LOCALINC/ARGINC and friends, which fuse
        2558                 :      * a binary operation before writing over the local/arg.
        2559                 :      */
        2560           53077 :     JS_ASSERT(cx->typeInferenceEnabled());
        2561                 :
        2562           53077 :     if (deadEntry(fe, 2))
        2563           32403 :         return false;
        2564                 :
        2565           20674 :     switch (JSOp(*a->PC)) {
        2566                 :       case JSOP_INCLOCAL:
        2567                 :       case JSOP_DECLOCAL:
        2568                 :       case JSOP_LOCALINC:
        2569                 :       case JSOP_LOCALDEC:
        2570           11270 :         if (fe - a->locals == (int) GET_SLOTNO(a->PC))
        2571           10886 :             return false;
        2572                 :       case JSOP_INCARG:
        2573                 :       case JSOP_DECARG:
        2574                 :       case JSOP_ARGINC:
        2575                 :       case JSOP_ARGDEC:
        2576             581 :         if (fe - a->args == (int) GET_SLOTNO(a->PC))
        2577             129 :             return false;
        2578                 :       default:;
        2579                 :     }
        2580                 :
        2581            9659 :     JS_ASSERT(fe != a->callee_);
        2582                 :
        2583                 :     /* Arguments are always treated as live within inline frames, see bestEvictReg. */
        2584            9659 :     if (a->parent && fe < a->locals)
        2585              89 :         return true;
        2586                 :
        2587                 :     /* Caller must check that no copies are invalidated by rewriting the entry. */
        2588            9570 :     return fe >= a->spBase || variableLive(fe, a->PC);
        2589                 : }
        2590                 :
        2591                 : void
        2592          389580 : FrameState::allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAlloc &alloc,
        2593                 :                            bool needsResult)
        2594                 : {
        2595          389580 :     FrameEntry *backingLeft = lhs;
        2596          389580 :     FrameEntry *backingRight = rhs;
        2597                 :
        2598          389580 :     if (backingLeft->isCopy())
        2599           30597 :         backingLeft = backingLeft->copyOf();
        2600          389580 :     if (backingRight->isCopy())
        2601            2229 :         backingRight = backingRight->copyOf();
        2602                 :
        2603                 :     /*
        2604                 :      * For each remat piece of both FEs, if a register is assigned, get it now
        2605                 :      * and pin it. This is safe - constants and known types will be avoided.
        2606                 :      */
        2607          389580 :     if (AllocHelper(backingLeft->type, alloc.lhsType))
        2608           53955 :         pinReg(alloc.lhsType.reg());
        2609          389580 :     if (AllocHelper(backingLeft->data, alloc.lhsData))
        2610          370255 :         pinReg(alloc.lhsData.reg());
        2611          389580 :     if (AllocHelper(backingRight->type, alloc.rhsType))
        2612          312105 :         pinReg(alloc.rhsType.reg());
        2613          389580 :     if (AllocHelper(backingRight->data, alloc.rhsData))
        2614          321518 :         pinReg(alloc.rhsData.reg());
        2615                 :
        2616                 :     /* For each type without a register, give it a register if needed. */
        2617          389580 :     if (!alloc.lhsType.isSet() && backingLeft->type.inMemory()) {
        2618          307573 :         alloc.lhsType = tempRegForType(lhs);
        2619          307573 :         pinReg(alloc.lhsType.reg());
        2620                 :     }
        2621          389580 :     if (!alloc.rhsType.isSet() && backingRight->type.inMemory()) {
        2622            2542 :         alloc.rhsType = tempRegForType(rhs);
        2623            2542 :         pinReg(alloc.rhsType.reg());
        2624                 :     }
        2625                 :
        2626                 :     /*
        2627                 :      * Allocate floating point registers.  These are temporaries with no pre-existing data;
        2628                 :      * floating point registers are only allocated for known doubles, and BinaryAlloc is not
        2629                 :      * used for such operations.
        2630                 :      */
        2631          389580 :     JS_ASSERT(!backingLeft->isType(JSVAL_TYPE_DOUBLE));
        2632          389580 :     JS_ASSERT(!backingRight->isType(JSVAL_TYPE_DOUBLE));
        2633          389580 :     alloc.lhsFP = allocFPReg();
        2634          389580 :     alloc.rhsFP = allocFPReg();
        2635                 :
        2636                 :     bool commu;
        2637          389580 :     switch (op) {
        2638                 :       case JSOP_EQ:
        2639                 :       case JSOP_GT:
        2640                 :       case JSOP_GE:
        2641                 :       case JSOP_LT:
        2642                 :       case JSOP_LE:
        2643                 :         /* fall through */
        2644                 :       case JSOP_ADD:
        2645                 :       case JSOP_MUL:
        2646                 :       case JSOP_SUB:
        2647          389580 :         commu = true;
        2648          389580 :         break;
        2649                 :
        2650                 :       case JSOP_DIV:
        2651               0 :         commu = false;
        2652               0 :         break;
        2653                 :
        2654                 :       default:
        2655               0 :         JS_NOT_REACHED("unknown op");
        2656                 :         return;
        2657                 :     }
        2658                 :
        2659                 :     /*
        2660                 :      * Allocate data registers. If the op is not commutative, the LHS
        2661                 :      * _must_ be in a register.
        2662                 :      */
        2663          389580 :     JS_ASSERT_IF(lhs->isConstant(), !rhs->isConstant());
        2664          389580 :     JS_ASSERT_IF(rhs->isConstant(), !lhs->isConstant());
        2665                 :
        2666          389580 :     if (!alloc.lhsData.isSet()) {
        2667           19325 :         if (backingLeft->data.inMemory()) {
        2668           17776 :             alloc.lhsData = tempRegForData(lhs);
        2669           17776 :             pinReg(alloc.lhsData.reg());
        2670            1549 :         } else if (!commu) {
        2671               0 :             JS_ASSERT(lhs->isConstant());
        2672               0 :             alloc.lhsData = allocReg();
        2673               0 :             alloc.extraFree = alloc.lhsData;
        2674               0 :             masm.move(Imm32(lhs->getValue().toInt32()), alloc.lhsData.reg());
        2675                 :         }
        2676                 :     }
        2677          389580 :     if (!alloc.rhsData.isSet() && backingRight->data.inMemory()) {
        2678            2748 :         alloc.rhsData = tempRegForData(rhs);
        2679            2748 :         pinReg(alloc.rhsData.reg());
        2680                 :     }
        2681                 :
        2682          389580 :     alloc.lhsNeedsRemat = false;
        2683          389580 :     alloc.rhsNeedsRemat = false;
        2684          389580 :     alloc.resultHasRhs = false;
        2685          389580 :     alloc.undoResult = false;
        2686                 :
        2687          389580 :     if (!needsResult)
        2688           24811 :         goto skip;
        2689                 :
        2690                 :     /*
        2691                 :      * Now a result register is needed. It must contain a mutable copy of the
        2692                 :      * LHS. For commutative operations, we can opt to use the RHS instead. At
        2693                 :      * this point, if for some reason either must be in a register, that has
        2694                 :      * already been guaranteed at this point.
        2695                 :      */
        2696                 :
        2697                 :     /*
        2698                 :      * Try to reuse operand registers without syncing for ADD and constant SUB,
        2699                 :      * so long as the backing for the operand is dead.
        2700                 :      */
        2701          511517 :     if (cx->typeInferenceEnabled() &&
        2702          107327 :         backingLeft->data.inRegister() && !binaryEntryLive(backingLeft) &&
        2703           27460 :         (op == JSOP_ADD || (op == JSOP_SUB && backingRight->isConstant())) &&
        2704           11961 :         (lhs == backingLeft || hasOnlyCopy(backingLeft, lhs))) {
        2705           41001 :         alloc.result = backingLeft->data.reg();
        2706           41001 :         alloc.undoResult = true;
        2707           41001 :         alloc.resultHasRhs = false;
        2708           41001 :         goto skip;
        2709                 :     }
        2710                 :
        2711          323768 :     if (cx->typeInferenceEnabled())
        2712           13249 :         evictDeadEntries(true);
        2713                 :
        2714          323768 :     if (!freeRegs.empty(Registers::AvailRegs)) {
        2715                 :         /* Free reg - just grab it. */
        2716          320423 :         alloc.result = allocReg();
        2717          320423 :         if (!alloc.lhsData.isSet()) {
        2718            1344 :             JS_ASSERT(alloc.rhsData.isSet());
        2719            1344 :             JS_ASSERT(commu);
        2720            1344 :             masm.move(alloc.rhsData.reg(), alloc.result);
        2721            1344 :             alloc.resultHasRhs = true;
        2722                 :         } else {
        2723          319079 :             masm.move(alloc.lhsData.reg(), alloc.result);
        2724          319079 :             alloc.resultHasRhs = false;
        2725                 :         }
        2726            3345 :     } else if (cx->typeInferenceEnabled()) {
        2727                 :         /* No free regs. Evict a register or reuse one of the operands. */
        2728            1150 :         bool leftInReg = backingLeft->data.inRegister();
        2729            1150 :         bool rightInReg = backingRight->data.inRegister();
        2730                 :
        2731                 :         /* If the LHS/RHS types are in registers, don't use them for the result. */
        2732            1150 :         uint32_t mask = Registers::AvailRegs;
        2733            1150 :         if (backingLeft->type.inRegister())
        2734             781 :             mask &= ~Registers::maskReg(backingLeft->type.reg());
        2735            1150 :         if (backingRight->type.inRegister())
        2736             679 :             mask &= ~Registers::maskReg(backingRight->type.reg());
        2737                 :
        2738            1150 :         RegisterID result = bestEvictReg(mask, true).reg();
        2739            1150 :         if (!commu && rightInReg && backingRight->data.reg() == result) {
        2740                 :             /* Can't put the result in the RHS for non-commutative operations. */
        2741               0 :             alloc.result = allocReg();
        2742               0 :             masm.move(alloc.lhsData.reg(), alloc.result);
        2743                 :         } else {
        2744            1150 :             alloc.result = result;
        2745            1150 :             if (leftInReg && result == backingLeft->data.reg()) {
        2746             241 :                 alloc.lhsNeedsRemat = true;
        2747             241 :                 unpinReg(result);
        2748             241 :                 takeReg(result);
        2749             909 :             } else if (rightInReg && result == backingRight->data.reg()) {
        2750             456 :                 alloc.rhsNeedsRemat = true;
        2751             456 :                 alloc.resultHasRhs = true;
        2752             456 :                 unpinReg(result);
        2753             456 :                 takeReg(result);
        2754                 :             } else {
        2755             453 :                 JS_ASSERT(!regstate(result).isPinned());
        2756             453 :                 takeReg(result);
        2757             453 :                 if (leftInReg) {
        2758             393 :                     masm.move(alloc.lhsData.reg(), result);
        2759                 :                 } else {
        2760              60 :                     masm.move(alloc.rhsData.reg(), result);
        2761              60 :                     alloc.resultHasRhs = true;
        2762                 :                 }
        2763                 :             }
        2764                 :         }
        2765                 :     } else {
        2766                 :         /*
        2767                 :          * No free regs. Find a good candidate to re-use. Best candidates don't
        2768                 :          * require syncs on the inline path.
        2769                 :          */
        2770            2195 :         bool leftInReg = backingLeft->data.inRegister();
        2771            2195 :         bool rightInReg = backingRight->data.inRegister();
        2772            2195 :         bool leftSynced = backingLeft->data.synced();
        2773            2195 :         bool rightSynced = backingRight->data.synced();
        2774            2195 :         if (!commu || (leftInReg && (leftSynced || (!rightInReg || !rightSynced)))) {
        2775            1965 :             JS_ASSERT(backingLeft->data.inRegister() || !commu);
        2776            5895 :             JS_ASSERT_IF(backingLeft->data.inRegister(),
        2777            5895 :                          backingLeft->data.reg() == alloc.lhsData.reg());
        2778            1965 :             if (backingLeft->data.inRegister()) {
        2779            1965 :                 alloc.result = backingLeft->data.reg();
        2780            1965 :                 unpinReg(alloc.result);
        2781            1965 :                 takeReg(alloc.result);
        2782            1965 :                 alloc.lhsNeedsRemat = true;
        2783                 :             } else {
        2784                 :                 /* For now, just spill... */
        2785               0 :                 alloc.result = allocReg();
        2786               0 :                 masm.move(alloc.lhsData.reg(), alloc.result);
        2787                 :             }
        2788            1965 :             alloc.resultHasRhs = false;
        2789                 :         } else {
        2790             230 :             JS_ASSERT(commu);
        2791             230 :             JS_ASSERT(!leftInReg || (rightInReg && rightSynced));
        2792             230 :             alloc.result = backingRight->data.reg();
        2793             230 :             unpinReg(alloc.result);
        2794             230 :             takeReg(alloc.result);
        2795             230 :             alloc.resultHasRhs = true;
        2796             230 :             alloc.rhsNeedsRemat = true;
        2797                 :         }
        2798                 :     }
        2799                 :
        2800                 :   skip:
        2801                 :     /* Unpin everything that was pinned. */
        2802          389580 :     if (backingLeft->type.inRegister())
        2803          361528 :         unpinReg(backingLeft->type.reg());
        2804          389580 :     if (backingRight->type.inRegister())
        2805          314647 :         unpinReg(backingRight->type.reg());
        2806          389580 :     if (backingLeft->data.inRegister())
        2807          385825 :         unpinReg(backingLeft->data.reg());
        2808          389580 :     if (backingRight->data.inRegister())
        2809          323580 :         unpinReg(backingRight->data.reg());
        2810          389580 : }
        2811                 :
        2812                 : void
        2813          365240 : FrameState::rematBinary(FrameEntry *lhs, FrameEntry *rhs, const BinaryAlloc &alloc, Assembler &masm)
        2814                 : {
        2815          365240 :     if (alloc.rhsNeedsRemat)
        2816             907 :         masm.loadPayload(addressForDataRemat(rhs), alloc.rhsData.reg());
        2817          365240 :     if (alloc.lhsNeedsRemat)
        2818            2603 :         masm.loadPayload(addressForDataRemat(lhs), alloc.lhsData.reg());
        2819          365240 : }
        2820                 :
        2821                 : MaybeRegisterID
        2822           64243 : FrameState::maybePinData(FrameEntry *fe)
        2823                 : {
        2824           64243 :     fe = fe->isCopy() ? fe->copyOf() : fe;
        2825           64243 :     if (fe->data.inRegister()) {
        2826           33475 :         pinReg(fe->data.reg());
        2827           33475 :         return fe->data.reg();
        2828                 :     }
        2829           30768 :     return MaybeRegisterID();
        2830                 : }
        2831                 :
        2832                 : MaybeRegisterID
        2833           99209 : FrameState::maybePinType(FrameEntry *fe)
        2834                 : {
        2835           99209 :     fe = fe->isCopy() ? fe->copyOf() : fe;
        2836           99209 :     if (fe->type.inRegister()) {
        2837           29936 :         pinReg(fe->type.reg());
        2838           29936 :         return fe->type.reg();
        2839                 :     }
        2840           69273 :     return MaybeRegisterID();
        2841                 : }
        2842                 :
        2843                 : void
        2844          108391 : FrameState::maybeUnpinReg(MaybeRegisterID reg)
        2845                 : {
        2846          108391 :     if (reg.isSet())
        2847           55326 :         unpinReg(reg.reg());
        2848          108391 : }
        2849                 :
        2850                 : uint32_t
        2851            2443 : FrameState::allocTemporary()
        2852                 : {
        2853            2443 :     if (temporariesTop == temporaries + TEMPORARY_LIMIT)
        2854               0 :         return UINT32_MAX;
        2855            2443 :     FrameEntry *fe = temporariesTop++;
        2856            2443 :     fe->lastLoop = 0;
        2857            2443 :     fe->temporary = true;
        2858            2443 :     return fe - temporaries;
        2859                 : }
        2860                 :
        2861                 : void
        2862           33560 : FrameState::clearTemporaries()
        2863                 : {
        2864           33560 :     JS_ASSERT(!a->parent);
        2865                 :
        2866           36003 :     for (FrameEntry *fe = temporaries; fe < temporariesTop; fe++) {
        2867            2443 :         if (!fe->isTracked())
        2868            1557 :             continue;
        2869             886 :         if (fe->isCopied())
        2870               1 :             uncopy(fe);
        2871             886 :         forgetAllRegs(fe);
        2872             886 :         fe->resetSynced();
        2873                 :     }
        2874                 :
        2875           33560 :     temporariesTop = temporaries;
        2876           33560 : }
        2877                 :
        2878                 : Vector<TemporaryCopy> *
        2879           31932 : FrameState::getTemporaryCopies(Uses uses)
        2880                 : {
        2881                 :     /* :XXX: handle OOM */
        2882           31932 :     Vector<TemporaryCopy> *res = NULL;
        2883                 :
        2884           46248 :     for (FrameEntry *fe = temporaries; fe < temporariesTop; fe++) {
        2885           14316 :         if (!fe->isTracked())
        2886            3691 :             continue;
        2887           10625 :         if (fe->isCopied()) {
        2888             555 :             for (uint32_t i = fe->trackerIndex() + 1; i < tracker.nentries; i++) {
        2889             446 :                 FrameEntry *nfe = tracker[i];
        2890             446 :                 if (!deadEntry(nfe, uses.nuses) && nfe->isCopy() && nfe->copyOf() == fe) {
        2891             110 :                     if (!res)
        2892              90 :                         res = OffTheBooks::new_< Vector<TemporaryCopy> >(cx);
        2893             110 :                     res->append(TemporaryCopy(addressOf(nfe), addressOf(fe)));
        2894                 :                 }
        2895                 :             }
        2896                 :         }
        2897                 :     }
        2898                 :
        2899           31932 :     return res;
        2900                 : }

Generated by: LCOV version 1.7