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
|
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "stack.h"
#include "compiler.h"
#include "object.h"
#include "object_utils.h"
#include "thread_list.h"
int oatVRegOffset(const art::DexFile::CodeItem* code_item,
uint32_t core_spills, uint32_t fp_spills,
size_t frame_size, int reg);
namespace art {
bool Frame::HasMethod() const {
return GetMethod() != NULL && (!GetMethod()->IsCalleeSaveMethod());
}
void Frame::Next() {
size_t frame_size = GetMethod()->GetFrameSizeInBytes();
DCHECK_NE(frame_size, 0u);
DCHECK_LT(frame_size, 1024u);
byte* next_sp = reinterpret_cast<byte*>(sp_) + frame_size;
sp_ = reinterpret_cast<Method**>(next_sp);
if (*sp_ != NULL) {
DCHECK((*sp_)->GetClass() == Method::GetMethodClass() ||
(*sp_)->GetClass() == Method::GetConstructorClass());
}
}
uintptr_t Frame::GetReturnPC() const {
byte* pc_addr = reinterpret_cast<byte*>(sp_) + GetMethod()->GetReturnPcOffsetInBytes();
return *reinterpret_cast<uintptr_t*>(pc_addr);
}
void Frame::SetReturnPC(uintptr_t pc) {
byte* pc_addr = reinterpret_cast<byte*>(sp_) + GetMethod()->GetReturnPcOffsetInBytes();
*reinterpret_cast<uintptr_t*>(pc_addr) = pc;
}
uint32_t Frame::GetVReg(const DexFile::CodeItem* code_item, uint32_t core_spills,
uint32_t fp_spills, size_t frame_size, int vreg) const {
int offset = oatVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg);
byte* vreg_addr = reinterpret_cast<byte*>(sp_) + offset;
return *reinterpret_cast<uint32_t*>(vreg_addr);
}
uint32_t Frame::GetVReg(Method* m, int vreg) const {
DCHECK(m == GetMethod());
const art::DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
DCHECK(code_item != NULL); // can't be NULL or how would we compile its instructions?
uint32_t core_spills = m->GetCoreSpillMask();
uint32_t fp_spills = m->GetFpSpillMask();
size_t frame_size = m->GetFrameSizeInBytes();
return GetVReg(code_item, core_spills, fp_spills, frame_size, vreg);
}
void Frame::SetVReg(Method* m, int vreg, uint32_t new_value) {
DCHECK(m == GetMethod());
const art::DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
DCHECK(code_item != NULL); // can't be NULL or how would we compile its instructions?
uint32_t core_spills = m->GetCoreSpillMask();
uint32_t fp_spills = m->GetFpSpillMask();
size_t frame_size = m->GetFrameSizeInBytes();
int offset = oatVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg);
byte* vreg_addr = reinterpret_cast<byte*>(sp_) + offset;
*reinterpret_cast<uint32_t*>(vreg_addr) = new_value;
}
uintptr_t Frame::LoadCalleeSave(int num) const {
// Callee saves are held at the top of the frame
Method* method = GetMethod();
DCHECK(method != NULL);
size_t frame_size = method->GetFrameSizeInBytes();
byte* save_addr = reinterpret_cast<byte*>(sp_) + frame_size - ((num + 1) * kPointerSize);
#if defined(__i386__)
save_addr -= kPointerSize; // account for return address
#endif
return *reinterpret_cast<uintptr_t*>(save_addr);
}
Method* Frame::NextMethod() const {
byte* next_sp = reinterpret_cast<byte*>(sp_) + GetMethod()->GetFrameSizeInBytes();
return *reinterpret_cast<Method**>(next_sp);
}
class StackGetter {
public:
StackGetter(JNIEnv* env, Thread* thread) : env_(env), thread_(thread), trace_(NULL) {
}
static void Callback(void* arg) {
reinterpret_cast<StackGetter*>(arg)->Callback();
}
jobject GetTrace() {
return trace_;
}
private:
void Callback() {
trace_ = thread_->CreateInternalStackTrace(env_);
}
JNIEnv* env_;
Thread* thread_;
jobject trace_;
};
jobject GetThreadStack(JNIEnv* env, Thread* thread) {
ThreadList* thread_list = Runtime::Current()->GetThreadList();
StackGetter stack_getter(env, thread);
thread_list->RunWhileSuspended(thread, StackGetter::Callback, &stack_getter);
return stack_getter.GetTrace();
}
} // namespace art
|