1
// Copyright 2009 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
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.
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.
28
#ifndef V8_ARM_VIRTUAL_FRAME_ARM_H_
29
#define V8_ARM_VIRTUAL_FRAME_ARM_H_
31
#include "register-allocator.h"
36
// This dummy class is only used to create invalid virtual frames.
37
extern class InvalidVirtualFrameInitializer {}* kInvalidVirtualFrameInitializer;
40
// -------------------------------------------------------------------------
43
// The virtual frame is an abstraction of the physical stack frame. It
44
// encapsulates the parameters, frame-allocated locals, and the expression
45
// stack. It supports push/pop operations on the expression stack, as well
46
// as random access to the expression stack elements, locals, and
49
class VirtualFrame : public ZoneObject {
51
class RegisterAllocationScope;
52
// A utility class to introduce a scope where the virtual frame is
53
// expected to remain spilled. The constructor spills the code
54
// generator's current frame, and keeps it spilled.
55
class SpilledScope BASE_EMBEDDED {
57
explicit SpilledScope(VirtualFrame* frame)
58
: old_is_spilled_(is_spilled_) {
63
frame->AssertIsSpilled();
69
is_spilled_ = old_is_spilled_;
71
static bool is_spilled() { return is_spilled_; }
74
static bool is_spilled_;
79
friend class RegisterAllocationScope;
82
class RegisterAllocationScope BASE_EMBEDDED {
84
// A utility class to introduce a scope where the virtual frame
85
// is not spilled, ie. where register allocation occurs. Eventually
86
// when RegisterAllocationScope is ubiquitous it can be removed
87
// along with the (by then unused) SpilledScope class.
88
inline explicit RegisterAllocationScope(CodeGenerator* cgen);
89
inline ~RegisterAllocationScope();
95
RegisterAllocationScope() { }
98
// An illegal index into the virtual frame.
99
static const int kIllegalIndex = -1;
101
// Construct an initial virtual frame on entry to a JS function.
102
inline VirtualFrame();
104
// Construct an invalid virtual frame, used by JumpTargets.
105
inline VirtualFrame(InvalidVirtualFrameInitializer* dummy);
107
// Construct a virtual frame as a clone of an existing one.
108
explicit inline VirtualFrame(VirtualFrame* original);
110
inline CodeGenerator* cgen() const;
111
inline MacroAssembler* masm();
113
// The number of elements on the virtual frame.
114
int element_count() const { return element_count_; }
116
// The height of the virtual expression stack.
117
inline int height() const;
119
bool is_used(int num) {
122
return kR0InUse[top_of_stack_state_];
125
return kR1InUse[top_of_stack_state_];
131
case 6: { // r2 to r6.
132
ASSERT(num - kFirstAllocatedRegister < kNumberOfAllocatedRegisters);
133
ASSERT(num >= kFirstAllocatedRegister);
134
if ((register_allocation_map_ &
135
(1 << (num - kFirstAllocatedRegister))) == 0) {
142
ASSERT(num < kFirstAllocatedRegister ||
143
num >= kFirstAllocatedRegister + kNumberOfAllocatedRegisters);
149
// Add extra in-memory elements to the top of the frame to match an actual
150
// frame (eg, the frame after an exception handler is pushed). No code is
152
void Adjust(int count);
154
// Forget elements from the top of the frame to match an actual frame (eg,
155
// the frame after a runtime call). No code is emitted except to bring the
156
// frame to a spilled state.
157
void Forget(int count);
159
// Spill all values from the frame to memory.
162
void AssertIsSpilled() const {
163
ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
164
ASSERT(register_allocation_map_ == 0);
167
void AssertIsNotSpilled() {
168
ASSERT(!SpilledScope::is_spilled());
171
// Spill all occurrences of a specific register from the frame.
172
void Spill(Register reg) {
176
// Spill all occurrences of an arbitrary register if possible. Return the
177
// register spilled or no_reg if it was not possible to free any register
178
// (ie, they all have frame-external references). Unimplemented.
179
Register SpillAnyRegister();
181
// Make this virtual frame have a state identical to an expected virtual
182
// frame. As a side effect, code may be emitted to make this frame match
184
void MergeTo(VirtualFrame* expected, Condition cond = al);
185
void MergeTo(const VirtualFrame* expected, Condition cond = al);
187
// Checks whether this frame can be branched to by the other frame.
188
bool IsCompatibleWith(const VirtualFrame* other) const {
189
return (tos_known_smi_map_ & (~other->tos_known_smi_map_)) == 0;
192
inline void ForgetTypeInfo() {
193
tos_known_smi_map_ = 0;
196
// Detach a frame from its code generator, perhaps temporarily. This
197
// tells the register allocator that it is free to use frame-internal
198
// registers. Used when the code generator's frame is switched from this
199
// one to NULL by an unconditional jump.
200
void DetachFromCodeGenerator() {
203
// (Re)attach a frame to its code generator. This informs the register
204
// allocator that the frame-internal register references are active again.
205
// Used when a code generator's frame is switched from NULL to this one by
207
void AttachToCodeGenerator() {
210
// Emit code for the physical JS entry and exit frame sequences. After
211
// calling Enter, the virtual frame is ready for use; and after calling
212
// Exit it should not be used. Note that Enter does not allocate space in
213
// the physical frame for storing frame-allocated locals.
217
// Prepare for returning from the frame by elements in the virtual frame. This
218
// avoids generating unnecessary merge code when jumping to the
219
// shared return site. No spill code emitted. Value to return should be in r0.
220
inline void PrepareForReturn();
222
// Number of local variables after when we use a loop for allocating.
223
static const int kLocalVarBound = 5;
225
// Allocate and initialize the frame-allocated locals.
226
void AllocateStackSlots();
228
// The current top of the expression stack as an assembly operand.
231
return MemOperand(sp, 0);
234
// An element of the expression stack as an assembly operand.
235
MemOperand ElementAt(int index) {
236
int adjusted_index = index - kVirtualElements[top_of_stack_state_];
237
ASSERT(adjusted_index >= 0);
238
return MemOperand(sp, adjusted_index * kPointerSize);
241
bool KnownSmiAt(int index) {
242
if (index >= kTOSKnownSmiMapSize) return false;
243
return (tos_known_smi_map_ & (1 << index)) != 0;
246
// A frame-allocated local as an assembly operand.
247
inline MemOperand LocalAt(int index);
249
// Push the address of the receiver slot on the frame.
250
void PushReceiverSlotAddress();
252
// The function frame slot.
253
MemOperand Function() { return MemOperand(fp, kFunctionOffset); }
255
// The context frame slot.
256
MemOperand Context() { return MemOperand(fp, kContextOffset); }
258
// A parameter as an assembly operand.
259
inline MemOperand ParameterAt(int index);
261
// The receiver frame slot.
262
inline MemOperand Receiver();
264
// Push a try-catch or try-finally handler on top of the virtual frame.
265
void PushTryHandler(HandlerType type);
267
// Call stub given the number of arguments it expects on (and
268
// removes from) the stack.
269
inline void CallStub(CodeStub* stub, int arg_count);
271
// Call JS function from top of the stack with arguments
272
// taken from the stack.
273
void CallJSFunction(int arg_count);
275
// Call runtime given the number of arguments expected on (and
276
// removed from) the stack.
277
void CallRuntime(Runtime::Function* f, int arg_count);
278
void CallRuntime(Runtime::FunctionId id, int arg_count);
280
#ifdef ENABLE_DEBUGGER_SUPPORT
284
// Invoke builtin given the number of arguments it expects on (and
285
// removes from) the stack.
286
void InvokeBuiltin(Builtins::JavaScript id,
290
// Call load IC. Receiver is on the stack and is consumed. Result is returned
292
void CallLoadIC(Handle<String> name, RelocInfo::Mode mode);
294
// Call store IC. If the load is contextual, value is found on top of the
295
// frame. If not, value and receiver are on the frame. Both are consumed.
296
// Result is returned in r0.
297
void CallStoreIC(Handle<String> name, bool is_contextual,
298
StrictModeFlag strict_mode);
300
// Call keyed load IC. Key and receiver are on the stack. Both are consumed.
301
// Result is returned in r0.
302
void CallKeyedLoadIC();
304
// Call keyed store IC. Value, key and receiver are on the stack. All three
305
// are consumed. Result is returned in r0.
306
void CallKeyedStoreIC(StrictModeFlag strict_mode);
308
// Call into an IC stub given the number of arguments it removes
309
// from the stack. Register arguments to the IC stub are implicit,
310
// and depend on the type of IC stub.
311
void CallCodeObject(Handle<Code> ic,
312
RelocInfo::Mode rmode,
315
// Drop a number of elements from the top of the expression stack. May
316
// emit code to affect the physical frame. Does not clobber any registers
317
// excepting possibly the stack pointer.
318
void Drop(int count);
321
void Drop() { Drop(1); }
323
// Pop an element from the top of the expression stack. Discards
327
// Pop an element from the top of the expression stack. The register
328
// will be one normally used for the top of stack register allocation
329
// so you can't hold on to it if you push on the stack.
330
Register PopToRegister(Register but_not_to_this_one = no_reg);
332
// Look at the top of the stack. The register returned is aliased and
333
// must be copied to a scratch register before modification.
336
// Look at the value beneath the top of the stack. The register returned is
337
// aliased and must be copied to a scratch register before modification.
340
// Duplicate the top of stack.
343
// Duplicate the two elements on top of stack.
346
// Flushes all registers, but it puts a copy of the top-of-stack in r0.
347
void SpillAllButCopyTOSToR0();
349
// Flushes all registers, but it puts a copy of the top-of-stack in r1.
350
void SpillAllButCopyTOSToR1();
352
// Flushes all registers, but it puts a copy of the top-of-stack in r1
353
// and the next value on the stack in r0.
354
void SpillAllButCopyTOSToR1R0();
356
// Pop and save an element from the top of the expression stack and
357
// emit a corresponding pop instruction.
358
void EmitPop(Register reg);
360
// Takes the top two elements and puts them in r0 (top element) and r1
364
// Takes the top element and puts it in r1.
367
// Takes the top element and puts it in r0.
370
// Push an element on top of the expression stack and emit a
371
// corresponding push instruction.
372
void EmitPush(Register reg, TypeInfo type_info = TypeInfo::Unknown());
373
void EmitPush(Operand operand, TypeInfo type_info = TypeInfo::Unknown());
374
void EmitPush(MemOperand operand, TypeInfo type_info = TypeInfo::Unknown());
375
void EmitPushRoot(Heap::RootListIndex index);
377
// Overwrite the nth thing on the stack. If the nth position is in a
378
// register then this turns into a mov, otherwise an str. Afterwards
379
// you can still use the register even if it is a register that can be
380
// used for TOS (r0 or r1).
381
void SetElementAt(Register reg, int this_far_down);
383
// Get a register which is free and which must be immediately used to
384
// push on the top of the stack.
385
Register GetTOSRegister();
387
// Push multiple registers on the stack and the virtual frame
388
// Register are selected by setting bit in src_regs and
389
// are pushed in decreasing order: r15 .. r0.
390
void EmitPushMultiple(int count, int src_regs);
392
static Register scratch0() { return r7; }
393
static Register scratch1() { return r9; }
396
static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
397
static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
398
static const int kContextOffset = StandardFrameConstants::kContextOffset;
400
static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
401
static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots.
403
// 5 states for the top of stack, which can be in memory or in r0 and r1.
413
static const int kMaxTOSRegisters = 2;
415
static const bool kR0InUse[TOS_STATES];
416
static const bool kR1InUse[TOS_STATES];
417
static const int kVirtualElements[TOS_STATES];
418
static const TopOfStack kStateAfterPop[TOS_STATES];
419
static const TopOfStack kStateAfterPush[TOS_STATES];
420
static const Register kTopRegister[TOS_STATES];
421
static const Register kBottomRegister[TOS_STATES];
423
// We allocate up to 5 locals in registers.
424
static const int kNumberOfAllocatedRegisters = 5;
425
// r2 to r6 are allocated to locals.
426
static const int kFirstAllocatedRegister = 2;
428
static const Register kAllocatedRegisters[kNumberOfAllocatedRegisters];
430
static Register AllocatedRegister(int r) {
431
ASSERT(r >= 0 && r < kNumberOfAllocatedRegisters);
432
return kAllocatedRegisters[r];
435
// The number of elements on the stack frame.
437
TopOfStack top_of_stack_state_:3;
438
int register_allocation_map_:kNumberOfAllocatedRegisters;
439
static const int kTOSKnownSmiMapSize = 4;
440
unsigned tos_known_smi_map_:kTOSKnownSmiMapSize;
442
// The index of the element that is at the processor's stack pointer
443
// (the sp register). For now since everything is in memory it is given
444
// by the number of elements on the not-very-virtual stack frame.
445
int stack_pointer() { return element_count_ - 1; }
447
// The number of frame-allocated locals and parameters respectively.
448
inline int parameter_count() const;
449
inline int local_count() const;
451
// The index of the element that is at the processor's frame pointer
452
// (the fp register). The parameters, receiver, function, and context
453
// are below the frame pointer.
454
inline int frame_pointer() const;
456
// The index of the first parameter. The receiver lies below the first
458
int param0_index() { return 1; }
460
// The index of the context slot in the frame. It is immediately
461
// below the frame pointer.
462
inline int context_index();
464
// The index of the function slot in the frame. It is below the frame
465
// pointer and context slot.
466
inline int function_index();
468
// The index of the first local. Between the frame pointer and the
469
// locals lies the return address.
470
inline int local0_index() const;
472
// The index of the base of the expression stack.
473
inline int expression_base_index() const;
475
// Convert a frame index into a frame pointer relative offset into the
477
inline int fp_relative(int index);
479
// Spill all elements in registers. Spill the top spilled_args elements
480
// on the frame. Sync all other frame elements.
481
// Then drop dropped_args elements from the virtual frame, to match
482
// the effect of an upcoming call that will drop them from the stack.
483
void PrepareForCall(int spilled_args, int dropped_args);
485
// If all top-of-stack registers are in use then the lowest one is pushed
486
// onto the physical stack and made free.
487
void EnsureOneFreeTOSRegister();
489
// Emit instructions to get the top of stack state from where we are to where
491
void MergeTOSTo(TopOfStack expected_state, Condition cond = al);
493
inline bool Equals(const VirtualFrame* other);
495
inline void LowerHeight(int count) {
496
element_count_ -= count;
497
if (count >= kTOSKnownSmiMapSize) {
498
tos_known_smi_map_ = 0;
500
tos_known_smi_map_ >>= count;
504
inline void RaiseHeight(int count, unsigned known_smi_map = 0) {
505
ASSERT(count >= 32 || known_smi_map < (1u << count));
506
element_count_ += count;
507
if (count >= kTOSKnownSmiMapSize) {
508
tos_known_smi_map_ = known_smi_map;
510
tos_known_smi_map_ = ((tos_known_smi_map_ << count) | known_smi_map);
514
friend class JumpTarget;
518
} } // namespace v8::internal
520
#endif // V8_ARM_VIRTUAL_FRAME_ARM_H_