aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/sparc/vm/frame_sparc.hpp
blob: fb0eee67a39e4f9260ed91b1788ab7bd0309a8b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/*
 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef CPU_SPARC_VM_FRAME_SPARC_HPP
#define CPU_SPARC_VM_FRAME_SPARC_HPP

#include "runtime/synchronizer.hpp"
#include "utilities/top.hpp"

// A frame represents a physical stack frame (an activation).  Frames can be
// C or Java frames, and the Java frames can be interpreted or compiled.
// In contrast, vframes represent source-level activations, so that one physical frame
// can correspond to multiple source level frames because of inlining.
// A frame is comprised of {pc, sp, younger_sp}


// Layout of asm interpreter frame:
//
//  0xfffffff
//  ......
// [last  extra incoming arg,  (local # Nargs > 6 ? Nargs-1 : undef)]
// .. Note: incoming args are copied to local frame area upon entry
// [first extra incoming arg,  (local # Nargs > 6 ? 6       : undef)]
// [6 words for C-arg storage (unused)] Are this and next one really needed?
// [C-aggregate-word (unused)] Yes, if want extra params to be  in same place as C convention
// [16 words for register saving]                                    <--- FP
// [interpreter_frame_vm_locals ] (see below)

//              Note: Llocals is always double-word aligned
// [first local i.e. local # 0]        <-- Llocals
// ...
// [last local, i.e. local # Nlocals-1]

// [monitors                 ]
// ....
// [monitors                 ]    <-- Lmonitors (same as Llocals + 6*4 if none)
//                                    (must be double-word aligned because
//                                     monitor element size is constrained to
//                                     doubleword)
//
//                                <-- Lesp (points 1 past TOS)
// [bottom word used for stack ]
// ...
// [top word used for stack]    (first word of stack is double-word aligned)

// [space for outgoing args (conservatively allocated as max_stack - 6 + interpreter_frame_extra_outgoing_argument_words)]
// [6 words for C-arg storage]
// [C-aggregate-word (unused)]
// [16 words for register saving]                                    <--- SP
// ...
// 0x0000000
//
// The in registers and local registers are preserved in a block at SP.
//
// The first six in registers (I0..I5) hold the first six locals.
// The locals are used as follows:
//    Lesp         first free element of expression stack
//                 (which grows towards __higher__ addresses)
//    Lbcp         is set to address of bytecode to execute
//                 It is accessed in the frame under the name "bcx".
//                 It may at times (during GC) be an index instead.
//    Lmethod      the method being interpreted
//    Llocals      the base pointer for accessing the locals array
//                 (lower-numbered locals have lower addresses)
//    Lmonitors    the base pointer for accessing active monitors
//    Lcache       a saved pointer to the method's constant pool cache
//
//
// When calling out to another method,
// G5_method is set to method to call, G5_inline_cache_klass may be set,
// parameters are put in O registers, and also extra parameters
// must be cleverly copied from the top of stack to the outgoing param area in the frame,
// ------------------------------ C++ interpreter ----------------------------------------
// Layout of C++ interpreter frame:
//



// All frames:

 public:

  enum {
    // normal return address is 2 words past PC
    pc_return_offset                             = 2 * BytesPerInstWord,

    // size of each block, in order of increasing address:
    register_save_words                          = 16,
#ifdef _LP64
    callee_aggregate_return_pointer_words        =  0,
#else
    callee_aggregate_return_pointer_words        =  1,
#endif
    callee_register_argument_save_area_words     =  6,
    // memory_parameter_words                    = <arbitrary>,

    // offset of each block, in order of increasing address:
    // (note: callee_register_argument_save_area_words == Assembler::n_register_parameters)
    register_save_words_sp_offset                = 0,
    callee_aggregate_return_pointer_sp_offset    = register_save_words_sp_offset + register_save_words,
    callee_register_argument_save_area_sp_offset = callee_aggregate_return_pointer_sp_offset + callee_aggregate_return_pointer_words,
    memory_parameter_word_sp_offset              = callee_register_argument_save_area_sp_offset + callee_register_argument_save_area_words,
    varargs_offset                               = memory_parameter_word_sp_offset
  };

 private:
  intptr_t*  _younger_sp;                 // optional SP of callee (used to locate O7)
  int        _sp_adjustment_by_callee;   // adjustment in words to SP by callee for making locals contiguous

  // Note:  On SPARC, unlike Intel, the saved PC for a stack frame
  // is stored at a __variable__ distance from that frame's SP.
  // (In fact, it may be in the register save area of the callee frame,
  // but that fact need not bother us.)  Thus, we must store the
  // address of that saved PC explicitly.  On the other hand, SPARC
  // stores the FP for a frame at a fixed offset from the frame's SP,
  // so there is no need for a separate "frame::_fp" field.

 public:
  // Accessors

  intptr_t* younger_sp() const {
    assert(_younger_sp != NULL, "frame must possess a younger_sp");
    return _younger_sp;
  }

  int callee_sp_adjustment() const { return _sp_adjustment_by_callee; }
  void set_sp_adjustment_by_callee(int number_of_words) { _sp_adjustment_by_callee = number_of_words; }

  // Constructors

  // This constructor relies on the fact that the creator of a frame
  // has flushed register windows which the frame will refer to, and
  // that those register windows will not be reloaded until the frame is
  // done reading and writing the stack.  Moreover, if the "younger_sp"
  // argument points into the register save area of the next younger
  // frame (though it need not), the register window for that next
  // younger frame must also stay flushed.  (The caller is responsible
  // for ensuring this.)

  frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_adjusted_stack = false);

  // make a deficient frame which doesn't know where its PC is:
  enum unpatchable_t { unpatchable };
  frame(intptr_t* sp, unpatchable_t, address pc = NULL, CodeBlob* cb = NULL);

  // Walk from sp outward looking for old_sp, and return old_sp's predecessor
  // (i.e. return the sp from the frame where old_sp is the fp).
  // Register windows are assumed to be flushed for the stack in question.

  static intptr_t* next_younger_sp_or_null(intptr_t* old_sp, intptr_t* sp);

  // Return true if sp is a younger sp in the stack described by valid_sp.
  static bool is_valid_stack_pointer(intptr_t* valid_sp, intptr_t* sp);

 public:
  // accessors for the instance variables
  intptr_t*   fp() const { return (intptr_t*) ((intptr_t)(sp()[FP->sp_offset_in_saved_window()]) + STACK_BIAS ); }

  // All frames

  intptr_t*  fp_addr_at(int index) const   { return &fp()[index];    }
  intptr_t*  sp_addr_at(int index) const   { return &sp()[index];    }
  intptr_t   fp_at(     int index) const   { return *fp_addr_at(index); }
  intptr_t   sp_at(     int index) const   { return *sp_addr_at(index); }

 private:
  inline address* I7_addr() const;
  inline address* O7_addr() const;

  inline address* I0_addr() const;
  inline address* O0_addr() const;
  intptr_t*  younger_sp_addr_at(int index) const   { return &younger_sp()[index];    }

 public:
  // access to SPARC arguments and argument registers

  // Assumes reg is an in/local register
  intptr_t*     register_addr(Register reg) const {
    return sp_addr_at(reg->sp_offset_in_saved_window());
  }

  // Assumes reg is an out register
  intptr_t*     out_register_addr(Register reg) const {
    return younger_sp_addr_at(reg->after_save()->sp_offset_in_saved_window());
  }
  intptr_t* memory_param_addr(int param_ix, bool is_in) const {
    int offset = callee_register_argument_save_area_sp_offset + param_ix;
    if (is_in)
      return fp_addr_at(offset);
    else
      return sp_addr_at(offset);
  }
  intptr_t*        param_addr(int param_ix, bool is_in) const {
    if (param_ix >= callee_register_argument_save_area_words)
      return memory_param_addr(param_ix, is_in);
    else if (is_in)
      return register_addr(Argument(param_ix, true).as_register());
    else {
      // the registers are stored in the next younger frame
      // %%% is this really necessary?
      ShouldNotReachHere();
      return NULL;
    }
  }


  // Interpreter frames

 public:
  // Asm interpreter
#ifndef CC_INTERP
  enum interpreter_frame_vm_locals {
       // 2 words, also used to save float regs across  calls to C
       interpreter_frame_d_scratch_fp_offset          = -2,
       interpreter_frame_l_scratch_fp_offset          = -4,
       interpreter_frame_padding_offset               = -5, // for native calls only
       interpreter_frame_oop_temp_offset              = -6, // for native calls only
       interpreter_frame_vm_locals_fp_offset          = -6, // should be same as above, and should be zero mod 8

       interpreter_frame_vm_local_words = -interpreter_frame_vm_locals_fp_offset,


       // interpreter frame set-up needs to save 2 extra words in outgoing param area
       // for class and jnienv arguments for native stubs (see nativeStubGen_sparc.cpp_

       interpreter_frame_extra_outgoing_argument_words = 2
  };
#else
  enum interpreter_frame_vm_locals {
       // 2 words, also used to save float regs across  calls to C
       interpreter_state_ptr_offset                   = 0,  // Is in L0 (Lstate) in save area
       interpreter_frame_mirror_offset                = 1,  // Is in L1 (Lmirror) in save area (for native calls only)

       // interpreter frame set-up needs to save 2 extra words in outgoing param area
       // for class and jnienv arguments for native stubs (see nativeStubGen_sparc.cpp_

       interpreter_frame_extra_outgoing_argument_words = 2
  };
#endif /* CC_INTERP */

  enum compiler_frame_fixed_locals {
       compiler_frame_vm_locals_fp_offset          = -2
  };

 private:
  constantPoolCacheOop* interpreter_frame_cpoolcache_addr() const;

#ifndef CC_INTERP

  // where Lmonitors is saved:
  BasicObjectLock**  interpreter_frame_monitors_addr() const {
    return (BasicObjectLock**) sp_addr_at(Lmonitors->sp_offset_in_saved_window());
  }
  intptr_t** interpreter_frame_esp_addr() const {
    return (intptr_t**)sp_addr_at(Lesp->sp_offset_in_saved_window());
  }

  inline void interpreter_frame_set_tos_address(intptr_t* x);

  // monitors:

  // next two fns read and write Lmonitors value,
 private:
  BasicObjectLock* interpreter_frame_monitors()           const  { return *interpreter_frame_monitors_addr(); }
  void interpreter_frame_set_monitors(BasicObjectLock* monitors) {        *interpreter_frame_monitors_addr() = monitors; }
#else
 public:
  inline interpreterState get_interpreterState() const {
    return ((interpreterState)sp_at(interpreter_state_ptr_offset));
  }

#endif /* CC_INTERP */

 public:

#endif // CPU_SPARC_VM_FRAME_SPARC_HPP