Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: src/mips/virtual-frame-mips.h

Issue 6709022: Re-establish mips basic infrastructure. (Closed) Base URL: git://github.com/v8/v8.git@master
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 12 matching lines...) Expand all
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 28
29 #ifndef V8_MIPS_VIRTUAL_FRAME_MIPS_H_ 29 #ifndef V8_MIPS_VIRTUAL_FRAME_MIPS_H_
30 #define V8_MIPS_VIRTUAL_FRAME_MIPS_H_ 30 #define V8_MIPS_VIRTUAL_FRAME_MIPS_H_
31 31
32 #include "register-allocator.h" 32 #include "register-allocator.h"
33 #include "scopes.h"
34 33
35 namespace v8 { 34 namespace v8 {
36 namespace internal { 35 namespace internal {
37 36
37 // This dummy class is only used to create invalid virtual frames.
38 extern class InvalidVirtualFrameInitializer {}* kInvalidVirtualFrameInitializer;
39
38 40
39 // ------------------------------------------------------------------------- 41 // -------------------------------------------------------------------------
40 // Virtual frames 42 // Virtual frames
41 // 43 //
42 // The virtual frame is an abstraction of the physical stack frame. It 44 // The virtual frame is an abstraction of the physical stack frame. It
43 // encapsulates the parameters, frame-allocated locals, and the expression 45 // encapsulates the parameters, frame-allocated locals, and the expression
44 // stack. It supports push/pop operations on the expression stack, as well 46 // stack. It supports push/pop operations on the expression stack, as well
45 // as random access to the expression stack elements, locals, and 47 // as random access to the expression stack elements, locals, and
46 // parameters. 48 // parameters.
47 49
48 class VirtualFrame : public ZoneObject { 50 class VirtualFrame : public ZoneObject {
49 public: 51 public:
52 class RegisterAllocationScope;
50 // A utility class to introduce a scope where the virtual frame is 53 // A utility class to introduce a scope where the virtual frame is
51 // expected to remain spilled. The constructor spills the code 54 // expected to remain spilled. The constructor spills the code
52 // generator's current frame, but no attempt is made to require it 55 // generator's current frame, and keeps it spilled.
53 // to stay spilled. It is intended as documentation while the code
54 // generator is being transformed.
55 class SpilledScope BASE_EMBEDDED { 56 class SpilledScope BASE_EMBEDDED {
56 public: 57 public:
58 explicit SpilledScope(VirtualFrame* frame)
59 : old_is_spilled_(is_spilled_) {
60 if (frame != NULL) {
61 if (!is_spilled_) {
62 frame->SpillAll();
63 } else {
64 frame->AssertIsSpilled();
65 }
66 }
67 is_spilled_ = true;
68 }
69 ~SpilledScope() {
70 is_spilled_ = old_is_spilled_;
71 }
72 static bool is_spilled() { return is_spilled_; }
73
74 private:
75 static bool is_spilled_;
76 int old_is_spilled_;
77
57 SpilledScope() {} 78 SpilledScope() {}
79
80 friend class RegisterAllocationScope;
81 };
82
83 class RegisterAllocationScope BASE_EMBEDDED {
84 public:
85 // A utility class to introduce a scope where the virtual frame
86 // is not spilled, ie. where register allocation occurs. Eventually
87 // when RegisterAllocationScope is ubiquitous it can be removed
88 // along with the (by then unused) SpilledScope class.
89 inline explicit RegisterAllocationScope(CodeGenerator* cgen);
90 inline ~RegisterAllocationScope();
91
92 private:
93 CodeGenerator* cgen_;
94 bool old_is_spilled_;
95
96 RegisterAllocationScope() {}
58 }; 97 };
59 98
60 // An illegal index into the virtual frame. 99 // An illegal index into the virtual frame.
61 static const int kIllegalIndex = -1; 100 static const int kIllegalIndex = -1;
62 101
63 // Construct an initial virtual frame on entry to a JS function. 102 // Construct an initial virtual frame on entry to a JS function.
64 inline VirtualFrame(); 103 inline VirtualFrame();
65 104
105 // Construct an invalid virtual frame, used by JumpTargets.
106 inline VirtualFrame(InvalidVirtualFrameInitializer* dummy);
107
66 // Construct a virtual frame as a clone of an existing one. 108 // Construct a virtual frame as a clone of an existing one.
67 explicit inline VirtualFrame(VirtualFrame* original); 109 explicit inline VirtualFrame(VirtualFrame* original);
68 110
69 CodeGenerator* cgen() { return CodeGeneratorScope::Current(); } 111 inline CodeGenerator* cgen() const;
70 MacroAssembler* masm() { return cgen()->masm(); } 112 inline MacroAssembler* masm();
71
72 // Create a duplicate of an existing valid frame element.
73 FrameElement CopyElementAt(int index,
74 NumberInfo info = NumberInfo::Unknown());
75 113
76 // The number of elements on the virtual frame. 114 // The number of elements on the virtual frame.
77 int element_count() { return elements_.length(); } 115 int element_count() const { return element_count_; }
78 116
79 // The height of the virtual expression stack. 117 // The height of the virtual expression stack.
80 int height() { 118 inline int height() const;
81 return element_count() - expression_base_index();
82 }
83
84 int register_location(int num) {
85 ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
86 return register_locations_[num];
87 }
88
89 int register_location(Register reg) {
90 return register_locations_[RegisterAllocator::ToNumber(reg)];
91 }
92
93 void set_register_location(Register reg, int index) {
94 register_locations_[RegisterAllocator::ToNumber(reg)] = index;
95 }
96 119
97 bool is_used(int num) { 120 bool is_used(int num) {
98 ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters); 121 switch (num) {
99 return register_locations_[num] != kIllegalIndex; 122 case 0: { // a0.
100 } 123 return kA0InUse[top_of_stack_state_];
101 124 }
102 bool is_used(Register reg) { 125 case 1: { // a1.
103 return register_locations_[RegisterAllocator::ToNumber(reg)] 126 return kA1InUse[top_of_stack_state_];
104 != kIllegalIndex; 127 }
128 case 2:
129 case 3:
130 case 4:
131 case 5:
132 case 6: { // a2 to a3, t0 to t2.
133 ASSERT(num - kFirstAllocatedRegister < kNumberOfAllocatedRegisters);
134 ASSERT(num >= kFirstAllocatedRegister);
135 if ((register_allocation_map_ &
136 (1 << (num - kFirstAllocatedRegister))) == 0) {
137 return false;
138 } else {
139 return true;
140 }
141 }
142 default: {
143 ASSERT(num < kFirstAllocatedRegister ||
144 num >= kFirstAllocatedRegister + kNumberOfAllocatedRegisters);
145 return false;
146 }
147 }
105 } 148 }
106 149
107 // Add extra in-memory elements to the top of the frame to match an actual 150 // Add extra in-memory elements to the top of the frame to match an actual
108 // frame (eg, the frame after an exception handler is pushed). No code is 151 // frame (eg, the frame after an exception handler is pushed). No code is
109 // emitted. 152 // emitted.
110 void Adjust(int count); 153 void Adjust(int count);
111 154
112 // Forget elements from the top of the frame to match an actual frame (eg, 155 // Forget elements from the top of the frame to match an actual frame (eg,
113 // the frame after a runtime call). No code is emitted. 156 // the frame after a runtime call). No code is emitted except to bring the
114 void Forget(int count) { 157 // frame to a spilled state.
115 ASSERT(count >= 0); 158 void Forget(int count);
116 ASSERT(stack_pointer_ == element_count() - 1);
117 stack_pointer_ -= count;
118 // On mips, all elements are in memory, so there is no extra bookkeeping
119 // (registers, copies, etc.) beyond dropping the elements.
120 elements_.Rewind(stack_pointer_ + 1);
121 }
122 159
123 // Forget count elements from the top of the frame and adjust the stack
124 // pointer downward. This is used, for example, before merging frames at
125 // break, continue, and return targets.
126 void ForgetElements(int count);
127 160
128 // Spill all values from the frame to memory. 161 // Spill all values from the frame to memory.
129 void SpillAll(); 162 void SpillAll();
130 163
164 void AssertIsSpilled() const {
165 ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
166 ASSERT(register_allocation_map_ == 0);
167 }
168
169 void AssertIsNotSpilled() {
170 ASSERT(!SpilledScope::is_spilled());
171 }
172
131 // Spill all occurrences of a specific register from the frame. 173 // Spill all occurrences of a specific register from the frame.
132 void Spill(Register reg) { 174 void Spill(Register reg) {
133 if (is_used(reg)) SpillElementAt(register_location(reg)); 175 UNIMPLEMENTED();
134 } 176 }
135 177
136 // Spill all occurrences of an arbitrary register if possible. Return the 178 // Spill all occurrences of an arbitrary register if possible. Return the
137 // register spilled or no_reg if it was not possible to free any register 179 // register spilled or no_reg if it was not possible to free any register
138 // (ie, they all have frame-external references). 180 // (ie, they all have frame-external references). Unimplemented.
139 Register SpillAnyRegister(); 181 Register SpillAnyRegister();
140 182
141 // Prepare this virtual frame for merging to an expected frame by
142 // performing some state changes that do not require generating
143 // code. It is guaranteed that no code will be generated.
144 void PrepareMergeTo(VirtualFrame* expected);
145
146 // Make this virtual frame have a state identical to an expected virtual 183 // Make this virtual frame have a state identical to an expected virtual
147 // frame. As a side effect, code may be emitted to make this frame match 184 // frame. As a side effect, code may be emitted to make this frame match
148 // the expected one. 185 // the expected one.
149 void MergeTo(VirtualFrame* expected); 186 void MergeTo(const VirtualFrame* expected,
187 Condition cond = al,
188 Register r1 = no_reg,
189 const Operand& r2 = Operand(no_reg));
190
191 void MergeTo(VirtualFrame* expected,
192 Condition cond = al,
193 Register r1 = no_reg,
194 const Operand& r2 = Operand(no_reg));
195
196 // Checks whether this frame can be branched to by the other frame.
197 bool IsCompatibleWith(const VirtualFrame* other) const {
198 return (tos_known_smi_map_ & (~other->tos_known_smi_map_)) == 0;
199 }
200
201 inline void ForgetTypeInfo() {
202 tos_known_smi_map_ = 0;
203 }
150 204
151 // Detach a frame from its code generator, perhaps temporarily. This 205 // Detach a frame from its code generator, perhaps temporarily. This
152 // tells the register allocator that it is free to use frame-internal 206 // tells the register allocator that it is free to use frame-internal
153 // registers. Used when the code generator's frame is switched from this 207 // registers. Used when the code generator's frame is switched from this
154 // one to NULL by an unconditional jump. 208 // one to NULL by an unconditional jump.
155 void DetachFromCodeGenerator() { 209 void DetachFromCodeGenerator() {
156 RegisterAllocator* cgen_allocator = cgen()->allocator();
157 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
158 if (is_used(i)) cgen_allocator->Unuse(i);
159 }
160 } 210 }
161 211
162 // (Re)attach a frame to its code generator. This informs the register 212 // (Re)attach a frame to its code generator. This informs the register
163 // allocator that the frame-internal register references are active again. 213 // allocator that the frame-internal register references are active again.
164 // Used when a code generator's frame is switched from NULL to this one by 214 // Used when a code generator's frame is switched from NULL to this one by
165 // binding a label. 215 // binding a label.
166 void AttachToCodeGenerator() { 216 void AttachToCodeGenerator() {
167 RegisterAllocator* cgen_allocator = cgen()->allocator();
168 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
169 if (is_used(i)) cgen_allocator->Unuse(i);
170 }
171 } 217 }
172 218
173 // Emit code for the physical JS entry and exit frame sequences. After 219 // Emit code for the physical JS entry and exit frame sequences. After
174 // calling Enter, the virtual frame is ready for use; and after calling 220 // calling Enter, the virtual frame is ready for use; and after calling
175 // Exit it should not be used. Note that Enter does not allocate space in 221 // Exit it should not be used. Note that Enter does not allocate space in
176 // the physical frame for storing frame-allocated locals. 222 // the physical frame for storing frame-allocated locals.
177 void Enter(); 223 void Enter();
178 void Exit(); 224 void Exit();
179 225
180 // Prepare for returning from the frame by spilling locals and 226 // Prepare for returning from the frame by elements in the virtual frame.
181 // dropping all non-locals elements in the virtual frame. This 227 // This avoids generating unnecessary merge code when jumping to the shared
182 // avoids generating unnecessary merge code when jumping to the 228 // return site. No spill code emitted. Value to return should be in v0.
183 // shared return site. Emits code for spills. 229 inline void PrepareForReturn();
184 void PrepareForReturn(); 230
231 // Number of local variables after when we use a loop for allocating.
232 static const int kLocalVarBound = 5;
185 233
186 // Allocate and initialize the frame-allocated locals. 234 // Allocate and initialize the frame-allocated locals.
187 void AllocateStackSlots(); 235 void AllocateStackSlots();
188 236
189 // The current top of the expression stack as an assembly operand. 237 // The current top of the expression stack as an assembly operand.
190 MemOperand Top() { return MemOperand(sp, 0); } 238 MemOperand Top() {
239 AssertIsSpilled();
240 return MemOperand(sp, 0);
241 }
191 242
192 // An element of the expression stack as an assembly operand. 243 // An element of the expression stack as an assembly operand.
193 MemOperand ElementAt(int index) { 244 MemOperand ElementAt(int index) {
194 return MemOperand(sp, index * kPointerSize); 245 int adjusted_index = index - kVirtualElements[top_of_stack_state_];
246 ASSERT(adjusted_index >= 0);
247 return MemOperand(sp, adjusted_index * kPointerSize);
195 } 248 }
196 249
197 // Random-access store to a frame-top relative frame element. The result 250 bool KnownSmiAt(int index) {
198 // becomes owned by the frame and is invalidated. 251 if (index >= kTOSKnownSmiMapSize) return false;
199 void SetElementAt(int index, Result* value); 252 return (tos_known_smi_map_ & (1 << index)) != 0;
200
201 // Set a frame element to a constant. The index is frame-top relative.
202 void SetElementAt(int index, Handle<Object> value) {
203 Result temp(value);
204 SetElementAt(index, &temp);
205 } 253 }
206
207 void PushElementAt(int index) {
208 PushFrameSlotAt(element_count() - index - 1);
209 }
210
211 // A frame-allocated local as an assembly operand. 254 // A frame-allocated local as an assembly operand.
212 MemOperand LocalAt(int index) { 255 inline MemOperand LocalAt(int index);
213 ASSERT(0 <= index);
214 ASSERT(index < local_count());
215 return MemOperand(s8_fp, kLocal0Offset - index * kPointerSize);
216 }
217
218 // Push a copy of the value of a local frame slot on top of the frame.
219 void PushLocalAt(int index) {
220 PushFrameSlotAt(local0_index() + index);
221 }
222
223 // Push the value of a local frame slot on top of the frame and invalidate
224 // the local slot. The slot should be written to before trying to read
225 // from it again.
226 void TakeLocalAt(int index) {
227 TakeFrameSlotAt(local0_index() + index);
228 }
229
230 // Store the top value on the virtual frame into a local frame slot. The
231 // value is left in place on top of the frame.
232 void StoreToLocalAt(int index) {
233 StoreToFrameSlotAt(local0_index() + index);
234 }
235 256
236 // Push the address of the receiver slot on the frame. 257 // Push the address of the receiver slot on the frame.
237 void PushReceiverSlotAddress(); 258 void PushReceiverSlotAddress();
238 259
239 // The function frame slot. 260 // The function frame slot.
240 MemOperand Function() { return MemOperand(s8_fp, kFunctionOffset); } 261 MemOperand Function() { return MemOperand(fp, kFunctionOffset); }
241
242 // Push the function on top of the frame.
243 void PushFunction() { PushFrameSlotAt(function_index()); }
244 262
245 // The context frame slot. 263 // The context frame slot.
246 MemOperand Context() { return MemOperand(s8_fp, kContextOffset); } 264 MemOperand Context() { return MemOperand(fp, kContextOffset); }
247
248 // Save the value of the cp register to the context frame slot.
249 void SaveContextRegister();
250
251 // Restore the cp register from the value of the context frame
252 // slot.
253 void RestoreContextRegister();
254 265
255 // A parameter as an assembly operand. 266 // A parameter as an assembly operand.
256 MemOperand ParameterAt(int index) { 267 inline MemOperand ParameterAt(int index);
257 // Index -1 corresponds to the receiver.
258 ASSERT(-1 <= index); // -1 is the receiver.
259 ASSERT(index <= parameter_count());
260 uint16_t a = 0; // Number of argument slots.
261 return MemOperand(s8_fp, (1 + parameter_count() + a - index) *kPointerSize);
262 }
263
264 // Push a copy of the value of a parameter frame slot on top of the frame.
265 void PushParameterAt(int index) {
266 PushFrameSlotAt(param0_index() + index);
267 }
268
269 // Push the value of a paramter frame slot on top of the frame and
270 // invalidate the parameter slot. The slot should be written to before
271 // trying to read from it again.
272 void TakeParameterAt(int index) {
273 TakeFrameSlotAt(param0_index() + index);
274 }
275
276 // Store the top value on the virtual frame into a parameter frame slot.
277 // The value is left in place on top of the frame.
278 void StoreToParameterAt(int index) {
279 StoreToFrameSlotAt(param0_index() + index);
280 }
281 268
282 // The receiver frame slot. 269 // The receiver frame slot.
283 MemOperand Receiver() { return ParameterAt(-1); } 270 inline MemOperand Receiver();
284 271
285 // Push a try-catch or try-finally handler on top of the virtual frame. 272 // Push a try-catch or try-finally handler on top of the virtual frame.
286 void PushTryHandler(HandlerType type); 273 void PushTryHandler(HandlerType type);
287 274
288 // Call stub given the number of arguments it expects on (and 275 // Call stub given the number of arguments it expects on (and
289 // removes from) the stack. 276 // removes from) the stack.
290 void CallStub(CodeStub* stub, int arg_count) { 277 inline void CallStub(CodeStub* stub, int arg_count);
291 PrepareForCall(arg_count, arg_count);
292 RawCallStub(stub);
293 }
294 278
295 void CallStub(CodeStub* stub, Result* arg); 279 // Call JS function from top of the stack with arguments
296 280 // taken from the stack.
297 void CallStub(CodeStub* stub, Result* arg0, Result* arg1); 281 void CallJSFunction(int arg_count);
298 282
299 // Call runtime given the number of arguments expected on (and 283 // Call runtime given the number of arguments expected on (and
300 // removed from) the stack. 284 // removed from) the stack.
301 void CallRuntime(Runtime::Function* f, int arg_count); 285 void CallRuntime(Runtime::Function* f, int arg_count);
302 void CallRuntime(Runtime::FunctionId id, int arg_count); 286 void CallRuntime(Runtime::FunctionId id, int arg_count);
303 287
304 // Call runtime with sp aligned to 8 bytes. 288 #ifdef ENABLE_DEBUGGER_SUPPORT
305 void CallAlignedRuntime(Runtime::Function* f, int arg_count); 289 void DebugBreak();
306 void CallAlignedRuntime(Runtime::FunctionId id, int arg_count); 290 #endif
307 291
308 // Invoke builtin given the number of arguments it expects on (and 292 // Invoke builtin given the number of arguments it expects on (and
309 // removes from) the stack. 293 // removes from) the stack.
310 void InvokeBuiltin(Builtins::JavaScript id, 294 void InvokeBuiltin(Builtins::JavaScript id,
311 InvokeJSFlags flag, 295 InvokeJSFlags flag,
312 Result* arg_count_register,
313 int arg_count); 296 int arg_count);
314 297
298 // Call load IC. Receiver is on the stack and is consumed. Result is returned
299 // in v0.
300 void CallLoadIC(Handle<String> name, RelocInfo::Mode mode);
301
302 // Call store IC. If the load is contextual, value is found on top of the
303 // frame. If not, value and receiver are on the frame. Both are consumed.
304 // Result is returned in v0.
305 void CallStoreIC(Handle<String> name, bool is_contextual);
306
307 // Call keyed load IC. Key and receiver are on the stack. Both are consumed.
308 // Result is returned in v0.
309 void CallKeyedLoadIC();
310
311 // Call keyed store IC. Value, key and receiver are on the stack. All three
312 // are consumed. Result is returned in v0 (and a0).
313 void CallKeyedStoreIC();
314
315 // Call into an IC stub given the number of arguments it removes 315 // Call into an IC stub given the number of arguments it removes
316 // from the stack. Register arguments are passed as results and 316 // from the stack. Register arguments to the IC stub are implicit,
317 // consumed by the call. 317 // and depend on the type of IC stub.
318 void CallCodeObject(Handle<Code> ic, 318 void CallCodeObject(Handle<Code> ic,
319 RelocInfo::Mode rmode, 319 RelocInfo::Mode rmode,
320 int dropped_args); 320 int dropped_args);
321 void CallCodeObject(Handle<Code> ic,
322 RelocInfo::Mode rmode,
323 Result* arg,
324 int dropped_args);
325 void CallCodeObject(Handle<Code> ic,
326 RelocInfo::Mode rmode,
327 Result* arg0,
328 Result* arg1,
329 int dropped_args,
330 bool set_auto_args_slots = false);
331 321
332 // Drop a number of elements from the top of the expression stack. May 322 // Drop a number of elements from the top of the expression stack. May
333 // emit code to affect the physical frame. Does not clobber any registers 323 // emit code to affect the physical frame. Does not clobber any registers
334 // excepting possibly the stack pointer. 324 // excepting possibly the stack pointer.
335 void Drop(int count); 325 void Drop(int count);
336 // Similar to VirtualFrame::Drop but we don't modify the actual stack.
337 // This is because we need to manually restore sp to the correct position.
338 void DropFromVFrameOnly(int count);
339 326
340 // Drop one element. 327 // Drop one element.
341 void Drop() { Drop(1); } 328 void Drop() { Drop(1); }
342 void DropFromVFrameOnly() { DropFromVFrameOnly(1); }
343 329
344 // Duplicate the top element of the frame. 330 // Pop an element from the top of the expression stack. Discards
345 void Dup() { PushFrameSlotAt(element_count() - 1); } 331 // the result.
332 void Pop();
346 333
347 // Pop an element from the top of the expression stack. Returns a 334 // Pop an element from the top of the expression stack. The register
348 // Result, which may be a constant or a register. 335 // will be one normally used for the top of stack register allocation
349 Result Pop(); 336 // so you can't hold on to it if you push on the stack.
337 Register PopToRegister(Register but_not_to_this_one = no_reg);
338
339 // Look at the top of the stack. The register returned is aliased and
340 // must be copied to a scratch register before modification.
341 Register Peek();
342
343 // Look at the value beneath the top of the stack. The register returned is
344 // aliased and must be copied to a scratch register before modification.
345 Register Peek2();
346
347 // Duplicate the top of stack.
348 void Dup();
349
350 // Duplicate the two elements on top of stack.
351 void Dup2();
352
353 // Flushes all registers, but it puts a copy of the top-of-stack in a0.
354 void SpillAllButCopyTOSToA0();
355
356 // Flushes all registers, but it puts a copy of the top-of-stack in a1.
357 void SpillAllButCopyTOSToA1();
358
359 // Flushes all registers, but it puts a copy of the top-of-stack in a1
360 // and the next value on the stack in a0.
361 void SpillAllButCopyTOSToA1A0();
350 362
351 // Pop and save an element from the top of the expression stack and 363 // Pop and save an element from the top of the expression stack and
352 // emit a corresponding pop instruction. 364 // emit a corresponding pop instruction.
353 void EmitPop(Register reg); 365 void EmitPop(Register reg);
354 // Same but for multiple registers 366 // Same but for multiple registers
355 void EmitMultiPop(RegList regs); 367 void EmitMultiPop(RegList regs);
356 void EmitMultiPopReversed(RegList regs); 368 void EmitMultiPopReversed(RegList regs);
357 369
370
371 // Takes the top two elements and puts them in a0 (top element) and a1
372 // (second element).
373 void PopToA1A0();
374
375 // Takes the top element and puts it in a1.
376 void PopToA1();
377
378 // Takes the top element and puts it in a0.
379 void PopToA0();
380
358 // Push an element on top of the expression stack and emit a 381 // Push an element on top of the expression stack and emit a
359 // corresponding push instruction. 382 // corresponding push instruction.
360 void EmitPush(Register reg); 383 void EmitPush(Register reg, TypeInfo type_info = TypeInfo::Unknown());
384 void EmitPush(Operand operand, TypeInfo type_info = TypeInfo::Unknown());
385 void EmitPush(MemOperand operand, TypeInfo type_info = TypeInfo::Unknown());
386 void EmitPushRoot(Heap::RootListIndex index);
387
388 // Overwrite the nth thing on the stack. If the nth position is in a
389 // register then this turns into a Move, otherwise an sw. Afterwards
390 // you can still use the register even if it is a register that can be
391 // used for TOS (a0 or a1).
392 void SetElementAt(Register reg, int this_far_down);
393
394 // Get a register which is free and which must be immediately used to
395 // push on the top of the stack.
396 Register GetTOSRegister();
397
361 // Same but for multiple registers. 398 // Same but for multiple registers.
362 void EmitMultiPush(RegList regs); 399 void EmitMultiPush(RegList regs);
363 void EmitMultiPushReversed(RegList regs); 400 void EmitMultiPushReversed(RegList regs);
364 401
365 // Push an element on the virtual frame. 402 static Register scratch0() { return t4; }
366 inline void Push(Register reg, NumberInfo info = NumberInfo::Unknown()); 403 static Register scratch1() { return t5; }
367 inline void Push(Handle<Object> value); 404 static Register scratch2() { return t6; }
368 inline void Push(Smi* value);
369
370 // Pushing a result invalidates it (its contents become owned by the frame).
371 void Push(Result* result) {
372 if (result->is_register()) {
373 Push(result->reg());
374 } else {
375 ASSERT(result->is_constant());
376 Push(result->handle());
377 }
378 result->Unuse();
379 }
380
381 // Nip removes zero or more elements from immediately below the top
382 // of the frame, leaving the previous top-of-frame value on top of
383 // the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
384 inline void Nip(int num_dropped);
385
386 // This pushes 4 arguments slots on the stack and saves asked 'a' registers
387 // 'a' registers are arguments register a0 to a3.
388 void EmitArgumentSlots(RegList reglist);
389
390 inline void SetTypeForLocalAt(int index, NumberInfo info);
391 inline void SetTypeForParamAt(int index, NumberInfo info);
392 405
393 private: 406 private:
394 static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; 407 static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
395 static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset; 408 static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
396 static const int kContextOffset = StandardFrameConstants::kContextOffset; 409 static const int kContextOffset = StandardFrameConstants::kContextOffset;
397 410
398 static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize; 411 static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
399 static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots. 412 static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots.
400 413
401 ZoneList<FrameElement> elements_; 414 // 5 states for the top of stack, which can be in memory or in a0 and a1.
415 enum TopOfStack { NO_TOS_REGISTERS, A0_TOS, A1_TOS, A1_A0_TOS, A0_A1_TOS,
416 TOS_STATES};
417 static const int kMaxTOSRegisters = 2;
418
419 static const bool kA0InUse[TOS_STATES];
420 static const bool kA1InUse[TOS_STATES];
421 static const int kVirtualElements[TOS_STATES];
422 static const TopOfStack kStateAfterPop[TOS_STATES];
423 static const TopOfStack kStateAfterPush[TOS_STATES];
424 static const Register kTopRegister[TOS_STATES];
425 static const Register kBottomRegister[TOS_STATES];
426
427 // We allocate up to 5 locals in registers.
428 static const int kNumberOfAllocatedRegisters = 5;
429 // r2 to r6 are allocated to locals.
430 static const int kFirstAllocatedRegister = 2;
431
432 static const Register kAllocatedRegisters[kNumberOfAllocatedRegisters];
433
434 static Register AllocatedRegister(int r) {
435 ASSERT(r >= 0 && r < kNumberOfAllocatedRegisters);
436 return kAllocatedRegisters[r];
437 }
438
439 // The number of elements on the stack frame.
440 int element_count_;
441 TopOfStack top_of_stack_state_:3;
442 int register_allocation_map_:kNumberOfAllocatedRegisters;
443 static const int kTOSKnownSmiMapSize = 4;
444 unsigned tos_known_smi_map_:kTOSKnownSmiMapSize;
402 445
403 // The index of the element that is at the processor's stack pointer 446 // The index of the element that is at the processor's stack pointer
404 // (the sp register). 447 // (the sp register). For now since everything is in memory it is given
405 int stack_pointer_; 448 // by the number of elements on the not-very-virtual stack frame.
406 449 int stack_pointer() { return element_count_ - 1; }
407 // The index of the register frame element using each register, or
408 // kIllegalIndex if a register is not on the frame.
409 int register_locations_[RegisterAllocator::kNumRegisters];
410 450
411 // The number of frame-allocated locals and parameters respectively. 451 // The number of frame-allocated locals and parameters respectively.
412 int parameter_count() { return cgen()->scope()->num_parameters(); } 452 inline int parameter_count() const;
413 int local_count() { return cgen()->scope()->num_stack_slots(); } 453 inline int local_count() const;
414 454
415 // The index of the element that is at the processor's frame pointer 455 // The index of the element that is at the processor's frame pointer
416 // (the fp register). The parameters, receiver, function, and context 456 // (the fp register). The parameters, receiver, function, and context
417 // are below the frame pointer. 457 // are below the frame pointer.
418 int frame_pointer() { return parameter_count() + 3; } 458 inline int frame_pointer() const;
419 459
420 // The index of the first parameter. The receiver lies below the first 460 // The index of the first parameter. The receiver lies below the first
421 // parameter. 461 // parameter.
422 int param0_index() { return 1; } 462 int param0_index() { return 1; }
423 463
424 // The index of the context slot in the frame. It is immediately 464 // The index of the context slot in the frame. It is immediately
425 // below the frame pointer. 465 // below the frame pointer.
426 int context_index() { return frame_pointer() - 1; } 466 inline int context_index();
427 467
428 // The index of the function slot in the frame. It is below the frame 468 // The index of the function slot in the frame. It is below the frame
429 // pointer and context slot. 469 // pointer and context slot.
430 int function_index() { return frame_pointer() - 2; } 470 inline int function_index();
431 471
432 // The index of the first local. Between the frame pointer and the 472 // The index of the first local. Between the frame pointer and the
433 // locals lies the return address. 473 // locals lies the return address.
434 int local0_index() { return frame_pointer() + 2; } 474 inline int local0_index() const;
435 475
436 // The index of the base of the expression stack. 476 // The index of the base of the expression stack.
437 int expression_base_index() { return local0_index() + local_count(); } 477 inline int expression_base_index() const;
438 478
439 // Convert a frame index into a frame pointer relative offset into the 479 // Convert a frame index into a frame pointer relative offset into the
440 // actual stack. 480 // actual stack.
441 int fp_relative(int index) { 481 inline int fp_relative(int index);
442 ASSERT(index < element_count());
443 ASSERT(frame_pointer() < element_count()); // FP is on the frame.
444 return (frame_pointer() - index) * kPointerSize;
445 }
446
447 // Record an occurrence of a register in the virtual frame. This has the
448 // effect of incrementing the register's external reference count and
449 // of updating the index of the register's location in the frame.
450 void Use(Register reg, int index) {
451 ASSERT(!is_used(reg));
452 set_register_location(reg, index);
453 cgen()->allocator()->Use(reg);
454 }
455
456 // Record that a register reference has been dropped from the frame. This
457 // decrements the register's external reference count and invalidates the
458 // index of the register's location in the frame.
459 void Unuse(Register reg) {
460 ASSERT(is_used(reg));
461 set_register_location(reg, kIllegalIndex);
462 cgen()->allocator()->Unuse(reg);
463 }
464
465 // Spill the element at a particular index---write it to memory if
466 // necessary, free any associated register, and forget its value if
467 // constant.
468 void SpillElementAt(int index);
469
470 // Sync the element at a particular index. If it is a register or
471 // constant that disagrees with the value on the stack, write it to memory.
472 // Keep the element type as register or constant, and clear the dirty bit.
473 void SyncElementAt(int index);
474
475 // Sync the range of elements in [begin, end] with memory.
476 void SyncRange(int begin, int end);
477
478 // Sync a single unsynced element that lies beneath or at the stack pointer.
479 void SyncElementBelowStackPointer(int index);
480
481 // Sync a single unsynced element that lies just above the stack pointer.
482 void SyncElementByPushing(int index);
483
484 // Push a copy of a frame slot (typically a local or parameter) on top of
485 // the frame.
486 inline void PushFrameSlotAt(int index);
487
488 // Push a the value of a frame slot (typically a local or parameter) on
489 // top of the frame and invalidate the slot.
490 void TakeFrameSlotAt(int index);
491
492 // Store the value on top of the frame to a frame slot (typically a local
493 // or parameter).
494 void StoreToFrameSlotAt(int index);
495 482
496 // Spill all elements in registers. Spill the top spilled_args elements 483 // Spill all elements in registers. Spill the top spilled_args elements
497 // on the frame. Sync all other frame elements. 484 // on the frame. Sync all other frame elements.
498 // Then drop dropped_args elements from the virtual frame, to match 485 // Then drop dropped_args elements from the virtual frame, to match
499 // the effect of an upcoming call that will drop them from the stack. 486 // the effect of an upcoming call that will drop them from the stack.
500 void PrepareForCall(int spilled_args, int dropped_args); 487 void PrepareForCall(int spilled_args, int dropped_args);
501 488
502 // Move frame elements currently in registers or constants, that 489 // If all top-of-stack registers are in use then the lowest one is pushed
503 // should be in memory in the expected frame, to memory. 490 // onto the physical stack and made free.
504 void MergeMoveRegistersToMemory(VirtualFrame* expected); 491 void EnsureOneFreeTOSRegister();
505 492
506 // Make the register-to-register moves necessary to 493 // Emit instructions to get the top of stack state from where we are to where
507 // merge this frame with the expected frame. 494 // we want to be.
508 // Register to memory moves must already have been made, 495 void MergeTOSTo(TopOfStack expected_state,
509 // and memory to register moves must follow this call. 496 Condition cond = al,
510 // This is because some new memory-to-register moves are 497 Register r1 = no_reg,
511 // created in order to break cycles of register moves. 498 const Operand& r2 = Operand(no_reg));
512 // Used in the implementation of MergeTo().
513 void MergeMoveRegistersToRegisters(VirtualFrame* expected);
514 499
515 // Make the memory-to-register and constant-to-register moves 500 inline bool Equals(const VirtualFrame* other);
516 // needed to make this frame equal the expected frame.
517 // Called after all register-to-memory and register-to-register
518 // moves have been made. After this function returns, the frames
519 // should be equal.
520 void MergeMoveMemoryToRegisters(VirtualFrame* expected);
521 501
522 // Invalidates a frame slot (puts an invalid frame element in it). 502 inline void LowerHeight(int count) {
523 // Copies on the frame are correctly handled, and if this slot was 503 element_count_ -= count;
524 // the backing store of copies, the index of the new backing store 504 if (count >= kTOSKnownSmiMapSize) {
525 // is returned. Otherwise, returns kIllegalIndex. 505 tos_known_smi_map_ = 0;
526 // Register counts are correctly updated. 506 } else {
527 int InvalidateFrameSlotAt(int index); 507 tos_known_smi_map_ >>= count;
508 }
509 }
528 510
529 // Call a code stub that has already been prepared for calling (via 511 inline void RaiseHeight(int count, unsigned known_smi_map = 0) {
530 // PrepareForCall). 512 ASSERT(known_smi_map < (1u << count));
531 void RawCallStub(CodeStub* stub); 513 element_count_ += count;
532 514 if (count >= kTOSKnownSmiMapSize) {
533 // Calls a code object which has already been prepared for calling 515 tos_known_smi_map_ = known_smi_map;
534 // (via PrepareForCall). 516 } else {
535 void RawCallCodeObject(Handle<Code> code, RelocInfo::Mode rmode); 517 tos_known_smi_map_ = ((tos_known_smi_map_ << count) | known_smi_map);
536 518 }
537 inline bool Equals(VirtualFrame* other); 519 }
538
539 // Classes that need raw access to the elements_ array.
540 friend class DeferredCode;
541 friend class JumpTarget; 520 friend class JumpTarget;
542 }; 521 };
543 522
544 523
545 } } // namespace v8::internal 524 } } // namespace v8::internal
546 525
547 #endif // V8_MIPS_VIRTUAL_FRAME_MIPS_H_ 526 #endif // V8_MIPS_VIRTUAL_FRAME_MIPS_H_
548 527
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698