LCOV - code coverage report
Current view: directory - js/src/methodjit - FrameState.h (source / functions) Found Hit Coverage
Test: app.info Lines: 176 176 100.0 %
Date: 2012-06-02 Functions: 62 62 100.0 %

       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                 : 
      40                 : #if !defined jsjaeger_framestate_h__ && defined JS_METHODJIT
      41                 : #define jsjaeger_framestate_h__
      42                 : 
      43                 : #include "jsanalyze.h"
      44                 : #include "jsapi.h"
      45                 : #include "methodjit/MachineRegs.h"
      46                 : #include "methodjit/FrameEntry.h"
      47                 : #include "CodeGenIncludes.h"
      48                 : #include "ImmutableSync.h"
      49                 : #include "jscompartment.h"
      50                 : 
      51                 : namespace js {
      52                 : namespace mjit {
      53                 : 
      54                 : struct Uses {
      55        13075680 :     explicit Uses(uint32_t nuses)
      56        13075680 :       : nuses(nuses)
      57        13075680 :     { }
      58                 :     uint32_t nuses;
      59                 : };
      60                 : 
      61                 : struct Changes {
      62         3017272 :     explicit Changes(uint32_t nchanges)
      63         3017272 :       : nchanges(nchanges)
      64         3017272 :     { }
      65                 :     uint32_t nchanges;
      66                 : };
      67                 : 
      68             130 : struct TemporaryCopy {
      69             110 :     TemporaryCopy(JSC::MacroAssembler::Address copy, JSC::MacroAssembler::Address temporary)
      70             110 :         : copy(copy), temporary(temporary)
      71             110 :     {}
      72                 :     JSC::MacroAssembler::Address copy;
      73                 :     JSC::MacroAssembler::Address temporary;
      74                 : };
      75                 : 
      76                 : class StubCompiler;
      77                 : class LoopState;
      78                 : 
      79                 : /*
      80                 :  * The FrameState keeps track of values on the frame during compilation.
      81                 :  * The compiler can query FrameState for information about arguments, locals,
      82                 :  * and stack slots (all hereby referred to as "slots"). Slot information can
      83                 :  * be requested in constant time. For each slot there is a FrameEntry *. If
      84                 :  * this is non-NULL, it contains valid information and can be returned.
      85                 :  *
      86                 :  * The register allocator keeps track of registers as being in one of two
      87                 :  * states. These are:
      88                 :  *
      89                 :  * 1) Unowned. Some code in the compiler is working on a register.
      90                 :  * 2) Owned. The FrameState owns the register, and may spill it at any time.
      91                 :  *
      92                 :  * ------------------ Implementation Details ------------------
      93                 :  * 
      94                 :  * Observations:
      95                 :  *
      96                 :  * 1) Every time we need a slow call, we must sync everything.
      97                 :  * 2) Efficient side-exits need to quickly deltize state snapshots.
      98                 :  * 3) Syncing is limited to constants and registers.
      99                 :  * 4) Entries are not forgotten unless they are entirely in memory and are
     100                 :  *    not constants or copies.
     101                 :  * 
     102                 :  * With these in mind, we want to make sure that the compiler doesn't degrade
     103                 :  * badly as functions get larger.
     104                 :  *
     105                 :  * If the FE is NULL, a new one is allocated, initialized, and stored. They
     106                 :  * are allocated from a pool such that (fe - pool) can be used to compute
     107                 :  * the slot's Address.
     108                 :  *
     109                 :  * We keep a side vector of all tracked FrameEntry * to quickly generate
     110                 :  * memory stores and clear the tracker.
     111                 :  *
     112                 :  * It is still possible to get really bad behavior with a very large script
     113                 :  * that doesn't have branches or calls. That's okay, having this code in
     114                 :  * minimizes damage and lets us introduce a hard cut-off point.
     115                 :  */
     116                 : class FrameState
     117                 : {
     118                 :     friend class ImmutableSync;
     119                 : 
     120                 :     typedef JSC::MacroAssembler::RegisterID RegisterID;
     121                 :     typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
     122                 :     typedef JSC::MacroAssembler::Address Address;
     123                 :     typedef JSC::MacroAssembler::AbsoluteAddress AbsoluteAddress;
     124                 :     typedef JSC::MacroAssembler::Jump Jump;
     125                 :     typedef JSC::MacroAssembler::Imm32 Imm32;
     126                 :     typedef JSC::MacroAssembler::ImmPtr ImmPtr;
     127                 : 
     128                 :     static const uint32_t InvalidIndex = 0xFFFFFFFF;
     129                 : 
     130                 :     struct Tracker {
     131          134091 :         Tracker()
     132          134091 :           : entries(NULL), nentries(0)
     133          134091 :         { }
     134                 : 
     135         2606451 :         void add(FrameEntry *fe) {
     136         2606451 :             entries[nentries++] = fe;
     137         2606451 :         }
     138                 : 
     139         1018153 :         void reset() {
     140         1018153 :             nentries = 0;
     141         1018153 :         }
     142                 : 
     143       507223394 :         FrameEntry * operator [](uint32_t n) const {
     144       507223394 :             JS_ASSERT(n < nentries);
     145       507223394 :             return entries[n];
     146                 :         }
     147                 : 
     148                 :         FrameEntry **entries;
     149                 :         uint32_t nentries;
     150                 :     };
     151                 : 
     152                 :     /*
     153                 :      * Some RegisterState invariants.
     154                 :      *
     155                 :      *  If |fe| is non-NULL, |save| is NULL.
     156                 :      *  If |save| is non-NULL, |fe| is NULL.
     157                 :      *  That is, both |fe| and |save| cannot be non-NULL.
     158                 :      *
     159                 :      *  If either |fe| or |save| is non-NULL, the register is not in freeRegs.
     160                 :      *  If both |fe| and |save| are NULL, the register is either in freeRegs,
     161                 :      *  or owned by the compiler.
     162                 :      */
     163                 :     struct RegisterState {
     164         2011365 :         RegisterState() : fe_(NULL), save_(NULL)
     165         2011365 :         { }
     166                 : 
     167                 :         RegisterState(FrameEntry *fe, RematInfo::RematType type)
     168                 :           : fe_(fe), save_(NULL), type_(type)
     169                 :         {
     170                 :             JS_ASSERT(!save_);
     171                 :         }
     172                 : 
     173       279171784 :         bool isPinned() const {
     174       279171784 :             assertConsistency();
     175       279171784 :             return !!save_;
     176                 :         }
     177                 : 
     178      1025142387 :         void assertConsistency() const {
     179      1025142387 :             JS_ASSERT_IF(fe_, !save_);
     180      1025142387 :             JS_ASSERT_IF(save_, !fe_);
     181      1025142387 :         }
     182                 : 
     183       715027854 :         FrameEntry *fe() const {
     184       715027854 :             assertConsistency();
     185       715027854 :             return fe_;
     186                 :         }
     187                 : 
     188        12899418 :         RematInfo::RematType type() const {
     189        12899418 :             assertConsistency();
     190        12899418 :             return type_;
     191                 :         }
     192                 : 
     193        70358595 :         FrameEntry *usedBy() const {
     194        70358595 :             if (fe_)
     195        15512400 :                 return fe_;
     196        54846195 :             return save_;
     197                 :         }
     198                 : 
     199         6697117 :         void associate(FrameEntry *fe, RematInfo::RematType type) {
     200         6697117 :             JS_ASSERT(!fe_);
     201         6697117 :             JS_ASSERT(!save_);
     202                 : 
     203         6697117 :             fe_ = fe;
     204         6697117 :             type_ = type;
     205         6697117 :         }
     206                 : 
     207                 :         /* Change ownership. */
     208         4760343 :         void reassociate(FrameEntry *fe) {
     209         4760343 :             assertConsistency();
     210         4760343 :             JS_ASSERT(fe);
     211                 : 
     212         4760343 :             fe_ = fe;
     213         4760343 :         }
     214                 : 
     215                 :         /* Unassociate this register from the FE. */
     216         6221401 :         void forget() {
     217         6221401 :             JS_ASSERT(fe_);
     218         6221401 :             fe_ = NULL;
     219         6221401 :             JS_ASSERT(!save_);
     220         6221401 :         }
     221                 : 
     222         6667079 :         void pin() {
     223         6667079 :             JS_ASSERT(fe_ != NULL);
     224         6667079 :             assertConsistency();
     225         6667079 :             save_ = fe_;
     226         6667079 :             fe_ = NULL;
     227         6667079 :         }
     228                 : 
     229         6271619 :         void unpin() {
     230         6271619 :             JS_ASSERT(save_ != NULL);
     231         6271619 :             assertConsistency();
     232         6271619 :             fe_ = save_;
     233         6271619 :             save_ = NULL;
     234         6271619 :         }
     235                 : 
     236          344290 :         void unpinUnsafe() {
     237          344290 :             assertConsistency();
     238          344290 :             save_ = NULL;
     239          344290 :         }
     240                 : 
     241                 :       private:
     242                 :         /* FrameEntry owning this register, or NULL if not owned by a frame. */
     243                 :         FrameEntry *fe_;
     244                 : 
     245                 :         /* Hack - simplifies register allocation for pairs. */
     246                 :         FrameEntry *save_;
     247                 : 
     248                 :         /* Part of the FrameEntry that owns the FE. */
     249                 :         RematInfo::RematType type_;
     250                 :     };
     251                 : 
     252                 :     struct ActiveFrame;
     253                 : 
     254                 :     FrameState *thisFromCtor() { return this; }
     255                 :   public:
     256                 :     FrameState(JSContext *cx, Compiler &cc, Assembler &masm, StubCompiler &stubcc);
     257                 :     ~FrameState();
     258                 : 
     259                 :     /*
     260                 :      * Pushes a synced slot that may have a known type.
     261                 :      */
     262                 :     inline void pushSynced(JSValueType knownType);
     263                 : 
     264                 :     /*
     265                 :      * Pushes a slot that has a known, synced type and payload.
     266                 :      */
     267                 :     inline void pushSynced(JSValueType knownType, RegisterID reg);
     268                 : 
     269                 :     /*
     270                 :      * Pushes a constant value.
     271                 :      */
     272                 :     inline void push(const Value &v);
     273                 : 
     274                 :     /*
     275                 :      * Loads a value from memory and pushes it. If reuseBase is set, the
     276                 :      * Compiler owns the register and it should be reused if possible.
     277                 :      */
     278                 :     inline void push(Address address, JSValueType knownType, bool reuseBase = false);
     279                 : 
     280                 :     /*
     281                 :      * Loads a word from memory and pushes it. If reuseBase is set, the
     282                 :      * Compiler owns the register and it should be reused if possible.
     283                 :      * It takes an address and loads/pushes an unboxed word of a given non-double type.
     284                 :      */
     285                 :     inline void pushWord(Address address, JSValueType knownType, bool reuseBase = false);
     286                 : 
     287                 :     /* Loads a value from memory into a register pair, returning the register. */
     288                 :     inline void loadIntoRegisters(Address address, bool reuseBase,
     289                 :                                   RegisterID *ptypeReg, RegisterID *pdataReg);
     290                 : 
     291                 :     /*
     292                 :      * Pushes a known type and allocated payload onto the operation stack.
     293                 :      */
     294                 :     inline void pushTypedPayload(JSValueType type, RegisterID payload);
     295                 : 
     296                 :     /*
     297                 :      * Clobbers a stack entry with a type register and data register pair,
     298                 :      * converting to the specified known type if necessary.  If the type is
     299                 :      * JSVAL_TYPE_DOUBLE, the registers are converted into a floating point
     300                 :      * register, which is returned.
     301                 :      */
     302                 :     inline FPRegisterID storeRegs(int32_t depth, RegisterID type, RegisterID data,
     303                 :                                   JSValueType knownType);
     304                 :     inline FPRegisterID pushRegs(RegisterID type, RegisterID data, JSValueType knownType);
     305                 : 
     306                 :     /*
     307                 :      * Load an address into a frame entry in registers. For handling call paths
     308                 :      * where merge() would otherwise reload from the wrong address.
     309                 :      */
     310                 :     inline void reloadEntry(Assembler &masm, Address address, FrameEntry *fe);
     311                 : 
     312                 :     /* Push a value which is definitely a double. */
     313                 :     void pushDouble(FPRegisterID fpreg);
     314                 :     void pushDouble(Address address);
     315                 : 
     316                 :     /* Ensure that fe is definitely a double. It must already be either int or double. */
     317                 :     void ensureDouble(FrameEntry *fe);
     318                 : 
     319                 :     /* Revert an entry just converted to double by ensureDouble. */
     320                 :     void ensureInteger(FrameEntry *fe);
     321                 : 
     322                 :     /*
     323                 :      * Emit code to masm ensuring that all in memory slots thought to be
     324                 :      * doubles are in fact doubles.
     325                 :      */
     326                 :     void ensureInMemoryDoubles(Assembler &masm);
     327                 : 
     328                 :     /* Forget that fe is definitely a double. */
     329                 :     void forgetKnownDouble(FrameEntry *fe);
     330                 : 
     331                 :     /*
     332                 :      * Pushes a known type and allocated payload onto the operation stack.
     333                 :      * This must be used when the type is known, but cannot be propagated
     334                 :      * because it is not known to be correct at a slow-path merge point.
     335                 :      *
     336                 :      * The caller guarantees that the tag was a fast-path check; that is,
     337                 :      * the value it replaces on the stack had the same tag if the fast-path
     338                 :      * was taken.
     339                 :      */
     340                 :     inline void pushUntypedPayload(JSValueType type, RegisterID payload);
     341                 : 
     342                 :     /*
     343                 :      * Pushes a value onto the operation stack. This must be used when the
     344                 :      * value is known, but its type cannot be propagated because it is not
     345                 :      * known to be correct at a slow-path merge point.
     346                 :      */
     347                 :     inline void pushUntypedValue(const Value &value);
     348                 : 
     349                 :     /*
     350                 :      * Pushes a number onto the operation stack.
     351                 :      *
     352                 :      * If asInt32 is set to true, then the FS will attempt to optimize
     353                 :      * syncing the type as int32. Only use this parameter when the fast-path
     354                 :      * guaranteed that the stack slot was guarded to be an int32_t originally.
     355                 :      *
     356                 :      * For example, checking LHS and RHS as ints guarantees that if the LHS
     357                 :      * was synced, then popping both and pushing a maybe-int32_t does not need
     358                 :      * to be synced.
     359                 :      */
     360                 :     inline void pushNumber(RegisterID payload, bool asInt32 = false);
     361                 : 
     362                 :     /*
     363                 :      * Pushes an int32_t onto the operation stack. This is a specialized version
     364                 :      * of pushNumber. The caller must guarantee that (a) an int32_t is to be 
     365                 :      * pushed on the inline path, and (b) if any slow path pushes a double,
     366                 :      * the slow path also stores the double to memory.
     367                 :      */
     368                 :     inline void pushInt32(RegisterID payload);
     369                 : 
     370                 :     /*
     371                 :      * Pops a value off the operation stack, freeing any of its resources.
     372                 :      */
     373                 :     inline void pop();
     374                 : 
     375                 :     /*
     376                 :      * Pops a number of values off the operation stack, freeing any of their
     377                 :      * resources.
     378                 :      */
     379                 :     inline void popn(uint32_t n);
     380                 : 
     381                 :     /*
     382                 :      * Returns true iff lhs and rhs are copies of the same FrameEntry.
     383                 :      */
     384                 :     inline bool haveSameBacking(FrameEntry *lhs, FrameEntry *rhs);
     385                 : 
     386                 :     /* If the rhs to a binary operation directly copies the lhs, uncopy the lhs. */
     387                 :     void separateBinaryEntries(FrameEntry *lhs, FrameEntry *rhs);
     388                 : 
     389                 :     /*
     390                 :      * Temporarily increase and decrease local variable depth.
     391                 :      */
     392                 :     inline void enterBlock(uint32_t n);
     393                 :     inline void leaveBlock(uint32_t n);
     394                 : 
     395                 :     // Pushes a copy of a slot (formal argument, local variable, or stack slot)
     396                 :     // onto the operation stack.
     397                 :     void pushLocal(uint32_t n);
     398                 :     void pushArg(uint32_t n);
     399                 :     void pushCallee();
     400                 :     void pushThis();
     401                 :     void pushCopyOf(FrameEntry *fe);
     402                 :     inline void setThis(RegisterID reg);
     403                 :     inline void syncThis();
     404                 :     inline void learnThisIsObject(bool unsync = true);
     405                 : 
     406                 :     inline FrameEntry *getStack(uint32_t slot);
     407                 :     inline FrameEntry *getLocal(uint32_t slot);
     408                 :     inline FrameEntry *getArg(uint32_t slot);
     409                 :     inline FrameEntry *getSlotEntry(uint32_t slot);
     410                 : 
     411                 :     /*
     412                 :      * Allocates a temporary register for a FrameEntry's type. The register
     413                 :      * can be spilled or clobbered by the frame. The compiler may only operate
     414                 :      * on it temporarily, and must take care not to clobber it.
     415                 :      */
     416                 :     inline RegisterID tempRegForType(FrameEntry *fe);
     417                 : 
     418                 :     /*
     419                 :      * Try to use a register already allocated for fe's type, but if one
     420                 :      * is not already available, use fallback.
     421                 :      *
     422                 :      * Note: this does NOT change fe's type-register remat info. It's supposed
     423                 :      * to be a super lightweight/transparent operation.
     424                 :      */
     425                 :     inline RegisterID tempRegForType(FrameEntry *fe, RegisterID fallback);
     426                 : 
     427                 :     inline void loadTypeIntoReg(const FrameEntry *fe, RegisterID reg);
     428                 :     inline void loadDataIntoReg(const FrameEntry *fe, RegisterID reg);
     429                 : 
     430                 :     /*
     431                 :      * Returns a register that is guaranteed to contain the frame entry's
     432                 :      * data payload. The compiler may not modify the contents of the register.
     433                 :      * The compiler should NOT explicitly free it.
     434                 :      */
     435                 :     inline RegisterID tempRegForData(FrameEntry *fe);
     436                 :     inline FPRegisterID tempFPRegForData(FrameEntry *fe);
     437                 : 
     438                 :     /*
     439                 :      * Same as above, except register must match identically.
     440                 :      */
     441                 :     inline AnyRegisterID tempRegInMaskForData(FrameEntry *fe, uint32_t mask);
     442                 : 
     443                 :     /*
     444                 :      * Same as above, except loads into reg (using masm) if the entry does not
     445                 :      * already have a register, and does not change the frame state in doing so.
     446                 :      */
     447                 :     inline RegisterID tempRegForData(FrameEntry *fe, RegisterID reg, Assembler &masm) const;
     448                 : 
     449                 :     /*
     450                 :      * For opcodes which expect to operate on an object, forget the entry if it
     451                 :      * is either a known constant or a non-object. This simplifies path
     452                 :      * generation in the Compiler for such unusual cases.
     453                 :      */
     454                 :     inline void forgetMismatchedObject(FrameEntry *fe);
     455                 : 
     456                 :     /*
     457                 :      * Convert an integer to a double without applying
     458                 :      * additional Register pressure.
     459                 :      */
     460                 :     inline void convertInt32ToDouble(Assembler &masm, FrameEntry *fe,
     461                 :                                      FPRegisterID fpreg) const;
     462                 : 
     463                 :     /*
     464                 :      * Dive into a FrameEntry and check whether it's in a register.
     465                 :      */
     466                 :     inline bool peekTypeInRegister(FrameEntry *fe) const;
     467                 : 
     468                 :     /*
     469                 :      * Allocates a register for a FrameEntry's data, such that the compiler
     470                 :      * can modify it in-place.
     471                 :      *
     472                 :      * The caller guarantees the FrameEntry will not be observed again. This
     473                 :      * allows the compiler to avoid spilling. Only call this if the FE is
     474                 :      * going to be popped before stubcc joins/guards or the end of the current
     475                 :      * opcode.
     476                 :      */
     477                 :     RegisterID ownRegForData(FrameEntry *fe);
     478                 : 
     479                 :     /*
     480                 :      * Allocates a register for a FrameEntry's type, such that the compiler
     481                 :      * can modify it in-place.
     482                 :      *
     483                 :      * The caller guarantees the FrameEntry will not be observed again. This
     484                 :      * allows the compiler to avoid spilling. Only call this if the FE is
     485                 :      * going to be popped before stubcc joins/guards or the end of the current
     486                 :      * opcode.
     487                 :      */
     488                 :     RegisterID ownRegForType(FrameEntry *fe);
     489                 : 
     490                 :     /*
     491                 :      * Allocates a register for a FrameEntry's data, such that the compiler
     492                 :      * can modify it in-place. The actual FE is not modified.
     493                 :      */
     494                 :     RegisterID copyDataIntoReg(FrameEntry *fe);
     495                 :     void copyDataIntoReg(FrameEntry *fe, RegisterID exact);
     496                 :     RegisterID copyDataIntoReg(Assembler &masm, FrameEntry *fe);
     497                 : 
     498                 :     /*
     499                 :      * Allocates a register for a FrameEntry's type, such that the compiler
     500                 :      * can modify it in-place. The actual FE is not modified.
     501                 :      */
     502                 :     RegisterID copyTypeIntoReg(FrameEntry *fe);
     503                 : 
     504                 :     /*
     505                 :      * Returns a register that contains the constant Int32 value of the
     506                 :      * frame entry's data payload.
     507                 :      * Since the register is not bound to a FrameEntry,
     508                 :      * it MUST be explicitly freed with freeReg().
     509                 :      */
     510                 :     RegisterID copyInt32ConstantIntoReg(FrameEntry *fe);
     511                 :     RegisterID copyInt32ConstantIntoReg(Assembler &masm, FrameEntry *fe);
     512                 : 
     513                 :     /*
     514                 :      * Gets registers for the components of fe where needed, pins them and
     515                 :      * stores into vr. If breakDouble is set, vr is guaranteed not to be a
     516                 :      * floating point register.
     517                 :      */
     518                 :     void pinEntry(FrameEntry *fe, ValueRemat &vr, bool breakDouble = true);
     519                 : 
     520                 :     /* Unpins registers from a call to pinEntry. */
     521                 :     void unpinEntry(const ValueRemat &vr);
     522                 : 
     523                 :     /* Syncs fe to memory, given its state as constructed by a call to pinEntry. */
     524                 :     void ensureValueSynced(Assembler &masm, FrameEntry *fe, const ValueRemat &vr);
     525                 : 
     526          641906 :     struct BinaryAlloc {
     527                 :         MaybeRegisterID lhsType;
     528                 :         MaybeRegisterID lhsData;
     529                 :         MaybeRegisterID rhsType;
     530                 :         MaybeRegisterID rhsData;
     531                 :         MaybeRegisterID extraFree;
     532                 :         RegisterID result;  // mutable result reg
     533                 :         FPRegisterID lhsFP; // mutable scratch floating point reg
     534                 :         FPRegisterID rhsFP; // mutable scratch floating point reg
     535                 :         bool resultHasRhs;  // whether the result has the RHS instead of the LHS
     536                 :         bool lhsNeedsRemat; // whether LHS needs memory remat
     537                 :         bool rhsNeedsRemat; // whether RHS needs memory remat
     538                 :         bool undoResult;    // whether to remat LHS/RHS by undoing operation
     539                 :     };
     540                 : 
     541                 :     /*
     542                 :      * Ensures that the two given FrameEntries have registers for both their
     543                 :      * type and data. The register allocations are returned in a struct.
     544                 :      *
     545                 :      * One mutable register is allocated as well, holding the LHS payload. If
     546                 :      * this would cause a spill that could be avoided by using a mutable RHS,
     547                 :      * and the operation is commutative, then the resultHasRhs is set to true.
     548                 :      */
     549                 :     void allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAlloc &alloc,
     550                 :                         bool resultNeeded = true);
     551                 : 
     552                 :     /*
     553                 :      * After the result register in a BinaryAlloc has been clobbered, rematerialize
     554                 :      * the left or right side if necessary to restore the original values.
     555                 :      */
     556                 :     void rematBinary(FrameEntry *lhs, FrameEntry *rhs, const BinaryAlloc &alloc, Assembler &masm);
     557                 : 
     558                 :     /* Ensures that an FE has both type and data remat'd in registers. */
     559                 :     void ensureFullRegs(FrameEntry *fe, MaybeRegisterID *typeReg, MaybeRegisterID *dataReg);
     560                 : 
     561                 :     /*
     562                 :      * Similar to allocForBinary, except works when the LHS and RHS have the
     563                 :      * same backing FE. Only a reduced subset of BinaryAlloc is used:
     564                 :      *   lhsType
     565                 :      *   lhsData
     566                 :      *   result
     567                 :      *   lhsNeedsRemat
     568                 :      */
     569                 :     void allocForSameBinary(FrameEntry *fe, JSOp op, BinaryAlloc &alloc);
     570                 : 
     571                 :     /* Loads an FE into an fp reg. */
     572                 :     inline void loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const;
     573                 : 
     574                 :     /*
     575                 :      * Slightly more specialized version when more precise register
     576                 :      * information is known.
     577                 :      */
     578                 :     inline void loadDouble(RegisterID type, RegisterID data, FrameEntry *fe, FPRegisterID fpReg,
     579                 :                            Assembler &masm) const;
     580                 : 
     581                 :     /*
     582                 :      * Types don't always have to be in registers, sometimes the compiler
     583                 :      * can use addresses and avoid spilling. If this FrameEntry has a synced
     584                 :      * address and no register, this returns true.
     585                 :      */
     586                 :     inline bool shouldAvoidTypeRemat(FrameEntry *fe);
     587                 : 
     588                 :     /*
     589                 :      * Payloads don't always have to be in registers, sometimes the compiler
     590                 :      * can use addresses and avoid spilling. If this FrameEntry has a synced
     591                 :      * address and no register, this returns true.
     592                 :      */
     593                 :     inline bool shouldAvoidDataRemat(FrameEntry *fe);
     594                 : 
     595                 :     /*
     596                 :      * Frees a temporary register. If this register is being tracked, then it
     597                 :      * is not spilled; the backing data becomes invalidated!
     598                 :      */
     599                 :     inline void freeReg(AnyRegisterID reg);
     600                 : 
     601                 :     /*
     602                 :      * Allocates a register. If none are free, one may be spilled from the
     603                 :      * tracker. If there are none available for spilling in the tracker,
     604                 :      * then this is considered a compiler bug and an assert will fire.
     605                 :      */
     606                 :     inline RegisterID allocReg();
     607                 :     inline FPRegisterID allocFPReg();
     608                 : 
     609                 :     /*
     610                 :      * Allocates a register, except using a mask.
     611                 :      */
     612                 :     inline AnyRegisterID allocReg(uint32_t mask);
     613                 : 
     614                 :     /*
     615                 :      * Allocates a specific register, evicting it if it's not avaliable.
     616                 :      */
     617                 :     void takeReg(AnyRegisterID reg);
     618                 : 
     619                 :     /*
     620                 :      * Returns a FrameEntry * for a slot on the operation stack.
     621                 :      */
     622                 :     inline FrameEntry *peek(int32_t depth);
     623                 : 
     624                 :     /*
     625                 :      * Fully stores a FrameEntry at an arbitrary address. popHint specifies
     626                 :      * how hard the register allocator should try to keep the FE in registers.
     627                 :      */
     628                 :     void storeTo(FrameEntry *fe, Address address, bool popHint = false);
     629                 : 
     630                 :     /*
     631                 :      * Fully stores a FrameEntry into two arbitrary registers. tempReg may be
     632                 :      * used as a temporary.
     633                 :      */
     634                 :     void loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
     635                 :     void loadThisForReturn(RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
     636                 : 
     637                 :     /* Stores the top stack slot back to a local or slot. */
     638                 :     void storeLocal(uint32_t n, bool popGuaranteed = false);
     639                 :     void storeArg(uint32_t n, bool popGuaranteed = false);
     640                 :     void storeTop(FrameEntry *target);
     641                 : 
     642                 :     /*
     643                 :      * Restores state from a slow path.
     644                 :      */
     645                 :     void merge(Assembler &masm, Changes changes) const;
     646                 : 
     647                 :     /*
     648                 :      * Writes unsynced stores to an arbitrary buffer.
     649                 :      */
     650                 :     void sync(Assembler &masm, Uses uses) const;
     651                 : 
     652                 :     /*
     653                 :      * Syncs all outstanding stores to memory and possibly kills regs in the
     654                 :      * process.  The top [ignored..uses-1] frame entries will be synced.
     655                 :      */
     656                 :     void syncAndKill(Registers kill, Uses uses, Uses ignored);
     657         1527571 :     void syncAndKill(Registers kill, Uses uses) { syncAndKill(kill, uses, Uses(0)); }
     658          295711 :     void syncAndKill(Uses uses) { syncAndKill(Registers(Registers::AvailAnyRegs), uses, Uses(0)); }
     659                 : 
     660                 :     /* Syncs and kills everything. */
     661          466024 :     void syncAndKillEverything() {
     662          466024 :         syncAndKill(Registers(Registers::AvailAnyRegs), Uses(frameSlots()));
     663          466024 :     }
     664                 : 
     665                 :     /*
     666                 :      * Throw away the entire frame state, without syncing anything.
     667                 :      * This can only be called after a syncAndKill() against all registers.
     668                 :      */
     669                 :     void forgetEverything();
     670                 : 
     671          405333 :     void syncAndForgetEverything()
     672                 :     {
     673          405333 :         syncAndKillEverything();
     674          405333 :         forgetEverything();
     675          405333 :     }
     676                 : 
     677                 :     /*
     678                 :      * Discard the entire framestate forcefully.
     679                 :      */
     680                 :     void discardFrame();
     681                 : 
     682                 :     /*
     683                 :      * Make a copy of the current frame state, and restore from that snapshot.
     684                 :      * The stack depth must match between the snapshot and restore points.
     685                 :      */
     686                 :     FrameEntry *snapshotState();
     687                 :     void restoreFromSnapshot(FrameEntry *snapshot);
     688                 : 
     689                 :     /*
     690                 :      * Tries to sync and shuffle registers in accordance with the register state
     691                 :      * at target, constructing that state if necessary. Forgets all constants and
     692                 :      * copies, and nothing can be pinned. Keeps the top Uses in registers; if Uses
     693                 :      * is non-zero the state may not actually be consistent with target.
     694                 :      */
     695                 :     bool syncForBranch(jsbytecode *target, Uses uses);
     696                 :     void syncForAllocation(RegisterAllocation *alloc, bool inlineReturn, Uses uses);
     697                 : 
     698                 :     /* Discards the current frame state and updates to a new register allocation. */
     699                 :     bool discardForJoin(RegisterAllocation *&alloc, uint32_t stackDepth);
     700                 : 
     701                 :     RegisterAllocation * computeAllocation(jsbytecode *target);
     702                 : 
     703                 :     /* Return whether the register state is consistent with that at target. */
     704                 :     bool consistentRegisters(jsbytecode *target);
     705                 : 
     706                 :     /*
     707                 :      * Load all registers to update from either the current register state (if synced
     708                 :      * is unset) or a synced state (if synced is set) to target.
     709                 :      */
     710                 :     void prepareForJump(jsbytecode *target, Assembler &masm, bool synced);
     711                 : 
     712                 :     /*
     713                 :      * Mark an existing slot with a type. unsync indicates whether type is already synced.
     714                 :      * Do not call this on entries which might be copied.
     715                 :      */
     716                 :     inline void learnType(FrameEntry *fe, JSValueType type, bool unsync = true);
     717                 :     inline void learnType(FrameEntry *fe, JSValueType type, RegisterID payload);
     718                 : 
     719                 :     /*
     720                 :      * Forget a type, syncing in the process.
     721                 :      */
     722                 :     inline void forgetType(FrameEntry *fe);
     723                 : 
     724                 :     /*
     725                 :      * Discards a FrameEntry, tricking the FS into thinking it's synced.
     726                 :      */
     727                 :     void discardFe(FrameEntry *fe);
     728                 : 
     729                 :     /* Compiler-owned metadata about stack entries, reset on push/pop/copy. */
     730                 :     struct StackEntryExtra {
     731                 :         bool initArray;
     732                 :         JSObject *initObject;
     733                 :         types::TypeSet *types;
     734                 :         JSAtom *name;
     735        22461062 :         void reset() { PodZero(this); }
     736                 :     };
     737         3298122 :     StackEntryExtra& extra(const FrameEntry *fe) {
     738         3298122 :         JS_ASSERT(fe >= a->args && fe < a->sp);
     739         3298122 :         return extraArray[fe - entries];
     740                 :     }
     741                 :     StackEntryExtra& extra(uint32_t slot) { return extra(entries + slot); }
     742                 : 
     743                 :     /*
     744                 :      * Helper function. Tests if a slot's type is null. Condition must
     745                 :      * be Equal or NotEqual.
     746                 :      */
     747                 :     inline Jump testNull(Assembler::Condition cond, FrameEntry *fe);
     748                 : 
     749                 :     /*
     750                 :      * Helper function. Tests if a slot's type is undefined. Condition must
     751                 :      * be Equal or NotEqual.
     752                 :      */
     753                 :     inline Jump testUndefined(Assembler::Condition cond, FrameEntry *fe);
     754                 : 
     755                 :     /*
     756                 :      * Helper function. Tests if a slot's type is an integer. Condition must
     757                 :      * be Equal or NotEqual.
     758                 :      */
     759                 :     inline Jump testInt32(Assembler::Condition cond, FrameEntry *fe);
     760                 : 
     761                 :     /*
     762                 :      * Helper function. Tests if a slot's type is a double. Condition must
     763                 :      * be Equal or Not Equal.
     764                 :      */
     765                 :     inline Jump testDouble(Assembler::Condition cond, FrameEntry *fe);
     766                 : 
     767                 :     /*
     768                 :      * Helper function. Tests if a slot's type is a boolean. Condition must
     769                 :      * be Equal or NotEqual.
     770                 :      */
     771                 :     inline Jump testBoolean(Assembler::Condition cond, FrameEntry *fe);
     772                 : 
     773                 :     /*
     774                 :      * Helper function. Tests if a slot's type is a string. Condition must
     775                 :      * be Equal or NotEqual.
     776                 :      */
     777                 :     inline Jump testString(Assembler::Condition cond, FrameEntry *fe);
     778                 : 
     779                 :     /*
     780                 :      * Helper function. Tests if a slot's type is a non-funobj. Condition must
     781                 :      * be Equal or NotEqual.
     782                 :      */
     783                 :     inline Jump testObject(Assembler::Condition cond, FrameEntry *fe);
     784                 : 
     785                 :     inline Jump testGCThing(FrameEntry *fe);
     786                 : 
     787                 :     /*
     788                 :      * Helper function. Tests if a slot's type is primitive. Condition must
     789                 :      * be Equal or NotEqual.
     790                 :      */
     791                 :     inline Jump testPrimitive(Assembler::Condition cond, FrameEntry *fe);
     792                 : 
     793                 :     /*
     794                 :      * Marks a register such that it cannot be spilled by the register
     795                 :      * allocator. Any pinned registers must be unpinned at the end of the op,
     796                 :      * no matter what. In addition, pinReg() can only be used on registers
     797                 :      * which are associated with FrameEntries.
     798                 :      */
     799         6667079 :     inline void pinReg(AnyRegisterID reg) { regstate(reg).pin(); }
     800                 : 
     801                 :     /*
     802                 :      * Unpins a previously pinned register.
     803                 :      */
     804         6271619 :     inline void unpinReg(AnyRegisterID reg) { regstate(reg).unpin(); }
     805                 : 
     806                 :     /*
     807                 :      * Same as unpinReg(), but does not restore the FrameEntry.
     808                 :      */
     809                 :     inline void unpinKilledReg(AnyRegisterID reg);
     810                 : 
     811                 :     /* Pins a data or type register if one exists. */
     812                 :     MaybeRegisterID maybePinData(FrameEntry *fe);
     813                 :     MaybeRegisterID maybePinType(FrameEntry *fe);
     814                 :     void maybeUnpinReg(MaybeRegisterID reg);
     815                 : 
     816                 :     /*
     817                 :      * Dups the top item on the stack.
     818                 :      */
     819                 :     inline void dup();
     820                 : 
     821                 :     /*
     822                 :      * Dups the top 2 items on the stack.
     823                 :      */
     824                 :     inline void dup2();
     825                 : 
     826                 :     /*
     827                 :      * Dups an item n-deep in the stack. n must be < 0
     828                 :      */
     829                 :     inline void dupAt(int32_t n);
     830                 : 
     831                 :     /*
     832                 :      * Syncs an item n-deep in the stack.
     833                 :      */
     834                 :     inline void syncAt(int32_t n);
     835                 : 
     836                 :     /*
     837                 :      * If the frameentry is a copy, give it its own registers.
     838                 :      * This may only be called on the topmost fe.
     839                 :      */
     840                 :     inline void giveOwnRegs(FrameEntry *fe);
     841                 : 
     842        14096935 :     uint32_t stackDepth() const { return a->sp - a->spBase; }
     843                 : 
     844                 :     /*
     845                 :      * The stack depth of the current frame plus any locals and space
     846                 :      * for inlined frames, i.e. the difference between the end of the
     847                 :      * current fp and sp.
     848                 :      */
     849         5277622 :     uint32_t totalDepth() const { return a->depth + a->script->nfixed + stackDepth(); }
     850                 : 
     851                 :     // Returns the number of entries in the frame, that is:
     852                 :     //   2 for callee, this +
     853                 :     //   nargs +
     854                 :     //   nfixed +
     855                 :     //   currently pushed stack slots
     856          741171 :     uint32_t frameSlots() const { return uint32_t(a->sp - a->callee_); }
     857                 : 
     858                 : #ifdef DEBUG
     859                 :     void assertValidRegisterState() const;
     860                 : #else
     861                 :     inline void assertValidRegisterState() const {};
     862                 : #endif
     863                 : 
     864                 :     // Return an address, relative to the StackFrame, that represents where
     865                 :     // this FrameEntry is stored in memory. Note that this is its canonical
     866                 :     // address, not its backing store. There is no guarantee that the memory
     867                 :     // is coherent.
     868                 :     Address addressOf(const FrameEntry *fe) const;
     869           55679 :     Address addressOf(uint32_t slot) const { return addressOf(a->callee_ + slot); }
     870                 : 
     871           38155 :     Address addressOfTop() const { return addressOf(a->sp); }
     872                 : 
     873                 :     // Returns an address, relative to the StackFrame, that represents where
     874                 :     // this FrameEntry is backed in memory. This is not necessarily its
     875                 :     // canonical address, but the address for which the payload has been synced
     876                 :     // to memory. The caller guarantees that the payload has been synced.
     877                 :     Address addressForDataRemat(const FrameEntry *fe) const;
     878                 : 
     879                 :     // Inside an inline frame, the address for the return value in the caller.
     880                 :     Address addressForInlineReturn();
     881                 : 
     882                 :     inline StateRemat dataRematInfo(const FrameEntry *fe) const;
     883                 : 
     884                 :     /*
     885                 :      * This is similar to freeReg(ownRegForData(fe)) - except no movement takes place.
     886                 :      * The fe is simply invalidated as if it were popped. This can be used to free
     887                 :      * registers in the working area of the stack. Obviously, this can only be called
     888                 :      * in infallible code that will pop these entries soon after.
     889                 :      */
     890                 :     inline void eviscerate(FrameEntry *fe);
     891                 : 
     892                 :     /*
     893                 :      * Moves the top of the stack down N slots, popping each item above it.
     894                 :      * Caller guarantees the slots below have been observed and eviscerated.
     895                 :      */
     896                 :     void shimmy(uint32_t n);
     897                 : 
     898                 :     /*
     899                 :      * Stores the top item on the stack to a stack slot, count down from the
     900                 :      * current stack depth. For example, to move the top (-1) to -3, you would
     901                 :      * call shift(-2).
     902                 :      */
     903                 :     void shift(int32_t n);
     904                 : 
     905                 :     /* Swaps the top two items on the stack. Requires two temp slots. */
     906                 :     void swap();
     907                 : 
     908         8820573 :     inline void setInTryBlock(bool inTryBlock) {
     909         8820573 :         this->inTryBlock = inTryBlock;
     910         8820573 :     }
     911                 : 
     912            5692 :     inline uint32_t regsInUse() const { return Registers::AvailRegs & ~freeRegs.freeMask; }
     913                 : 
     914         8820573 :     void setPC(jsbytecode *PC) { a->PC = PC; }
     915           67192 :     void setLoop(LoopState *loop) { this->loop = loop; }
     916                 : 
     917                 :     void pruneDeadEntries();
     918                 : 
     919                 :     bool pushActiveFrame(JSScript *script, uint32_t argc);
     920                 :     void popActiveFrame();
     921                 : 
     922          608277 :     uint32_t entrySlot(const FrameEntry *fe) const {
     923          608277 :         return frameSlot(a, fe);
     924                 :     }
     925                 : 
     926           18076 :     uint32_t outerSlot(const FrameEntry *fe) const {
     927           18076 :         ActiveFrame *na = a;
     928           18076 :         while (na->parent) { na = na->parent; }
     929           18076 :         return frameSlot(na, fe);
     930                 :     }
     931                 : 
     932           20637 :     bool isOuterSlot(const FrameEntry *fe) const {
     933           20637 :         if (isTemporary(fe))
     934             655 :             return true;
     935           19982 :         ActiveFrame *na = a;
     936           19982 :         while (na->parent) { na = na->parent; }
     937           19982 :         return fe < na->spBase && fe != na->callee_;
     938                 :     }
     939                 : 
     940                 : #ifdef DEBUG
     941                 :     const char * entryName(const FrameEntry *fe) const;
     942                 :     void dumpAllocation(RegisterAllocation *alloc);
     943                 : #else
     944                 :     const char * entryName(const FrameEntry *fe) const { return NULL; }
     945                 : #endif
     946           28876 :     const char * entryName(uint32_t slot) { return entryName(entries + slot); }
     947                 : 
     948                 :     /* Maximum number of analysis temporaries the FrameState can track. */
     949                 :     static const uint32_t TEMPORARY_LIMIT = 10;
     950                 : 
     951                 :     uint32_t allocTemporary();  /* -1 if limit reached. */
     952                 :     void clearTemporaries();
     953                 :     inline FrameEntry *getTemporary(uint32_t which);
     954                 : 
     955                 :     /*
     956                 :      * Return NULL or a new vector with all current copies of temporaries,
     957                 :      * excluding those about to be popped per 'uses'.
     958                 :      */
     959                 :     Vector<TemporaryCopy> *getTemporaryCopies(Uses uses);
     960                 : 
     961                 :     inline void syncAndForgetFe(FrameEntry *fe, bool markSynced = false);
     962                 :     inline void forgetLoopReg(FrameEntry *fe);
     963                 : 
     964                 :     /*
     965                 :      * Get an address for the specified name access in another script.
     966                 :      * The compiler owns the result's base register.
     967                 :      */
     968                 :     inline Address loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access);
     969                 :     inline Address loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access,
     970                 :                                    RegisterID reg);
     971                 : 
     972                 :   private:
     973                 :     inline AnyRegisterID allocAndLoadReg(FrameEntry *fe, bool fp, RematInfo::RematType type);
     974                 :     inline void forgetReg(AnyRegisterID reg);
     975                 :     AnyRegisterID evictSomeReg(uint32_t mask);
     976                 :     void evictReg(AnyRegisterID reg);
     977                 :     inline FrameEntry *rawPush();
     978                 :     inline void addToTracker(FrameEntry *fe);
     979                 : 
     980                 :     /* Guarantee sync, but do not set any sync flag. */
     981                 :     inline void ensureFeSynced(const FrameEntry *fe, Assembler &masm) const;
     982                 :     inline void ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const;
     983                 :     inline void ensureDataSynced(const FrameEntry *fe, Assembler &masm) const;
     984                 : 
     985                 :     /* Guarantee sync, even if register allocation is required, and set sync. */
     986                 :     inline void syncFe(FrameEntry *fe);
     987                 :     inline void syncType(FrameEntry *fe);
     988                 :     inline void syncData(FrameEntry *fe);
     989                 : 
     990                 :     /* For a frame entry whose value is dead, mark as synced. */
     991                 :     inline void fakeSync(FrameEntry *fe);
     992                 : 
     993                 :     inline FrameEntry *getCallee();
     994                 :     inline FrameEntry *getThis();
     995                 :     inline FrameEntry *getOrTrack(uint32_t index);
     996                 : 
     997                 :     inline void forgetAllRegs(FrameEntry *fe);
     998                 :     inline void swapInTracker(FrameEntry *lhs, FrameEntry *rhs);
     999                 : #if defined JS_NUNBOX32
    1000                 :     void syncFancy(Assembler &masm, Registers avail, int trackerIndex) const;
    1001                 : #endif
    1002                 :     inline bool tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const;
    1003                 :     void resetInternalState();
    1004                 : 
    1005                 :     /*
    1006                 :      * "Uncopies" the backing store of a FrameEntry that has been copied. The
    1007                 :      * original FrameEntry is not invalidated; this is the responsibility of
    1008                 :      * the caller. The caller can check isCopied() to see if the registers
    1009                 :      * were moved to a copy.
    1010                 :      *
    1011                 :      * Later addition: uncopy() returns the first copy found.
    1012                 :      */
    1013                 :     FrameEntry *uncopy(FrameEntry *original);
    1014                 :     FrameEntry *walkTrackerForUncopy(FrameEntry *original);
    1015                 :     FrameEntry *walkFrameForUncopy(FrameEntry *original);
    1016                 : 
    1017                 :     /* Whether fe is the only copy of backing. */
    1018                 :     bool hasOnlyCopy(FrameEntry *backing, FrameEntry *fe);
    1019                 : 
    1020                 :     /*
    1021                 :      * All registers in the FE are forgotten. If it is copied, it is uncopied
    1022                 :      * beforehand.
    1023                 :      */
    1024                 :     void forgetEntry(FrameEntry *fe);
    1025                 : 
    1026                 :     /* Stack and temporary entries whose contents should be disregarded. */
    1027       488474427 :     bool deadEntry(const FrameEntry *fe, unsigned uses = 0) const {
    1028       488474427 :         return (fe >= (a->sp - uses) && fe < temporaries) || fe >= temporariesTop;
    1029                 :     }
    1030                 : 
    1031        71423587 :     RegisterState & regstate(AnyRegisterID reg) {
    1032        71423587 :         JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
    1033        71423587 :         return regstate_[reg.reg_];
    1034                 :     }
    1035                 : 
    1036      1036995913 :     const RegisterState & regstate(AnyRegisterID reg) const {
    1037      1036995913 :         JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
    1038      1036995913 :         return regstate_[reg.reg_];
    1039                 :     }
    1040                 : 
    1041                 :     AnyRegisterID bestEvictReg(uint32_t mask, bool includePinned) const;
    1042                 :     void evictDeadEntries(bool includePinned);
    1043                 : 
    1044                 :     inline analyze::Lifetime * variableLive(FrameEntry *fe, jsbytecode *pc) const;
    1045                 :     inline bool binaryEntryLive(FrameEntry *fe) const;
    1046                 :     void relocateReg(AnyRegisterID reg, RegisterAllocation *alloc, Uses uses);
    1047                 : 
    1048          370299 :     bool isThis(const FrameEntry *fe) const {
    1049          370299 :         return fe == a->this_;
    1050                 :     }
    1051                 : 
    1052                 :     inline bool isConstructorThis(const FrameEntry *fe) const;
    1053                 : 
    1054          206158 :     bool isArg(const FrameEntry *fe) const {
    1055          206158 :         return a->script->function() && fe >= a->args && fe - a->args < a->script->function()->nargs;
    1056                 :     }
    1057                 : 
    1058          480927 :     bool isLocal(const FrameEntry *fe) const {
    1059          480927 :         return fe >= a->locals && fe - a->locals < a->script->nfixed;
    1060                 :     }
    1061                 : 
    1062        32704268 :     bool isTemporary(const FrameEntry *fe) const {
    1063        32704268 :         JS_ASSERT_IF(fe >= temporaries, fe < temporariesTop);
    1064        32704268 :         return fe >= temporaries;
    1065                 :     }
    1066                 : 
    1067                 :     int32_t frameOffset(const FrameEntry *fe, ActiveFrame *a) const;
    1068                 :     Address addressOf(const FrameEntry *fe, ActiveFrame *a) const;
    1069                 :     uint32_t frameSlot(ActiveFrame *a, const FrameEntry *fe) const;
    1070                 : 
    1071                 :     void associateReg(FrameEntry *fe, RematInfo::RematType type, AnyRegisterID reg);
    1072                 : 
    1073                 :     inline void modifyReg(AnyRegisterID reg);
    1074                 : 
    1075                 :     MaybeJump guardArrayLengthBase(FrameEntry *obj, Int32Key key);
    1076                 : 
    1077                 :   private:
    1078                 :     JSContext *cx;
    1079                 :     Assembler &masm;
    1080                 :     Compiler &cc;
    1081                 :     StubCompiler &stubcc;
    1082                 : 
    1083                 :     /* State for the active stack frame. */
    1084                 : 
    1085            2995 :     struct ActiveFrame {
    1086          131876 :         ActiveFrame() { PodZero(this); }
    1087                 : 
    1088                 :         ActiveFrame *parent;
    1089                 : 
    1090                 :         /* Number of values between the start of the outer frame and the start of this frame. */
    1091                 :         uint32_t depth;
    1092                 : 
    1093                 :         JSScript *script;
    1094                 :         jsbytecode *PC;
    1095                 :         analyze::ScriptAnalysis *analysis;
    1096                 : 
    1097                 :         /* Indexes into the main FrameEntry buffer of entries for this frame. */
    1098                 :         FrameEntry *callee_;
    1099                 :         FrameEntry *this_;
    1100                 :         FrameEntry *args;
    1101                 :         FrameEntry *locals;
    1102                 :         FrameEntry *spBase;
    1103                 :         FrameEntry *sp;
    1104                 :     };
    1105                 :     ActiveFrame *a;
    1106                 : 
    1107                 :     /* Common buffer of frame entries. */
    1108                 :     FrameEntry *entries;
    1109                 :     uint32_t nentries;
    1110                 : 
    1111                 :     /* Compiler-owned metadata for stack contents. */
    1112                 :     StackEntryExtra *extraArray;
    1113                 : 
    1114                 :     /* Vector of tracked slot indexes. */
    1115                 :     Tracker tracker;
    1116                 : 
    1117                 : #if defined JS_NUNBOX32
    1118                 :     mutable ImmutableSync reifier;
    1119                 : #endif
    1120                 : 
    1121                 :     /*
    1122                 :      * Register ownership state. This can't be used alone; to find whether an
    1123                 :      * entry is active, you must check the allocated registers.
    1124                 :      */
    1125                 :     RegisterState regstate_[Registers::TotalAnyRegisters];
    1126                 : 
    1127                 :     /* All unallocated registers. */
    1128                 :     Registers freeRegs;
    1129                 : 
    1130                 :     /* Stack of active loops. */
    1131                 :     LoopState *loop;
    1132                 : 
    1133                 :     /*
    1134                 :      * Track state for analysis temporaries. The meaning of these temporaries
    1135                 :      * is opaque to the frame state, which just tracks where they are stored.
    1136                 :      */
    1137                 :     FrameEntry *temporaries;
    1138                 :     FrameEntry *temporariesTop;
    1139                 : 
    1140                 :     bool inTryBlock;
    1141                 : };
    1142                 : 
    1143                 : /*
    1144                 :  * Register allocation overview. We want to allocate registers at the same time
    1145                 :  * as we emit code, in a single forward pass over the script. This is good both
    1146                 :  * for compilation speed and for design simplicity; we allocate registers for
    1147                 :  * variables and temporaries as the compiler needs them. To get a good allocation,
    1148                 :  * however, we need knowledge of which variables will be used in the future and
    1149                 :  * in what order --- we must prioritize keeping variables in registers which
    1150                 :  * will be used soon, and evict variables after they are no longer needed.
    1151                 :  * We get this from the analyze::LifetimeScript analysis, an initial backwards
    1152                 :  * pass over the script.
    1153                 :  *
    1154                 :  * Combining a backwards lifetime pass with a forward allocation pass in this
    1155                 :  * way produces a Linear-scan register allocator. These can generate code at
    1156                 :  * a speed close to that produced by a graph coloring register allocator,
    1157                 :  * at a fraction of the compilation time.
    1158                 :  */
    1159                 : 
    1160                 : /* Register allocation to use at a join point. */
    1161                 : struct RegisterAllocation {
    1162                 :   private:
    1163                 :     typedef JSC::MacroAssembler::RegisterID RegisterID;
    1164                 :     typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
    1165                 : 
    1166                 :     /* Entry for an unassigned register at the join point. */
    1167                 :     static const uint32_t UNASSIGNED_REGISTER = UINT32_MAX;
    1168                 : 
    1169                 :     /*
    1170                 :      * In the body of a loop, entry for an unassigned register that has not been
    1171                 :      * used since the start of the loop. We do not finalize the register state
    1172                 :      * at the start of a loop body until after generating code for the entire loop,
    1173                 :      * so we can decide on which variables to carry around the loop after seeing
    1174                 :      * them accessed early on in the body.
    1175                 :      */
    1176                 :     static const uint32_t LOOP_REGISTER = uint32_t(-2);
    1177                 : 
    1178                 :     /*
    1179                 :      * Assignment of registers to payloads. Type tags are always in memory,
    1180                 :      * except for known doubles in FP registers. These are indexes into the
    1181                 :      * frame's entries[] buffer, not slots.
    1182                 :      */
    1183                 :     uint32_t regstate_[Registers::TotalAnyRegisters];
    1184                 : 
    1185                 :     /* Mask for regstate entries indicating if the slot is synced. */
    1186                 :     static const uint32_t SYNCED = 0x80000000;
    1187                 : 
    1188        18978894 :     uint32_t & regstate(AnyRegisterID reg) {
    1189        18978894 :         JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
    1190        18978894 :         return regstate_[reg.reg_];
    1191                 :     }
    1192                 : 
    1193                 :   public:
    1194          174438 :     RegisterAllocation(bool forLoop)
    1195                 :     {
    1196          174438 :         uint32_t entry = forLoop ? (uint32_t) LOOP_REGISTER : (uint32_t) UNASSIGNED_REGISTER;
    1197         2791008 :         for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
    1198         2616570 :             AnyRegisterID reg = AnyRegisterID::fromRaw(i);
    1199         2616570 :             bool avail = Registers::maskReg(reg) & Registers::AvailAnyRegs;
    1200         2616570 :             regstate_[i] = avail ? entry : UNASSIGNED_REGISTER;
    1201                 :         }
    1202          174438 :     }
    1203                 : 
    1204        13495631 :     bool assigned(AnyRegisterID reg) {
    1205        13495631 :         return regstate(reg) != UNASSIGNED_REGISTER && regstate(reg) != LOOP_REGISTER;
    1206                 :     }
    1207                 : 
    1208         3195778 :     bool loop(AnyRegisterID reg) {
    1209         3195778 :         return regstate(reg) == LOOP_REGISTER;
    1210                 :     }
    1211                 : 
    1212           60240 :     bool synced(AnyRegisterID reg) {
    1213           60240 :         JS_ASSERT(assigned(reg));
    1214           60240 :         return regstate(reg) & SYNCED;
    1215                 :     }
    1216                 : 
    1217          378120 :     uint32_t index(AnyRegisterID reg) {
    1218          378120 :         JS_ASSERT(assigned(reg));
    1219          378120 :         return regstate(reg) & ~SYNCED;
    1220                 :     }
    1221                 : 
    1222           55669 :     void set(AnyRegisterID reg, uint32_t index, bool synced) {
    1223           55669 :         JS_ASSERT(index != LOOP_REGISTER && index != UNASSIGNED_REGISTER);
    1224           55669 :         regstate(reg) = index | (synced ? SYNCED : 0);
    1225           55669 :     }
    1226                 : 
    1227          421076 :     void setUnassigned(AnyRegisterID reg) {
    1228          421076 :         regstate(reg) = UNASSIGNED_REGISTER;
    1229          421076 :     }
    1230                 : 
    1231           77850 :     bool synced() {
    1232         1074727 :         for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
    1233         1011581 :             if (assigned(AnyRegisterID::fromRaw(i)))
    1234           14704 :                 return false;
    1235                 :         }
    1236           63146 :         return true;
    1237                 :     }
    1238                 : 
    1239          154271 :     void clearLoops() {
    1240         2468336 :         for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
    1241         2314065 :             AnyRegisterID reg = AnyRegisterID::fromRaw(i);
    1242         2314065 :             if (loop(reg))
    1243          284111 :                 setUnassigned(reg);
    1244                 :         }
    1245          154271 :     }
    1246                 : 
    1247          287316 :     bool hasAnyReg(uint32_t n) {
    1248         4058692 :         for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
    1249         3823787 :             AnyRegisterID reg = AnyRegisterID::fromRaw(i);
    1250         3823787 :             if (assigned(reg) && index(reg) == n)
    1251           52411 :                 return true;
    1252                 :         }
    1253          234905 :         return false;
    1254                 :     }
    1255                 : };
    1256                 : 
    1257                 : class AutoPreserveAcrossSyncAndKill;
    1258                 : 
    1259                 : } /* namespace mjit */
    1260                 : } /* namespace js */
    1261                 : 
    1262                 : #endif /* jsjaeger_framestate_h__ */
    1263                 : 

Generated by: LCOV version 1.7