blob: cf30b09326a5a372f10c139285e288fc559d0480 [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +00001// 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"
Andrei Popescu31002712010-02-23 13:46:05 +000033
34namespace v8 {
35namespace internal {
36
Steve Block44f0eee2011-05-26 01:26:41 +010037// This dummy class is only used to create invalid virtual frames.
38extern class InvalidVirtualFrameInitializer {}* kInvalidVirtualFrameInitializer;
39
Andrei Popescu31002712010-02-23 13:46:05 +000040
41// -------------------------------------------------------------------------
42// Virtual frames
43//
Steve Block6ded16b2010-05-10 14:33:55 +010044// The virtual frame is an abstraction of the physical stack frame. It
Andrei Popescu31002712010-02-23 13:46:05 +000045// encapsulates the parameters, frame-allocated locals, and the expression
Steve Block6ded16b2010-05-10 14:33:55 +010046// stack. It supports push/pop operations on the expression stack, as well
Andrei Popescu31002712010-02-23 13:46:05 +000047// as random access to the expression stack elements, locals, and
48// parameters.
49
50class VirtualFrame : public ZoneObject {
51 public:
Steve Block44f0eee2011-05-26 01:26:41 +010052 class RegisterAllocationScope;
Andrei Popescu31002712010-02-23 13:46:05 +000053 // A utility class to introduce a scope where the virtual frame is
Steve Block6ded16b2010-05-10 14:33:55 +010054 // expected to remain spilled. The constructor spills the code
Steve Block44f0eee2011-05-26 01:26:41 +010055 // generator's current frame, and keeps it spilled.
Andrei Popescu31002712010-02-23 13:46:05 +000056 class SpilledScope BASE_EMBEDDED {
57 public:
Steve Block44f0eee2011-05-26 01:26:41 +010058 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
Andrei Popescu31002712010-02-23 13:46:05 +000081 SpilledScope() {}
Steve Block44f0eee2011-05-26 01:26:41 +010082
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() {}
Andrei Popescu31002712010-02-23 13:46:05 +0000100 };
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.
Steve Block6ded16b2010-05-10 14:33:55 +0100106 inline VirtualFrame();
Andrei Popescu31002712010-02-23 13:46:05 +0000107
Steve Block44f0eee2011-05-26 01:26:41 +0100108 // Construct an invalid virtual frame, used by JumpTargets.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100109 explicit inline VirtualFrame(InvalidVirtualFrameInitializer* dummy);
Steve Block44f0eee2011-05-26 01:26:41 +0100110
Andrei Popescu31002712010-02-23 13:46:05 +0000111 // Construct a virtual frame as a clone of an existing one.
Steve Block6ded16b2010-05-10 14:33:55 +0100112 explicit inline VirtualFrame(VirtualFrame* original);
Andrei Popescu31002712010-02-23 13:46:05 +0000113
Steve Block44f0eee2011-05-26 01:26:41 +0100114 inline CodeGenerator* cgen() const;
115 inline MacroAssembler* masm();
Andrei Popescu31002712010-02-23 13:46:05 +0000116
117 // The number of elements on the virtual frame.
Steve Block44f0eee2011-05-26 01:26:41 +0100118 int element_count() const { return element_count_; }
Andrei Popescu31002712010-02-23 13:46:05 +0000119
120 // The height of the virtual expression stack.
Steve Block44f0eee2011-05-26 01:26:41 +0100121 inline int height() const;
Andrei Popescu31002712010-02-23 13:46:05 +0000122
123 bool is_used(int num) {
Steve Block44f0eee2011-05-26 01:26:41 +0100124 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 }
Andrei Popescu31002712010-02-23 13:46:05 +0000151 }
152
153 // Add extra in-memory elements to the top of the frame to match an actual
Steve Block6ded16b2010-05-10 14:33:55 +0100154 // frame (eg, the frame after an exception handler is pushed). No code is
Andrei Popescu31002712010-02-23 13:46:05 +0000155 // emitted.
156 void Adjust(int count);
157
158 // Forget elements from the top of the frame to match an actual frame (eg,
Steve Block44f0eee2011-05-26 01:26:41 +0100159 // 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);
Andrei Popescu31002712010-02-23 13:46:05 +0000162
Andrei Popescu31002712010-02-23 13:46:05 +0000163
164 // Spill all values from the frame to memory.
165 void SpillAll();
166
Steve Block44f0eee2011-05-26 01:26:41 +0100167 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
Andrei Popescu31002712010-02-23 13:46:05 +0000176 // Spill all occurrences of a specific register from the frame.
177 void Spill(Register reg) {
Steve Block44f0eee2011-05-26 01:26:41 +0100178 UNIMPLEMENTED();
Andrei Popescu31002712010-02-23 13:46:05 +0000179 }
180
Steve Block6ded16b2010-05-10 14:33:55 +0100181 // Spill all occurrences of an arbitrary register if possible. Return the
Andrei Popescu31002712010-02-23 13:46:05 +0000182 // register spilled or no_reg if it was not possible to free any register
Steve Block44f0eee2011-05-26 01:26:41 +0100183 // (ie, they all have frame-external references). Unimplemented.
Andrei Popescu31002712010-02-23 13:46:05 +0000184 Register SpillAnyRegister();
185
Andrei Popescu31002712010-02-23 13:46:05 +0000186 // Make this virtual frame have a state identical to an expected virtual
Steve Block6ded16b2010-05-10 14:33:55 +0100187 // frame. As a side effect, code may be emitted to make this frame match
Andrei Popescu31002712010-02-23 13:46:05 +0000188 // the expected one.
Steve Block44f0eee2011-05-26 01:26:41 +0100189 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 }
Andrei Popescu31002712010-02-23 13:46:05 +0000207
Steve Block6ded16b2010-05-10 14:33:55 +0100208 // Detach a frame from its code generator, perhaps temporarily. This
Andrei Popescu31002712010-02-23 13:46:05 +0000209 // tells the register allocator that it is free to use frame-internal
Steve Block6ded16b2010-05-10 14:33:55 +0100210 // registers. Used when the code generator's frame is switched from this
Andrei Popescu31002712010-02-23 13:46:05 +0000211 // one to NULL by an unconditional jump.
212 void DetachFromCodeGenerator() {
Andrei Popescu31002712010-02-23 13:46:05 +0000213 }
214
Steve Block6ded16b2010-05-10 14:33:55 +0100215 // (Re)attach a frame to its code generator. This informs the register
Andrei Popescu31002712010-02-23 13:46:05 +0000216 // 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() {
Andrei Popescu31002712010-02-23 13:46:05 +0000220 }
221
Steve Block6ded16b2010-05-10 14:33:55 +0100222 // Emit code for the physical JS entry and exit frame sequences. After
Andrei Popescu31002712010-02-23 13:46:05 +0000223 // calling Enter, the virtual frame is ready for use; and after calling
Steve Block6ded16b2010-05-10 14:33:55 +0100224 // Exit it should not be used. Note that Enter does not allocate space in
Andrei Popescu31002712010-02-23 13:46:05 +0000225 // the physical frame for storing frame-allocated locals.
226 void Enter();
227 void Exit();
228
Steve Block44f0eee2011-05-26 01:26:41 +0100229 // 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;
Andrei Popescu31002712010-02-23 13:46:05 +0000236
237 // Allocate and initialize the frame-allocated locals.
238 void AllocateStackSlots();
239
240 // The current top of the expression stack as an assembly operand.
Steve Block44f0eee2011-05-26 01:26:41 +0100241 MemOperand Top() {
242 AssertIsSpilled();
243 return MemOperand(sp, 0);
244 }
Andrei Popescu31002712010-02-23 13:46:05 +0000245
246 // An element of the expression stack as an assembly operand.
247 MemOperand ElementAt(int index) {
Steve Block44f0eee2011-05-26 01:26:41 +0100248 int adjusted_index = index - kVirtualElements[top_of_stack_state_];
249 ASSERT(adjusted_index >= 0);
250 return MemOperand(sp, adjusted_index * kPointerSize);
Andrei Popescu31002712010-02-23 13:46:05 +0000251 }
252
Steve Block44f0eee2011-05-26 01:26:41 +0100253 bool KnownSmiAt(int index) {
254 if (index >= kTOSKnownSmiMapSize) return false;
255 return (tos_known_smi_map_ & (1 << index)) != 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000256 }
Andrei Popescu31002712010-02-23 13:46:05 +0000257 // A frame-allocated local as an assembly operand.
Steve Block44f0eee2011-05-26 01:26:41 +0100258 inline MemOperand LocalAt(int index);
Andrei Popescu31002712010-02-23 13:46:05 +0000259
260 // Push the address of the receiver slot on the frame.
261 void PushReceiverSlotAddress();
262
263 // The function frame slot.
Steve Block44f0eee2011-05-26 01:26:41 +0100264 MemOperand Function() { return MemOperand(fp, kFunctionOffset); }
Andrei Popescu31002712010-02-23 13:46:05 +0000265
266 // The context frame slot.
Steve Block44f0eee2011-05-26 01:26:41 +0100267 MemOperand Context() { return MemOperand(fp, kContextOffset); }
Andrei Popescu31002712010-02-23 13:46:05 +0000268
269 // A parameter as an assembly operand.
Steve Block44f0eee2011-05-26 01:26:41 +0100270 inline MemOperand ParameterAt(int index);
Andrei Popescu31002712010-02-23 13:46:05 +0000271
272 // The receiver frame slot.
Steve Block44f0eee2011-05-26 01:26:41 +0100273 inline MemOperand Receiver();
Andrei Popescu31002712010-02-23 13:46:05 +0000274
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.
Steve Block44f0eee2011-05-26 01:26:41 +0100280 inline void CallStub(CodeStub* stub, int arg_count);
Andrei Popescu31002712010-02-23 13:46:05 +0000281
Steve Block44f0eee2011-05-26 01:26:41 +0100282 // Call JS function from top of the stack with arguments
283 // taken from the stack.
284 void CallJSFunction(int arg_count);
Andrei Popescu31002712010-02-23 13:46:05 +0000285
286 // Call runtime given the number of arguments expected on (and
287 // removed from) the stack.
Steve Block44f0eee2011-05-26 01:26:41 +0100288 void CallRuntime(const Runtime::Function* f, int arg_count);
Andrei Popescu31002712010-02-23 13:46:05 +0000289 void CallRuntime(Runtime::FunctionId id, int arg_count);
290
Steve Block44f0eee2011-05-26 01:26:41 +0100291#ifdef ENABLE_DEBUGGER_SUPPORT
292 void DebugBreak();
293#endif
Andrei Popescu31002712010-02-23 13:46:05 +0000294
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,
Andrei Popescu31002712010-02-23 13:46:05 +0000299 int arg_count);
300
Steve Block44f0eee2011-05-26 01:26:41 +0100301 // 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
Andrei Popescu31002712010-02-23 13:46:05 +0000318 // Call into an IC stub given the number of arguments it removes
Steve Block44f0eee2011-05-26 01:26:41 +0100319 // from the stack. Register arguments to the IC stub are implicit,
320 // and depend on the type of IC stub.
Andrei Popescu31002712010-02-23 13:46:05 +0000321 void CallCodeObject(Handle<Code> ic,
322 RelocInfo::Mode rmode,
323 int dropped_args);
Andrei Popescu31002712010-02-23 13:46:05 +0000324
Steve Block6ded16b2010-05-10 14:33:55 +0100325 // 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
Andrei Popescu31002712010-02-23 13:46:05 +0000327 // excepting possibly the stack pointer.
328 void Drop(int count);
Andrei Popescu31002712010-02-23 13:46:05 +0000329
330 // Drop one element.
331 void Drop() { Drop(1); }
Andrei Popescu31002712010-02-23 13:46:05 +0000332
Steve Block44f0eee2011-05-26 01:26:41 +0100333 // Pop an element from the top of the expression stack. Discards
334 // the result.
335 void Pop();
Andrei Popescu31002712010-02-23 13:46:05 +0000336
Steve Block44f0eee2011-05-26 01:26:41 +0100337 // 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();
Andrei Popescu31002712010-02-23 13:46:05 +0000365
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
Steve Block6ded16b2010-05-10 14:33:55 +0100370 void EmitMultiPop(RegList regs);
371 void EmitMultiPopReversed(RegList regs);
Andrei Popescu31002712010-02-23 13:46:05 +0000372
Steve Block44f0eee2011-05-26 01:26:41 +0100373
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
Andrei Popescu31002712010-02-23 13:46:05 +0000384 // Push an element on top of the expression stack and emit a
385 // corresponding push instruction.
Steve Block44f0eee2011-05-26 01:26:41 +0100386 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
Andrei Popescu31002712010-02-23 13:46:05 +0000401 // Same but for multiple registers.
Steve Block6ded16b2010-05-10 14:33:55 +0100402 void EmitMultiPush(RegList regs);
403 void EmitMultiPushReversed(RegList regs);
Andrei Popescu31002712010-02-23 13:46:05 +0000404
Steve Block44f0eee2011-05-26 01:26:41 +0100405 static Register scratch0() { return t4; }
406 static Register scratch1() { return t5; }
407 static Register scratch2() { return t6; }
Steve Block6ded16b2010-05-10 14:33:55 +0100408
Andrei Popescu31002712010-02-23 13:46:05 +0000409 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
Steve Block44f0eee2011-05-26 01:26:41 +0100417 // 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;
Andrei Popescu31002712010-02-23 13:46:05 +0000448
449 // The index of the element that is at the processor's stack pointer
Steve Block44f0eee2011-05-26 01:26:41 +0100450 // (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; }
Andrei Popescu31002712010-02-23 13:46:05 +0000453
454 // The number of frame-allocated locals and parameters respectively.
Steve Block44f0eee2011-05-26 01:26:41 +0100455 inline int parameter_count() const;
456 inline int local_count() const;
Andrei Popescu31002712010-02-23 13:46:05 +0000457
458 // The index of the element that is at the processor's frame pointer
Steve Block6ded16b2010-05-10 14:33:55 +0100459 // (the fp register). The parameters, receiver, function, and context
Andrei Popescu31002712010-02-23 13:46:05 +0000460 // are below the frame pointer.
Steve Block44f0eee2011-05-26 01:26:41 +0100461 inline int frame_pointer() const;
Andrei Popescu31002712010-02-23 13:46:05 +0000462
Steve Block6ded16b2010-05-10 14:33:55 +0100463 // The index of the first parameter. The receiver lies below the first
Andrei Popescu31002712010-02-23 13:46:05 +0000464 // parameter.
465 int param0_index() { return 1; }
466
Steve Block6ded16b2010-05-10 14:33:55 +0100467 // The index of the context slot in the frame. It is immediately
Andrei Popescu31002712010-02-23 13:46:05 +0000468 // below the frame pointer.
Steve Block44f0eee2011-05-26 01:26:41 +0100469 inline int context_index();
Andrei Popescu31002712010-02-23 13:46:05 +0000470
Steve Block6ded16b2010-05-10 14:33:55 +0100471 // The index of the function slot in the frame. It is below the frame
Andrei Popescu31002712010-02-23 13:46:05 +0000472 // pointer and context slot.
Steve Block44f0eee2011-05-26 01:26:41 +0100473 inline int function_index();
Andrei Popescu31002712010-02-23 13:46:05 +0000474
Steve Block6ded16b2010-05-10 14:33:55 +0100475 // The index of the first local. Between the frame pointer and the
Andrei Popescu31002712010-02-23 13:46:05 +0000476 // locals lies the return address.
Steve Block44f0eee2011-05-26 01:26:41 +0100477 inline int local0_index() const;
Andrei Popescu31002712010-02-23 13:46:05 +0000478
479 // The index of the base of the expression stack.
Steve Block44f0eee2011-05-26 01:26:41 +0100480 inline int expression_base_index() const;
Andrei Popescu31002712010-02-23 13:46:05 +0000481
482 // Convert a frame index into a frame pointer relative offset into the
483 // actual stack.
Steve Block44f0eee2011-05-26 01:26:41 +0100484 inline int fp_relative(int index);
Andrei Popescu31002712010-02-23 13:46:05 +0000485
486 // Spill all elements in registers. Spill the top spilled_args elements
Steve Block6ded16b2010-05-10 14:33:55 +0100487 // on the frame. Sync all other frame elements.
Andrei Popescu31002712010-02-23 13:46:05 +0000488 // 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
Steve Block44f0eee2011-05-26 01:26:41 +0100492 // 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();
Andrei Popescu31002712010-02-23 13:46:05 +0000495
Steve Block44f0eee2011-05-26 01:26:41 +0100496 // 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));
Andrei Popescu31002712010-02-23 13:46:05 +0000502
Steve Block44f0eee2011-05-26 01:26:41 +0100503 inline bool Equals(const VirtualFrame* other);
Andrei Popescu31002712010-02-23 13:46:05 +0000504
Steve Block44f0eee2011-05-26 01:26:41 +0100505 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 }
Andrei Popescu31002712010-02-23 13:46:05 +0000513
Steve Block44f0eee2011-05-26 01:26:41 +0100514 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 }
Andrei Popescu31002712010-02-23 13:46:05 +0000523 friend class JumpTarget;
524};
525
526
527} } // namespace v8::internal
528
529#endif // V8_MIPS_VIRTUAL_FRAME_MIPS_H_
530