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

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

Issue 561072: MIPS port initial commit (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 10 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 | Annotate | Revision Log
« no previous file with comments | « src/mips/stub-cache-mips.cc ('k') | src/mips/virtual-frame-mips.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 #include "scopes.h"
34
35 namespace v8 {
36 namespace internal {
37
38
39 // -------------------------------------------------------------------------
40 // Virtual frames
41 //
42 // The virtual frame is an abstraction of the physical stack frame. It
43 // encapsulates the parameters, frame-allocated locals, and the expression
44 // stack. It supports push/pop operations on the expression stack, as well
45 // as random access to the expression stack elements, locals, and
46 // parameters.
47
48 class VirtualFrame : public ZoneObject {
49 public:
50 // A utility class to introduce a scope where the virtual frame is
51 // expected to remain spilled. The constructor spills the code
52 // generator's current frame, but no attempt is made to require it
53 // to stay spilled. It is intended as documentation while the code
54 // generator is being transformed.
55 class SpilledScope BASE_EMBEDDED {
56 public:
57 SpilledScope() {}
58 };
59
60 // An illegal index into the virtual frame.
61 static const int kIllegalIndex = -1;
62
63 // Construct an initial virtual frame on entry to a JS function.
64 VirtualFrame();
65
66 // Construct a virtual frame as a clone of an existing one.
67 explicit VirtualFrame(VirtualFrame* original);
68
69 CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
70 MacroAssembler* masm() { return cgen()->masm(); }
71
72 // Create a duplicate of an existing valid frame element.
73 FrameElement CopyElementAt(int index);
74
75 // The number of elements on the virtual frame.
76 int element_count() { return elements_.length(); }
77
78 // The height of the virtual expression stack.
79 int height() {
80 return element_count() - expression_base_index();
81 }
82
83 int register_location(int num) {
84 ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
85 return register_locations_[num];
86 }
87
88 int register_location(Register reg) {
89 return register_locations_[RegisterAllocator::ToNumber(reg)];
90 }
91
92 void set_register_location(Register reg, int index) {
93 register_locations_[RegisterAllocator::ToNumber(reg)] = index;
94 }
95
96 bool is_used(int num) {
97 ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
98 return register_locations_[num] != kIllegalIndex;
99 }
100
101 bool is_used(Register reg) {
102 return register_locations_[RegisterAllocator::ToNumber(reg)]
103 != kIllegalIndex;
104 }
105
106 // Add extra in-memory elements to the top of the frame to match an actual
107 // frame (eg, the frame after an exception handler is pushed). No code is
108 // emitted.
109 void Adjust(int count);
110
111 // Forget elements from the top of the frame to match an actual frame (eg,
112 // the frame after a runtime call). No code is emitted.
113 void Forget(int count) {
114 ASSERT(count >= 0);
115 ASSERT(stack_pointer_ == element_count() - 1);
116 stack_pointer_ -= count;
117 // On mips, all elements are in memory, so there is no extra bookkeeping
118 // (registers, copies, etc.) beyond dropping the elements.
119 elements_.Rewind(stack_pointer_ + 1);
120 }
121
122 // Forget count elements from the top of the frame and adjust the stack
123 // pointer downward. This is used, for example, before merging frames at
124 // break, continue, and return targets.
125 void ForgetElements(int count);
126
127 // Spill all values from the frame to memory.
128 void SpillAll();
129
130 // Spill all occurrences of a specific register from the frame.
131 void Spill(Register reg) {
132 if (is_used(reg)) SpillElementAt(register_location(reg));
133 }
134
135 // Spill all occurrences of an arbitrary register if possible. Return the
136 // register spilled or no_reg if it was not possible to free any register
137 // (ie, they all have frame-external references).
138 Register SpillAnyRegister();
139
140 // Prepare this virtual frame for merging to an expected frame by
141 // performing some state changes that do not require generating
142 // code. It is guaranteed that no code will be generated.
143 void PrepareMergeTo(VirtualFrame* expected);
144
145 // Make this virtual frame have a state identical to an expected virtual
146 // frame. As a side effect, code may be emitted to make this frame match
147 // the expected one.
148 void MergeTo(VirtualFrame* expected);
149
150 // Detach a frame from its code generator, perhaps temporarily. This
151 // tells the register allocator that it is free to use frame-internal
152 // registers. Used when the code generator's frame is switched from this
153 // one to NULL by an unconditional jump.
154 void DetachFromCodeGenerator() {
155 RegisterAllocator* cgen_allocator = cgen()->allocator();
156 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
157 if (is_used(i)) cgen_allocator->Unuse(i);
158 }
159 }
160
161 // (Re)attach a frame to its code generator. This informs the register
162 // allocator that the frame-internal register references are active again.
163 // Used when a code generator's frame is switched from NULL to this one by
164 // binding a label.
165 void AttachToCodeGenerator() {
166 RegisterAllocator* cgen_allocator = cgen()->allocator();
167 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
168 if (is_used(i)) cgen_allocator->Unuse(i);
169 }
170 }
171
172 // Emit code for the physical JS entry and exit frame sequences. After
173 // calling Enter, the virtual frame is ready for use; and after calling
174 // Exit it should not be used. Note that Enter does not allocate space in
175 // the physical frame for storing frame-allocated locals.
176 void Enter();
177 void Exit();
178
179 // Prepare for returning from the frame by spilling locals and
180 // dropping all non-locals elements in the virtual frame. This
181 // avoids generating unnecessary merge code when jumping to the
182 // shared return site. Emits code for spills.
183 void PrepareForReturn();
184
185 // Allocate and initialize the frame-allocated locals.
186 void AllocateStackSlots();
187
188 // The current top of the expression stack as an assembly operand.
189 MemOperand Top() { return MemOperand(sp, 0); }
190
191 // An element of the expression stack as an assembly operand.
192 MemOperand ElementAt(int index) {
193 return MemOperand(sp, index * kPointerSize);
194 }
195
196 // Random-access store to a frame-top relative frame element. The result
197 // becomes owned by the frame and is invalidated.
198 void SetElementAt(int index, Result* value);
199
200 // Set a frame element to a constant. The index is frame-top relative.
201 void SetElementAt(int index, Handle<Object> value) {
202 Result temp(value);
203 SetElementAt(index, &temp);
204 }
205
206 void PushElementAt(int index) {
207 PushFrameSlotAt(element_count() - index - 1);
208 }
209
210 // A frame-allocated local as an assembly operand.
211 MemOperand LocalAt(int index) {
212 ASSERT(0 <= index);
213 ASSERT(index < local_count());
214 return MemOperand(s8_fp, kLocal0Offset - index * kPointerSize);
215 }
216
217 // Push a copy of the value of a local frame slot on top of the frame.
218 void PushLocalAt(int index) {
219 PushFrameSlotAt(local0_index() + index);
220 }
221
222 // Push the value of a local frame slot on top of the frame and invalidate
223 // the local slot. The slot should be written to before trying to read
224 // from it again.
225 void TakeLocalAt(int index) {
226 TakeFrameSlotAt(local0_index() + index);
227 }
228
229 // Store the top value on the virtual frame into a local frame slot. The
230 // value is left in place on top of the frame.
231 void StoreToLocalAt(int index) {
232 StoreToFrameSlotAt(local0_index() + index);
233 }
234
235 // Push the address of the receiver slot on the frame.
236 void PushReceiverSlotAddress();
237
238 // The function frame slot.
239 MemOperand Function() { return MemOperand(s8_fp, kFunctionOffset); }
240
241 // Push the function on top of the frame.
242 void PushFunction() { PushFrameSlotAt(function_index()); }
243
244 // The context frame slot.
245 MemOperand Context() { return MemOperand(s8_fp, kContextOffset); }
246
247 // Save the value of the cp register to the context frame slot.
248 void SaveContextRegister();
249
250 // Restore the cp register from the value of the context frame
251 // slot.
252 void RestoreContextRegister();
253
254 // A parameter as an assembly operand.
255 MemOperand ParameterAt(int index) {
256 // Index -1 corresponds to the receiver.
257 ASSERT(-1 <= index); // -1 is the receiver.
258 ASSERT(index <= parameter_count());
259 uint16_t a = 0; // Number of argument slots.
260 return MemOperand(s8_fp, (1 + parameter_count() + a - index) *kPointerSize);
261 }
262
263 // Push a copy of the value of a parameter frame slot on top of the frame.
264 void PushParameterAt(int index) {
265 PushFrameSlotAt(param0_index() + index);
266 }
267
268 // Push the value of a paramter frame slot on top of the frame and
269 // invalidate the parameter slot. The slot should be written to before
270 // trying to read from it again.
271 void TakeParameterAt(int index) {
272 TakeFrameSlotAt(param0_index() + index);
273 }
274
275 // Store the top value on the virtual frame into a parameter frame slot.
276 // The value is left in place on top of the frame.
277 void StoreToParameterAt(int index) {
278 StoreToFrameSlotAt(param0_index() + index);
279 }
280
281 // The receiver frame slot.
282 MemOperand Receiver() { return ParameterAt(-1); }
283
284 // Push a try-catch or try-finally handler on top of the virtual frame.
285 void PushTryHandler(HandlerType type);
286
287 // Call stub given the number of arguments it expects on (and
288 // removes from) the stack.
289 void CallStub(CodeStub* stub, int arg_count) {
290 PrepareForCall(arg_count, arg_count);
291 RawCallStub(stub);
292 }
293
294 // Call stub that expects its argument in r0. The argument is given
295 // as a result which must be the register r0.
296 void CallStub(CodeStub* stub, Result* arg);
297
298 // Call stub that expects its arguments in r1 and r0. The arguments
299 // are given as results which must be the appropriate registers.
300 void CallStub(CodeStub* stub, Result* arg0, Result* arg1);
301
302 // Call runtime given the number of arguments expected on (and
303 // removed from) the stack.
304 void CallRuntime(Runtime::Function* f, int arg_count);
305 void CallRuntime(Runtime::FunctionId id, int arg_count);
306
307 // Call runtime with sp aligned to 8 bytes.
308 void CallAlignedRuntime(Runtime::Function* f, int arg_count);
309 void CallAlignedRuntime(Runtime::FunctionId id, int arg_count);
310
311 // Invoke builtin given the number of arguments it expects on (and
312 // removes from) the stack.
313 void InvokeBuiltin(Builtins::JavaScript id,
314 InvokeJSFlags flag,
315 Result* arg_count_register,
316 int arg_count);
317
318 // Call into an IC stub given the number of arguments it removes
319 // from the stack. Register arguments are passed as results and
320 // consumed by the call.
321 void CallCodeObject(Handle<Code> ic,
322 RelocInfo::Mode rmode,
323 int dropped_args);
324 void CallCodeObject(Handle<Code> ic,
325 RelocInfo::Mode rmode,
326 Result* arg,
327 int dropped_args);
328 void CallCodeObject(Handle<Code> ic,
329 RelocInfo::Mode rmode,
330 Result* arg0,
331 Result* arg1,
332 int dropped_args,
333 bool set_auto_args_slots = false);
334
335 // Drop a number of elements from the top of the expression stack. May
336 // emit code to affect the physical frame. Does not clobber any registers
337 // excepting possibly the stack pointer.
338 void Drop(int count);
339 // Similar to VirtualFrame::Drop but we don't modify the actual stack.
340 // This is because we need to manually restore sp to the correct position.
341 void DropFromVFrameOnly(int count);
342
343 // Drop one element.
344 void Drop() { Drop(1); }
345 void DropFromVFrameOnly() { DropFromVFrameOnly(1); }
346
347 // Duplicate the top element of the frame.
348 void Dup() { PushFrameSlotAt(element_count() - 1); }
349
350 // Pop an element from the top of the expression stack. Returns a
351 // Result, which may be a constant or a register.
352 Result Pop();
353
354 // Pop and save an element from the top of the expression stack and
355 // emit a corresponding pop instruction.
356 void EmitPop(Register reg);
357 // Same but for multiple registers
358 void EmitMultiPop(RegList regs); // higher indexed registers popped first
359 void EmitMultiPopReversed(RegList regs); // lower first
360
361 // Push an element on top of the expression stack and emit a
362 // corresponding push instruction.
363 void EmitPush(Register reg);
364 // Same but for multiple registers.
365 void EmitMultiPush(RegList regs); // lower indexed registers are pushed first
366 void EmitMultiPushReversed(RegList regs); // higher first
367
368 // Push an element on the virtual frame.
369 void Push(Register reg);
370 void Push(Handle<Object> value);
371 void Push(Smi* value) { Push(Handle<Object>(value)); }
372
373 // Pushing a result invalidates it (its contents become owned by the frame).
374 void Push(Result* result) {
375 if (result->is_register()) {
376 Push(result->reg());
377 } else {
378 ASSERT(result->is_constant());
379 Push(result->handle());
380 }
381 result->Unuse();
382 }
383
384 // Nip removes zero or more elements from immediately below the top
385 // of the frame, leaving the previous top-of-frame value on top of
386 // the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
387 void Nip(int num_dropped);
388
389 // This pushes 4 arguments slots on the stack and saves asked 'a' registers
390 // 'a' registers are arguments register a0 to a3.
391 void EmitArgumentSlots(RegList reglist);
392
393 private:
394 static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
395 static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
396 static const int kContextOffset = StandardFrameConstants::kContextOffset;
397
398 static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
399 static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots.
400
401 ZoneList<FrameElement> elements_;
402
403 // The index of the element that is at the processor's stack pointer
404 // (the sp register).
405 int stack_pointer_;
406
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
411 // The number of frame-allocated locals and parameters respectively.
412 int parameter_count() { return cgen()->scope()->num_parameters(); }
413 int local_count() { return cgen()->scope()->num_stack_slots(); }
414
415 // The index of the element that is at the processor's frame pointer
416 // (the fp register). The parameters, receiver, function, and context
417 // are below the frame pointer.
418 int frame_pointer() { return parameter_count() + 3; }
419
420 // The index of the first parameter. The receiver lies below the first
421 // parameter.
422 int param0_index() { return 1; }
423
424 // The index of the context slot in the frame. It is immediately
425 // below the frame pointer.
426 int context_index() { return frame_pointer() - 1; }
427
428 // The index of the function slot in the frame. It is below the frame
429 // pointer and context slot.
430 int function_index() { return frame_pointer() - 2; }
431
432 // The index of the first local. Between the frame pointer and the
433 // locals lies the return address.
434 int local0_index() { return frame_pointer() + 2; }
435
436 // The index of the base of the expression stack.
437 int expression_base_index() { return local0_index() + local_count(); }
438
439 // Convert a frame index into a frame pointer relative offset into the
440 // actual stack.
441 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 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
496 // Spill all elements in registers. Spill the top spilled_args elements
497 // on the frame. Sync all other frame elements.
498 // 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.
500 void PrepareForCall(int spilled_args, int dropped_args);
501
502 // Move frame elements currently in registers or constants, that
503 // should be in memory in the expected frame, to memory.
504 void MergeMoveRegistersToMemory(VirtualFrame* expected);
505
506 // Make the register-to-register moves necessary to
507 // merge this frame with the expected frame.
508 // Register to memory moves must already have been made,
509 // and memory to register moves must follow this call.
510 // This is because some new memory-to-register moves are
511 // created in order to break cycles of register moves.
512 // Used in the implementation of MergeTo().
513 void MergeMoveRegistersToRegisters(VirtualFrame* expected);
514
515 // Make the memory-to-register and constant-to-register moves
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
522 // Invalidates a frame slot (puts an invalid frame element in it).
523 // Copies on the frame are correctly handled, and if this slot was
524 // the backing store of copies, the index of the new backing store
525 // is returned. Otherwise, returns kIllegalIndex.
526 // Register counts are correctly updated.
527 int InvalidateFrameSlotAt(int index);
528
529 // Call a code stub that has already been prepared for calling (via
530 // PrepareForCall).
531 void RawCallStub(CodeStub* stub);
532
533 // Calls a code object which has already been prepared for calling
534 // (via PrepareForCall).
535 void RawCallCodeObject(Handle<Code> code, RelocInfo::Mode rmode);
536
537 bool Equals(VirtualFrame* other);
538
539 // Classes that need raw access to the elements_ array.
540 friend class DeferredCode;
541 friend class JumpTarget;
542 };
543
544
545 } } // namespace v8::internal
546
547 #endif // V8_MIPS_VIRTUAL_FRAME_MIPS_H_
548
OLDNEW
« no previous file with comments | « src/mips/stub-cache-mips.cc ('k') | src/mips/virtual-frame-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698