stack.cc revision 6bc4374e3fa00e3ee5e832e1761c43e0b8a71558
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#include "stack.h" 18 19#include "arch/context.h" 20#include "art_code.h" 21#include "art_method-inl.h" 22#include "base/hex_dump.h" 23#include "entrypoints/entrypoint_utils-inl.h" 24#include "entrypoints/runtime_asm_entrypoints.h" 25#include "gc_map.h" 26#include "gc/space/image_space.h" 27#include "gc/space/space-inl.h" 28#include "linear_alloc.h" 29#include "mirror/class-inl.h" 30#include "mirror/object-inl.h" 31#include "mirror/object_array-inl.h" 32#include "quick/quick_method_frame_info.h" 33#include "runtime.h" 34#include "thread.h" 35#include "thread_list.h" 36#include "verify_object-inl.h" 37#include "vmap_table.h" 38 39namespace art { 40 41static constexpr bool kDebugStackWalk = false; 42 43mirror::Object* ShadowFrame::GetThisObject() const { 44 ArtMethod* m = GetMethod(); 45 if (m->IsStatic()) { 46 return nullptr; 47 } else if (m->IsNative()) { 48 return GetVRegReference(0); 49 } else { 50 const DexFile::CodeItem* code_item = m->GetCodeItem(); 51 CHECK(code_item != nullptr) << PrettyMethod(m); 52 uint16_t reg = code_item->registers_size_ - code_item->ins_size_; 53 return GetVRegReference(reg); 54 } 55} 56 57mirror::Object* ShadowFrame::GetThisObject(uint16_t num_ins) const { 58 ArtMethod* m = GetMethod(); 59 if (m->IsStatic()) { 60 return nullptr; 61 } else { 62 return GetVRegReference(NumberOfVRegs() - num_ins); 63 } 64} 65 66size_t ManagedStack::NumJniShadowFrameReferences() const { 67 size_t count = 0; 68 for (const ManagedStack* current_fragment = this; current_fragment != nullptr; 69 current_fragment = current_fragment->GetLink()) { 70 for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != nullptr; 71 current_frame = current_frame->GetLink()) { 72 if (current_frame->GetMethod()->IsNative()) { 73 // The JNI ShadowFrame only contains references. (For indirect reference.) 74 count += current_frame->NumberOfVRegs(); 75 } 76 } 77 } 78 return count; 79} 80 81bool ManagedStack::ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const { 82 for (const ManagedStack* current_fragment = this; current_fragment != nullptr; 83 current_fragment = current_fragment->GetLink()) { 84 for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != nullptr; 85 current_frame = current_frame->GetLink()) { 86 if (current_frame->Contains(shadow_frame_entry)) { 87 return true; 88 } 89 } 90 } 91 return false; 92} 93 94StackVisitor::StackVisitor(Thread* thread, Context* context, StackWalkKind walk_kind) 95 : StackVisitor(thread, context, walk_kind, 0) {} 96 97StackVisitor::StackVisitor(Thread* thread, 98 Context* context, 99 StackWalkKind walk_kind, 100 size_t num_frames) 101 : thread_(thread), 102 walk_kind_(walk_kind), 103 cur_shadow_frame_(nullptr), 104 cur_quick_frame_(nullptr), 105 cur_quick_frame_pc_(0), 106 num_frames_(num_frames), 107 cur_depth_(0), 108 current_inlining_depth_(0), 109 context_(context) { 110 DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread; 111} 112 113InlineInfo StackVisitor::GetCurrentInlineInfo() const { 114 ArtCode outer_code = GetCurrentCode(); 115 uint32_t native_pc_offset = outer_code.NativeQuickPcOffset(cur_quick_frame_pc_); 116 CodeInfo code_info = outer_code.GetOptimizedCodeInfo(); 117 StackMapEncoding encoding = code_info.ExtractEncoding(); 118 StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); 119 DCHECK(stack_map.IsValid()); 120 return code_info.GetInlineInfoOf(stack_map, encoding); 121} 122 123ArtMethod* StackVisitor::GetMethod() const { 124 if (cur_shadow_frame_ != nullptr) { 125 return cur_shadow_frame_->GetMethod(); 126 } else if (cur_quick_frame_ != nullptr) { 127 if (IsInInlinedFrame()) { 128 size_t depth_in_stack_map = current_inlining_depth_ - 1; 129 InlineInfo inline_info = GetCurrentInlineInfo(); 130 return GetResolvedMethod(*GetCurrentQuickFrame(), inline_info, depth_in_stack_map); 131 } else { 132 return *cur_quick_frame_; 133 } 134 } 135 return nullptr; 136} 137 138uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const { 139 if (cur_shadow_frame_ != nullptr) { 140 return cur_shadow_frame_->GetDexPC(); 141 } else if (cur_quick_frame_ != nullptr) { 142 if (IsInInlinedFrame()) { 143 size_t depth_in_stack_map = current_inlining_depth_ - 1; 144 return GetCurrentInlineInfo().GetDexPcAtDepth(depth_in_stack_map); 145 } else { 146 return GetCurrentCode().ToDexPc(cur_quick_frame_pc_, abort_on_failure); 147 } 148 } else { 149 return 0; 150 } 151} 152 153extern "C" mirror::Object* artQuickGetProxyThisObject(ArtMethod** sp) 154 SHARED_REQUIRES(Locks::mutator_lock_); 155 156mirror::Object* StackVisitor::GetThisObject() const { 157 DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), sizeof(void*)); 158 ArtMethod* m = GetMethod(); 159 if (m->IsStatic()) { 160 return nullptr; 161 } else if (m->IsNative()) { 162 if (cur_quick_frame_ != nullptr) { 163 HandleScope* hs = reinterpret_cast<HandleScope*>( 164 reinterpret_cast<char*>(cur_quick_frame_) + 165 GetCurrentCode().GetHandleScopeOffset().SizeValue()); 166 return hs->GetReference(0); 167 } else { 168 return cur_shadow_frame_->GetVRegReference(0); 169 } 170 } else if (m->IsProxyMethod()) { 171 if (cur_quick_frame_ != nullptr) { 172 return artQuickGetProxyThisObject(cur_quick_frame_); 173 } else { 174 return cur_shadow_frame_->GetVRegReference(0); 175 } 176 } else { 177 const DexFile::CodeItem* code_item = m->GetCodeItem(); 178 if (code_item == nullptr) { 179 UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: " 180 << PrettyMethod(m); 181 return nullptr; 182 } else { 183 uint16_t reg = code_item->registers_size_ - code_item->ins_size_; 184 uint32_t value = 0; 185 bool success = GetVReg(m, reg, kReferenceVReg, &value); 186 // We currently always guarantee the `this` object is live throughout the method. 187 CHECK(success) << "Failed to read the this object in " << PrettyMethod(m); 188 return reinterpret_cast<mirror::Object*>(value); 189 } 190 } 191} 192 193size_t StackVisitor::GetNativePcOffset() const { 194 DCHECK(!IsShadowFrame()); 195 return GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_); 196} 197 198bool StackVisitor::IsReferenceVReg(ArtMethod* m, uint16_t vreg) { 199 DCHECK_EQ(m, GetMethod()); 200 // Process register map (which native and runtime methods don't have) 201 if (m->IsNative() || m->IsRuntimeMethod() || m->IsProxyMethod()) { 202 return false; 203 } 204 if (GetCurrentCode().IsOptimized(sizeof(void*))) { 205 return true; // TODO: Implement. 206 } 207 const uint8_t* native_gc_map = GetCurrentCode().GetNativeGcMap(sizeof(void*)); 208 CHECK(native_gc_map != nullptr) << PrettyMethod(m); 209 const DexFile::CodeItem* code_item = m->GetCodeItem(); 210 // Can't be null or how would we compile its instructions? 211 DCHECK(code_item != nullptr) << PrettyMethod(m); 212 NativePcOffsetToReferenceMap map(native_gc_map); 213 size_t num_regs = std::min(map.RegWidth() * 8, static_cast<size_t>(code_item->registers_size_)); 214 const uint8_t* reg_bitmap = nullptr; 215 if (num_regs > 0) { 216 uintptr_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(GetCurrentQuickFramePc()); 217 reg_bitmap = map.FindBitMap(native_pc_offset); 218 DCHECK(reg_bitmap != nullptr); 219 } 220 // Does this register hold a reference? 221 return vreg < num_regs && TestBitmap(vreg, reg_bitmap); 222} 223 224bool StackVisitor::GetVRegFromDebuggerShadowFrame(uint16_t vreg, 225 VRegKind kind, 226 uint32_t* val) const { 227 size_t frame_id = const_cast<StackVisitor*>(this)->GetFrameId(); 228 ShadowFrame* shadow_frame = thread_->FindDebuggerShadowFrame(frame_id); 229 if (shadow_frame != nullptr) { 230 bool* updated_vreg_flags = thread_->GetUpdatedVRegFlags(frame_id); 231 DCHECK(updated_vreg_flags != nullptr); 232 if (updated_vreg_flags[vreg]) { 233 // Value is set by the debugger. 234 if (kind == kReferenceVReg) { 235 *val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>( 236 shadow_frame->GetVRegReference(vreg))); 237 } else { 238 *val = shadow_frame->GetVReg(vreg); 239 } 240 return true; 241 } 242 } 243 // No value is set by the debugger. 244 return false; 245} 246 247bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const { 248 if (cur_quick_frame_ != nullptr) { 249 DCHECK(context_ != nullptr); // You can't reliably read registers without a context. 250 DCHECK(m == GetMethod()); 251 // Check if there is value set by the debugger. 252 if (GetVRegFromDebuggerShadowFrame(vreg, kind, val)) { 253 return true; 254 } 255 if (GetCurrentCode().IsOptimized(sizeof(void*))) { 256 return GetVRegFromOptimizedCode(m, vreg, kind, val); 257 } else { 258 return GetVRegFromQuickCode(m, vreg, kind, val); 259 } 260 } else { 261 DCHECK(cur_shadow_frame_ != nullptr); 262 *val = cur_shadow_frame_->GetVReg(vreg); 263 return true; 264 } 265} 266 267bool StackVisitor::GetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind, 268 uint32_t* val) const { 269 DCHECK_EQ(m, GetMethod()); 270 const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); 271 QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); 272 uint32_t vmap_offset; 273 // TODO: IsInContext stops before spotting floating point registers. 274 if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) { 275 bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); 276 uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); 277 uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind); 278 return GetRegisterIfAccessible(reg, kind, val); 279 } else { 280 const DexFile::CodeItem* code_item = m->GetCodeItem(); 281 DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile 282 // its instructions? 283 *val = *GetVRegAddrFromQuickCode(cur_quick_frame_, code_item, frame_info.CoreSpillMask(), 284 frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg); 285 return true; 286 } 287} 288 289bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind, 290 uint32_t* val) const { 291 DCHECK_EQ(m, GetMethod()); 292 const DexFile::CodeItem* code_item = m->GetCodeItem(); 293 DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile 294 // its instructions? 295 uint16_t number_of_dex_registers = code_item->registers_size_; 296 DCHECK_LT(vreg, code_item->registers_size_); 297 CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo(); 298 StackMapEncoding encoding = code_info.ExtractEncoding(); 299 300 uint32_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_); 301 StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); 302 DCHECK(stack_map.IsValid()); 303 size_t depth_in_stack_map = current_inlining_depth_ - 1; 304 305 DexRegisterMap dex_register_map = IsInInlinedFrame() 306 ? code_info.GetDexRegisterMapAtDepth(depth_in_stack_map, 307 code_info.GetInlineInfoOf(stack_map, encoding), 308 encoding, 309 number_of_dex_registers) 310 : code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); 311 312 DexRegisterLocation::Kind location_kind = 313 dex_register_map.GetLocationKind(vreg, number_of_dex_registers, code_info, encoding); 314 switch (location_kind) { 315 case DexRegisterLocation::Kind::kInStack: { 316 const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg, 317 number_of_dex_registers, 318 code_info, 319 encoding); 320 const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset; 321 *val = *reinterpret_cast<const uint32_t*>(addr); 322 return true; 323 } 324 case DexRegisterLocation::Kind::kInRegister: 325 case DexRegisterLocation::Kind::kInRegisterHigh: 326 case DexRegisterLocation::Kind::kInFpuRegister: 327 case DexRegisterLocation::Kind::kInFpuRegisterHigh: { 328 uint32_t reg = 329 dex_register_map.GetMachineRegister(vreg, number_of_dex_registers, code_info, encoding); 330 return GetRegisterIfAccessible(reg, kind, val); 331 } 332 case DexRegisterLocation::Kind::kConstant: 333 *val = dex_register_map.GetConstant(vreg, number_of_dex_registers, code_info, encoding); 334 return true; 335 case DexRegisterLocation::Kind::kNone: 336 return false; 337 default: 338 LOG(FATAL) 339 << "Unexpected location kind" 340 << DexRegisterLocation::PrettyDescriptor( 341 dex_register_map.GetLocationInternalKind(vreg, 342 number_of_dex_registers, 343 code_info, 344 encoding)); 345 UNREACHABLE(); 346 } 347} 348 349bool StackVisitor::GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t* val) const { 350 const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); 351 352 // X86 float registers are 64-bit and the logic below does not apply. 353 DCHECK(!is_float || kRuntimeISA != InstructionSet::kX86); 354 355 if (!IsAccessibleRegister(reg, is_float)) { 356 return false; 357 } 358 uintptr_t ptr_val = GetRegister(reg, is_float); 359 const bool target64 = Is64BitInstructionSet(kRuntimeISA); 360 if (target64) { 361 const bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg); 362 const bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg); 363 int64_t value_long = static_cast<int64_t>(ptr_val); 364 if (wide_lo) { 365 ptr_val = static_cast<uintptr_t>(Low32Bits(value_long)); 366 } else if (wide_hi) { 367 ptr_val = static_cast<uintptr_t>(High32Bits(value_long)); 368 } 369 } 370 *val = ptr_val; 371 return true; 372} 373 374bool StackVisitor::GetVRegPairFromDebuggerShadowFrame(uint16_t vreg, 375 VRegKind kind_lo, 376 VRegKind kind_hi, 377 uint64_t* val) const { 378 uint32_t low_32bits; 379 uint32_t high_32bits; 380 bool success = GetVRegFromDebuggerShadowFrame(vreg, kind_lo, &low_32bits); 381 success &= GetVRegFromDebuggerShadowFrame(vreg + 1, kind_hi, &high_32bits); 382 if (success) { 383 *val = (static_cast<uint64_t>(high_32bits) << 32) | static_cast<uint64_t>(low_32bits); 384 } 385 return success; 386} 387 388bool StackVisitor::GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, 389 VRegKind kind_hi, uint64_t* val) const { 390 if (kind_lo == kLongLoVReg) { 391 DCHECK_EQ(kind_hi, kLongHiVReg); 392 } else if (kind_lo == kDoubleLoVReg) { 393 DCHECK_EQ(kind_hi, kDoubleHiVReg); 394 } else { 395 LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi; 396 UNREACHABLE(); 397 } 398 // Check if there is value set by the debugger. 399 if (GetVRegPairFromDebuggerShadowFrame(vreg, kind_lo, kind_hi, val)) { 400 return true; 401 } 402 if (cur_quick_frame_ != nullptr) { 403 DCHECK(context_ != nullptr); // You can't reliably read registers without a context. 404 DCHECK(m == GetMethod()); 405 if (GetCurrentCode().IsOptimized(sizeof(void*))) { 406 return GetVRegPairFromOptimizedCode(m, vreg, kind_lo, kind_hi, val); 407 } else { 408 return GetVRegPairFromQuickCode(m, vreg, kind_lo, kind_hi, val); 409 } 410 } else { 411 DCHECK(cur_shadow_frame_ != nullptr); 412 *val = cur_shadow_frame_->GetVRegLong(vreg); 413 return true; 414 } 415} 416 417bool StackVisitor::GetVRegPairFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, 418 VRegKind kind_hi, uint64_t* val) const { 419 DCHECK_EQ(m, GetMethod()); 420 const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); 421 QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); 422 uint32_t vmap_offset_lo, vmap_offset_hi; 423 // TODO: IsInContext stops before spotting floating point registers. 424 if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) && 425 vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) { 426 bool is_float = (kind_lo == kDoubleLoVReg); 427 uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); 428 uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo); 429 uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi); 430 return GetRegisterPairIfAccessible(reg_lo, reg_hi, kind_lo, val); 431 } else { 432 const DexFile::CodeItem* code_item = m->GetCodeItem(); 433 DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile 434 // its instructions? 435 uint32_t* addr = GetVRegAddrFromQuickCode( 436 cur_quick_frame_, code_item, frame_info.CoreSpillMask(), 437 frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg); 438 *val = *reinterpret_cast<uint64_t*>(addr); 439 return true; 440 } 441} 442 443bool StackVisitor::GetVRegPairFromOptimizedCode(ArtMethod* m, uint16_t vreg, 444 VRegKind kind_lo, VRegKind kind_hi, 445 uint64_t* val) const { 446 uint32_t low_32bits; 447 uint32_t high_32bits; 448 bool success = GetVRegFromOptimizedCode(m, vreg, kind_lo, &low_32bits); 449 success &= GetVRegFromOptimizedCode(m, vreg + 1, kind_hi, &high_32bits); 450 if (success) { 451 *val = (static_cast<uint64_t>(high_32bits) << 32) | static_cast<uint64_t>(low_32bits); 452 } 453 return success; 454} 455 456bool StackVisitor::GetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, 457 VRegKind kind_lo, uint64_t* val) const { 458 const bool is_float = (kind_lo == kDoubleLoVReg); 459 if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) { 460 return false; 461 } 462 uintptr_t ptr_val_lo = GetRegister(reg_lo, is_float); 463 uintptr_t ptr_val_hi = GetRegister(reg_hi, is_float); 464 bool target64 = Is64BitInstructionSet(kRuntimeISA); 465 if (target64) { 466 int64_t value_long_lo = static_cast<int64_t>(ptr_val_lo); 467 int64_t value_long_hi = static_cast<int64_t>(ptr_val_hi); 468 ptr_val_lo = static_cast<uintptr_t>(Low32Bits(value_long_lo)); 469 ptr_val_hi = static_cast<uintptr_t>(High32Bits(value_long_hi)); 470 } 471 *val = (static_cast<uint64_t>(ptr_val_hi) << 32) | static_cast<uint32_t>(ptr_val_lo); 472 return true; 473} 474 475bool StackVisitor::SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value, 476 VRegKind kind) { 477 if (cur_quick_frame_ != nullptr) { 478 DCHECK(context_ != nullptr); // You can't reliably write registers without a context. 479 DCHECK(m == GetMethod()); 480 if (GetCurrentCode().IsOptimized(sizeof(void*))) { 481 return false; 482 } else { 483 return SetVRegFromQuickCode(m, vreg, new_value, kind); 484 } 485 } else { 486 cur_shadow_frame_->SetVReg(vreg, new_value); 487 return true; 488 } 489} 490 491bool StackVisitor::SetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, uint32_t new_value, 492 VRegKind kind) { 493 DCHECK(context_ != nullptr); // You can't reliably write registers without a context. 494 DCHECK(m == GetMethod()); 495 const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); 496 QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); 497 uint32_t vmap_offset; 498 // TODO: IsInContext stops before spotting floating point registers. 499 if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) { 500 bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); 501 uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); 502 uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind); 503 return SetRegisterIfAccessible(reg, new_value, kind); 504 } else { 505 const DexFile::CodeItem* code_item = m->GetCodeItem(); 506 DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile 507 // its instructions? 508 uint32_t* addr = GetVRegAddrFromQuickCode( 509 cur_quick_frame_, code_item, frame_info.CoreSpillMask(), 510 frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg); 511 *addr = new_value; 512 return true; 513 } 514} 515 516bool StackVisitor::SetVRegFromDebugger(ArtMethod* m, 517 uint16_t vreg, 518 uint32_t new_value, 519 VRegKind kind) { 520 const DexFile::CodeItem* code_item = m->GetCodeItem(); 521 if (code_item == nullptr) { 522 return false; 523 } 524 ShadowFrame* shadow_frame = GetCurrentShadowFrame(); 525 if (shadow_frame == nullptr) { 526 // This is a compiled frame: we must prepare and update a shadow frame that will 527 // be executed by the interpreter after deoptimization of the stack. 528 const size_t frame_id = GetFrameId(); 529 const uint16_t num_regs = code_item->registers_size_; 530 shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc()); 531 CHECK(shadow_frame != nullptr); 532 // Remember the vreg has been set for debugging and must not be overwritten by the 533 // original value during deoptimization of the stack. 534 thread_->GetUpdatedVRegFlags(frame_id)[vreg] = true; 535 } 536 if (kind == kReferenceVReg) { 537 shadow_frame->SetVRegReference(vreg, reinterpret_cast<mirror::Object*>(new_value)); 538 } else { 539 shadow_frame->SetVReg(vreg, new_value); 540 } 541 return true; 542} 543 544bool StackVisitor::SetRegisterIfAccessible(uint32_t reg, uint32_t new_value, VRegKind kind) { 545 const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); 546 if (!IsAccessibleRegister(reg, is_float)) { 547 return false; 548 } 549 const bool target64 = Is64BitInstructionSet(kRuntimeISA); 550 551 // Create a new value that can hold both low 32 and high 32 bits, in 552 // case we are running 64 bits. 553 uintptr_t full_new_value = new_value; 554 // Deal with 32 or 64-bit wide registers in a way that builds on all targets. 555 if (target64) { 556 bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg); 557 bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg); 558 if (wide_lo || wide_hi) { 559 uintptr_t old_reg_val = GetRegister(reg, is_float); 560 uint64_t new_vreg_portion = static_cast<uint64_t>(new_value); 561 uint64_t old_reg_val_as_wide = static_cast<uint64_t>(old_reg_val); 562 uint64_t mask = 0xffffffff; 563 if (wide_lo) { 564 mask = mask << 32; 565 } else { 566 new_vreg_portion = new_vreg_portion << 32; 567 } 568 full_new_value = static_cast<uintptr_t>((old_reg_val_as_wide & mask) | new_vreg_portion); 569 } 570 } 571 SetRegister(reg, full_new_value, is_float); 572 return true; 573} 574 575bool StackVisitor::SetVRegPair(ArtMethod* m, uint16_t vreg, uint64_t new_value, 576 VRegKind kind_lo, VRegKind kind_hi) { 577 if (kind_lo == kLongLoVReg) { 578 DCHECK_EQ(kind_hi, kLongHiVReg); 579 } else if (kind_lo == kDoubleLoVReg) { 580 DCHECK_EQ(kind_hi, kDoubleHiVReg); 581 } else { 582 LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi; 583 } 584 if (cur_quick_frame_ != nullptr) { 585 DCHECK(context_ != nullptr); // You can't reliably write registers without a context. 586 DCHECK(m == GetMethod()); 587 if (GetCurrentCode().IsOptimized(sizeof(void*))) { 588 return false; 589 } else { 590 return SetVRegPairFromQuickCode(m, vreg, new_value, kind_lo, kind_hi); 591 } 592 } else { 593 DCHECK(cur_shadow_frame_ != nullptr); 594 cur_shadow_frame_->SetVRegLong(vreg, new_value); 595 return true; 596 } 597} 598 599bool StackVisitor::SetVRegPairFromQuickCode( 600 ArtMethod* m, uint16_t vreg, uint64_t new_value, VRegKind kind_lo, VRegKind kind_hi) { 601 DCHECK_EQ(m, GetMethod()); 602 const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*))); 603 QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo(); 604 uint32_t vmap_offset_lo, vmap_offset_hi; 605 // TODO: IsInContext stops before spotting floating point registers. 606 if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) && 607 vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) { 608 bool is_float = (kind_lo == kDoubleLoVReg); 609 uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); 610 uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo); 611 uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi); 612 return SetRegisterPairIfAccessible(reg_lo, reg_hi, new_value, is_float); 613 } else { 614 const DexFile::CodeItem* code_item = m->GetCodeItem(); 615 DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile 616 // its instructions? 617 uint32_t* addr = GetVRegAddrFromQuickCode( 618 cur_quick_frame_, code_item, frame_info.CoreSpillMask(), 619 frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg); 620 *reinterpret_cast<uint64_t*>(addr) = new_value; 621 return true; 622 } 623} 624 625bool StackVisitor::SetVRegPairFromDebugger(ArtMethod* m, 626 uint16_t vreg, 627 uint64_t new_value, 628 VRegKind kind_lo, 629 VRegKind kind_hi) { 630 if (kind_lo == kLongLoVReg) { 631 DCHECK_EQ(kind_hi, kLongHiVReg); 632 } else if (kind_lo == kDoubleLoVReg) { 633 DCHECK_EQ(kind_hi, kDoubleHiVReg); 634 } else { 635 LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi; 636 UNREACHABLE(); 637 } 638 const DexFile::CodeItem* code_item = m->GetCodeItem(); 639 if (code_item == nullptr) { 640 return false; 641 } 642 ShadowFrame* shadow_frame = GetCurrentShadowFrame(); 643 if (shadow_frame == nullptr) { 644 // This is a compiled frame: we must prepare for deoptimization (see SetVRegFromDebugger). 645 const size_t frame_id = GetFrameId(); 646 const uint16_t num_regs = code_item->registers_size_; 647 shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc()); 648 CHECK(shadow_frame != nullptr); 649 // Remember the vreg pair has been set for debugging and must not be overwritten by the 650 // original value during deoptimization of the stack. 651 thread_->GetUpdatedVRegFlags(frame_id)[vreg] = true; 652 thread_->GetUpdatedVRegFlags(frame_id)[vreg + 1] = true; 653 } 654 shadow_frame->SetVRegLong(vreg, new_value); 655 return true; 656} 657 658bool StackVisitor::SetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, 659 uint64_t new_value, bool is_float) { 660 if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) { 661 return false; 662 } 663 uintptr_t new_value_lo = static_cast<uintptr_t>(new_value & 0xFFFFFFFF); 664 uintptr_t new_value_hi = static_cast<uintptr_t>(new_value >> 32); 665 bool target64 = Is64BitInstructionSet(kRuntimeISA); 666 // Deal with 32 or 64-bit wide registers in a way that builds on all targets. 667 if (target64) { 668 DCHECK_EQ(reg_lo, reg_hi); 669 SetRegister(reg_lo, new_value, is_float); 670 } else { 671 SetRegister(reg_lo, new_value_lo, is_float); 672 SetRegister(reg_hi, new_value_hi, is_float); 673 } 674 return true; 675} 676 677bool StackVisitor::IsAccessibleGPR(uint32_t reg) const { 678 DCHECK(context_ != nullptr); 679 return context_->IsAccessibleGPR(reg); 680} 681 682uintptr_t* StackVisitor::GetGPRAddress(uint32_t reg) const { 683 DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine"; 684 DCHECK(context_ != nullptr); 685 return context_->GetGPRAddress(reg); 686} 687 688uintptr_t StackVisitor::GetGPR(uint32_t reg) const { 689 DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine"; 690 DCHECK(context_ != nullptr); 691 return context_->GetGPR(reg); 692} 693 694void StackVisitor::SetGPR(uint32_t reg, uintptr_t value) { 695 DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine"; 696 DCHECK(context_ != nullptr); 697 context_->SetGPR(reg, value); 698} 699 700bool StackVisitor::IsAccessibleFPR(uint32_t reg) const { 701 DCHECK(context_ != nullptr); 702 return context_->IsAccessibleFPR(reg); 703} 704 705uintptr_t StackVisitor::GetFPR(uint32_t reg) const { 706 DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine"; 707 DCHECK(context_ != nullptr); 708 return context_->GetFPR(reg); 709} 710 711void StackVisitor::SetFPR(uint32_t reg, uintptr_t value) { 712 DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine"; 713 DCHECK(context_ != nullptr); 714 context_->SetFPR(reg, value); 715} 716 717uintptr_t StackVisitor::GetReturnPc() const { 718 uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame()); 719 DCHECK(sp != nullptr); 720 uint8_t* pc_addr = sp + GetCurrentCode().GetReturnPcOffset().SizeValue(); 721 return *reinterpret_cast<uintptr_t*>(pc_addr); 722} 723 724void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) { 725 uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame()); 726 CHECK(sp != nullptr); 727 uint8_t* pc_addr = sp + GetCurrentCode().GetReturnPcOffset().SizeValue(); 728 *reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc; 729} 730 731size_t StackVisitor::ComputeNumFrames(Thread* thread, StackWalkKind walk_kind) { 732 struct NumFramesVisitor : public StackVisitor { 733 NumFramesVisitor(Thread* thread_in, StackWalkKind walk_kind_in) 734 : StackVisitor(thread_in, nullptr, walk_kind_in), frames(0) {} 735 736 bool VisitFrame() OVERRIDE { 737 frames++; 738 return true; 739 } 740 741 size_t frames; 742 }; 743 NumFramesVisitor visitor(thread, walk_kind); 744 visitor.WalkStack(true); 745 return visitor.frames; 746} 747 748bool StackVisitor::GetNextMethodAndDexPc(ArtMethod** next_method, uint32_t* next_dex_pc) { 749 struct HasMoreFramesVisitor : public StackVisitor { 750 HasMoreFramesVisitor(Thread* thread, 751 StackWalkKind walk_kind, 752 size_t num_frames, 753 size_t frame_height) 754 : StackVisitor(thread, nullptr, walk_kind, num_frames), 755 frame_height_(frame_height), 756 found_frame_(false), 757 has_more_frames_(false), 758 next_method_(nullptr), 759 next_dex_pc_(0) { 760 } 761 762 bool VisitFrame() OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { 763 if (found_frame_) { 764 ArtMethod* method = GetMethod(); 765 if (method != nullptr && !method->IsRuntimeMethod()) { 766 has_more_frames_ = true; 767 next_method_ = method; 768 next_dex_pc_ = GetDexPc(); 769 return false; // End stack walk once next method is found. 770 } 771 } else if (GetFrameHeight() == frame_height_) { 772 found_frame_ = true; 773 } 774 return true; 775 } 776 777 size_t frame_height_; 778 bool found_frame_; 779 bool has_more_frames_; 780 ArtMethod* next_method_; 781 uint32_t next_dex_pc_; 782 }; 783 HasMoreFramesVisitor visitor(thread_, walk_kind_, GetNumFrames(), GetFrameHeight()); 784 visitor.WalkStack(true); 785 *next_method = visitor.next_method_; 786 *next_dex_pc = visitor.next_dex_pc_; 787 return visitor.has_more_frames_; 788} 789 790void StackVisitor::DescribeStack(Thread* thread) { 791 struct DescribeStackVisitor : public StackVisitor { 792 explicit DescribeStackVisitor(Thread* thread_in) 793 : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {} 794 795 bool VisitFrame() OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { 796 LOG(INFO) << "Frame Id=" << GetFrameId() << " " << DescribeLocation(); 797 return true; 798 } 799 }; 800 DescribeStackVisitor visitor(thread); 801 visitor.WalkStack(true); 802} 803 804std::string StackVisitor::DescribeLocation() const { 805 std::string result("Visiting method '"); 806 ArtMethod* m = GetMethod(); 807 if (m == nullptr) { 808 return "upcall"; 809 } 810 result += PrettyMethod(m); 811 result += StringPrintf("' at dex PC 0x%04x", GetDexPc()); 812 if (!IsShadowFrame()) { 813 result += StringPrintf(" (native PC %p)", reinterpret_cast<void*>(GetCurrentQuickFramePc())); 814 } 815 return result; 816} 817 818static instrumentation::InstrumentationStackFrame& GetInstrumentationStackFrame(Thread* thread, 819 uint32_t depth) { 820 CHECK_LT(depth, thread->GetInstrumentationStack()->size()); 821 return thread->GetInstrumentationStack()->at(depth); 822} 823 824void StackVisitor::SanityCheckFrame() const { 825 if (kIsDebugBuild) { 826 ArtMethod* method = GetMethod(); 827 auto* declaring_class = method->GetDeclaringClass(); 828 // Runtime methods have null declaring class. 829 if (!method->IsRuntimeMethod()) { 830 CHECK(declaring_class != nullptr); 831 CHECK_EQ(declaring_class->GetClass(), declaring_class->GetClass()->GetClass()) 832 << declaring_class; 833 } else { 834 CHECK(declaring_class == nullptr); 835 } 836 Runtime* const runtime = Runtime::Current(); 837 LinearAlloc* const linear_alloc = runtime->GetLinearAlloc(); 838 if (!linear_alloc->Contains(method)) { 839 // Check class linker linear allocs. 840 mirror::Class* klass = method->GetDeclaringClass(); 841 LinearAlloc* const class_linear_alloc = (klass != nullptr) 842 ? ClassLinker::GetAllocatorForClassLoader(klass->GetClassLoader()) 843 : linear_alloc; 844 if (!class_linear_alloc->Contains(method)) { 845 // Check image space. 846 bool in_image = false; 847 for (auto& space : runtime->GetHeap()->GetContinuousSpaces()) { 848 if (space->IsImageSpace()) { 849 auto* image_space = space->AsImageSpace(); 850 const auto& header = image_space->GetImageHeader(); 851 const auto* methods = &header.GetMethodsSection(); 852 if (methods->Contains(reinterpret_cast<const uint8_t*>(method) - image_space->Begin())) { 853 in_image = true; 854 break; 855 } 856 } 857 } 858 CHECK(in_image) << PrettyMethod(method) << " not in linear alloc or image"; 859 } 860 } 861 if (cur_quick_frame_ != nullptr) { 862 GetCurrentCode().AssertPcIsWithinQuickCode(cur_quick_frame_pc_); 863 // Frame sanity. 864 size_t frame_size = GetCurrentCode().GetFrameSizeInBytes(); 865 CHECK_NE(frame_size, 0u); 866 // A rough guess at an upper size we expect to see for a frame. 867 // 256 registers 868 // 2 words HandleScope overhead 869 // 3+3 register spills 870 // TODO: this seems architecture specific for the case of JNI frames. 871 // TODO: 083-compiler-regressions ManyFloatArgs shows this estimate is wrong. 872 // const size_t kMaxExpectedFrameSize = (256 + 2 + 3 + 3) * sizeof(word); 873 const size_t kMaxExpectedFrameSize = 2 * KB; 874 CHECK_LE(frame_size, kMaxExpectedFrameSize); 875 size_t return_pc_offset = GetCurrentCode().GetReturnPcOffset().SizeValue(); 876 CHECK_LT(return_pc_offset, frame_size); 877 } 878 } 879} 880 881void StackVisitor::WalkStack(bool include_transitions) { 882 DCHECK(thread_ == Thread::Current() || thread_->IsSuspended()); 883 CHECK_EQ(cur_depth_, 0U); 884 bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled(); 885 uint32_t instrumentation_stack_depth = 0; 886 887 for (const ManagedStack* current_fragment = thread_->GetManagedStack(); 888 current_fragment != nullptr; current_fragment = current_fragment->GetLink()) { 889 cur_shadow_frame_ = current_fragment->GetTopShadowFrame(); 890 cur_quick_frame_ = current_fragment->GetTopQuickFrame(); 891 cur_quick_frame_pc_ = 0; 892 893 if (cur_quick_frame_ != nullptr) { // Handle quick stack frames. 894 // Can't be both a shadow and a quick fragment. 895 DCHECK(current_fragment->GetTopShadowFrame() == nullptr); 896 ArtMethod* method = *cur_quick_frame_; 897 while (method != nullptr) { 898 SanityCheckFrame(); 899 900 if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames) 901 && GetCurrentCode().IsOptimized(sizeof(void*))) { 902 CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo(); 903 StackMapEncoding encoding = code_info.ExtractEncoding(); 904 uint32_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_); 905 StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); 906 if (stack_map.IsValid() && stack_map.HasInlineInfo(encoding)) { 907 InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); 908 DCHECK_EQ(current_inlining_depth_, 0u); 909 for (current_inlining_depth_ = inline_info.GetDepth(); 910 current_inlining_depth_ != 0; 911 --current_inlining_depth_) { 912 bool should_continue = VisitFrame(); 913 if (UNLIKELY(!should_continue)) { 914 return; 915 } 916 cur_depth_++; 917 } 918 } 919 } 920 921 bool should_continue = VisitFrame(); 922 if (UNLIKELY(!should_continue)) { 923 return; 924 } 925 926 if (context_ != nullptr) { 927 context_->FillCalleeSaves(*this); 928 } 929 size_t frame_size = GetCurrentCode().GetFrameSizeInBytes(); 930 // Compute PC for next stack frame from return PC. 931 size_t return_pc_offset = GetCurrentCode().GetReturnPcOffset().SizeValue(); 932 uint8_t* return_pc_addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + return_pc_offset; 933 uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr); 934 if (UNLIKELY(exit_stubs_installed)) { 935 // While profiling, the return pc is restored from the side stack, except when walking 936 // the stack for an exception where the side stack will be unwound in VisitFrame. 937 if (reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == return_pc) { 938 const instrumentation::InstrumentationStackFrame& instrumentation_frame = 939 GetInstrumentationStackFrame(thread_, instrumentation_stack_depth); 940 instrumentation_stack_depth++; 941 if (GetMethod() == Runtime::Current()->GetCalleeSaveMethod(Runtime::kSaveAll)) { 942 // Skip runtime save all callee frames which are used to deliver exceptions. 943 } else if (instrumentation_frame.interpreter_entry_) { 944 ArtMethod* callee = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs); 945 CHECK_EQ(GetMethod(), callee) << "Expected: " << PrettyMethod(callee) << " Found: " 946 << PrettyMethod(GetMethod()); 947 } else if (instrumentation_frame.method_ != GetMethod()) { 948 LOG(FATAL) << "Expected: " << PrettyMethod(instrumentation_frame.method_) 949 << " Found: " << PrettyMethod(GetMethod()); 950 } 951 if (num_frames_ != 0) { 952 // Check agreement of frame Ids only if num_frames_ is computed to avoid infinite 953 // recursion. 954 CHECK(instrumentation_frame.frame_id_ == GetFrameId()) 955 << "Expected: " << instrumentation_frame.frame_id_ 956 << " Found: " << GetFrameId(); 957 } 958 return_pc = instrumentation_frame.return_pc_; 959 } 960 } 961 ArtCode code = GetCurrentCode(); 962 963 cur_quick_frame_pc_ = return_pc; 964 uint8_t* next_frame = reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size; 965 cur_quick_frame_ = reinterpret_cast<ArtMethod**>(next_frame); 966 967 if (kDebugStackWalk) { 968 LOG(INFO) << PrettyMethod(method) << "@" << method << " size=" << frame_size 969 << " optimized=" << code.IsOptimized(sizeof(void*)) 970 << " native=" << method->IsNative() 971 << " entrypoints=" << method->GetEntryPointFromQuickCompiledCode() 972 << "," << method->GetEntryPointFromJni() 973 << " next=" << *cur_quick_frame_; 974 } 975 976 cur_depth_++; 977 method = *cur_quick_frame_; 978 } 979 } else if (cur_shadow_frame_ != nullptr) { 980 do { 981 SanityCheckFrame(); 982 bool should_continue = VisitFrame(); 983 if (UNLIKELY(!should_continue)) { 984 return; 985 } 986 cur_depth_++; 987 cur_shadow_frame_ = cur_shadow_frame_->GetLink(); 988 } while (cur_shadow_frame_ != nullptr); 989 } 990 if (include_transitions) { 991 bool should_continue = VisitFrame(); 992 if (!should_continue) { 993 return; 994 } 995 } 996 cur_depth_++; 997 } 998 if (num_frames_ != 0) { 999 CHECK_EQ(cur_depth_, num_frames_); 1000 } 1001} 1002 1003void JavaFrameRootInfo::Describe(std::ostream& os) const { 1004 const StackVisitor* visitor = stack_visitor_; 1005 CHECK(visitor != nullptr); 1006 os << "Type=" << GetType() << " thread_id=" << GetThreadId() << " location=" << 1007 visitor->DescribeLocation() << " vreg=" << vreg_; 1008} 1009 1010int StackVisitor::GetVRegOffsetFromQuickCode(const DexFile::CodeItem* code_item, 1011 uint32_t core_spills, uint32_t fp_spills, 1012 size_t frame_size, int reg, InstructionSet isa) { 1013 size_t pointer_size = InstructionSetPointerSize(isa); 1014 if (kIsDebugBuild) { 1015 auto* runtime = Runtime::Current(); 1016 if (runtime != nullptr) { 1017 CHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), pointer_size); 1018 } 1019 } 1020 DCHECK_ALIGNED(frame_size, kStackAlignment); 1021 DCHECK_NE(reg, -1); 1022 int spill_size = POPCOUNT(core_spills) * GetBytesPerGprSpillLocation(isa) 1023 + POPCOUNT(fp_spills) * GetBytesPerFprSpillLocation(isa) 1024 + sizeof(uint32_t); // Filler. 1025 int num_regs = code_item->registers_size_ - code_item->ins_size_; 1026 int temp_threshold = code_item->registers_size_; 1027 const int max_num_special_temps = 1; 1028 if (reg == temp_threshold) { 1029 // The current method pointer corresponds to special location on stack. 1030 return 0; 1031 } else if (reg >= temp_threshold + max_num_special_temps) { 1032 /* 1033 * Special temporaries may have custom locations and the logic above deals with that. 1034 * However, non-special temporaries are placed relative to the outs. 1035 */ 1036 int temps_start = code_item->outs_size_ * sizeof(uint32_t) + pointer_size /* art method */; 1037 int relative_offset = (reg - (temp_threshold + max_num_special_temps)) * sizeof(uint32_t); 1038 return temps_start + relative_offset; 1039 } else if (reg < num_regs) { 1040 int locals_start = frame_size - spill_size - num_regs * sizeof(uint32_t); 1041 return locals_start + (reg * sizeof(uint32_t)); 1042 } else { 1043 // Handle ins. 1044 return frame_size + ((reg - num_regs) * sizeof(uint32_t)) + pointer_size /* art method */; 1045 } 1046} 1047 1048void LockCountData::AddMonitorInternal(Thread* self, mirror::Object* obj) { 1049 if (obj == nullptr) { 1050 return; 1051 } 1052 1053 // If there's an error during enter, we won't have locked the monitor. So check there's no 1054 // exception. 1055 if (self->IsExceptionPending()) { 1056 return; 1057 } 1058 1059 if (monitors_ == nullptr) { 1060 monitors_.reset(new std::vector<mirror::Object*>()); 1061 } 1062 monitors_->push_back(obj); 1063} 1064 1065void LockCountData::RemoveMonitorInternal(Thread* self, const mirror::Object* obj) { 1066 if (obj == nullptr) { 1067 return; 1068 } 1069 bool found_object = false; 1070 if (monitors_ != nullptr) { 1071 // We need to remove one pointer to ref, as duplicates are used for counting recursive locks. 1072 // We arbitrarily choose the first one. 1073 auto it = std::find(monitors_->begin(), monitors_->end(), obj); 1074 if (it != monitors_->end()) { 1075 monitors_->erase(it); 1076 found_object = true; 1077 } 1078 } 1079 if (!found_object) { 1080 // The object wasn't found. Time for an IllegalMonitorStateException. 1081 // The order here isn't fully clear. Assume that any other pending exception is swallowed. 1082 // TODO: Maybe make already pending exception a suppressed exception. 1083 self->ClearException(); 1084 self->ThrowNewExceptionF("Ljava/lang/IllegalMonitorStateException;", 1085 "did not lock monitor on object of type '%s' before unlocking", 1086 PrettyTypeOf(const_cast<mirror::Object*>(obj)).c_str()); 1087 } 1088} 1089 1090// Helper to unlock a monitor. Must be NO_THREAD_SAFETY_ANALYSIS, as we can't statically show 1091// that the object was locked. 1092void MonitorExitHelper(Thread* self, mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS { 1093 DCHECK(self != nullptr); 1094 DCHECK(obj != nullptr); 1095 obj->MonitorExit(self); 1096} 1097 1098bool LockCountData::CheckAllMonitorsReleasedInternal(Thread* self) { 1099 DCHECK(self != nullptr); 1100 if (monitors_ != nullptr) { 1101 if (!monitors_->empty()) { 1102 // There may be an exception pending, if the method is terminating abruptly. Clear it. 1103 // TODO: Should we add this as a suppressed exception? 1104 self->ClearException(); 1105 1106 // OK, there are monitors that are still locked. To enforce structured locking (and avoid 1107 // deadlocks) we unlock all of them before we raise the IllegalMonitorState exception. 1108 for (mirror::Object* obj : *monitors_) { 1109 MonitorExitHelper(self, obj); 1110 // If this raised an exception, ignore. TODO: Should we add this as suppressed 1111 // exceptions? 1112 if (self->IsExceptionPending()) { 1113 self->ClearException(); 1114 } 1115 } 1116 // Raise an exception, just give the first object as the sample. 1117 mirror::Object* first = (*monitors_)[0]; 1118 self->ThrowNewExceptionF("Ljava/lang/IllegalMonitorStateException;", 1119 "did not unlock monitor on object of type '%s'", 1120 PrettyTypeOf(first).c_str()); 1121 1122 // To make sure this path is not triggered again, clean out the monitors. 1123 monitors_->clear(); 1124 1125 return false; 1126 } 1127 } 1128 return true; 1129} 1130 1131} // namespace art 1132