| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2011 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #ifndef ART_SRC_STACK_H_ | 
|  | 18 | #define ART_SRC_STACK_H_ | 
|  | 19 |  | 
| Ian Rogers | 6d4d9fc | 2011-11-30 16:24:48 -0800 | [diff] [blame] | 20 | #include "dex_file.h" | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 21 | #include "heap.h" | 
|  | 22 | #include "jdwp/jdwp.h" | 
| Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 23 | #include "jni.h" | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 24 | #include "macros.h" | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 25 | #include "oat/runtime/context.h" | 
|  | 26 | #include "trace.h" | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 27 |  | 
|  | 28 | #include <stdint.h> | 
|  | 29 |  | 
|  | 30 | namespace art { | 
|  | 31 |  | 
|  | 32 | class Method; | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 33 | class Object; | 
|  | 34 | class ShadowFrame; | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 35 | class Thread; | 
|  | 36 |  | 
| Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 37 | jobject GetThreadStack(JNIEnv*, Thread*); | 
|  | 38 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 39 | class ShadowFrame { | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 40 | public: | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 41 | // Number of references contained within this shadow frame | 
|  | 42 | uint32_t NumberOfReferences() const { | 
|  | 43 | return number_of_references_; | 
|  | 44 | } | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 45 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 46 | void SetNumberOfReferences(uint32_t number_of_references) { | 
|  | 47 | number_of_references_ = number_of_references; | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | // Caller dex pc | 
|  | 51 | uint32_t GetDexPC() const { | 
|  | 52 | return dex_pc_; | 
|  | 53 | } | 
|  | 54 |  | 
|  | 55 | void SetDexPC(uint32_t dex_pc) { | 
|  | 56 | dex_pc_ = dex_pc; | 
|  | 57 | } | 
|  | 58 |  | 
|  | 59 | // Link to previous shadow frame or NULL | 
|  | 60 | ShadowFrame* GetLink() const { | 
|  | 61 | return link_; | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | void SetLink(ShadowFrame* frame) { | 
|  | 65 | DCHECK_NE(this, frame); | 
|  | 66 | link_ = frame; | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | Object* GetReference(size_t i) const { | 
|  | 70 | DCHECK_LT(i, number_of_references_); | 
|  | 71 | return references_[i]; | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | void SetReference(size_t i, Object* object) { | 
|  | 75 | DCHECK_LT(i, number_of_references_); | 
|  | 76 | references_[i] = object; | 
|  | 77 | } | 
| Elliott Hughes | 91bf6cd | 2012-02-14 17:27:48 -0800 | [diff] [blame] | 78 |  | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 79 | Method* GetMethod() const { | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 80 | DCHECK_NE(method_, static_cast<void*>(NULL)); | 
|  | 81 | return method_; | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 82 | } | 
|  | 83 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 84 | void SetMethod(Method* method) { | 
|  | 85 | DCHECK_NE(method, static_cast<void*>(NULL)); | 
|  | 86 | method_ = method; | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 87 | } | 
|  | 88 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 89 | bool Contains(Object** shadow_frame_entry) const { | 
|  | 90 | return ((&references_[0] <= shadow_frame_entry) && | 
|  | 91 | (shadow_frame_entry <= (&references_[number_of_references_ - 1]))); | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 92 | } | 
|  | 93 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 94 | void VisitRoots(Heap::RootVisitor* visitor, void* arg) { | 
|  | 95 | size_t num_refs = NumberOfReferences(); | 
|  | 96 | for (size_t j = 0; j < num_refs; j++) { | 
|  | 97 | Object* object = GetReference(j); | 
|  | 98 | if (object != NULL) { | 
|  | 99 | visitor(object, arg); | 
|  | 100 | } | 
|  | 101 | } | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 102 | } | 
|  | 103 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 104 | // Offset of link within shadow frame | 
|  | 105 | static size_t LinkOffset() { | 
|  | 106 | return OFFSETOF_MEMBER(ShadowFrame, link_); | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | // Offset of method within shadow frame | 
|  | 110 | static size_t MethodOffset() { | 
|  | 111 | return OFFSETOF_MEMBER(ShadowFrame, method_); | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | // Offset of dex pc within shadow frame | 
|  | 115 | static size_t DexPCOffset() { | 
|  | 116 | return OFFSETOF_MEMBER(ShadowFrame, dex_pc_); | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | // Offset of length within shadow frame | 
|  | 120 | static size_t NumberOfReferencesOffset() { | 
|  | 121 | return OFFSETOF_MEMBER(ShadowFrame, number_of_references_); | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | // Offset of references within shadow frame | 
|  | 125 | static size_t ReferencesOffset() { | 
|  | 126 | return OFFSETOF_MEMBER(ShadowFrame, references_); | 
|  | 127 | } | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 128 |  | 
|  | 129 | private: | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 130 | // ShadowFrame should be allocated by the generated code directly. | 
|  | 131 | // We should not create new shadow stack in the runtime support function. | 
|  | 132 | ~ShadowFrame() {} | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 133 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 134 | uint32_t number_of_references_; | 
|  | 135 | ShadowFrame* link_; | 
|  | 136 | Method* method_; | 
|  | 137 | uint32_t dex_pc_; | 
|  | 138 | Object* references_[]; | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 139 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 140 | DISALLOW_IMPLICIT_CONSTRUCTORS(ShadowFrame); | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 141 | }; | 
|  | 142 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame^] | 143 | // The managed stack is used to record fragments of managed code stacks. Managed code stacks | 
|  | 144 | // may either be shadow frames or lists of frames using fixed frame sizes. Transition records are | 
|  | 145 | // necessary for transitions between code using different frame layouts and transitions into native | 
|  | 146 | // code. | 
|  | 147 | class PACKED ManagedStack { | 
|  | 148 | public: | 
|  | 149 | ManagedStack() : link_(NULL), top_shadow_frame_(NULL), | 
|  | 150 | top_quick_frame_(NULL), top_quick_frame_pc_(0) {} | 
|  | 151 | void PushManagedStackFragment(ManagedStack* fragment); | 
|  | 152 | void PopManagedStackFragment(const ManagedStack& record); | 
|  | 153 |  | 
|  | 154 | ManagedStack* GetLink() const { | 
|  | 155 | return link_; | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | Method** GetTopQuickFrame() const { | 
|  | 159 | return top_quick_frame_; | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | void SetTopQuickFrame(Method** top) { | 
|  | 163 | top_quick_frame_ = top; | 
|  | 164 | } | 
|  | 165 |  | 
|  | 166 | uintptr_t GetTopQuickFramePc() const { | 
|  | 167 | return top_quick_frame_pc_; | 
|  | 168 | } | 
|  | 169 |  | 
|  | 170 | void SetTopQuickFramePc(uintptr_t pc) { | 
|  | 171 | top_quick_frame_pc_ = pc; | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | static size_t TopQuickFrameOffset() { | 
|  | 175 | return OFFSETOF_MEMBER(ManagedStack, top_quick_frame_); | 
|  | 176 | } | 
|  | 177 |  | 
|  | 178 | static size_t TopQuickFramePcOffset() { | 
|  | 179 | return OFFSETOF_MEMBER(ManagedStack, top_quick_frame_pc_); | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame) { | 
|  | 183 | ShadowFrame* old_frame = top_shadow_frame_; | 
|  | 184 | top_shadow_frame_ = new_top_frame; | 
|  | 185 | new_top_frame->SetLink(old_frame); | 
|  | 186 | return old_frame; | 
|  | 187 | } | 
|  | 188 |  | 
|  | 189 | ShadowFrame* PopShadowFrame() { | 
|  | 190 | CHECK(top_shadow_frame_ != NULL); | 
|  | 191 | ShadowFrame* frame = top_shadow_frame_; | 
|  | 192 | top_shadow_frame_ = frame->GetLink(); | 
|  | 193 | return frame; | 
|  | 194 | } | 
|  | 195 |  | 
|  | 196 | ShadowFrame* GetTopShadowFrame() const { | 
|  | 197 | return top_shadow_frame_; | 
|  | 198 | } | 
|  | 199 |  | 
|  | 200 | static size_t TopShadowFrameOffset() { | 
|  | 201 | return OFFSETOF_MEMBER(ManagedStack, top_shadow_frame_); | 
|  | 202 | } | 
|  | 203 |  | 
|  | 204 | size_t NumShadowFrameReferences() const; | 
|  | 205 |  | 
|  | 206 | bool ShadowFramesContain(Object** shadow_frame_entry) const; | 
|  | 207 |  | 
|  | 208 | private: | 
|  | 209 | ManagedStack* link_; | 
|  | 210 | ShadowFrame* top_shadow_frame_; | 
|  | 211 | Method** top_quick_frame_; | 
|  | 212 | uintptr_t top_quick_frame_pc_; | 
|  | 213 | }; | 
|  | 214 |  | 
|  | 215 | class StackVisitor { | 
|  | 216 | protected: | 
|  | 217 | StackVisitor(const ManagedStack* stack, const std::vector<TraceStackFrame>* trace_stack, | 
|  | 218 | Context* context = NULL) : | 
|  | 219 | stack_start_(stack), trace_stack_(trace_stack), cur_shadow_frame_(NULL), cur_quick_frame_(NULL), | 
|  | 220 | cur_quick_frame_pc_(0), num_frames_(0), cur_depth_(0), context_(context) {} | 
|  | 221 |  | 
|  | 222 | public: | 
|  | 223 | virtual ~StackVisitor() {} | 
|  | 224 |  | 
|  | 225 | // Return 'true' if we should continue to visit more frames, 'false' to stop. | 
|  | 226 | virtual bool VisitFrame() = 0; | 
|  | 227 |  | 
|  | 228 | void WalkStack(bool include_transitions = false); | 
|  | 229 |  | 
|  | 230 | Method* GetMethod() const { | 
|  | 231 | if (cur_shadow_frame_ != NULL) { | 
|  | 232 | return cur_shadow_frame_->GetMethod(); | 
|  | 233 | } else if (cur_quick_frame_ != NULL) { | 
|  | 234 | return *cur_quick_frame_; | 
|  | 235 | } else { | 
|  | 236 | return NULL; | 
|  | 237 | } | 
|  | 238 | } | 
|  | 239 |  | 
|  | 240 | bool IsShadowFrame() const { | 
|  | 241 | return cur_shadow_frame_ != NULL; | 
|  | 242 | } | 
|  | 243 |  | 
|  | 244 | uintptr_t LoadCalleeSave(int num, size_t frame_size) const { | 
|  | 245 | // Callee saves are held at the top of the frame | 
|  | 246 | Method* method = GetMethod(); | 
|  | 247 | DCHECK(method != NULL); | 
|  | 248 | byte* save_addr = | 
|  | 249 | reinterpret_cast<byte*>(cur_quick_frame_) + frame_size - ((num + 1) * kPointerSize); | 
|  | 250 | #if defined(__i386__) | 
|  | 251 | save_addr -= kPointerSize;  // account for return address | 
|  | 252 | #endif | 
|  | 253 | return *reinterpret_cast<uintptr_t*>(save_addr); | 
|  | 254 | } | 
|  | 255 |  | 
|  | 256 | uint32_t GetDexPc() const; | 
|  | 257 |  | 
|  | 258 | // Gets the height of the stack in the managed stack frames, including transitions. | 
|  | 259 | size_t GetFrameHeight() { | 
|  | 260 | return GetNumFrames() - cur_depth_; | 
|  | 261 | } | 
|  | 262 |  | 
|  | 263 | // Get a frame ID where 0 is a special value. | 
|  | 264 | size_t GetFrameId() { | 
|  | 265 | return GetFrameHeight() + 1; | 
|  | 266 | } | 
|  | 267 |  | 
|  | 268 | size_t GetNumFrames() { | 
|  | 269 | if (num_frames_ == 0) { | 
|  | 270 | num_frames_ = ComputeNumFrames(); | 
|  | 271 | } | 
|  | 272 | return num_frames_; | 
|  | 273 | } | 
|  | 274 |  | 
|  | 275 | uint32_t GetVReg(Method* m, int vreg) const; | 
|  | 276 |  | 
|  | 277 | void SetVReg(Method* m, int vreg, uint32_t new_value); | 
|  | 278 |  | 
|  | 279 | uintptr_t GetGPR(uint32_t reg) const; | 
|  | 280 |  | 
|  | 281 | uint32_t GetVReg(const DexFile::CodeItem* code_item, uint32_t core_spills, | 
|  | 282 | uint32_t fp_spills, size_t frame_size, int vreg) const { | 
|  | 283 | int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg); | 
|  | 284 | byte* vreg_addr = reinterpret_cast<byte*>(GetCurrentQuickFrame()) + offset; | 
|  | 285 | return *reinterpret_cast<uint32_t*>(vreg_addr); | 
|  | 286 | } | 
|  | 287 |  | 
|  | 288 | uintptr_t GetReturnPc() const; | 
|  | 289 |  | 
|  | 290 | void SetReturnPc(uintptr_t new_ret_pc); | 
|  | 291 |  | 
|  | 292 | /* | 
|  | 293 | * Return sp-relative offset for a Dalvik virtual register, compiler | 
|  | 294 | * spill or Method* in bytes using Method*. | 
|  | 295 | * Note that (reg >= 0) refers to a Dalvik register, (reg == -2) | 
|  | 296 | * denotes Method* and (reg <= -3) denotes a compiler temp. | 
|  | 297 | * | 
|  | 298 | *     +------------------------+ | 
|  | 299 | *     | IN[ins-1]              |  {Note: resides in caller's frame} | 
|  | 300 | *     |       .                | | 
|  | 301 | *     | IN[0]                  | | 
|  | 302 | *     | caller's Method*       | | 
|  | 303 | *     +========================+  {Note: start of callee's frame} | 
|  | 304 | *     | core callee-save spill |  {variable sized} | 
|  | 305 | *     +------------------------+ | 
|  | 306 | *     | fp callee-save spill   | | 
|  | 307 | *     +------------------------+ | 
|  | 308 | *     | filler word            |  {For compatibility, if V[locals-1] used as wide | 
|  | 309 | *     +------------------------+ | 
|  | 310 | *     | V[locals-1]            | | 
|  | 311 | *     | V[locals-2]            | | 
|  | 312 | *     |      .                 | | 
|  | 313 | *     |      .                 |  ... (reg == 2) | 
|  | 314 | *     | V[1]                   |  ... (reg == 1) | 
|  | 315 | *     | V[0]                   |  ... (reg == 0) <---- "locals_start" | 
|  | 316 | *     +------------------------+ | 
|  | 317 | *     | Compiler temps         |  ... (reg == -2) | 
|  | 318 | *     |                        |  ... (reg == -3) | 
|  | 319 | *     |                        |  ... (reg == -4) | 
|  | 320 | *     +------------------------+ | 
|  | 321 | *     | stack alignment padding|  {0 to (kStackAlignWords-1) of padding} | 
|  | 322 | *     +------------------------+ | 
|  | 323 | *     | OUT[outs-1]            | | 
|  | 324 | *     | OUT[outs-2]            | | 
|  | 325 | *     |       .                | | 
|  | 326 | *     | OUT[0]                 | | 
|  | 327 | *     | curMethod*             |  ... (reg == -1) <<== sp, 16-byte aligned | 
|  | 328 | *     +========================+ | 
|  | 329 | */ | 
|  | 330 | static int GetVRegOffset(const DexFile::CodeItem* code_item, | 
|  | 331 | uint32_t core_spills, uint32_t fp_spills, | 
|  | 332 | size_t frame_size, int reg) { | 
|  | 333 | DCHECK_EQ(frame_size & (kStackAlignment - 1), 0U); | 
|  | 334 | int num_spills = __builtin_popcount(core_spills) + __builtin_popcount(fp_spills) + 1; // Filler. | 
|  | 335 | int num_ins = code_item->ins_size_; | 
|  | 336 | int num_regs = code_item->registers_size_ - num_ins; | 
|  | 337 | int locals_start = frame_size - ((num_spills + num_regs) * sizeof(uint32_t)); | 
|  | 338 | if (reg == -2) { | 
|  | 339 | return 0;  // Method* | 
|  | 340 | } else if (reg <= -3) { | 
|  | 341 | return locals_start - ((reg + 1) * sizeof(uint32_t));  // Compiler temp. | 
|  | 342 | } else if (reg < num_regs) { | 
|  | 343 | return locals_start + (reg * sizeof(uint32_t));        // Dalvik local reg. | 
|  | 344 | } else { | 
|  | 345 | return frame_size + ((reg - num_regs) * sizeof(uint32_t)) + sizeof(uint32_t); // Dalvik in. | 
|  | 346 | } | 
|  | 347 | } | 
|  | 348 |  | 
|  | 349 | uintptr_t GetCurrentQuickFramePc() const { | 
|  | 350 | return cur_quick_frame_pc_; | 
|  | 351 | } | 
|  | 352 |  | 
|  | 353 | Method** GetCurrentQuickFrame() const { | 
|  | 354 | return cur_quick_frame_; | 
|  | 355 | } | 
|  | 356 |  | 
|  | 357 | ShadowFrame* GetCurrentShadowFrame() const { | 
|  | 358 | return cur_shadow_frame_; | 
|  | 359 | } | 
|  | 360 |  | 
|  | 361 | private: | 
|  | 362 | size_t ComputeNumFrames() const; | 
|  | 363 |  | 
|  | 364 | TraceStackFrame GetTraceStackFrame(uint32_t depth) const { | 
|  | 365 | return trace_stack_->at(trace_stack_->size() - depth - 1); | 
|  | 366 | } | 
|  | 367 |  | 
|  | 368 | void SanityCheckFrame(); | 
|  | 369 |  | 
|  | 370 | const ManagedStack* const stack_start_; | 
|  | 371 | const std::vector<TraceStackFrame>* const trace_stack_; | 
|  | 372 | ShadowFrame* cur_shadow_frame_; | 
|  | 373 | Method** cur_quick_frame_; | 
|  | 374 | uintptr_t cur_quick_frame_pc_; | 
|  | 375 | // Lazily computed, number of frames in the stack. | 
|  | 376 | size_t num_frames_; | 
|  | 377 | // Depth of the frame we're currently at. | 
|  | 378 | size_t cur_depth_; | 
|  | 379 | protected: | 
|  | 380 | Context* const context_; | 
|  | 381 | }; | 
|  | 382 |  | 
|  | 383 | static inline uintptr_t AdjustQuickFramePcForDexPcComputation(uintptr_t pc) { | 
|  | 384 | // Quick methods record a mapping from quick PCs to Dex PCs at the beginning of the code for | 
|  | 385 | // each dex instruction. When walking the stack, the return PC will be set to the instruction | 
|  | 386 | // following call which will likely be the start of the next dex instruction. Adjust the PC | 
|  | 387 | // for these cases by 2 bytes in case the return PC also has the thumb bit set. | 
|  | 388 | if (pc > 0) { pc -= 2; } | 
|  | 389 | return pc; | 
|  | 390 | } | 
|  | 391 |  | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 392 | }  // namespace art | 
|  | 393 |  | 
|  | 394 | #endif  // ART_SRC_STACK_H_ |