Home | History | Annotate | Download | only in mips
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 
     29 #ifndef V8_MIPS_VIRTUAL_FRAME_MIPS_H_
     30 #define V8_MIPS_VIRTUAL_FRAME_MIPS_H_
     31 
     32 #include "register-allocator.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 // This dummy class is only used to create invalid virtual frames.
     38 extern class InvalidVirtualFrameInitializer {}* kInvalidVirtualFrameInitializer;
     39 
     40 
     41 // -------------------------------------------------------------------------
     42 // Virtual frames
     43 //
     44 // The virtual frame is an abstraction of the physical stack frame. It
     45 // encapsulates the parameters, frame-allocated locals, and the expression
     46 // stack. It supports push/pop operations on the expression stack, as well
     47 // as random access to the expression stack elements, locals, and
     48 // parameters.
     49 
     50 class VirtualFrame : public ZoneObject {
     51  public:
     52   class RegisterAllocationScope;
     53   // A utility class to introduce a scope where the virtual frame is
     54   // expected to remain spilled. The constructor spills the code
     55   // generator's current frame, and keeps it spilled.
     56   class SpilledScope BASE_EMBEDDED {
     57    public:
     58     explicit SpilledScope(VirtualFrame* frame)
     59       : old_is_spilled_(
     60           Isolate::Current()->is_virtual_frame_in_spilled_scope()) {
     61       if (frame != NULL) {
     62         if (!old_is_spilled_) {
     63           frame->SpillAll();
     64         } else {
     65           frame->AssertIsSpilled();
     66         }
     67       }
     68       Isolate::Current()->set_is_virtual_frame_in_spilled_scope(true);
     69     }
     70     ~SpilledScope() {
     71       Isolate::Current()->set_is_virtual_frame_in_spilled_scope(
     72           old_is_spilled_);
     73     }
     74     static bool is_spilled() {
     75       return Isolate::Current()->is_virtual_frame_in_spilled_scope();
     76     }
     77 
     78    private:
     79     int old_is_spilled_;
     80 
     81     SpilledScope() {}
     82 
     83     friend class RegisterAllocationScope;
     84   };
     85 
     86   class RegisterAllocationScope BASE_EMBEDDED {
     87    public:
     88     // A utility class to introduce a scope where the virtual frame
     89     // is not spilled, ie. where register allocation occurs.  Eventually
     90     // when RegisterAllocationScope is ubiquitous it can be removed
     91     // along with the (by then unused) SpilledScope class.
     92     inline explicit RegisterAllocationScope(CodeGenerator* cgen);
     93     inline ~RegisterAllocationScope();
     94 
     95    private:
     96     CodeGenerator* cgen_;
     97     bool old_is_spilled_;
     98 
     99     RegisterAllocationScope() {}
    100   };
    101 
    102   // An illegal index into the virtual frame.
    103   static const int kIllegalIndex = -1;
    104 
    105   // Construct an initial virtual frame on entry to a JS function.
    106   inline VirtualFrame();
    107 
    108   // Construct an invalid virtual frame, used by JumpTargets.
    109   explicit inline VirtualFrame(InvalidVirtualFrameInitializer* dummy);
    110 
    111   // Construct a virtual frame as a clone of an existing one.
    112   explicit inline VirtualFrame(VirtualFrame* original);
    113 
    114   inline CodeGenerator* cgen() const;
    115   inline MacroAssembler* masm();
    116 
    117   // The number of elements on the virtual frame.
    118   int element_count() const { return element_count_; }
    119 
    120   // The height of the virtual expression stack.
    121   inline int height() const;
    122 
    123   bool is_used(int num) {
    124     switch (num) {
    125       case 0: {  // a0.
    126         return kA0InUse[top_of_stack_state_];
    127       }
    128       case 1: {  // a1.
    129         return kA1InUse[top_of_stack_state_];
    130       }
    131       case 2:
    132       case 3:
    133       case 4:
    134       case 5:
    135       case 6: {  // a2 to a3, t0 to t2.
    136         ASSERT(num - kFirstAllocatedRegister < kNumberOfAllocatedRegisters);
    137         ASSERT(num >= kFirstAllocatedRegister);
    138         if ((register_allocation_map_ &
    139              (1 << (num - kFirstAllocatedRegister))) == 0) {
    140           return false;
    141         } else {
    142           return true;
    143         }
    144       }
    145       default: {
    146         ASSERT(num < kFirstAllocatedRegister ||
    147                num >= kFirstAllocatedRegister + kNumberOfAllocatedRegisters);
    148         return false;
    149       }
    150     }
    151   }
    152 
    153   // Add extra in-memory elements to the top of the frame to match an actual
    154   // frame (eg, the frame after an exception handler is pushed). No code is
    155   // emitted.
    156   void Adjust(int count);
    157 
    158   // Forget elements from the top of the frame to match an actual frame (eg,
    159   // the frame after a runtime call). No code is emitted except to bring the
    160   // frame to a spilled state.
    161   void Forget(int count);
    162 
    163 
    164   // Spill all values from the frame to memory.
    165   void SpillAll();
    166 
    167   void AssertIsSpilled() const {
    168     ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
    169     ASSERT(register_allocation_map_ == 0);
    170   }
    171 
    172   void AssertIsNotSpilled() {
    173     ASSERT(!SpilledScope::is_spilled());
    174   }
    175 
    176   // Spill all occurrences of a specific register from the frame.
    177   void Spill(Register reg) {
    178     UNIMPLEMENTED();
    179   }
    180 
    181   // Spill all occurrences of an arbitrary register if possible. Return the
    182   // register spilled or no_reg if it was not possible to free any register
    183   // (ie, they all have frame-external references). Unimplemented.
    184   Register SpillAnyRegister();
    185 
    186   // Make this virtual frame have a state identical to an expected virtual
    187   // frame. As a side effect, code may be emitted to make this frame match
    188   // the expected one.
    189   void MergeTo(const VirtualFrame* expected,
    190                Condition cond = al,
    191                Register r1 = no_reg,
    192                const Operand& r2 = Operand(no_reg));
    193 
    194   void MergeTo(VirtualFrame* expected,
    195                Condition cond = al,
    196                Register r1 = no_reg,
    197                const Operand& r2 = Operand(no_reg));
    198 
    199   // Checks whether this frame can be branched to by the other frame.
    200   bool IsCompatibleWith(const VirtualFrame* other) const {
    201     return (tos_known_smi_map_ & (~other->tos_known_smi_map_)) == 0;
    202   }
    203 
    204   inline void ForgetTypeInfo() {
    205     tos_known_smi_map_ = 0;
    206   }
    207 
    208   // Detach a frame from its code generator, perhaps temporarily. This
    209   // tells the register allocator that it is free to use frame-internal
    210   // registers. Used when the code generator's frame is switched from this
    211   // one to NULL by an unconditional jump.
    212   void DetachFromCodeGenerator() {
    213   }
    214 
    215   // (Re)attach a frame to its code generator. This informs the register
    216   // allocator that the frame-internal register references are active again.
    217   // Used when a code generator's frame is switched from NULL to this one by
    218   // binding a label.
    219   void AttachToCodeGenerator() {
    220   }
    221 
    222   // Emit code for the physical JS entry and exit frame sequences. After
    223   // calling Enter, the virtual frame is ready for use; and after calling
    224   // Exit it should not be used. Note that Enter does not allocate space in
    225   // the physical frame for storing frame-allocated locals.
    226   void Enter();
    227   void Exit();
    228 
    229   // Prepare for returning from the frame by elements in the virtual frame.
    230   // This avoids generating unnecessary merge code when jumping to the shared
    231   // return site. No spill code emitted. Value to return should be in v0.
    232   inline void PrepareForReturn();
    233 
    234   // Number of local variables after when we use a loop for allocating.
    235   static const int kLocalVarBound = 5;
    236 
    237   // Allocate and initialize the frame-allocated locals.
    238   void AllocateStackSlots();
    239 
    240   // The current top of the expression stack as an assembly operand.
    241   MemOperand Top() {
    242     AssertIsSpilled();
    243     return MemOperand(sp, 0);
    244   }
    245 
    246   // An element of the expression stack as an assembly operand.
    247   MemOperand ElementAt(int index) {
    248     int adjusted_index = index - kVirtualElements[top_of_stack_state_];
    249     ASSERT(adjusted_index >= 0);
    250     return MemOperand(sp, adjusted_index * kPointerSize);
    251   }
    252 
    253   bool KnownSmiAt(int index) {
    254     if (index >= kTOSKnownSmiMapSize) return false;
    255     return (tos_known_smi_map_ & (1 << index)) != 0;
    256   }
    257   // A frame-allocated local as an assembly operand.
    258   inline MemOperand LocalAt(int index);
    259 
    260   // Push the address of the receiver slot on the frame.
    261   void PushReceiverSlotAddress();
    262 
    263   // The function frame slot.
    264   MemOperand Function() { return MemOperand(fp, kFunctionOffset); }
    265 
    266   // The context frame slot.
    267   MemOperand Context() { return MemOperand(fp, kContextOffset); }
    268 
    269   // A parameter as an assembly operand.
    270   inline MemOperand ParameterAt(int index);
    271 
    272   // The receiver frame slot.
    273   inline MemOperand Receiver();
    274 
    275   // Push a try-catch or try-finally handler on top of the virtual frame.
    276   void PushTryHandler(HandlerType type);
    277 
    278   // Call stub given the number of arguments it expects on (and
    279   // removes from) the stack.
    280   inline void CallStub(CodeStub* stub, int arg_count);
    281 
    282   // Call JS function from top of the stack with arguments
    283   // taken from the stack.
    284   void CallJSFunction(int arg_count);
    285 
    286   // Call runtime given the number of arguments expected on (and
    287   // removed from) the stack.
    288   void CallRuntime(const Runtime::Function* f, int arg_count);
    289   void CallRuntime(Runtime::FunctionId id, int arg_count);
    290 
    291 #ifdef ENABLE_DEBUGGER_SUPPORT
    292   void DebugBreak();
    293 #endif
    294 
    295   // Invoke builtin given the number of arguments it expects on (and
    296   // removes from) the stack.
    297   void InvokeBuiltin(Builtins::JavaScript id,
    298                      InvokeJSFlags flag,
    299                      int arg_count);
    300 
    301   // Call load IC. Receiver is on the stack and is consumed. Result is returned
    302   // in v0.
    303   void CallLoadIC(Handle<String> name, RelocInfo::Mode mode);
    304 
    305   // Call store IC. If the load is contextual, value is found on top of the
    306   // frame. If not, value and receiver are on the frame. Both are consumed.
    307   // Result is returned in v0.
    308   void CallStoreIC(Handle<String> name, bool is_contextual);
    309 
    310   // Call keyed load IC. Key and receiver are on the stack. Both are consumed.
    311   // Result is returned in v0.
    312   void CallKeyedLoadIC();
    313 
    314   // Call keyed store IC. Value, key and receiver are on the stack. All three
    315   // are consumed. Result is returned in v0 (and a0).
    316   void CallKeyedStoreIC();
    317 
    318   // Call into an IC stub given the number of arguments it removes
    319   // from the stack. Register arguments to the IC stub are implicit,
    320   // and depend on the type of IC stub.
    321   void CallCodeObject(Handle<Code> ic,
    322                       RelocInfo::Mode rmode,
    323                       int dropped_args);
    324 
    325   // Drop a number of elements from the top of the expression stack. May
    326   // emit code to affect the physical frame. Does not clobber any registers
    327   // excepting possibly the stack pointer.
    328   void Drop(int count);
    329 
    330   // Drop one element.
    331   void Drop() { Drop(1); }
    332 
    333   // Pop an element from the top of the expression stack. Discards
    334   // the result.
    335   void Pop();
    336 
    337   // Pop an element from the top of the expression stack.  The register
    338   // will be one normally used for the top of stack register allocation
    339   // so you can't hold on to it if you push on the stack.
    340   Register PopToRegister(Register but_not_to_this_one = no_reg);
    341 
    342   // Look at the top of the stack.  The register returned is aliased and
    343   // must be copied to a scratch register before modification.
    344   Register Peek();
    345 
    346   // Look at the value beneath the top of the stack. The register returned is
    347   // aliased and must be copied to a scratch register before modification.
    348   Register Peek2();
    349 
    350   // Duplicate the top of stack.
    351   void Dup();
    352 
    353   // Duplicate the two elements on top of stack.
    354   void Dup2();
    355 
    356   // Flushes all registers, but it puts a copy of the top-of-stack in a0.
    357   void SpillAllButCopyTOSToA0();
    358 
    359   // Flushes all registers, but it puts a copy of the top-of-stack in a1.
    360   void SpillAllButCopyTOSToA1();
    361 
    362   // Flushes all registers, but it puts a copy of the top-of-stack in a1
    363   // and the next value on the stack in a0.
    364   void SpillAllButCopyTOSToA1A0();
    365 
    366   // Pop and save an element from the top of the expression stack and
    367   // emit a corresponding pop instruction.
    368   void EmitPop(Register reg);
    369   // Same but for multiple registers
    370   void EmitMultiPop(RegList regs);
    371   void EmitMultiPopReversed(RegList regs);
    372 
    373 
    374   // Takes the top two elements and puts them in a0 (top element) and a1
    375   // (second element).
    376   void PopToA1A0();
    377 
    378   // Takes the top element and puts it in a1.
    379   void PopToA1();
    380 
    381   // Takes the top element and puts it in a0.
    382   void PopToA0();
    383 
    384   // Push an element on top of the expression stack and emit a
    385   // corresponding push instruction.
    386   void EmitPush(Register reg, TypeInfo type_info = TypeInfo::Unknown());
    387   void EmitPush(Operand operand, TypeInfo type_info = TypeInfo::Unknown());
    388   void EmitPush(MemOperand operand, TypeInfo type_info = TypeInfo::Unknown());
    389   void EmitPushRoot(Heap::RootListIndex index);
    390 
    391   // Overwrite the nth thing on the stack.  If the nth position is in a
    392   // register then this turns into a Move, otherwise an sw.  Afterwards
    393   // you can still use the register even if it is a register that can be
    394   // used for TOS (a0 or a1).
    395   void SetElementAt(Register reg, int this_far_down);
    396 
    397   // Get a register which is free and which must be immediately used to
    398   // push on the top of the stack.
    399   Register GetTOSRegister();
    400 
    401   // Same but for multiple registers.
    402   void EmitMultiPush(RegList regs);
    403   void EmitMultiPushReversed(RegList regs);
    404 
    405   static Register scratch0() { return t4; }
    406   static Register scratch1() { return t5; }
    407   static Register scratch2() { return t6; }
    408 
    409  private:
    410   static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
    411   static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
    412   static const int kContextOffset = StandardFrameConstants::kContextOffset;
    413 
    414   static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
    415   static const int kPreallocatedElements = 5 + 8;  // 8 expression stack slots.
    416 
    417   // 5 states for the top of stack, which can be in memory or in a0 and a1.
    418   enum TopOfStack { NO_TOS_REGISTERS, A0_TOS, A1_TOS, A1_A0_TOS, A0_A1_TOS,
    419                     TOS_STATES};
    420   static const int kMaxTOSRegisters = 2;
    421 
    422   static const bool kA0InUse[TOS_STATES];
    423   static const bool kA1InUse[TOS_STATES];
    424   static const int kVirtualElements[TOS_STATES];
    425   static const TopOfStack kStateAfterPop[TOS_STATES];
    426   static const TopOfStack kStateAfterPush[TOS_STATES];
    427   static const Register kTopRegister[TOS_STATES];
    428   static const Register kBottomRegister[TOS_STATES];
    429 
    430   // We allocate up to 5 locals in registers.
    431   static const int kNumberOfAllocatedRegisters = 5;
    432   // r2 to r6 are allocated to locals.
    433   static const int kFirstAllocatedRegister = 2;
    434 
    435   static const Register kAllocatedRegisters[kNumberOfAllocatedRegisters];
    436 
    437   static Register AllocatedRegister(int r) {
    438     ASSERT(r >= 0 && r < kNumberOfAllocatedRegisters);
    439     return kAllocatedRegisters[r];
    440   }
    441 
    442   // The number of elements on the stack frame.
    443   int element_count_;
    444   TopOfStack top_of_stack_state_:3;
    445   int register_allocation_map_:kNumberOfAllocatedRegisters;
    446   static const int kTOSKnownSmiMapSize = 4;
    447   unsigned tos_known_smi_map_:kTOSKnownSmiMapSize;
    448 
    449   // The index of the element that is at the processor's stack pointer
    450   // (the sp register).  For now since everything is in memory it is given
    451   // by the number of elements on the not-very-virtual stack frame.
    452   int stack_pointer() { return element_count_ - 1; }
    453 
    454   // The number of frame-allocated locals and parameters respectively.
    455   inline int parameter_count() const;
    456   inline int local_count() const;
    457 
    458   // The index of the element that is at the processor's frame pointer
    459   // (the fp register). The parameters, receiver, function, and context
    460   // are below the frame pointer.
    461   inline int frame_pointer() const;
    462 
    463   // The index of the first parameter. The receiver lies below the first
    464   // parameter.
    465   int param0_index() { return 1; }
    466 
    467   // The index of the context slot in the frame. It is immediately
    468   // below the frame pointer.
    469   inline int context_index();
    470 
    471   // The index of the function slot in the frame. It is below the frame
    472   // pointer and context slot.
    473   inline int function_index();
    474 
    475   // The index of the first local. Between the frame pointer and the
    476   // locals lies the return address.
    477   inline int local0_index() const;
    478 
    479   // The index of the base of the expression stack.
    480   inline int expression_base_index() const;
    481 
    482   // Convert a frame index into a frame pointer relative offset into the
    483   // actual stack.
    484   inline int fp_relative(int index);
    485 
    486   // Spill all elements in registers. Spill the top spilled_args elements
    487   // on the frame. Sync all other frame elements.
    488   // Then drop dropped_args elements from the virtual frame, to match
    489   // the effect of an upcoming call that will drop them from the stack.
    490   void PrepareForCall(int spilled_args, int dropped_args);
    491 
    492   // If all top-of-stack registers are in use then the lowest one is pushed
    493   // onto the physical stack and made free.
    494   void EnsureOneFreeTOSRegister();
    495 
    496   // Emit instructions to get the top of stack state from where we are to where
    497   // we want to be.
    498   void MergeTOSTo(TopOfStack expected_state,
    499                   Condition cond = al,
    500                   Register r1 = no_reg,
    501                   const Operand& r2 = Operand(no_reg));
    502 
    503   inline bool Equals(const VirtualFrame* other);
    504 
    505   inline void LowerHeight(int count) {
    506     element_count_ -= count;
    507     if (count >= kTOSKnownSmiMapSize) {
    508       tos_known_smi_map_ = 0;
    509     } else {
    510       tos_known_smi_map_ >>= count;
    511     }
    512   }
    513 
    514   inline void RaiseHeight(int count, unsigned known_smi_map = 0) {
    515     ASSERT(known_smi_map < (1u << count));
    516     element_count_ += count;
    517     if (count >= kTOSKnownSmiMapSize) {
    518       tos_known_smi_map_ = known_smi_map;
    519     } else {
    520       tos_known_smi_map_ = ((tos_known_smi_map_ << count) | known_smi_map);
    521     }
    522   }
    523   friend class JumpTarget;
    524 };
    525 
    526 
    527 } }  // namespace v8::internal
    528 
    529 #endif  // V8_MIPS_VIRTUAL_FRAME_MIPS_H_
    530 
    531