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

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-04-07 | 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         6853552 :     explicit Uses(uint32_t nuses)
          56         6853552 :       : nuses(nuses)
          57         6853552 :     { }
          58                 :     uint32_t nuses;
          59                 : };
          60                 :
          61                 : struct Changes {
          62         1605194 :     explicit Changes(uint32_t nchanges)
          63         1605194 :       : nchanges(nchanges)
          64         1605194 :     { }
          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           95862 :         Tracker()
         132           95862 :           : entries(NULL), nentries(0)
         133           95862 :         { }
         134                 :
         135         1392539 :         void add(FrameEntry *fe) {
         136         1392539 :             entries[nentries++] = fe;
         137         1392539 :         }
         138                 :
         139          604151 :         void reset() {
         140          604151 :             nentries = 0;
         141          604151 :         }
         142                 :
         143       431569036 :         FrameEntry * operator [](uint32_t n) const {
         144       431569036 :             JS_ASSERT(n < nentries);
         145       431569036 :             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         1437930 :         RegisterState() : fe_(NULL), save_(NULL)
         165         1437930 :         { }
         166                 :
         167                 :         RegisterState(FrameEntry *fe, RematInfo::RematType type)
         168                 :           : fe_(fe), save_(NULL), type_(type)
         169                 :         {
         170                 :             JS_ASSERT(!save_);
         171                 :         }
         172                 :
         173       131621797 :         bool isPinned() const {
         174       131621797 :             assertConsistency();
         175       131621797 :             return !!save_;
         176                 :         }
         177                 :
         178       474527075 :         void assertConsistency() const {
         179       474527075 :             JS_ASSERT_IF(fe_, !save_);
         180       474527075 :             JS_ASSERT_IF(save_, !fe_);
         181       474527075 :         }
         182                 :
         183       331395627 :         FrameEntry *fe() const {
         184       331395627 :             assertConsistency();
         185       331395627 :             return fe_;
         186                 :         }
         187                 :
         188         6797141 :         RematInfo::RematType type() const {
         189         6797141 :             assertConsistency();
         190         6797141 :             return type_;
         191                 :         }
         192                 :
         193        36038214 :         FrameEntry *usedBy() const {
         194        36038214 :             if (fe_)
         195         8420725 :                 return fe_;
         196        27617489 :             return save_;
         197                 :         }
         198                 :
         199         3221679 :         void associate(FrameEntry *fe, RematInfo::RematType type) {
         200         3221679 :             JS_ASSERT(!fe_);
         201         3221679 :             JS_ASSERT(!save_);
         202                 :
         203         3221679 :             fe_ = fe;
         204         3221679 :             type_ = type;
         205         3221679 :         }
         206                 :
         207                 :         /* Change ownership. */
         208          456141 :         void reassociate(FrameEntry *fe) {
         209          456141 :             assertConsistency();
         210          456141 :             JS_ASSERT(fe);
         211                 :
         212          456141 :             fe_ = fe;
         213          456141 :         }
         214                 :
         215                 :         /* Unassociate this register from the FE. */
         216         2936375 :         void forget() {
         217         2936375 :             JS_ASSERT(fe_);
         218         2936375 :             fe_ = NULL;
         219         2936375 :             JS_ASSERT(!save_);
         220         2936375 :         }
         221                 :
         222         2138454 :         void pin() {
         223         2138454 :             JS_ASSERT(fe_ != NULL);
         224         2138454 :             assertConsistency();
         225         2138454 :             save_ = fe_;
         226         2138454 :             fe_ = NULL;
         227         2138454 :         }
         228                 :
         229         1929706 :         void unpin() {
         230         1929706 :             JS_ASSERT(save_ != NULL);
         231         1929706 :             assertConsistency();
         232         1929706 :             fe_ = save_;
         233         1929706 :             save_ = NULL;
         234         1929706 :         }
         235                 :
         236          188209 :         void unpinUnsafe() {
         237          188209 :             assertConsistency();
         238          188209 :             save_ = NULL;
         239          188209 :         }
         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          389662 :     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          714108 :     void syncAndKill(Registers kill, Uses uses) { syncAndKill(kill, uses, Uses(0)); }
         658          177150 :     void syncAndKill(Uses uses) { syncAndKill(Registers(Registers::AvailAnyRegs), uses, Uses(0)); }
         659                 :
         660                 :     /* Syncs and kills everything. */
         661          232337 :     void syncAndKillEverything() {
         662          232337 :         syncAndKill(Registers(Registers::AvailAnyRegs), Uses(frameSlots()));
         663          232337 :     }
         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          204022 :     void syncAndForgetEverything()
         672                 :     {
         673          204022 :         syncAndKillEverything();
         674          204022 :         forgetEverything();
         675          204022 :     }
         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         8691802 :         void reset() { PodZero(this); }
         736                 :     };
         737         2689536 :     StackEntryExtra& extra(const FrameEntry *fe) {
         738         2689536 :         JS_ASSERT(fe >= a->args && fe < a->sp);
         739         2689536 :         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         2138454 :     inline void pinReg(AnyRegisterID reg) { regstate(reg).pin(); }
         800                 :
         801                 :     /*
         802                 :      * Unpins a previously pinned register.
         803                 :      */
         804         1929706 :     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         7019813 :     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         2902905 :     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          363741 :     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           56519 :     Address addressOf(uint32_t slot) const { return addressOf(a->callee_ + slot); }
         870                 :
         871           39229 :     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         4118172 :     inline void setInTryBlock(bool inTryBlock) {
         909         4118172 :         this->inTryBlock = inTryBlock;
         910         4118172 :     }
         911                 :
         912            5703 :     inline uint32_t regsInUse() const { return Registers::AvailRegs & ~freeRegs.freeMask; }
         913                 :
         914         4118172 :     void setPC(jsbytecode *PC) { a->PC = PC; }
         915           67133 :     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          516661 :     uint32_t entrySlot(const FrameEntry *fe) const {
         923          516661 :         return frameSlot(a, fe);
         924                 :     }
         925                 :
         926           18062 :     uint32_t outerSlot(const FrameEntry *fe) const {
         927           18062 :         ActiveFrame *na = a;
         928           18062 :         while (na->parent) { na = na->parent; }
         929           18062 :         return frameSlot(na, fe);
         930                 :     }
         931                 :
         932           20367 :     bool isOuterSlot(const FrameEntry *fe) const {
         933           20367 :         if (isTemporary(fe))
         934             669 :             return true;
         935           19698 :         ActiveFrame *na = a;
         936           19698 :         while (na->parent) { na = na->parent; }
         937           19698 :         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           28968 :     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       423098044 :     bool deadEntry(const FrameEntry *fe, unsigned uses = 0) const {
        1028       423098044 :         return (fe >= (a->sp - uses) && fe < temporaries) || fe >= temporariesTop;
        1029                 :     }
        1030                 :
        1031        29392201 :     RegisterState & regstate(AnyRegisterID reg) {
        1032        29392201 :         JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
        1033        29392201 :         return regstate_[reg.reg_];
        1034                 :     }
        1035                 :
        1036       487331142 :     const RegisterState & regstate(AnyRegisterID reg) const {
        1037       487331142 :         JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
        1038       487331142 :         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          376716 :     bool isThis(const FrameEntry *fe) const {
        1049          376716 :         return fe == a->this_;
        1050                 :     }
        1051                 :
        1052                 :     inline bool isConstructorThis(const FrameEntry *fe) const;
        1053                 :
        1054          145837 :     bool isArg(const FrameEntry *fe) const {
        1055          145837 :         return a->script->function() && fe >= a->args && fe - a->args < a->script->function()->nargs;
        1056                 :     }
        1057                 :
        1058          437783 :     bool isLocal(const FrameEntry *fe) const {
        1059          437783 :         return fe >= a->locals && fe - a->locals < a->script->nfixed;
        1060                 :     }
        1061                 :
        1062        15529487 :     bool isTemporary(const FrameEntry *fe) const {
        1063        15529487 :         JS_ASSERT_IF(fe >= temporaries, fe < temporariesTop);
        1064        15529487 :         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            2932 :     struct ActiveFrame {
        1086           96663 :         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        20246952 :     uint32_t & regstate(AnyRegisterID reg) {
        1189        20246952 :         JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
        1190        20246952 :         return regstate_[reg.reg_];
        1191                 :     }
        1192                 :
        1193                 :   public:
        1194          191555 :     RegisterAllocation(bool forLoop)
        1195                 :     {
        1196          191555 :         uint32_t entry = forLoop ? (uint32_t) LOOP_REGISTER : (uint32_t) UNASSIGNED_REGISTER;
        1197         3064880 :         for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
        1198         2873325 :             AnyRegisterID reg = AnyRegisterID::fromRaw(i);
        1199         2873325 :             bool avail = Registers::maskReg(reg) & Registers::AvailAnyRegs;
        1200         2873325 :             regstate_[i] = avail ? entry : UNASSIGNED_REGISTER;
        1201                 :         }
        1202          191555 :     }
        1203                 :
        1204        14766712 :     bool assigned(AnyRegisterID reg) {
        1205        14766712 :         return regstate(reg) != UNASSIGNED_REGISTER && regstate(reg) != LOOP_REGISTER;
        1206                 :     }
        1207                 :
        1208         3196365 :     bool loop(AnyRegisterID reg) {
        1209         3196365 :         return regstate(reg) == LOOP_REGISTER;
        1210                 :     }
        1211                 :
        1212           60263 :     bool synced(AnyRegisterID reg) {
        1213           60263 :         JS_ASSERT(assigned(reg));
        1214           60263 :         return regstate(reg) & SYNCED;
        1215                 :     }
        1216                 :
        1217          378139 :     uint32_t index(AnyRegisterID reg) {
        1218          378139 :         JS_ASSERT(assigned(reg));
        1219          378139 :         return regstate(reg) & ~SYNCED;
        1220                 :     }
        1221                 :
        1222           55674 :     void set(AnyRegisterID reg, uint32_t index, bool synced) {
        1223           55674 :         JS_ASSERT(index != LOOP_REGISTER && index != UNASSIGNED_REGISTER);
        1224           55674 :         regstate(reg) = index | (synced ? SYNCED : 0);
        1225           55674 :     }
        1226                 :
        1227          420713 :     void setUnassigned(AnyRegisterID reg) {
        1228          420713 :         regstate(reg) = UNASSIGNED_REGISTER;
        1229          420713 :     }
        1230                 :
        1231           86445 :     bool synced() {
        1232         1212313 :         for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
        1233         1140569 :             if (assigned(AnyRegisterID::fromRaw(i)))
        1234           14701 :                 return false;
        1235                 :         }
        1236           71744 :         return true;
        1237                 :     }
        1238                 :
        1239          154366 :     void clearLoops() {
        1240         2469856 :         for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
        1241         2315490 :             AnyRegisterID reg = AnyRegisterID::fromRaw(i);
        1242         2315490 :             if (loop(reg))
        1243          283885 :                 setUnassigned(reg);
        1244                 :         }
        1245          154366 :     }
        1246                 :
        1247          304180 :     bool hasAnyReg(uint32_t n) {
        1248         4328335 :         for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
        1249         4076584 :             AnyRegisterID reg = AnyRegisterID::fromRaw(i);
        1250         4076584 :             if (assigned(reg) && index(reg) == n)
        1251           52429 :                 return true;
        1252                 :         }
        1253          251751 :         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