The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / virtual-frame-arm.h @ 40c0f755

History | View | Annotate | Download (18 KB)

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
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
#ifndef V8_VIRTUAL_FRAME_ARM_H_
29
#define V8_VIRTUAL_FRAME_ARM_H_
30

    
31
#include "register-allocator.h"
32

    
33
namespace v8 { namespace internal {
34

    
35
// -------------------------------------------------------------------------
36
// Virtual frames
37
//
38
// The virtual frame is an abstraction of the physical stack frame.  It
39
// encapsulates the parameters, frame-allocated locals, and the expression
40
// stack.  It supports push/pop operations on the expression stack, as well
41
// as random access to the expression stack elements, locals, and
42
// parameters.
43

    
44
class VirtualFrame : public Malloced {
45
 public:
46
  // A utility class to introduce a scope where the virtual frame is
47
  // expected to remain spilled.  The constructor spills the code
48
  // generator's current frame, but no attempt is made to require it
49
  // to stay spilled.  It is intended as documentation while the code
50
  // generator is being transformed.
51
  class SpilledScope BASE_EMBEDDED {
52
   public:
53
    explicit SpilledScope(CodeGenerator* cgen);
54

    
55
    ~SpilledScope();
56

    
57
   private:
58
    CodeGenerator* cgen_;
59
    bool previous_state_;
60
  };
61

    
62
  // An illegal index into the virtual frame.
63
  static const int kIllegalIndex = -1;
64

    
65
  // Construct an initial virtual frame on entry to a JS function.
66
  explicit VirtualFrame(CodeGenerator* cgen);
67

    
68
  // Construct a virtual frame as a clone of an existing one.
69
  explicit VirtualFrame(VirtualFrame* original);
70

    
71
  // Create a duplicate of an existing valid frame element.
72
  FrameElement CopyElementAt(int index);
73

    
74
  // The height of the virtual expression stack.
75
  int height() const {
76
    return elements_.length() - expression_base_index();
77
  }
78

    
79
  int register_index(Register reg) {
80
    return register_locations_[reg.code()];
81
  }
82

    
83
  bool is_used(int reg_code) {
84
    return register_locations_[reg_code] != kIllegalIndex;
85
  }
86

    
87
  bool is_used(Register reg) {
88
    return is_used(reg.code());
89
  }
90

    
91
  // Add extra in-memory elements to the top of the frame to match an actual
92
  // frame (eg, the frame after an exception handler is pushed).  No code is
93
  // emitted.
94
  void Adjust(int count);
95

    
96
  // Forget elements from the top of the frame to match an actual frame (eg,
97
  // the frame after a runtime call).  No code is emitted.
98
  void Forget(int count);
99

    
100
  // Forget count elements from the top of the frame without adjusting
101
  // the stack pointer downward.  This is used, for example, before
102
  // merging frames at break, continue, and return targets.
103
  void ForgetElements(int count);
104

    
105
  // Spill all values from the frame to memory.
106
  void SpillAll();
107

    
108
  // Spill all occurrences of a specific register from the frame.
109
  void Spill(Register reg);
110

    
111
  // Spill all occurrences of an arbitrary register if possible.  Return the
112
  // register spilled or no_reg if it was not possible to free any register
113
  // (ie, they all have frame-external references).
114
  Register SpillAnyRegister();
115

    
116
  // Prepare this virtual frame for merging to an expected frame by
117
  // performing some state changes that do not require generating
118
  // code.  It is guaranteed that no code will be generated.
119
  void PrepareMergeTo(VirtualFrame* expected);
120

    
121
  // Make this virtual frame have a state identical to an expected virtual
122
  // frame.  As a side effect, code may be emitted to make this frame match
123
  // the expected one.
124
  void MergeTo(VirtualFrame* expected);
125

    
126
  // Detach a frame from its code generator, perhaps temporarily.  This
127
  // tells the register allocator that it is free to use frame-internal
128
  // registers.  Used when the code generator's frame is switched from this
129
  // one to NULL by an unconditional jump.
130
  void DetachFromCodeGenerator();
131

    
132
  // (Re)attach a frame to its code generator.  This informs the register
133
  // allocator that the frame-internal register references are active again.
134
  // Used when a code generator's frame is switched from NULL to this one by
135
  // binding a label.
136
  void AttachToCodeGenerator();
137

    
138
  // Emit code for the physical JS entry and exit frame sequences.  After
139
  // calling Enter, the virtual frame is ready for use; and after calling
140
  // Exit it should not be used.  Note that Enter does not allocate space in
141
  // the physical frame for storing frame-allocated locals.
142
  void Enter();
143
  void Exit();
144

    
145
  // Prepare for returning from the frame by spilling locals and
146
  // dropping all non-locals elements in the virtual frame.  This
147
  // avoids generating unnecessary merge code when jumping to the
148
  // shared return site.  Emits code for spills.
149
  void PrepareForReturn();
150

    
151
  // Allocate and initialize the frame-allocated locals.
152
  void AllocateStackSlots(int count);
153

    
154
  // The current top of the expression stack as an assembly operand.
155
  MemOperand Top() const { return MemOperand(sp, 0); }
156

    
157
  // An element of the expression stack as an assembly operand.
158
  MemOperand ElementAt(int index) const {
159
    return MemOperand(sp, index * kPointerSize);
160
  }
161

    
162
  // Random-access store to a frame-top relative frame element.  The result
163
  // becomes owned by the frame and is invalidated.
164
  void SetElementAt(int index, Result* value);
165

    
166
  // Set a frame element to a constant.  The index is frame-top relative.
167
  void SetElementAt(int index, Handle<Object> value) {
168
    Result temp(value, cgen_);
169
    SetElementAt(index, &temp);
170
  }
171

    
172
  void PushElementAt(int index) {
173
    PushFrameSlotAt(elements_.length() - index - 1);
174
  }
175

    
176
  // A frame-allocated local as an assembly operand.
177
  MemOperand LocalAt(int index) const {
178
    ASSERT(0 <= index);
179
    ASSERT(index < local_count_);
180
    return MemOperand(fp, kLocal0Offset - index * kPointerSize);
181
  }
182

    
183
  // Push a copy of the value of a local frame slot on top of the frame.
184
  void PushLocalAt(int index) {
185
    PushFrameSlotAt(local0_index() + index);
186
  }
187

    
188
  // Push the value of a local frame slot on top of the frame and invalidate
189
  // the local slot.  The slot should be written to before trying to read
190
  // from it again.
191
  void TakeLocalAt(int index) {
192
    TakeFrameSlotAt(local0_index() + index);
193
  }
194

    
195
  // Store the top value on the virtual frame into a local frame slot.  The
196
  // value is left in place on top of the frame.
197
  void StoreToLocalAt(int index) {
198
    StoreToFrameSlotAt(local0_index() + index);
199
  }
200

    
201
  // Push the address of the receiver slot on the frame.
202
  void PushReceiverSlotAddress();
203

    
204
  // The function frame slot.
205
  MemOperand Function() const { return MemOperand(fp, kFunctionOffset); }
206

    
207
  // Push the function on top of the frame.
208
  void PushFunction() { PushFrameSlotAt(function_index()); }
209

    
210
  // The context frame slot.
211
  MemOperand Context() const { return MemOperand(fp, kContextOffset); }
212

    
213
  // Save the value of the esi register to the context frame slot.
214
  void SaveContextRegister();
215

    
216
  // Restore the esi register from the value of the context frame
217
  // slot.
218
  void RestoreContextRegister();
219

    
220
  // A parameter as an assembly operand.
221
  MemOperand ParameterAt(int index) const {
222
    // Index -1 corresponds to the receiver.
223
    ASSERT(-1 <= index && index <= parameter_count_);
224
    return MemOperand(fp, (1 + parameter_count_ - index) * kPointerSize);
225
  }
226

    
227
  // Push a copy of the value of a parameter frame slot on top of the frame.
228
  void PushParameterAt(int index) {
229
    PushFrameSlotAt(param0_index() + index);
230
  }
231

    
232
  // Push the value of a paramter frame slot on top of the frame and
233
  // invalidate the parameter slot.  The slot should be written to before
234
  // trying to read from it again.
235
  void TakeParameterAt(int index) {
236
    TakeFrameSlotAt(param0_index() + index);
237
  }
238

    
239
  // Store the top value on the virtual frame into a parameter frame slot.
240
  // The value is left in place on top of the frame.
241
  void StoreToParameterAt(int index) {
242
    StoreToFrameSlotAt(param0_index() + index);
243
  }
244

    
245
  // The receiver frame slot.
246
  MemOperand Receiver() const { return ParameterAt(-1); }
247

    
248
  // Push a try-catch or try-finally handler on top of the virtual frame.
249
  void PushTryHandler(HandlerType type);
250

    
251
  // Call stub given the number of arguments it expects on (and
252
  // removes from) the stack.
253
  Result CallStub(CodeStub* stub, int arg_count);
254

    
255
  // Call stub that expects its argument in r0.  The argument is given
256
  // as a result which must be the register r0.
257
  Result CallStub(CodeStub* stub, Result* arg);
258

    
259
  // Call stub that expects its arguments in r1 and r0.  The arguments
260
  // are given as results which must be the appropriate registers.
261
  Result CallStub(CodeStub* stub, Result* arg0, Result* arg1);
262

    
263
  // Call runtime given the number of arguments expected on (and
264
  // removed from) the stack.
265
  Result CallRuntime(Runtime::Function* f, int arg_count);
266
  Result CallRuntime(Runtime::FunctionId id, int arg_count);
267

    
268
  // Invoke builtin given the number of arguments it expects on (and
269
  // removes from) the stack.
270
  Result InvokeBuiltin(Builtins::JavaScript id,
271
                       InvokeJSFlags flag,
272
                       Result* arg_count_register,
273
                       int arg_count);
274

    
275
  // Call into an IC stub given the number of arguments it removes
276
  // from the stack.  Register arguments are passed as results and
277
  // consumed by the call.
278
  Result CallCodeObject(Handle<Code> ic,
279
                        RelocInfo::Mode rmode,
280
                        int dropped_args);
281
  Result CallCodeObject(Handle<Code> ic,
282
                        RelocInfo::Mode rmode,
283
                        Result* arg,
284
                        int dropped_args);
285
  Result CallCodeObject(Handle<Code> ic,
286
                        RelocInfo::Mode rmode,
287
                        Result* arg0,
288
                        Result* arg1,
289
                        int dropped_args);
290

    
291
  // Drop a number of elements from the top of the expression stack.  May
292
  // emit code to affect the physical frame.  Does not clobber any registers
293
  // excepting possibly the stack pointer.
294
  void Drop(int count);
295

    
296
  // Drop one element.
297
  void Drop() { Drop(1); }
298

    
299
  // Duplicate the top element of the frame.
300
  void Dup() { PushFrameSlotAt(elements_.length() - 1); }
301

    
302
  // Pop an element from the top of the expression stack.  Returns a
303
  // Result, which may be a constant or a register.
304
  Result Pop();
305

    
306
  // Pop and save an element from the top of the expression stack and
307
  // emit a corresponding pop instruction.
308
  void EmitPop(Register reg);
309

    
310
  // Push an element on top of the expression stack and emit a
311
  // corresponding push instruction.
312
  void EmitPush(Register reg);
313

    
314
  // Push an element on the virtual frame.
315
  void Push(Register reg, StaticType static_type = StaticType());
316
  void Push(Handle<Object> value);
317
  void Push(Smi* value) { Push(Handle<Object>(value)); }
318

    
319
  // Pushing a result invalidates it (its contents become owned by the frame).
320
  void Push(Result* result);
321

    
322
  // Nip removes zero or more elements from immediately below the top
323
  // of the frame, leaving the previous top-of-frame value on top of
324
  // the frame.  Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
325
  void Nip(int num_dropped);
326

    
327
 private:
328
  static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
329
  static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
330
  static const int kContextOffset = StandardFrameConstants::kContextOffset;
331

    
332
  static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
333
  static const int kPreallocatedElements = 5 + 8;  // 8 expression stack slots.
334

    
335
  CodeGenerator* cgen_;
336
  MacroAssembler* masm_;
337

    
338
  List<FrameElement> elements_;
339

    
340
  // The number of frame-allocated locals and parameters respectively.
341
  int parameter_count_;
342
  int local_count_;
343

    
344
  // The index of the element that is at the processor's stack pointer
345
  // (the sp register).
346
  int stack_pointer_;
347

    
348
  // The index of the element that is at the processor's frame pointer
349
  // (the fp register).
350
  int frame_pointer_;
351

    
352
  // The index of the register frame element using each register, or
353
  // kIllegalIndex if a register is not on the frame.
354
  int register_locations_[kNumRegisters];
355

    
356
  // The index of the first parameter.  The receiver lies below the first
357
  // parameter.
358
  int param0_index() const { return 1; }
359

    
360
  // The index of the context slot in the frame.
361
  int context_index() const {
362
    ASSERT(frame_pointer_ != kIllegalIndex);
363
    return frame_pointer_ - 1;
364
  }
365

    
366
  // The index of the function slot in the frame.  It lies above the context
367
  // slot.
368
  int function_index() const {
369
    ASSERT(frame_pointer_ != kIllegalIndex);
370
    return frame_pointer_ - 2;
371
  }
372

    
373
  // The index of the first local.  Between the parameters and the locals
374
  // lie the return address, the saved frame pointer, the context, and the
375
  // function.
376
  int local0_index() const {
377
    ASSERT(frame_pointer_ != kIllegalIndex);
378
    return frame_pointer_ + 2;
379
  }
380

    
381
  // The index of the base of the expression stack.
382
  int expression_base_index() const { return local0_index() + local_count_; }
383

    
384
  // Convert a frame index into a frame pointer relative offset into the
385
  // actual stack.
386
  int fp_relative(int index) const {
387
    return (frame_pointer_ - index) * kPointerSize;
388
  }
389

    
390
  // Record an occurrence of a register in the virtual frame.  This has the
391
  // effect of incrementing the register's external reference count and
392
  // of updating the index of the register's location in the frame.
393
  void Use(Register reg, int index);
394

    
395
  // Record that a register reference has been dropped from the frame.  This
396
  // decrements the register's external reference count and invalidates the
397
  // index of the register's location in the frame.
398
  void Unuse(Register reg);
399

    
400
  // Spill the element at a particular index---write it to memory if
401
  // necessary, free any associated register, and forget its value if
402
  // constant.
403
  void SpillElementAt(int index);
404

    
405
  // Sync the element at a particular index.  If it is a register or
406
  // constant that disagrees with the value on the stack, write it to memory.
407
  // Keep the element type as register or constant, and clear the dirty bit.
408
  void SyncElementAt(int index);
409

    
410
  // Sync the range of elements in [begin, end).
411
  void SyncRange(int begin, int end);
412

    
413
  // Sync a single unsynced element that lies beneath or at the stack pointer.
414
  void SyncElementBelowStackPointer(int index);
415

    
416
  // Sync a single unsynced element that lies just above the stack pointer.
417
  void SyncElementByPushing(int index);
418

    
419
  // Push a copy of a frame slot (typically a local or parameter) on top of
420
  // the frame.
421
  void PushFrameSlotAt(int index);
422

    
423
  // Push a the value of a frame slot (typically a local or parameter) on
424
  // top of the frame and invalidate the slot.
425
  void TakeFrameSlotAt(int index);
426

    
427
  // Store the value on top of the frame to a frame slot (typically a local
428
  // or parameter).
429
  void StoreToFrameSlotAt(int index);
430

    
431
  // Spill all elements in registers. Spill the top spilled_args elements
432
  // on the frame.  Sync all other frame elements.
433
  // Then drop dropped_args elements from the virtual frame, to match
434
  // the effect of an upcoming call that will drop them from the stack.
435
  void PrepareForCall(int spilled_args, int dropped_args);
436

    
437
  // Move frame elements currently in registers or constants, that
438
  // should be in memory in the expected frame, to memory.
439
  void MergeMoveRegistersToMemory(VirtualFrame* expected);
440

    
441
  // Make the register-to-register moves necessary to
442
  // merge this frame with the expected frame.
443
  // Register to memory moves must already have been made,
444
  // and memory to register moves must follow this call.
445
  // This is because some new memory-to-register moves are
446
  // created in order to break cycles of register moves.
447
  // Used in the implementation of MergeTo().
448
  void MergeMoveRegistersToRegisters(VirtualFrame* expected);
449

    
450
  // Make the memory-to-register and constant-to-register moves
451
  // needed to make this frame equal the expected frame.
452
  // Called after all register-to-memory and register-to-register
453
  // moves have been made.  After this function returns, the frames
454
  // should be equal.
455
  void MergeMoveMemoryToRegisters(VirtualFrame* expected);
456

    
457
  // Invalidates a frame slot (puts an invalid frame element in it).
458
  // Copies on the frame are correctly handled, and if this slot was
459
  // the backing store of copies, the index of the new backing store
460
  // is returned.  Otherwise, returns kIllegalIndex.
461
  // Register counts are correctly updated.
462
  int InvalidateFrameSlotAt(int index);
463

    
464
  // Call a code stub that has already been prepared for calling (via
465
  // PrepareForCall).
466
  Result RawCallStub(CodeStub* stub);
467

    
468
  // Calls a code object which has already been prepared for calling
469
  // (via PrepareForCall).
470
  Result RawCallCodeObject(Handle<Code> code, RelocInfo::Mode rmode);
471

    
472
  bool Equals(VirtualFrame* other);
473

    
474
  friend class JumpTarget;
475
};
476

    
477

    
478
} }  // namespace v8::internal
479

    
480
#endif  // V8_VIRTUAL_FRAME_ARM_H_