LCOV - code coverage report
Current view: directory - js/src/methodjit - FrameState.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1514 1399 92.4 %
Date: 2012-06-02 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          134091 : 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          134091 :     loop(NULL), inTryBlock(false)
      57                 : {
      58          134091 : }
      59                 : 
      60          268182 : FrameState::~FrameState()
      61                 : {
      62          397063 :     while (a) {
      63          128881 :         ActiveFrame *parent = a->parent;
      64          128881 :         a->script->analysis()->clearAllocations();
      65          128881 :         cx->free_(a);
      66          128881 :         a = parent;
      67                 :     }
      68          134091 :     cx->free_(entries);
      69          134091 : }
      70                 : 
      71                 : void
      72            2827 : FrameState::pruneDeadEntries()
      73                 : {
      74            2827 :     unsigned shift = 0;
      75           40898 :     for (unsigned i = 0; i < tracker.nentries; i++) {
      76           38071 :         FrameEntry *fe = tracker[i];
      77           38071 :         if (deadEntry(fe)) {
      78            6913 :             fe->untrack();
      79            6913 :             shift++;
      80           31158 :         } else if (shift) {
      81            1040 :             fe->index_ -= shift;
      82            1040 :             tracker.entries[fe->index_] = fe;
      83                 :         }
      84                 :     }
      85            2827 :     tracker.nentries -= shift;
      86            2827 : }
      87                 : 
      88                 : bool
      89          131876 : FrameState::pushActiveFrame(JSScript *script, uint32_t argc)
      90                 : {
      91          131876 :     if (!a) {
      92          128881 :         this->nentries = analyze::TotalSlots(script) + (script->nslots - script->nfixed) +
      93          128881 :             StackSpace::STACK_JIT_EXTRA - VALUES_PER_STACK_FRAME;
      94                 :         size_t totalBytes = sizeof(FrameEntry) * nentries +       // entries[]
      95                 :                             sizeof(FrameEntry *) * nentries +     // tracker.entries
      96          128881 :                             sizeof(StackEntryExtra) * nentries;   // extraArray
      97          128881 :         uint8_t *cursor = (uint8_t *)OffTheBooks::calloc_(totalBytes);
      98          128881 :         if (!cursor)
      99               0 :             return false;
     100                 : 
     101          128881 :         this->entries = (FrameEntry *) cursor;
     102          128881 :         cursor += sizeof(FrameEntry) * nentries;
     103                 : 
     104          128881 :         this->tracker.entries = (FrameEntry **)cursor;
     105          128881 :         cursor += sizeof(FrameEntry *) * nentries;
     106                 : 
     107          128881 :         this->extraArray = (StackEntryExtra *)cursor;
     108          128881 :         cursor += sizeof(StackEntryExtra) * nentries;
     109                 : 
     110          128881 :         JS_ASSERT(reinterpret_cast<uint8_t *>(this->entries) + totalBytes == cursor);
     111                 : 
     112                 : #if defined JS_NUNBOX32
     113          128881 :         if (!reifier.init(cx, *this, nentries))
     114               0 :             return false;
     115                 : #endif
     116                 : 
     117          128881 :         this->temporaries = this->temporariesTop = this->entries + nentries - TEMPORARY_LIMIT;
     118                 :     }
     119                 : 
     120                 :     /* We should have already checked that argc == nargs */
     121          131876 :     JS_ASSERT_IF(a, argc == script->function()->nargs);
     122                 : 
     123          131876 :     ActiveFrame *newa = OffTheBooks::new_<ActiveFrame>();
     124          131876 :     if (!newa)
     125               0 :         return false;
     126                 : 
     127          131876 :     newa->parent = a;
     128          131876 :     newa->depth = a ? (totalDepth() + VALUES_PER_STACK_FRAME) : 0;
     129                 : 
     130          131876 :     newa->script = script;
     131          131876 :     newa->PC = script->code;
     132          131876 :     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          131876 :     FrameEntry *entriesStart = a ? a->sp - (argc + 2) : entries;
     139          131876 :     newa->callee_ = entriesStart + analyze::CalleeSlot();
     140          131876 :     newa->this_   = entriesStart + analyze::ThisSlot();
     141          131876 :     newa->args    = entriesStart + analyze::ArgSlot(0);
     142          131876 :     newa->locals  = entriesStart + analyze::LocalSlot(script, 0);
     143          131876 :     newa->spBase  = entriesStart + analyze::TotalSlots(script);
     144          131876 :     newa->sp      = newa->spBase;
     145                 : 
     146          131876 :     this->a = newa;
     147                 : 
     148          131876 :     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            2995 : FrameState::popActiveFrame()
     167                 : {
     168            2995 :     a->analysis->clearAllocations();
     169                 : 
     170            2995 :     if (a->parent) {
     171                 :         /* Clear registers and copies used by local variables and stack slots. */
     172            7111 :         for (FrameEntry *fe = a->sp - 1; fe >= a->locals; fe--) {
     173            4116 :             if (!fe->isTracked())
     174             395 :                 continue;
     175            3721 :             forgetAllRegs(fe);
     176            3721 :             fe->clear();
     177                 :         }
     178                 :     }
     179                 : 
     180            2995 :     ActiveFrame *parent = a->parent;
     181            2995 :     cx->delete_(a);
     182            2995 :     a = parent;
     183            2995 : }
     184                 : 
     185                 : void
     186          728263 : FrameState::takeReg(AnyRegisterID reg)
     187                 : {
     188          728263 :     modifyReg(reg);
     189          728263 :     if (freeRegs.hasReg(reg)) {
     190          703061 :         freeRegs.takeReg(reg);
     191          703061 :         JS_ASSERT(!regstate(reg).usedBy());
     192                 :     } else {
     193           25202 :         JS_ASSERT(regstate(reg).fe());
     194           25202 :         evictReg(reg);
     195                 :     }
     196          728263 : }
     197                 : 
     198                 : #ifdef DEBUG
     199                 : const char *
     200          215064 : FrameState::entryName(const FrameEntry *fe) const
     201                 : {
     202                 :     static char bufs[4][50];
     203                 :     static unsigned which = 0;
     204          215064 :     which = (which + 1) & 3;
     205          215064 :     char *buf = bufs[which];
     206                 : 
     207          215064 :     if (isTemporary(fe)) {
     208            5366 :         JS_snprintf(buf, 50, "temp%d", fe - temporaries);
     209            5366 :         return buf;
     210                 :     }
     211                 : 
     212          209698 :     if (fe < a->callee_)
     213            1153 :         return "parent";
     214                 : 
     215          208545 :     JS_ASSERT(fe >= a->callee_ && fe < a->sp);
     216                 : 
     217          208545 :     if (fe == a->callee_)
     218             285 :         return "callee";
     219          208260 :     if (fe == a->this_)
     220            2102 :         return "'this'";
     221                 : 
     222          206158 :     if (isArg(fe))
     223           15464 :         JS_snprintf(buf, 50, "arg%d", fe - a->args);
     224          190694 :     else if (isLocal(fe))
     225           64927 :         JS_snprintf(buf, 50, "local%d", fe - a->locals);
     226                 :     else
     227          125767 :         JS_snprintf(buf, 50, "slot%d", fe - a->spBase);
     228          206158 :     return buf;
     229                 : }
     230                 : #endif
     231                 : 
     232                 : void
     233          154796 : FrameState::evictReg(AnyRegisterID reg)
     234                 : {
     235          154796 :     FrameEntry *fe = regstate(reg).fe();
     236                 : 
     237          154796 :     JaegerSpew(JSpew_Regalloc, "evicting %s from %s\n", entryName(fe), reg.name());
     238                 : 
     239          154796 :     if (regstate(reg).type() == RematInfo::TYPE) {
     240           63979 :         syncType(fe);
     241           63979 :         fe->type.setMemory();
     242           90817 :     } else if (reg.isReg()) {
     243           90805 :         syncData(fe);
     244           90805 :         fe->data.setMemory();
     245                 :     } else {
     246              12 :         syncFe(fe);
     247              12 :         fe->data.setMemory();
     248                 :     }
     249                 : 
     250          154796 :     regstate(reg).forget();
     251          154796 : }
     252                 : 
     253                 : inline Lifetime *
     254           89000 : 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           89000 :     JS_ASSERT(cx->typeInferenceEnabled());
     262           89000 :     JS_ASSERT(fe > a->callee_ && fe < a->spBase);
     263                 : 
     264           89000 :     uint32_t offset = pc - a->script->code;
     265           89000 :     return a->analysis->liveness(entrySlot(fe)).live(offset);
     266                 : }
     267                 : 
     268                 : AnyRegisterID
     269           54503 : FrameState::bestEvictReg(uint32_t mask, bool includePinned) const
     270                 : {
     271           54503 :     JS_ASSERT(cx->typeInferenceEnabled());
     272                 : 
     273                 :     /* Must be looking for a specific type of register. */
     274           54503 :     JS_ASSERT((mask & Registers::AvailRegs) != (mask & Registers::AvailFPRegs));
     275                 : 
     276           54503 :     AnyRegisterID fallback;
     277           54503 :     uint32_t fallbackOffset = UINT32_MAX;
     278                 : 
     279           54503 :     JaegerSpew(JSpew_Regalloc, "picking best register to evict:\n");
     280                 : 
     281          861069 :     for (uint32_t i = 0; i < Registers::TotalAnyRegisters; i++) {
     282          807452 :         AnyRegisterID reg = AnyRegisterID::fromRaw(i);
     283                 : 
     284                 :         /* Register is not allocatable, don't bother.  */
     285          807452 :         if (!(Registers::maskReg(reg) & mask))
     286          488474 :             continue;
     287                 : 
     288                 :         /* Register is not owned by the FrameState. */
     289          318978 :         FrameEntry *fe = includePinned ? regstate(reg).usedBy() : regstate(reg).fe();
     290          318978 :         if (!fe)
     291           70913 :             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          248065 :         if (fe == a->callee_) {
     301             285 :             JaegerSpew(JSpew_Regalloc, "result: %s is callee\n", reg.name());
     302             285 :             return reg;
     303                 :         }
     304                 : 
     305          247780 :         if (fe >= a->spBase && !isTemporary(fe)) {
     306          215248 :             if (!fallback.isSet()) {
     307           47132 :                 fallback = reg;
     308           47132 :                 fallbackOffset = 0;
     309                 :             }
     310          215248 :             JaegerSpew(JSpew_Regalloc, "    %s is on stack\n", reg.name());
     311          215248 :             continue;
     312                 :         }
     313                 : 
     314                 :         /* Prioritize keeping copied entries in registers. */
     315           32532 :         if (fe->isCopied()) {
     316           14952 :             if (!fallback.isSet()) {
     317            4265 :                 fallback = reg;
     318            4265 :                 fallbackOffset = 0;
     319                 :             }
     320           14952 :             JaegerSpew(JSpew_Regalloc, "    %s has copies\n", reg.name());
     321           14952 :             continue;
     322                 :         }
     323                 : 
     324           17580 :         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            4801 :             uint32_t offset = a->parent ? a->script->length : loop->backedgeOffset();
     332            4801 :             if (!fallback.isSet() || offset > fallbackOffset) {
     333            1932 :                 fallback = reg;
     334            1932 :                 fallbackOffset = offset;
     335                 :             }
     336            4801 :             JaegerSpew(JSpew_Regalloc, "    %s is a LICM or inline parent entry\n", reg.name());
     337            4801 :             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           12779 :         Lifetime *lifetime = variableLive(fe, a->PC);
     345                 : 
     346           12779 :         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           12762 :         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           12161 :         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           12161 :         if (!fallback.isSet() || lifetime->end > fallbackOffset) {
     376            8012 :             fallback = reg;
     377            8012 :             fallbackOffset = lifetime->end;
     378                 :         }
     379                 :     }
     380                 : 
     381           53617 :     JS_ASSERT(fallback.isSet());
     382                 : 
     383           53617 :     JaegerSpew(JSpew_Regalloc, "result %s\n", fallback.name());
     384           53617 :     return fallback;
     385                 : }
     386                 : 
     387                 : void
     388           67688 : FrameState::evictDeadEntries(bool includePinned)
     389                 : {
     390         1083008 :     for (uint32_t i = 0; i < Registers::TotalAnyRegisters; i++) {
     391         1015320 :         AnyRegisterID reg = AnyRegisterID::fromRaw(i);
     392                 : 
     393                 :         /* Follow along with the same filters as bestEvictReg. */
     394                 : 
     395         1015320 :         if (!(Registers::maskReg(reg) & Registers::AvailAnyRegs))
     396          135376 :             continue;
     397                 : 
     398          879944 :         FrameEntry *fe = includePinned ? regstate(reg).usedBy() : regstate(reg).fe();
     399          879944 :         if (!fe)
     400          589545 :             continue;
     401                 : 
     402          336986 :         if (fe == a->callee_ || isConstructorThis(fe) ||
     403           46587 :             fe >= a->spBase || fe->isCopied() || (a->parent && fe < a->locals)) {
     404          270630 :             continue;
     405                 :         }
     406                 : 
     407           19769 :         Lifetime *lifetime = variableLive(fe, a->PC);
     408           19769 :         if (lifetime)
     409           17738 :             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            2031 :         if (!fe->type.synced() && fe->isTypeKnown())
     416             225 :             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            2031 :         fakeSync(fe);
     423            2031 :         if (regstate(reg).type() == RematInfo::DATA)
     424            1489 :             fe->data.setMemory();
     425                 :         else
     426             542 :             fe->type.setMemory();
     427            2031 :         forgetReg(reg);
     428                 :     }
     429           67688 : }
     430                 : 
     431                 : AnyRegisterID
     432          174141 : FrameState::evictSomeReg(uint32_t mask)
     433                 : {
     434          174141 :     JS_ASSERT(!freeRegs.hasRegInMask(mask));
     435                 : 
     436          174141 :     if (cx->typeInferenceEnabled()) {
     437           54453 :         evictDeadEntries(false);
     438                 : 
     439           54453 :         if (freeRegs.hasRegInMask(mask)) {
     440                 :             /* There was a register in use by a dead local variable. */
     441            1100 :             AnyRegisterID reg = freeRegs.takeAnyReg(mask);
     442            1100 :             modifyReg(reg);
     443            1100 :             return reg;
     444                 :         }
     445                 : 
     446           53353 :         AnyRegisterID reg = bestEvictReg(mask, false);
     447           53353 :         evictReg(reg);
     448           53353 :         return reg;
     449                 :     }
     450                 : 
     451                 :     /* With inference disabled, only general purpose registers are managed. */
     452          119688 :     JS_ASSERT((mask & ~Registers::AvailRegs) == 0);
     453                 : 
     454          119688 :     MaybeRegisterID fallback;
     455                 : 
     456          823456 :     for (uint32_t i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
     457          747215 :         RegisterID reg = RegisterID(i);
     458                 : 
     459                 :         /* Register is not allocatable, don't bother.  */
     460          747215 :         if (!(Registers::maskReg(reg) & mask))
     461          175403 :             continue;
     462                 : 
     463                 :         /* Register is not owned by the FrameState. */
     464          571812 :         FrameEntry *fe = regstate(reg).fe();
     465          571812 :         if (!fe)
     466           99129 :             continue;
     467                 : 
     468                 :         /* Try to find a candidate... that doesn't need spilling. */
     469          472683 :         fallback = reg;
     470                 : 
     471          472683 :         if (regstate(reg).type() == RematInfo::TYPE && fe->type.synced()) {
     472           21225 :             fe->type.setMemory();
     473           21225 :             regstate(reg).forget();
     474           21225 :             return reg;
     475                 :         }
     476          451458 :         if (regstate(reg).type() == RematInfo::DATA && fe->data.synced()) {
     477           22222 :             fe->data.setMemory();
     478           22222 :             regstate(reg).forget();
     479           22222 :             return reg;
     480                 :         }
     481                 :     }
     482                 : 
     483           76241 :     evictReg(fallback.reg());
     484           76241 :     return fallback.reg();
     485                 : }
     486                 : 
     487                 : void
     488         1018153 : FrameState::resetInternalState()
     489                 : {
     490         3612897 :     for (uint32_t i = 0; i < tracker.nentries; i++)
     491         2594744 :         tracker[i]->untrack();
     492                 : 
     493         1018153 :     tracker.reset();
     494         1018153 :     freeRegs = Registers(Registers::AvailAnyRegs);
     495         1018153 : }
     496                 : 
     497                 : void
     498          157483 : FrameState::discardFrame()
     499                 : {
     500          157483 :     resetInternalState();
     501          157483 :     PodArrayZero(regstate_);
     502          157483 : }
     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          405333 : FrameState::forgetEverything()
     546                 : {
     547          405333 :     resetInternalState();
     548                 : 
     549                 : #ifdef DEBUG
     550         6485328 :     for (uint32_t i = 0; i < Registers::TotalAnyRegisters; i++) {
     551         6079995 :         AnyRegisterID reg = AnyRegisterID::fromRaw(i);
     552         6079995 :         JS_ASSERT(!regstate(reg).usedBy());
     553                 :     }
     554                 : #endif
     555          405333 : }
     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          129981 : FrameState::computeAllocation(jsbytecode *target)
     575                 : {
     576          129981 :     JS_ASSERT(cx->typeInferenceEnabled());
     577          129981 :     RegisterAllocation *alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
     578          129981 :     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          383822 :     if (a->analysis->getCode(target).safePoint ||
     588          253841 :         (!a->parent && !cc.bytecodeInChunk(target))) {
     589                 : #ifdef DEBUG
     590            1167 :         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            1167 :         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          128814 :     Registers regs = Registers::AvailAnyRegs;
     603         1932210 :     while (!regs.empty()) {
     604         1674582 :         AnyRegisterID reg = regs.takeAnyReg();
     605         1674582 :         if (freeRegs.hasReg(reg) || regstate(reg).type() == RematInfo::TYPE)
     606         1591869 :             continue;
     607           82713 :         FrameEntry *fe = regstate(reg).fe();
     608          261261 :         if (fe < a->callee_ ||
     609           80196 :             isConstructorThis(fe) ||
     610           53004 :             (fe > a->callee_ && fe < a->spBase && variableLive(fe, target)) ||
     611           45348 :             (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           38826 :             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           38826 :             alloc->set(reg, fe - entries, fe->data.synced());
     637                 :         }
     638                 :     }
     639                 : 
     640                 : #ifdef DEBUG
     641          128814 :     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          128814 :     return alloc;
     648                 : }
     649                 : 
     650                 : void
     651            2899 : FrameState::relocateReg(AnyRegisterID reg, RegisterAllocation *alloc, Uses uses)
     652                 : {
     653            2899 :     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            2899 :     JS_ASSERT(!freeRegs.hasReg(reg));
     663                 : 
     664            5226 :     for (unsigned i = 0; i < uses.nuses; i++) {
     665            3963 :         FrameEntry *fe = peek(-1 - i);
     666            3963 :         if (fe->isCopy())
     667            1954 :             fe = fe->copyOf();
     668            3963 :         if (reg.isReg() && fe->data.inRegister() && fe->data.reg() == reg.reg()) {
     669            1636 :             pinReg(reg);
     670            1636 :             RegisterID nreg = allocReg();
     671            1636 :             unpinReg(reg);
     672                 : 
     673            1636 :             JaegerSpew(JSpew_Regalloc, "relocating %s\n", reg.name());
     674                 : 
     675            1636 :             masm.move(reg.reg(), nreg);
     676            1636 :             regstate(reg).forget();
     677            1636 :             regstate(nreg).associate(fe, RematInfo::DATA);
     678            1636 :             fe->data.setRegister(nreg);
     679            1636 :             freeRegs.putReg(reg);
     680            1636 :             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          496478 : FrameState::syncForBranch(jsbytecode *target, Uses uses)
     692                 : {
     693                 :     /* There should be no unowned or pinned registers. */
     694                 : #ifdef DEBUG
     695          496478 :     Registers checkRegs(Registers::AvailAnyRegs);
     696         7447170 :     while (!checkRegs.empty()) {
     697         6454214 :         AnyRegisterID reg = checkRegs.takeAnyReg();
     698         6454214 :         JS_ASSERT_IF(!freeRegs.hasReg(reg), regstate(reg).fe());
     699                 :     }
     700                 : #endif
     701                 : 
     702          496478 :     if (!cx->typeInferenceEnabled()) {
     703          321105 :         syncAndForgetEverything();
     704          321105 :         return true;
     705                 :     }
     706                 : 
     707          175373 :     RegisterAllocation *&alloc = a->analysis->getAllocation(target);
     708          175373 :     if (!alloc) {
     709          129637 :         alloc = computeAllocation(target);
     710          129637 :         if (!alloc)
     711               0 :             return false;
     712                 :     }
     713                 : 
     714          175373 :     syncForAllocation(alloc, false, uses);
     715                 : 
     716          175373 :     return true;
     717                 : }
     718                 : 
     719                 : void
     720          176166 : 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          176166 :     FrameEntry *topEntry = NULL;
     729          176166 :     if (inlineReturn)
     730             793 :         topEntry = a->parent->sp - (GET_ARGC(a->parent->PC) + 2);
     731                 : 
     732          880054 :     for (uint32_t i = tracker.nentries - 1; i < tracker.nentries; i--) {
     733          703888 :         FrameEntry *fe = tracker[i];
     734                 : 
     735          703888 :         if (deadEntry(fe, uses.nuses))
     736          411880 :             continue;
     737          292008 :         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          290233 :         if (isLocal(fe) && !fe->copied && !a->analysis->slotEscapes(entrySlot(fe))) {
     752           87518 :             Lifetime *lifetime = a->analysis->liveness(entrySlot(fe)).live(a->PC - a->script->code);
     753           87518 :             if (!lifetime)
     754           38872 :                 fakeSync(fe);
     755                 :         }
     756                 : 
     757                 :         /* If returning from a script, fake syncs for dead locals in the immediate parent. */
     758          290709 :         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          290233 :         if (!fe->isCopy() && alloc->hasAnyReg(fe - entries)) {
     768                 :             /* Types are always synced, except for known doubles. */
     769           51843 :             if (!fe->isType(JSVAL_TYPE_DOUBLE))
     770           51244 :                 syncType(fe);
     771                 :         } else {
     772          238390 :             syncFe(fe);
     773          238390 :             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          176166 :     Registers regs = Registers(Registers::AvailAnyRegs);
     785         2642490 :     while (!regs.empty()) {
     786         2290158 :         AnyRegisterID reg = regs.takeAnyReg();
     787         2290158 :         if (!alloc->assigned(reg))
     788         2235072 :             continue;
     789           55086 :         FrameEntry *fe = getOrTrack(alloc->index(reg));
     790           55086 :         JS_ASSERT(!fe->isCopy());
     791                 : 
     792           55086 :         JS_ASSERT_IF(!fe->isType(JSVAL_TYPE_DOUBLE), fe->type.synced());
     793           55086 :         if (!fe->data.synced() && alloc->synced(reg))
     794            3984 :             syncFe(fe);
     795                 : 
     796           55086 :         if (fe->dataInRegister(reg))
     797           46919 :             continue;
     798                 : 
     799            8167 :         if (!freeRegs.hasReg(reg))
     800            2899 :             relocateReg(reg, alloc, uses);
     801                 : 
     802            8167 :         if (reg.isReg()) {
     803            8067 :             RegisterID nreg = reg.reg();
     804            8067 :             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            8067 :             if (fe->data.inMemory()) {
     812            4979 :                 masm.loadPayload(addressOf(fe), nreg);
     813            3088 :             } else if (fe->isConstant()) {
     814               7 :                 masm.loadValuePayload(fe->getValue(), nreg);
     815                 :             } else {
     816            3081 :                 JS_ASSERT(fe->data.inRegister() && fe->data.reg() != nreg);
     817            3081 :                 masm.move(fe->data.reg(), nreg);
     818            3081 :                 freeRegs.putReg(fe->data.reg());
     819            3081 :                 regstate(fe->data.reg()).forget();
     820                 :             }
     821            8067 :             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            8167 :         freeRegs.takeReg(reg);
     841            8167 :         regstate(reg).associate(fe, RematInfo::DATA);
     842                 :     }
     843          176166 : }
     844                 : 
     845                 : bool
     846          455337 : FrameState::discardForJoin(RegisterAllocation *&alloc, uint32_t stackDepth)
     847                 : {
     848          455337 :     if (!cx->typeInferenceEnabled()) {
     849          281413 :         resetInternalState();
     850          281413 :         PodArrayZero(regstate_);
     851          281413 :         a->sp = a->spBase + stackDepth;
     852          281413 :         return true;
     853                 :     }
     854                 : 
     855          173924 :     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            3978 :         alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
     861            3978 :         if (!alloc) {
     862               0 :             js_ReportOutOfMemory(cx);
     863               0 :             return false;
     864                 :         }
     865                 :     }
     866                 : 
     867          173924 :     resetInternalState();
     868          173924 :     PodArrayZero(regstate_);
     869                 : 
     870          173924 :     Registers regs(Registers::AvailAnyRegs);
     871         2608860 :     while (!regs.empty()) {
     872         2261012 :         AnyRegisterID reg = regs.takeAnyReg();
     873         2261012 :         if (!alloc->assigned(reg))
     874         2222233 :             continue;
     875           38779 :         FrameEntry *fe = getOrTrack(alloc->index(reg));
     876                 : 
     877           38779 :         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           38779 :         if (reg.isReg()) {
     884           38270 :             fe->data.setRegister(reg.reg());
     885                 :         } else {
     886             509 :             fe->setType(JSVAL_TYPE_DOUBLE);
     887             509 :             fe->data.setFPRegister(reg.fpreg());
     888                 :         }
     889                 : 
     890           38779 :         regstate(reg).associate(fe, RematInfo::DATA);
     891           38779 :         if (!alloc->synced(reg)) {
     892           16506 :             fe->data.unsync();
     893           16506 :             if (!reg.isReg())
     894             269 :                 fe->type.unsync();
     895                 :         }
     896                 :     }
     897                 : 
     898          173924 :     a->sp = a->spBase + stackDepth;
     899                 : 
     900          293128 :     for (unsigned i = 0; i < stackDepth; i++)
     901          119204 :         extraArray[a->spBase + i - entries].reset();
     902                 : 
     903          173924 :     return true;
     904                 : }
     905                 : 
     906                 : bool
     907          379946 : FrameState::consistentRegisters(jsbytecode *target)
     908                 : {
     909          379946 :     if (!cx->typeInferenceEnabled()) {
     910          179039 :         JS_ASSERT(freeRegs.freeMask == Registers::AvailAnyRegs);
     911          179039 :         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          200907 :     RegisterAllocation *alloc = a->analysis->getAllocation(target);
     921          200907 :     JS_ASSERT(alloc);
     922                 : 
     923          200907 :     Registers regs(Registers::AvailAnyRegs);
     924          200907 :     while (!regs.empty()) {
     925         2586411 :         AnyRegisterID reg = regs.takeAnyReg();
     926         2586411 :         if (alloc->assigned(reg)) {
     927           61135 :             FrameEntry *needed = getOrTrack(alloc->index(reg));
     928           61135 :             if (!freeRegs.hasReg(reg)) {
     929           54337 :                 FrameEntry *fe = regstate(reg).fe();
     930           54337 :                 if (fe != needed)
     931              14 :                     return false;
     932                 :             } else {
     933            6798 :                 return false;
     934                 :             }
     935                 :         }
     936                 :     }
     937                 : 
     938          194095 :     return true;
     939                 : }
     940                 : 
     941                 : void
     942           83360 : FrameState::prepareForJump(jsbytecode *target, Assembler &masm, bool synced)
     943                 : {
     944           83360 :     if (!cx->typeInferenceEnabled())
     945               0 :         return;
     946                 : 
     947           83360 :     JS_ASSERT_IF(!synced, !consistentRegisters(target));
     948                 : 
     949           83360 :     RegisterAllocation *alloc = a->analysis->getAllocation(target);
     950           83360 :     JS_ASSERT(alloc);
     951                 : 
     952           83360 :     Registers regs = 0;
     953                 : 
     954           83360 :     regs = Registers(Registers::AvailAnyRegs);
     955         1250400 :     while (!regs.empty()) {
     956         1083680 :         AnyRegisterID reg = regs.takeAnyReg();
     957         1083680 :         if (!alloc->assigned(reg))
     958         1021469 :             continue;
     959                 : 
     960           62211 :         const FrameEntry *fe = getOrTrack(alloc->index(reg));
     961           62211 :         if (synced || !fe->backing()->dataInRegister(reg)) {
     962           62168 :             JS_ASSERT_IF(!synced, fe->data.synced());
     963           62168 :             if (reg.isReg())
     964           61642 :                 masm.loadPayload(addressOf(fe), reg.reg());
     965                 :             else
     966             526 :                 masm.loadDouble(addressOf(fe), reg.fpreg());
     967                 :         }
     968                 :     }
     969                 : }
     970                 : 
     971                 : void
     972          301868 : FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
     973                 : {
     974          301868 :     if (fe->isConstant()) {
     975          101484 :         masm.storeValue(fe->getValue(), address);
     976          101484 :         return;
     977                 :     }
     978                 : 
     979          200384 :     if (fe->isCopy())
     980            3235 :         fe = fe->copyOf();
     981                 : 
     982          200384 :     JS_ASSERT(!freeRegs.hasReg(address.base));
     983                 : 
     984                 :     /* If loading from memory, ensure destination differs. */
     985          340817 :     JS_ASSERT_IF((fe->type.inMemory() || fe->data.inMemory()),
     986                 :                  addressOf(fe).base != address.base ||
     987          340817 :                  addressOf(fe).offset != address.offset);
     988                 : 
     989          200384 :     if (fe->data.inFPRegister()) {
     990            2430 :         masm.storeDouble(fe->data.fpreg(), address);
     991            2430 :         return;
     992                 :     }
     993                 : 
     994          197954 :     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          197853 :     bool pinAddressReg = !!regstate(address.base).fe();
    1003          197853 :     if (pinAddressReg)
    1004               0 :         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          197853 :     if (fe->data.inRegister()) {
    1079          158558 :         masm.storePayload(fe->data.reg(), address);
    1080                 :     } else {
    1081           39295 :         JS_ASSERT(fe->data.inMemory());
    1082                 :         RegisterID reg;
    1083           39295 :         if (popped) {
    1084           36886 :             reg = allocReg();
    1085           36886 :             masm.loadPayload(addressOf(fe), reg);
    1086                 :         } else {
    1087            2409 :             reg = allocAndLoadReg(fe, false, RematInfo::DATA).reg();
    1088                 :         }
    1089           39295 :         masm.storePayload(reg, address);
    1090           39295 :         if (popped)
    1091           36886 :             freeReg(reg);
    1092                 :         else
    1093            2409 :             fe->data.setRegister(reg);
    1094                 :     }
    1095                 : 
    1096          197853 :     if (fe->isTypeKnown()) {
    1097           64181 :         masm.storeTypeTag(ImmType(fe->getKnownType()), address);
    1098          133672 :     } else if (fe->type.inRegister()) {
    1099           73575 :         masm.storeTypeTag(fe->type.reg(), address);
    1100                 :     } else {
    1101           60097 :         JS_ASSERT(fe->type.inMemory());
    1102                 :         RegisterID reg;
    1103           60097 :         if (popped) {
    1104           58522 :             reg = allocReg();
    1105           58522 :             masm.loadTypeTag(addressOf(fe), reg);
    1106                 :         } else {
    1107            1575 :             reg = allocAndLoadReg(fe, false, RematInfo::TYPE).reg();
    1108                 :         }
    1109           60097 :         masm.storeTypeTag(reg, address);
    1110           60097 :         if (popped)
    1111           58522 :             freeReg(reg);
    1112                 :         else
    1113            1575 :             fe->type.setRegister(reg);
    1114                 :     }
    1115                 : #endif
    1116          197853 :     if (pinAddressReg)
    1117               0 :         unpinReg(address.base);
    1118                 : }
    1119                 : 
    1120                 : void
    1121             804 : FrameState::loadThisForReturn(RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
    1122                 : {
    1123             804 :     return loadForReturn(getThis(), typeReg, dataReg, tempReg);
    1124                 : }
    1125                 : 
    1126           23150 : void FrameState::loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg)
    1127                 : {
    1128           23150 :     JS_ASSERT(dataReg != typeReg && dataReg != tempReg && typeReg != tempReg);
    1129                 : 
    1130           23150 :     if (fe->isConstant()) {
    1131            5989 :         masm.loadValueAsComponents(fe->getValue(), typeReg, dataReg);
    1132            5989 :         return;
    1133                 :     }
    1134                 : 
    1135           17161 :     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           16826 :     if (fe->isCopy())
    1142            4779 :         fe = fe->copyOf();
    1143                 : 
    1144           16826 :     MaybeRegisterID maybeType = maybePinType(fe);
    1145           16826 :     MaybeRegisterID maybeData = maybePinData(fe);
    1146                 : 
    1147           16826 :     if (fe->isTypeKnown()) {
    1148                 :         // If the data is in memory, or in the wrong reg, load/move it.
    1149            3909 :         if (!maybeData.isSet())
    1150            1184 :             masm.loadPayload(addressOf(fe), dataReg);
    1151            2725 :         else if (maybeData.reg() != dataReg)
    1152            1540 :             masm.move(maybeData.reg(), dataReg);
    1153            3909 :         masm.move(ImmType(fe->getKnownType()), typeReg);
    1154            3909 :         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           12917 :     if (fe->type.inMemory() && fe->data.inMemory()) {
    1160            6183 :         masm.loadValueAsComponents(addressOf(fe), typeReg, dataReg);
    1161            6183 :         return;
    1162                 :     }
    1163                 : 
    1164                 :     // Now, we should be guaranteed that at least one part is in a register.
    1165            6734 :     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            6734 :     if (!maybeType.isSet()) {
    1171             304 :         JS_ASSERT(maybeData.isSet());
    1172             304 :         if (maybeData.reg() != typeReg)
    1173             274 :             maybeType = typeReg;
    1174                 :         else
    1175              30 :             maybeType = tempReg;
    1176             304 :         masm.loadTypeTag(addressOf(fe), maybeType.reg());
    1177            6430 :     } 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            6734 :     RegisterID type = maybeType.reg();
    1187            6734 :     RegisterID data = maybeData.reg();
    1188                 : 
    1189            6734 :     if (data == typeReg && type == dataReg) {
    1190             334 :         masm.move(type, tempReg);
    1191             334 :         masm.move(data, dataReg);
    1192             334 :         masm.move(tempReg, typeReg);
    1193            6400 :     } else if (data != dataReg) {
    1194            1703 :         if (type == typeReg) {
    1195             271 :             masm.move(data, dataReg);
    1196            1432 :         } else if (type != dataReg) {
    1197            1397 :             masm.move(data, dataReg);
    1198            1397 :             if (type != typeReg)
    1199            1397 :                 masm.move(type, typeReg);
    1200                 :         } else {
    1201              35 :             JS_ASSERT(data != typeReg);
    1202              35 :             masm.move(type, typeReg);
    1203              35 :             masm.move(data, dataReg);
    1204                 :         }
    1205            4697 :     } else if (type != typeReg) {
    1206              77 :         masm.move(type, typeReg);
    1207                 :     }
    1208                 : }
    1209                 : 
    1210                 : #ifdef DEBUG
    1211                 : void
    1212        17343229 : FrameState::assertValidRegisterState() const
    1213                 : {
    1214        17343229 :     Registers checkedFreeRegs(Registers::AvailAnyRegs);
    1215                 : 
    1216                 :     /* Check that copied and copy info balance out. */
    1217        17343229 :     int32_t copyCount = 0;
    1218                 : 
    1219       488034474 :     for (uint32_t i = 0; i < tracker.nentries; i++) {
    1220       470691245 :         FrameEntry *fe = tracker[i];
    1221       470691245 :         if (deadEntry(fe))
    1222        32948156 :             continue;
    1223                 : 
    1224       437743089 :         JS_ASSERT(i == fe->trackerIndex());
    1225                 : 
    1226       437743089 :         if (fe->isCopy()) {
    1227         3490954 :             JS_ASSERT_IF(!fe->copyOf()->temporary, fe > fe->copyOf());
    1228         3490954 :             JS_ASSERT(fe->trackerIndex() > fe->copyOf()->trackerIndex());
    1229         3490954 :             JS_ASSERT(!deadEntry(fe->copyOf()));
    1230         3490954 :             JS_ASSERT(fe->copyOf()->isCopied());
    1231         3490954 :             JS_ASSERT(!fe->isCopied());
    1232         3490954 :             copyCount--;
    1233         3490954 :             continue;
    1234                 :         }
    1235                 : 
    1236       434252135 :         copyCount += fe->copied;
    1237                 : 
    1238       434252135 :         if (fe->type.inRegister()) {
    1239        11976274 :             checkedFreeRegs.takeReg(fe->type.reg());
    1240        11976274 :             JS_ASSERT(regstate(fe->type.reg()).fe() == fe);
    1241        11976274 :             JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
    1242                 :         }
    1243       434252135 :         if (fe->data.inRegister()) {
    1244        16986844 :             checkedFreeRegs.takeReg(fe->data.reg());
    1245        16986844 :             JS_ASSERT(regstate(fe->data.reg()).fe() == fe);
    1246        16986844 :             JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
    1247                 :         }
    1248       434252135 :         if (fe->data.inFPRegister()) {
    1249          130251 :             JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
    1250          130251 :             checkedFreeRegs.takeReg(fe->data.fpreg());
    1251          130251 :             JS_ASSERT(regstate(fe->data.fpreg()).fe() == fe);
    1252                 :         }
    1253                 :     }
    1254                 : 
    1255        17343229 :     JS_ASSERT(copyCount == 0);
    1256        17343229 :     JS_ASSERT(checkedFreeRegs == freeRegs);
    1257                 : 
    1258       156089061 :     for (uint32_t i = 0; i < Registers::TotalRegisters; i++) {
    1259       138745832 :         AnyRegisterID reg = (RegisterID) i;
    1260       138745832 :         JS_ASSERT(!regstate(reg).isPinned());
    1261       138745832 :         JS_ASSERT_IF(regstate(reg).fe(), !freeRegs.hasReg(reg));
    1262       138745832 :         JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).fe()->isTracked());
    1263                 :     }
    1264                 : 
    1265       138745832 :     for (uint32_t i = 0; i < Registers::TotalFPRegisters; i++) {
    1266       121402603 :         AnyRegisterID reg = (FPRegisterID) i;
    1267       121402603 :         JS_ASSERT(!regstate(reg).isPinned());
    1268       121402603 :         JS_ASSERT_IF(regstate(reg).fe(), !freeRegs.hasReg(reg));
    1269       121402603 :         JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).fe()->isTracked());
    1270       121402603 :         JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).type() == RematInfo::DATA);
    1271                 :     }
    1272        17343229 : }
    1273                 : #endif
    1274                 : 
    1275                 : #if defined JS_NUNBOX32
    1276                 : void
    1277          171297 : FrameState::syncFancy(Assembler &masm, Registers avail, int trackerIndex) const
    1278                 : {
    1279          171297 :     reifier.reset(&masm, avail, a->sp, entries);
    1280                 : 
    1281         1206159 :     for (; trackerIndex >= 0; trackerIndex--) {
    1282         1034862 :         FrameEntry *fe = tracker[trackerIndex];
    1283         1034862 :         if (fe >= a->sp)
    1284          228439 :             continue;
    1285                 : 
    1286          806423 :         reifier.sync(fe);
    1287                 :     }
    1288          171297 : }
    1289                 : 
    1290                 : #endif
    1291                 : void
    1292         4124757 : FrameState::sync(Assembler &masm, Uses uses) const
    1293                 : {
    1294         4124757 :     if (!entries)
    1295               0 :         return;
    1296                 : 
    1297                 :     /* Sync all registers up-front. */
    1298         4124757 :     Registers allRegs(Registers::AvailAnyRegs);
    1299        61871355 :     while (!allRegs.empty()) {
    1300        53621841 :         AnyRegisterID reg = allRegs.takeAnyReg();
    1301        53621841 :         FrameEntry *fe = regstate(reg).usedBy();
    1302        53621841 :         if (!fe)
    1303        44836858 :             continue;
    1304                 : 
    1305         8784983 :         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         8784983 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
    1319           27800 :             ensureFeSynced(fe, masm);
    1320         8757183 :         } else if (regstate(reg).type() == RematInfo::DATA) {
    1321         4915358 :             JS_ASSERT(fe->data.reg() == reg.reg());
    1322         4915358 :             ensureDataSynced(fe, masm);
    1323                 :         } else {
    1324         3841825 :             JS_ASSERT(fe->type.reg() == reg.reg());
    1325         3841825 :             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         4124757 :     Registers avail(freeRegs.freeMask & Registers::AvailRegs);
    1335         4124757 :     Registers temp(Registers::TempAnyRegs);
    1336                 : 
    1337         4124757 :     unsigned nentries = tracker.nentries;
    1338        21862872 :     for (int trackerIndex = nentries - 1; trackerIndex >= 0; trackerIndex--) {
    1339        17909412 :         JS_ASSERT(tracker.nentries == nentries);
    1340        17909412 :         FrameEntry *fe = tracker[trackerIndex];
    1341        17909412 :         if (fe >= a->sp)
    1342         5621515 :             continue;
    1343                 : 
    1344        12287897 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
    1345                 :             /* Copies of in-memory doubles can be synced without spilling. */
    1346           40618 :             if (fe->isCopy() || !fe->data.inFPRegister())
    1347           13174 :                 ensureFeSynced(fe, masm);
    1348           40618 :             continue;
    1349                 :         }
    1350                 : 
    1351        12247279 :         if (!fe->isCopy()) {
    1352        11088057 :             if (fe->data.inRegister() && !regstate(fe->data.reg()).isPinned())
    1353         4631901 :                 avail.putReg(fe->data.reg());
    1354        11088057 :             if (fe->type.inRegister() && !regstate(fe->type.reg()).isPinned())
    1355         3634805 :                 avail.putReg(fe->type.reg());
    1356                 :         } else {
    1357         1159222 :             FrameEntry *backing = fe->copyOf();
    1358         1159222 :             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         3310903 :             if ((!fe->type.synced() && backing->type.inMemory()) ||
    1387         2151681 :                 (!fe->data.synced() && backing->data.inMemory())) {
    1388          171297 :                 syncFancy(masm, avail, trackerIndex);
    1389          171297 :                 return;
    1390                 :             }
    1391                 : #endif
    1392                 :         }
    1393                 : 
    1394        12075982 :         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        12075982 :         if (copy || !fe->data.inRegister())
    1404         7326817 :             ensureDataSynced(fe, masm);
    1405        12075982 :         if (copy || !fe->type.inRegister())
    1406         8421455 :             ensureTypeSynced(fe, masm);
    1407                 : #endif
    1408                 :     }
    1409                 : }
    1410                 : 
    1411                 : void
    1412         1836353 : FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore)
    1413                 : {
    1414         1836353 :     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          116925 :         loop->clearLoopRegisters();
    1420                 :     }
    1421                 : 
    1422                 :     /* Sync all kill-registers up-front. */
    1423         1836353 :     Registers search(kill.freeMask & ~freeRegs.freeMask);
    1424         6365262 :     while (!search.empty()) {
    1425         2692556 :         AnyRegisterID reg = search.takeAnyReg();
    1426         2692556 :         FrameEntry *fe = regstate(reg).usedBy();
    1427         2692556 :         if (!fe || deadEntry(fe, ignore.nuses))
    1428          203111 :             continue;
    1429                 : 
    1430         2489445 :         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         2489445 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
    1456            7087 :             syncFe(fe);
    1457         2482358 :         } else if (regstate(reg).type() == RematInfo::DATA) {
    1458         1358356 :             JS_ASSERT(fe->data.reg() == reg.reg());
    1459         1358356 :             syncData(fe);
    1460                 :         } else {
    1461         1124002 :             JS_ASSERT(fe->type.reg() == reg.reg());
    1462         1124002 :             syncType(fe);
    1463                 :         }
    1464                 : #endif
    1465                 :     }
    1466                 : 
    1467                 : 
    1468         1836353 :     unsigned nentries = tracker.nentries;
    1469        11082628 :     for (int trackerIndex = nentries - 1; trackerIndex >= 0; trackerIndex--) {
    1470         9246275 :         JS_ASSERT(tracker.nentries == nentries);
    1471         9246275 :         FrameEntry *fe = tracker[trackerIndex];
    1472                 : 
    1473         9246275 :         if (fe >= a->sp || deadEntry(fe, ignore.nuses))
    1474         3049319 :             continue;
    1475                 : 
    1476         6196956 :         syncFe(fe);
    1477                 : 
    1478         6196956 :         if (fe->isCopy())
    1479          357641 :             continue;
    1480                 : 
    1481                 :         /* Forget registers. */
    1482         5839315 :         if (fe->data.inRegister() && !regstate(fe->data.reg()).isPinned()) {
    1483         1621740 :             forgetReg(fe->data.reg());
    1484         1621740 :             fe->data.setMemory();
    1485                 :         }
    1486         5839315 :         if (fe->data.inFPRegister() && !regstate(fe->data.fpreg()).isPinned()) {
    1487            5803 :             forgetReg(fe->data.fpreg());
    1488            5803 :             fe->data.setMemory();
    1489                 :         }
    1490         5839315 :         if (fe->type.inRegister() && !regstate(fe->type.reg()).isPinned()) {
    1491         1363539 :             forgetReg(fe->type.reg());
    1492         1363539 :             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         1836353 :     search = Registers(kill.freeMask & ~freeRegs.freeMask);
    1501         4170120 :     while (!search.empty()) {
    1502          497414 :         AnyRegisterID reg = search.takeAnyReg();
    1503          497414 :         FrameEntry *fe = regstate(reg).usedBy();
    1504          497414 :         if (!fe || deadEntry(fe, ignore.nuses))
    1505          203111 :             continue;
    1506                 : 
    1507          294303 :         JS_ASSERT(fe->isTracked());
    1508                 : 
    1509          294303 :         if (regstate(reg).type() == RematInfo::DATA) {
    1510          170056 :             JS_ASSERT_IF(reg.isFPReg(), fe->data.fpreg() == reg.fpreg());
    1511          170056 :             JS_ASSERT_IF(!reg.isFPReg(), fe->data.reg() == reg.reg());
    1512          170056 :             JS_ASSERT(fe->data.synced());
    1513          170056 :             fe->data.setMemory();
    1514                 :         } else {
    1515          124247 :             JS_ASSERT(fe->type.reg() == reg.reg());
    1516          124247 :             JS_ASSERT(fe->type.synced());
    1517          124247 :             fe->type.setMemory();
    1518                 :         }
    1519                 : 
    1520          294303 :         forgetReg(reg);
    1521                 :     }
    1522         1836353 : }
    1523                 : 
    1524                 : void
    1525         3017272 : 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         3017272 :     if (cx->typeInferenceEnabled()) {
    1540         1081324 :         for (unsigned i = 0; i < changes.nchanges; i++) {
    1541          378691 :             FrameEntry *fe = a->sp - 1 - i;
    1542          378691 :             if (fe->isTracked() && fe->isType(JSVAL_TYPE_DOUBLE))
    1543           19456 :                 masm.ensureInMemoryDouble(addressOf(fe));
    1544                 :         }
    1545                 :     }
    1546                 : 
    1547         3017272 :     uint32_t mask = Registers::AvailAnyRegs & ~freeRegs.freeMask;
    1548         3017272 :     Registers search(mask);
    1549                 : 
    1550        10311738 :     while (!search.empty(mask)) {
    1551         4277194 :         AnyRegisterID reg = search.peekReg(mask);
    1552         4277194 :         FrameEntry *fe = regstate(reg).usedBy();
    1553                 : 
    1554         4277194 :         if (!fe) {
    1555           21282 :             search.takeReg(reg);
    1556           21282 :             continue;
    1557                 :         }
    1558                 : 
    1559         4255912 :         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
    1560           42071 :             JS_ASSERT(fe->data.fpreg() == reg.fpreg());
    1561           42071 :             search.takeReg(fe->data.fpreg());
    1562           42071 :             masm.loadDouble(addressOf(fe), fe->data.fpreg());
    1563         4213841 :         } else if (fe->data.inRegister() && fe->type.inRegister()) {
    1564         2390846 :             search.takeReg(fe->data.reg());
    1565         2390846 :             search.takeReg(fe->type.reg());
    1566         2390846 :             masm.loadValueAsComponents(addressOf(fe), fe->type.reg(), fe->data.reg());
    1567                 :         } else {
    1568         1822995 :             if (fe->data.inRegister()) {
    1569         1741500 :                 search.takeReg(fe->data.reg());
    1570         1741500 :                 masm.loadPayload(addressOf(fe), fe->data.reg());
    1571                 :             }
    1572         1822995 :             if (fe->type.inRegister()) {
    1573           81495 :                 search.takeReg(fe->type.reg());
    1574           81495 :                 masm.loadTypeTag(addressOf(fe), fe->type.reg());
    1575                 :             }
    1576                 :         }
    1577                 :     }
    1578         3017272 : }
    1579                 : 
    1580                 : JSC::MacroAssembler::RegisterID
    1581          575737 : FrameState::copyDataIntoReg(FrameEntry *fe)
    1582                 : {
    1583          575737 :     return copyDataIntoReg(this->masm, fe);
    1584                 : }
    1585                 : 
    1586                 : void
    1587            3805 : FrameState::copyDataIntoReg(FrameEntry *fe, RegisterID hint)
    1588                 : {
    1589            3805 :     JS_ASSERT(!fe->isConstant());
    1590            3805 :     JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
    1591                 : 
    1592            3805 :     if (fe->isCopy())
    1593            1628 :         fe = fe->copyOf();
    1594                 : 
    1595            3805 :     if (!fe->data.inRegister())
    1596            1548 :         tempRegForData(fe);
    1597                 : 
    1598            3805 :     RegisterID reg = fe->data.reg();
    1599            3805 :     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            3720 :         pinReg(reg);
    1612            3720 :         takeReg(hint);
    1613            3720 :         unpinReg(reg);
    1614            3720 :         masm.move(reg, hint);
    1615                 :     }
    1616                 : 
    1617            3805 :     modifyReg(hint);
    1618            3805 : }
    1619                 : 
    1620                 : JSC::MacroAssembler::RegisterID
    1621          578122 : FrameState::copyDataIntoReg(Assembler &masm, FrameEntry *fe)
    1622                 : {
    1623          578122 :     JS_ASSERT(!fe->isConstant());
    1624                 : 
    1625          578122 :     if (fe->isCopy())
    1626          197344 :         fe = fe->copyOf();
    1627                 : 
    1628          578122 :     if (fe->data.inRegister()) {
    1629          453840 :         RegisterID reg = fe->data.reg();
    1630          453840 :         if (freeRegs.empty(Registers::AvailRegs)) {
    1631           21267 :             ensureDataSynced(fe, masm);
    1632           21267 :             fe->data.setMemory();
    1633           21267 :             regstate(reg).forget();
    1634           21267 :             modifyReg(reg);
    1635                 :         } else {
    1636          432573 :             RegisterID newReg = allocReg();
    1637          432573 :             masm.move(reg, newReg);
    1638          432573 :             reg = newReg;
    1639                 :         }
    1640          453840 :         return reg;
    1641                 :     }
    1642                 : 
    1643          124282 :     RegisterID reg = allocReg();
    1644                 : 
    1645          124282 :     if (!freeRegs.empty(Registers::AvailRegs))
    1646          118157 :         masm.move(tempRegForData(fe), reg);
    1647                 :     else
    1648            6125 :         masm.loadPayload(addressOf(fe),reg);
    1649                 : 
    1650          124282 :     return reg;
    1651                 : }
    1652                 : 
    1653                 : JSC::MacroAssembler::RegisterID
    1654            8529 : FrameState::copyTypeIntoReg(FrameEntry *fe)
    1655                 : {
    1656            8529 :     if (fe->isCopy())
    1657            2037 :         fe = fe->copyOf();
    1658                 : 
    1659            8529 :     JS_ASSERT(!fe->type.isConstant());
    1660                 : 
    1661            8529 :     if (fe->type.inRegister()) {
    1662            6041 :         RegisterID reg = fe->type.reg();
    1663            6041 :         if (freeRegs.empty(Registers::AvailRegs)) {
    1664            4063 :             ensureTypeSynced(fe, masm);
    1665            4063 :             fe->type.setMemory();
    1666            4063 :             regstate(reg).forget();
    1667            4063 :             modifyReg(reg);
    1668                 :         } else {
    1669            1978 :             RegisterID newReg = allocReg();
    1670            1978 :             masm.move(reg, newReg);
    1671            1978 :             reg = newReg;
    1672                 :         }
    1673            6041 :         return reg;
    1674                 :     }
    1675                 : 
    1676            2488 :     RegisterID reg = allocReg();
    1677                 : 
    1678            2488 :     if (!freeRegs.empty(Registers::AvailRegs))
    1679             871 :         masm.move(tempRegForType(fe), reg);
    1680                 :     else
    1681            1617 :         masm.loadTypeTag(addressOf(fe), reg);
    1682                 : 
    1683            2488 :     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            1306 : FrameState::ownRegForType(FrameEntry *fe)
    1707                 : {
    1708            1306 :     JS_ASSERT(!fe->isTypeKnown());
    1709                 : 
    1710                 :     RegisterID reg;
    1711            1306 :     if (fe->isCopy()) {
    1712                 :         /* For now, just do an extra move. The reg must be mutable. */
    1713             245 :         FrameEntry *backing = fe->copyOf();
    1714             245 :         if (!backing->type.inRegister()) {
    1715             157 :             JS_ASSERT(backing->type.inMemory());
    1716             157 :             tempRegForType(backing);
    1717                 :         }
    1718                 : 
    1719             245 :         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             236 :             reg = allocReg();
    1728             236 :             masm.move(backing->type.reg(), reg);
    1729                 :         }
    1730             245 :         return reg;
    1731                 :     }
    1732                 : 
    1733            1061 :     if (fe->type.inRegister()) {
    1734            1059 :         reg = fe->type.reg();
    1735                 : 
    1736                 :         /* Remove ownership of this register. */
    1737            1059 :         JS_ASSERT(regstate(reg).fe() == fe);
    1738            1059 :         JS_ASSERT(regstate(reg).type() == RematInfo::TYPE);
    1739            1059 :         regstate(reg).forget();
    1740            1059 :         fe->type.setMemory();
    1741            1059 :         modifyReg(reg);
    1742                 :     } else {
    1743               2 :         JS_ASSERT(fe->type.inMemory());
    1744               2 :         reg = allocReg();
    1745               2 :         masm.loadTypeTag(addressOf(fe), reg);
    1746                 :     }
    1747            1061 :     return reg;
    1748                 : }
    1749                 : 
    1750                 : JSC::MacroAssembler::RegisterID
    1751           34951 : FrameState::ownRegForData(FrameEntry *fe)
    1752                 : {
    1753           34951 :     JS_ASSERT(!fe->isConstant());
    1754           34951 :     JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
    1755                 : 
    1756                 :     RegisterID reg;
    1757           34951 :     if (fe->isCopy()) {
    1758                 :         /* For now, just do an extra move. The reg must be mutable. */
    1759            5391 :         FrameEntry *backing = fe->copyOf();
    1760            5391 :         if (!backing->data.inRegister()) {
    1761            2876 :             JS_ASSERT(backing->data.inMemory());
    1762            2876 :             tempRegForData(backing);
    1763                 :         }
    1764                 : 
    1765            5391 :         if (freeRegs.empty(Registers::AvailRegs)) {
    1766                 :             /* For now... just steal the register that already exists. */
    1767            1414 :             ensureDataSynced(backing, masm);
    1768            1414 :             reg = backing->data.reg();
    1769            1414 :             backing->data.setMemory();
    1770            1414 :             regstate(reg).forget();
    1771            1414 :             modifyReg(reg);
    1772                 :         } else {
    1773            3977 :             reg = allocReg();
    1774            3977 :             masm.move(backing->data.reg(), reg);
    1775                 :         }
    1776            5391 :         return reg;
    1777                 :     }
    1778                 : 
    1779           29560 :     if (fe->isCopied())
    1780               0 :         uncopy(fe);
    1781                 : 
    1782           29560 :     if (fe->data.inRegister()) {
    1783           29147 :         reg = fe->data.reg();
    1784                 :         /* Remove ownership of this register. */
    1785           29147 :         JS_ASSERT(regstate(reg).fe() == fe);
    1786           29147 :         JS_ASSERT(regstate(reg).type() == RematInfo::DATA);
    1787           29147 :         regstate(reg).forget();
    1788           29147 :         fe->data.setMemory();
    1789           29147 :         modifyReg(reg);
    1790                 :     } else {
    1791             413 :         JS_ASSERT(fe->data.inMemory());
    1792             413 :         reg = allocReg();
    1793             413 :         masm.loadPayload(addressOf(fe), reg);
    1794                 :     }
    1795           29560 :     return reg;
    1796                 : }
    1797                 : 
    1798                 : void
    1799           21434 : FrameState::discardFe(FrameEntry *fe)
    1800                 : {
    1801           21434 :     forgetEntry(fe);
    1802           21434 :     fe->type.setMemory();
    1803           21434 :     fe->data.setMemory();
    1804           21434 :     fe->clear();
    1805           21434 : }
    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            1686 : FrameState::ensureDouble(FrameEntry *fe)
    1827                 : {
    1828            1686 :     if (fe->isType(JSVAL_TYPE_DOUBLE))
    1829            1101 :         return;
    1830                 : 
    1831             585 :     if (fe->isConstant()) {
    1832             230 :         JS_ASSERT(fe->getValue().isInt32());
    1833             230 :         Value newValue = DoubleValue(double(fe->getValue().toInt32()));
    1834             230 :         fe->setConstant(newValue);
    1835             230 :         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              38 :         for (uint32_t i = fe->trackerIndex() + 1; i < tracker.nentries; i++) {
    1846              21 :             FrameEntry *nfe = tracker[i];
    1847              21 :             if (!deadEntry(nfe) && nfe->isCopy() && nfe->copyOf() == fe) {
    1848              17 :                 syncFe(nfe);
    1849              17 :                 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         3616922 : FrameState::pushCopyOf(FrameEntry *backing)
    1935                 : {
    1936         3616922 :     JS_ASSERT(backing->isTracked());
    1937         3616922 :     FrameEntry *fe = rawPush();
    1938         3616922 :     fe->resetUnsynced();
    1939         3616922 :     if (backing->isConstant()) {
    1940          852212 :         fe->setConstant(backing->getValue());
    1941                 :     } else {
    1942         2764710 :         if (backing->isCopy())
    1943           78759 :             backing = backing->copyOf();
    1944         2764710 :         fe->setCopyOf(backing);
    1945                 : 
    1946                 :         /* Maintain tracker ordering guarantees for copies. */
    1947         2764710 :         JS_ASSERT(backing->isCopied());
    1948         2764710 :         if (fe->trackerIndex() < backing->trackerIndex())
    1949          204568 :             swapInTracker(fe, backing);
    1950                 :     }
    1951         3616922 : }
    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          499768 : FrameState::walkFrameForUncopy(FrameEntry *original)
    2017                 : {
    2018          499768 :     FrameEntry *bestFe = NULL;
    2019          499768 :     uint32_t ncopies = 0;
    2020                 : 
    2021                 :     /* It's only necessary to visit as many FEs are being tracked. */
    2022          499768 :     uint32_t maxvisits = tracker.nentries;
    2023                 : 
    2024         2579974 :     for (FrameEntry *fe = original + 1; fe < a->sp && maxvisits; fe++) {
    2025         2080206 :         if (!fe->isTracked())
    2026             749 :             continue;
    2027                 : 
    2028         2079457 :         maxvisits--;
    2029                 : 
    2030         2079457 :         if (fe->isCopy() && fe->copyOf() == original) {
    2031          499771 :             if (!bestFe) {
    2032          499768 :                 bestFe = fe;
    2033          499768 :                 bestFe->setCopyOf(NULL);
    2034                 :             } else {
    2035               3 :                 fe->setCopyOf(bestFe);
    2036               3 :                 if (fe->trackerIndex() < bestFe->trackerIndex())
    2037               0 :                     swapInTracker(bestFe, fe);
    2038                 :             }
    2039          499771 :             ncopies++;
    2040                 :         }
    2041                 :     }
    2042                 : 
    2043          499768 :     return bestFe;
    2044                 : }
    2045                 : 
    2046                 : FrameEntry *
    2047          499818 : FrameState::uncopy(FrameEntry *original)
    2048                 : {
    2049          499818 :     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          499818 :     if ((tracker.nentries - original->trackerIndex()) * 2 > uint32_t(a->sp - original))
    2076          499768 :         fe = walkFrameForUncopy(original);
    2077                 :     else
    2078              50 :         fe = walkTrackerForUncopy(original);
    2079          499818 :     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          499818 :     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          473508 :         if (original->type.inMemory() && !fe->type.synced())
    2093          192847 :             tempRegForType(original);
    2094          473508 :         fe->type.inherit(original->type);
    2095          473508 :         if (fe->type.inRegister())
    2096          473496 :             regstate(fe->type.reg()).reassociate(fe);
    2097                 :     } else {
    2098           26310 :         fe->setType(original->getKnownType());
    2099                 :     }
    2100          499818 :     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          499718 :         if (fe->type.inRegister())
    2108          473496 :             pinReg(fe->type.reg());
    2109          499718 :         if (original->data.inMemory() && !fe->data.synced())
    2110          198498 :             tempRegForData(original);
    2111          499718 :         if (fe->type.inRegister())
    2112          473496 :             unpinReg(fe->type.reg());
    2113          499718 :         fe->data.inherit(original->data);
    2114          499718 :         if (fe->data.inRegister())
    2115          499681 :             regstate(fe->data.reg()).reassociate(fe);
    2116                 :     }
    2117                 : 
    2118          499818 :     return fe;
    2119                 : }
    2120                 : 
    2121                 : bool
    2122           11956 : FrameState::hasOnlyCopy(FrameEntry *backing, FrameEntry *fe)
    2123                 : {
    2124           11956 :     JS_ASSERT(backing->isCopied() && fe->copyOf() == backing);
    2125                 : 
    2126           66326 :     for (uint32_t i = backing->trackerIndex() + 1; i < tracker.nentries; i++) {
    2127           54735 :         FrameEntry *nfe = tracker[i];
    2128           54735 :         if (nfe != fe && !deadEntry(nfe) && nfe->isCopy() && nfe->copyOf() == backing)
    2129             365 :             return false;
    2130                 :     }
    2131                 : 
    2132           11591 :     return true;
    2133                 : }
    2134                 : 
    2135                 : void
    2136           13099 : FrameState::separateBinaryEntries(FrameEntry *lhs, FrameEntry *rhs)
    2137                 : {
    2138           13099 :     JS_ASSERT(lhs == a->sp - 2 && rhs == a->sp - 1);
    2139           13099 :     if (rhs->isCopy() && rhs->copyOf() == lhs) {
    2140               0 :         syncAndForgetFe(rhs);
    2141               0 :         syncAndForgetFe(lhs);
    2142               0 :         uncopy(lhs);
    2143                 :     }
    2144           13099 : }
    2145                 : 
    2146                 : void
    2147          287635 : FrameState::storeLocal(uint32_t n, bool popGuaranteed)
    2148                 : {
    2149          287635 :     FrameEntry *local = getLocal(n);
    2150                 : 
    2151          287635 :     if (a->analysis->slotEscapes(entrySlot(local))) {
    2152          160333 :         JS_ASSERT(local->data.inMemory());
    2153          160333 :         storeTo(peek(-1), addressOf(local), popGuaranteed);
    2154          160333 :         return;
    2155                 :     }
    2156                 : 
    2157          127302 :     storeTop(local);
    2158                 : 
    2159          127302 :     if (loop)
    2160           18660 :         local->lastLoop = loop->headOffset();
    2161                 : 
    2162          127302 :     if (inTryBlock)
    2163            2240 :         syncFe(local);
    2164                 : }
    2165                 : 
    2166                 : void
    2167            4099 : 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            4099 :     FrameEntry *arg = getArg(n);
    2172                 : 
    2173            4099 :     if (a->analysis->slotEscapes(entrySlot(arg))) {
    2174            1858 :         JS_ASSERT(arg->data.inMemory());
    2175            1858 :         storeTo(peek(-1), addressOf(arg), popGuaranteed);
    2176            1858 :         return;
    2177                 :     }
    2178                 : 
    2179            2241 :     storeTop(arg);
    2180                 : 
    2181            2241 :     if (loop)
    2182             373 :         arg->lastLoop = loop->headOffset();
    2183                 : 
    2184            2241 :     syncFe(arg);
    2185                 : }
    2186                 : 
    2187                 : void
    2188         4649445 : FrameState::forgetEntry(FrameEntry *fe)
    2189                 : {
    2190         4649445 :     if (fe->isCopied()) {
    2191          499816 :         uncopy(fe);
    2192          499816 :         fe->resetUnsynced();
    2193                 :     } else {
    2194         4149629 :         forgetAllRegs(fe);
    2195                 :     }
    2196                 : 
    2197         4649445 :     extraArray[fe - entries].reset();
    2198         4649445 : }
    2199                 : 
    2200                 : void
    2201         2728127 : FrameState::storeTop(FrameEntry *target)
    2202                 : {
    2203         2728127 :     JS_ASSERT(!isTemporary(target));
    2204                 : 
    2205                 :     /* Detect something like (x = x) which is a no-op. */
    2206         2728127 :     FrameEntry *top = peek(-1);
    2207         2728127 :     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         2728119 :     bool wasSynced = target->type.synced();
    2218         2728119 :     JSValueType oldType = target->isTypeKnown() ? target->getKnownType() : JSVAL_TYPE_UNKNOWN;
    2219         2728119 :     bool trySyncType = wasSynced && oldType != JSVAL_TYPE_UNKNOWN && oldType != JSVAL_TYPE_DOUBLE;
    2220                 : 
    2221                 :     /* Completely invalidate the local variable. */
    2222         2728119 :     forgetEntry(target);
    2223         2728119 :     target->resetUnsynced();
    2224                 : 
    2225                 :     /* Constants are easy to propagate. */
    2226         2728119 :     if (top->isConstant()) {
    2227          713638 :         target->clear();
    2228          713638 :         target->setConstant(top->getValue());
    2229          713638 :         if (trySyncType && target->isType(oldType))
    2230             172 :             target->type.sync();
    2231          713638 :         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         2014481 :     FrameEntry *backing = top;
    2248         2014481 :     if (top->isCopy()) {
    2249         1358258 :         backing = top->copyOf();
    2250         1358258 :         JS_ASSERT(backing->trackerIndex() < top->trackerIndex());
    2251                 : 
    2252         1358258 :         if (backing < target || isTemporary(backing)) {
    2253                 :             /* local.idx < backing.idx means local cannot be a copy yet */
    2254           57630 :             if (target->trackerIndex() < backing->trackerIndex())
    2255            2882 :                 swapInTracker(backing, target);
    2256           57630 :             target->setCopyOf(backing);
    2257           57630 :             if (trySyncType && target->isType(oldType))
    2258              37 :                 target->type.sync();
    2259           57630 :             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         5576501 :         for (uint32_t i = backing->trackerIndex() + 1; i < tracker.nentries; i++) {
    2281         4275873 :             FrameEntry *fe = tracker[i];
    2282         4275873 :             if (deadEntry(fe))
    2283          120549 :                 continue;
    2284         4155324 :             if (fe->isCopy() && fe->copyOf() == backing)
    2285         1300647 :                 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         1956851 :     if (backing->trackerIndex() < target->trackerIndex())
    2295          129384 :         swapInTracker(backing, target);
    2296                 : 
    2297         1956851 :     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         1953935 :         if (backing->type.inRegister())
    2310         1606783 :             pinReg(backing->type.reg());
    2311         1953935 :         RegisterID reg = tempRegForData(backing);
    2312         1953935 :         if (backing->type.inRegister())
    2313         1606783 :             unpinReg(backing->type.reg());
    2314         1953935 :         target->data.setRegister(reg);
    2315         1953935 :         regstate(reg).reassociate(target);
    2316                 : 
    2317         1953935 :         if (backing->isTypeKnown()) {
    2318          123720 :             target->setType(backing->getKnownType());
    2319                 :         } else {
    2320         1830215 :             pinReg(reg);
    2321         1830215 :             RegisterID typeReg = tempRegForType(backing);
    2322         1830215 :             unpinReg(reg);
    2323         1830215 :             target->type.setRegister(typeReg);
    2324         1830215 :             regstate(typeReg).reassociate(target);
    2325                 :         }
    2326                 :     }
    2327                 : 
    2328         1956851 :     backing->setCopyOf(target);
    2329         1956851 :     JS_ASSERT(top->copyOf() == target);
    2330                 : 
    2331         1956851 :     if (trySyncType && target->isType(oldType))
    2332           43589 :         target->type.sync();
    2333                 : }
    2334                 : 
    2335                 : void
    2336          710008 : FrameState::shimmy(uint32_t n)
    2337                 : {
    2338          710008 :     JS_ASSERT(a->sp - n >= a->spBase);
    2339          710008 :     int32_t depth = 0 - int32_t(n);
    2340          710008 :     storeTop(peek(depth - 1));
    2341          710008 :     popn(n);
    2342          710008 : }
    2343                 : 
    2344                 : void
    2345         1888576 : FrameState::shift(int32_t n)
    2346                 : {
    2347         1888576 :     JS_ASSERT(n < 0);
    2348         1888576 :     JS_ASSERT(a->sp + n - 1 >= a->spBase);
    2349         1888576 :     storeTop(peek(n - 1));
    2350         1888576 :     pop();
    2351         1888576 : }
    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             393 : 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             393 :     JS_ASSERT(!fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE));
    2380                 : 
    2381             393 :     RegisterID typeReg = allocReg();
    2382             393 :     RegisterID dataReg = allocReg();
    2383                 : 
    2384                 :     /* Copy into a different FP register, as breakDouble can modify fpreg. */
    2385             393 :     FPRegisterID fpreg = allocFPReg();
    2386             393 :     masm.moveDouble(tempFPRegForData(fe), fpreg);
    2387             393 :     masm.breakDouble(fpreg, typeReg, dataReg);
    2388                 : 
    2389             393 :     forgetAllRegs(fe);
    2390             393 :     fe->resetUnsynced();
    2391             393 :     fe->clear();
    2392                 : 
    2393             393 :     regstate(typeReg).associate(fe, RematInfo::TYPE);
    2394             393 :     regstate(dataReg).associate(fe, RematInfo::DATA);
    2395             393 :     fe->type.setRegister(typeReg);
    2396             393 :     fe->data.setRegister(dataReg);
    2397             393 :     freeReg(fpreg);
    2398             393 : }
    2399                 : 
    2400                 : void
    2401          105468 : FrameState::pinEntry(FrameEntry *fe, ValueRemat &vr, bool breakDouble)
    2402                 : {
    2403          105468 :     if (breakDouble && !fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE))
    2404             384 :         forgetKnownDouble(fe);
    2405                 : 
    2406          105468 :     if (fe->isConstant()) {
    2407           23338 :         vr = ValueRemat::FromConstant(fe->getValue());
    2408           82130 :     } else if (fe->isType(JSVAL_TYPE_DOUBLE)) {
    2409            1384 :         FPRegisterID fpreg = tempFPRegForData(fe);
    2410            1384 :         pinReg(fpreg);
    2411            1384 :         vr = ValueRemat::FromFPRegister(fpreg);
    2412                 :     } else {
    2413                 :         // Pin the type register so it can't spill.
    2414           80746 :         MaybeRegisterID maybePinnedType = maybePinType(fe);
    2415                 : 
    2416                 :         // Get and pin the data register.
    2417           80746 :         RegisterID dataReg = tempRegForData(fe);
    2418           80746 :         pinReg(dataReg);
    2419                 : 
    2420           80746 :         if (fe->isTypeKnown()) {
    2421           31068 :             vr = ValueRemat::FromKnownType(fe->getKnownType(), dataReg);
    2422                 :         } else {
    2423                 :             // The type might not be loaded yet, so unpin for simplicity.
    2424           49678 :             maybeUnpinReg(maybePinnedType);
    2425                 : 
    2426           49678 :             vr = ValueRemat::FromRegisters(tempRegForType(fe), dataReg);
    2427           49678 :             pinReg(vr.typeReg());
    2428                 :         }
    2429                 :     }
    2430                 : 
    2431                 :     // Set these bits last, since allocation could have caused a sync.
    2432          105468 :     vr.isDataSynced = fe->data.synced();
    2433          105468 :     vr.isTypeSynced = fe->type.synced();
    2434          105468 : }
    2435                 : 
    2436                 : void
    2437           79326 : FrameState::unpinEntry(const ValueRemat &vr)
    2438                 : {
    2439           79326 :     if (vr.isFPRegister()) {
    2440            1384 :         unpinReg(vr.fpReg());
    2441           77942 :     } else if (!vr.isConstant()) {
    2442           61473 :         if (!vr.isTypeKnown())
    2443           33667 :             unpinReg(vr.typeReg());
    2444           61473 :         unpinReg(vr.dataReg());
    2445                 :     }
    2446           79326 : }
    2447                 : 
    2448                 : void
    2449           26142 : 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           26142 :     if (vr.isConstant() || vr.isFPRegister()) {
    2456            6869 :         if (!vr.isDataSynced || !vr.isTypeSynced)
    2457            6855 :             masm.storeValue(vr.value(), addressOf(fe));
    2458                 :     } else {
    2459           19273 :         if (!vr.isDataSynced)
    2460           16879 :             masm.storePayload(vr.dataReg(), addressOf(fe));
    2461           19273 :         if (!vr.isTypeSynced) {
    2462           16776 :             if (vr.isTypeKnown())
    2463            3243 :                 masm.storeTypeTag(ImmType(vr.knownType()), addressOf(fe));
    2464                 :             else
    2465           13533 :                 masm.storeTypeTag(vr.typeReg(), addressOf(fe));
    2466                 :         }
    2467                 :     }
    2468                 : #endif
    2469           26142 : }
    2470                 : 
    2471                 : static inline bool
    2472         2567268 : AllocHelper(RematInfo &info, MaybeRegisterID &maybe)
    2473                 : {
    2474         2567268 :     if (info.inRegister()) {
    2475         1166078 :         maybe = info.reg();
    2476         1166078 :         return true;
    2477                 :     }
    2478         1401190 :     return false;
    2479                 : }
    2480                 : 
    2481                 : void
    2482              89 : FrameState::allocForSameBinary(FrameEntry *fe, JSOp op, BinaryAlloc &alloc)
    2483                 : {
    2484              89 :     alloc.rhsNeedsRemat = false;
    2485                 : 
    2486              89 :     if (!fe->isTypeKnown()) {
    2487              61 :         alloc.lhsType = tempRegForType(fe);
    2488              61 :         pinReg(alloc.lhsType.reg());
    2489                 :     }
    2490                 : 
    2491              89 :     alloc.lhsData = tempRegForData(fe);
    2492                 : 
    2493              89 :     if (!freeRegs.empty(Registers::AvailRegs)) {
    2494              69 :         alloc.result = allocReg();
    2495              69 :         masm.move(alloc.lhsData.reg(), alloc.result);
    2496              69 :         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              89 :     if (alloc.lhsType.isSet())
    2504              61 :         unpinReg(alloc.lhsType.reg());
    2505                 : 
    2506              89 :     alloc.lhsFP = alloc.rhsFP = allocFPReg();
    2507              89 : }
    2508                 : 
    2509                 : void
    2510          150465 : FrameState::ensureFullRegs(FrameEntry *fe, MaybeRegisterID *type, MaybeRegisterID *data)
    2511                 : {
    2512          150465 :     fe = fe->isCopy() ? fe->copyOf() : fe;
    2513                 : 
    2514          150465 :     JS_ASSERT(!data->isSet() && !type->isSet());
    2515          150465 :     if (!fe->type.inMemory()) {
    2516          106208 :         if (fe->type.inRegister())
    2517           68526 :             *type = fe->type.reg();
    2518          106208 :         if (fe->data.isConstant())
    2519               0 :             return;
    2520          106208 :         if (fe->data.inRegister()) {
    2521          102457 :             *data = fe->data.reg();
    2522          102457 :             return;
    2523                 :         }
    2524            3751 :         if (fe->type.inRegister())
    2525             843 :             pinReg(fe->type.reg());
    2526            3751 :         *data = tempRegForData(fe);
    2527            3751 :         if (fe->type.inRegister())
    2528             843 :             unpinReg(fe->type.reg());
    2529           44257 :     } else if (!fe->data.inMemory()) {
    2530            1114 :         if (fe->data.inRegister())
    2531            1114 :             *data = fe->data.reg();
    2532            1114 :         if (fe->type.isConstant())
    2533               0 :             return;
    2534            1114 :         if (fe->type.inRegister()) {
    2535               0 :             *type = fe->type.reg();
    2536               0 :             return;
    2537                 :         }
    2538            1114 :         if (fe->data.inRegister())
    2539            1114 :             pinReg(fe->data.reg());
    2540            1114 :         *type = tempRegForType(fe);
    2541            1114 :         if (fe->data.inRegister())
    2542            1114 :             unpinReg(fe->data.reg());
    2543                 :     } else {
    2544           43143 :         *data = tempRegForData(fe);
    2545           43143 :         pinReg(data->reg());
    2546           43143 :         *type = tempRegForType(fe);
    2547           43143 :         unpinReg(data->reg());
    2548                 :     }
    2549                 : }
    2550                 : 
    2551                 : inline bool
    2552           53026 : 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           53026 :     JS_ASSERT(cx->typeInferenceEnabled());
    2561                 : 
    2562           53026 :     if (deadEntry(fe, 2))
    2563           32368 :         return false;
    2564                 : 
    2565           20658 :     switch (JSOp(*a->PC)) {
    2566                 :       case JSOP_INCLOCAL:
    2567                 :       case JSOP_DECLOCAL:
    2568                 :       case JSOP_LOCALINC:
    2569                 :       case JSOP_LOCALDEC:
    2570           11265 :         if (fe - a->locals == (int) GET_SLOTNO(a->PC))
    2571           10881 :             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            9648 :     JS_ASSERT(fe != a->callee_);
    2582                 : 
    2583                 :     /* Arguments are always treated as live within inline frames, see bestEvictReg. */
    2584            9648 :     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            9559 :     return fe >= a->spBase || variableLive(fe, a->PC);
    2589                 : }
    2590                 : 
    2591                 : void
    2592          641817 : FrameState::allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAlloc &alloc,
    2593                 :                            bool needsResult)
    2594                 : {
    2595          641817 :     FrameEntry *backingLeft = lhs;
    2596          641817 :     FrameEntry *backingRight = rhs;
    2597                 : 
    2598          641817 :     if (backingLeft->isCopy())
    2599          242832 :         backingLeft = backingLeft->copyOf();
    2600          641817 :     if (backingRight->isCopy())
    2601            8645 :         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          641817 :     if (AllocHelper(backingLeft->type, alloc.lhsType))
    2608           87849 :         pinReg(alloc.lhsType.reg());
    2609          641817 :     if (AllocHelper(backingLeft->data, alloc.lhsData))
    2610          404242 :         pinReg(alloc.lhsData.reg());
    2611          641817 :     if (AllocHelper(backingRight->type, alloc.rhsType))
    2612          332239 :         pinReg(alloc.rhsType.reg());
    2613          641817 :     if (AllocHelper(backingRight->data, alloc.rhsData))
    2614          341748 :         pinReg(alloc.rhsData.reg());
    2615                 : 
    2616                 :     /* For each type without a register, give it a register if needed. */
    2617          641817 :     if (!alloc.lhsType.isSet() && backingLeft->type.inMemory()) {
    2618          525872 :         alloc.lhsType = tempRegForType(lhs);
    2619          525872 :         pinReg(alloc.lhsType.reg());
    2620                 :     }
    2621          641817 :     if (!alloc.rhsType.isSet() && backingRight->type.inMemory()) {
    2622           11760 :         alloc.rhsType = tempRegForType(rhs);
    2623           11760 :         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          641817 :     JS_ASSERT(!backingLeft->isType(JSVAL_TYPE_DOUBLE));
    2632          641817 :     JS_ASSERT(!backingRight->isType(JSVAL_TYPE_DOUBLE));
    2633          641817 :     alloc.lhsFP = allocFPReg();
    2634          641817 :     alloc.rhsFP = allocFPReg();
    2635                 : 
    2636                 :     bool commu;
    2637          641817 :     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          641817 :         commu = true;
    2648          641817 :         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          641817 :     JS_ASSERT_IF(lhs->isConstant(), !rhs->isConstant());
    2664          641817 :     JS_ASSERT_IF(rhs->isConstant(), !lhs->isConstant());
    2665                 : 
    2666          641817 :     if (!alloc.lhsData.isSet()) {
    2667          237575 :         if (backingLeft->data.inMemory()) {
    2668          236008 :             alloc.lhsData = tempRegForData(lhs);
    2669          236008 :             pinReg(alloc.lhsData.reg());
    2670            1567 :         } 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          641817 :     if (!alloc.rhsData.isSet() && backingRight->data.inMemory()) {
    2678           11921 :         alloc.rhsData = tempRegForData(rhs);
    2679           11921 :         pinReg(alloc.rhsData.reg());
    2680                 :     }
    2681                 : 
    2682          641817 :     alloc.lhsNeedsRemat = false;
    2683          641817 :     alloc.rhsNeedsRemat = false;
    2684          641817 :     alloc.resultHasRhs = false;
    2685          641817 :     alloc.undoResult = false;
    2686                 : 
    2687          641817 :     if (!needsResult)
    2688           44664 :         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          743780 :     if (cx->typeInferenceEnabled() &&
    2702          107225 :         backingLeft->data.inRegister() && !binaryEntryLive(backingLeft) &&
    2703           27446 :         (op == JSOP_ADD || (op == JSOP_SUB && backingRight->isConstant())) &&
    2704           11956 :         (lhs == backingLeft || hasOnlyCopy(backingLeft, lhs))) {
    2705           40964 :         alloc.result = backingLeft->data.reg();
    2706           40964 :         alloc.undoResult = true;
    2707           40964 :         alloc.resultHasRhs = false;
    2708           40964 :         goto skip;
    2709                 :     }
    2710                 : 
    2711          556189 :     if (cx->typeInferenceEnabled())
    2712           13235 :         evictDeadEntries(true);
    2713                 : 
    2714          556189 :     if (!freeRegs.empty(Registers::AvailRegs)) {
    2715                 :         /* Free reg - just grab it. */
    2716          545664 :         alloc.result = allocReg();
    2717          545664 :         if (!alloc.lhsData.isSet()) {
    2718            1362 :             JS_ASSERT(alloc.rhsData.isSet());
    2719            1362 :             JS_ASSERT(commu);
    2720            1362 :             masm.move(alloc.rhsData.reg(), alloc.result);
    2721            1362 :             alloc.resultHasRhs = true;
    2722                 :         } else {
    2723          544302 :             masm.move(alloc.lhsData.reg(), alloc.result);
    2724          544302 :             alloc.resultHasRhs = false;
    2725                 :         }
    2726           10525 :     } 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            9375 :         bool leftInReg = backingLeft->data.inRegister();
    2771            9375 :         bool rightInReg = backingRight->data.inRegister();
    2772            9375 :         bool leftSynced = backingLeft->data.synced();
    2773            9375 :         bool rightSynced = backingRight->data.synced();
    2774            9375 :         if (!commu || (leftInReg && (leftSynced || (!rightInReg || !rightSynced)))) {
    2775            8923 :             JS_ASSERT(backingLeft->data.inRegister() || !commu);
    2776           26769 :             JS_ASSERT_IF(backingLeft->data.inRegister(),
    2777           26769 :                          backingLeft->data.reg() == alloc.lhsData.reg());
    2778            8923 :             if (backingLeft->data.inRegister()) {
    2779            8923 :                 alloc.result = backingLeft->data.reg();
    2780            8923 :                 unpinReg(alloc.result);
    2781            8923 :                 takeReg(alloc.result);
    2782            8923 :                 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            8923 :             alloc.resultHasRhs = false;
    2789                 :         } else {
    2790             452 :             JS_ASSERT(commu);
    2791             452 :             JS_ASSERT(!leftInReg || (rightInReg && rightSynced));
    2792             452 :             alloc.result = backingRight->data.reg();
    2793             452 :             unpinReg(alloc.result);
    2794             452 :             takeReg(alloc.result);
    2795             452 :             alloc.resultHasRhs = true;
    2796             452 :             alloc.rhsNeedsRemat = true;
    2797                 :         }
    2798                 :     }
    2799                 : 
    2800                 :   skip:
    2801                 :     /* Unpin everything that was pinned. */
    2802          641817 :     if (backingLeft->type.inRegister())
    2803          613721 :         unpinReg(backingLeft->type.reg());
    2804          641817 :     if (backingRight->type.inRegister())
    2805          343999 :         unpinReg(backingRight->type.reg());
    2806          641817 :     if (backingLeft->data.inRegister())
    2807          631086 :         unpinReg(backingLeft->data.reg());
    2808          641817 :     if (backingRight->data.inRegister())
    2809          352761 :         unpinReg(backingRight->data.reg());
    2810          641817 : }
    2811                 : 
    2812                 : void
    2813          590874 : FrameState::rematBinary(FrameEntry *lhs, FrameEntry *rhs, const BinaryAlloc &alloc, Assembler &masm)
    2814                 : {
    2815          590874 :     if (alloc.rhsNeedsRemat)
    2816            1130 :         masm.loadPayload(addressForDataRemat(rhs), alloc.rhsData.reg());
    2817          590874 :     if (alloc.lhsNeedsRemat)
    2818            9550 :         masm.loadPayload(addressForDataRemat(lhs), alloc.lhsData.reg());
    2819          590874 : }
    2820                 : 
    2821                 : MaybeRegisterID
    2822           73166 : FrameState::maybePinData(FrameEntry *fe)
    2823                 : {
    2824           73166 :     fe = fe->isCopy() ? fe->copyOf() : fe;
    2825           73166 :     if (fe->data.inRegister()) {
    2826           37663 :         pinReg(fe->data.reg());
    2827           37663 :         return fe->data.reg();
    2828                 :     }
    2829           35503 :     return MaybeRegisterID();
    2830                 : }
    2831                 : 
    2832                 : MaybeRegisterID
    2833          124959 : FrameState::maybePinType(FrameEntry *fe)
    2834                 : {
    2835          124959 :     fe = fe->isCopy() ? fe->copyOf() : fe;
    2836          124959 :     if (fe->type.inRegister()) {
    2837           50174 :         pinReg(fe->type.reg());
    2838           50174 :         return fe->type.reg();
    2839                 :     }
    2840           74785 :     return MaybeRegisterID();
    2841                 : }
    2842                 : 
    2843                 : void
    2844          133518 : FrameState::maybeUnpinReg(MaybeRegisterID reg)
    2845                 : {
    2846          133518 :     if (reg.isSet())
    2847           71951 :         unpinReg(reg.reg());
    2848          133518 : }
    2849                 : 
    2850                 : uint32_t
    2851            2429 : FrameState::allocTemporary()
    2852                 : {
    2853            2429 :     if (temporariesTop == temporaries + TEMPORARY_LIMIT)
    2854               0 :         return UINT32_MAX;
    2855            2429 :     FrameEntry *fe = temporariesTop++;
    2856            2429 :     fe->lastLoop = 0;
    2857            2429 :     fe->temporary = true;
    2858            2429 :     return fe - temporaries;
    2859                 : }
    2860                 : 
    2861                 : void
    2862           33590 : FrameState::clearTemporaries()
    2863                 : {
    2864           33590 :     JS_ASSERT(!a->parent);
    2865                 : 
    2866           36019 :     for (FrameEntry *fe = temporaries; fe < temporariesTop; fe++) {
    2867            2429 :         if (!fe->isTracked())
    2868            1567 :             continue;
    2869             862 :         if (fe->isCopied())
    2870               1 :             uncopy(fe);
    2871             862 :         forgetAllRegs(fe);
    2872             862 :         fe->resetSynced();
    2873                 :     }
    2874                 : 
    2875           33590 :     temporariesTop = temporaries;
    2876           33590 : }
    2877                 : 
    2878                 : Vector<TemporaryCopy> *
    2879           31293 : FrameState::getTemporaryCopies(Uses uses)
    2880                 : {
    2881                 :     /* :XXX: handle OOM */
    2882           31293 :     Vector<TemporaryCopy> *res = NULL;
    2883                 : 
    2884           45351 :     for (FrameEntry *fe = temporaries; fe < temporariesTop; fe++) {
    2885           14058 :         if (!fe->isTracked())
    2886            3594 :             continue;
    2887           10464 :         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           31293 :     return res;
    2900                 : }

Generated by: LCOV version 1.7