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
|
use ui;
use progvis:program;
use core:lang;
/**
* Data for a thread in the program.
*/
class Thread extends Data {
// Original thread.
ProgThread src;
// Stack frames.
Frame[] frames;
// Mirrorred data from the thread.
Bool alive;
Bool sleeping;
Bool crashed;
Bool afterReturn;
Bool barriersAvailable;
// Create.
init(ProgThread thread) {
init {
src = thread;
}
}
// Copy.
init(Thread original) {
init {
src = original.src;
frames = Frame[](original.frames);
alive = original.alive;
sleeping = original.sleeping;
crashed = original.crashed;
afterReturn = original.afterReturn;
}
}
// Get current position.
SrcPos? pos() {
if (frames.any)
return frames.last.pos;
null;
}
// Get thread id.
Nat id() { src.threadId; }
// Traverse stack frames and find individual values.
void update(World:Traversal t, unsafe:RawPtr object, Nat offset) : override {
alive = src.alive;
sleeping = src.sleeping;
crashed = src.crashed;
afterReturn = false;
// In some cases, we can be executed before the thread has started properly.
if (src.frames.any)
afterReturn = src.frames.last.returned;
barriersAvailable = src.barriersAvailable;
if (!alive & !crashed) {
// Remove frames, but not if we crashed (makes it easier to find the crash).
frames.clear();
return;
}
for (k, v in src.frames) {
if (k >= frames.count)
frames.push(Frame(v));
if (frames[k].src !is v)
frames[k] = Frame(v);
frames[k].update(t, object, 0);
}
while (frames.count > src.frames.count)
frames.pop();
}
// Traverse pointers.
void traverse(World:Traversal t, unsafe:RawPtr object, Nat offset) : override {
for (f in frames)
f.traverse(t, object, 0);
}
// Title.
Str title(World world) : override {
"Thread " + src.threadId.toS;
}
// Type.
Type? type() : override {
null;
}
// Visit.
void visit(DataVisitor v) : override {
super:visit(v);
for (f in frames)
f.visit(v);
}
// Summary.
protected void putSummary(StrBuf to, SummaryData data) : override {
// Stack frames. We don't need a delimiter.
for (f in frames) {
f.summary(to, data);
}
}
// Copy.
protected Data copyObject() : override {
Thread(this);
}
protected void copyData(Data->Data data) : override {
for (Nat i = 0; i < frames.count; i++)
if (x = frames[i].copy(data) as Frame)
frames[i] = x;
}
// Stack frame.
class Frame extends Composite {
// Original stack frame.
StackFrame src;
// Source position for this stack frame.
SrcPos pos;
// Current offset in the function.
Nat offset;
// Create.
init(StackFrame src) {
init(null) {
src = src;
}
}
// Copy.
init(Frame original) {
init(original) {
src = original.src;
pos = original.pos;
}
}
Str title(World world) : override {
// This is safe: the same stack frame object does not modify its title.
src.function;
}
void update(World:Traversal t, unsafe:RawPtr object, Nat offset) : override {
pos = src.pos;
offset = src.lastOffset;
for (k, v in src.variables) {
var ptr = unsafe:RawPtr(v.value);
if (k >= parts.count) {
parts << Part(v.name, 0, t.createStack(ptr), false);
} else if (parts[k].name != v.name) {
parts[k] = Part(v.name, 0, t.createStack(ptr), false);
} else {
var oldType = parts[k].value.type;
var newType = ptr.type;
if (oldType.empty | newType.empty) {
// No need to replace if any of them said null.
} else if (newType !is oldType) {
parts[k].value = t.createStack(ptr);
}
}
parts[k].value.update(t, ptr, 0);
// Don't add the object if it is represented as a StackPointer object. The
// StackPointer object treats the data as a pointer to the data, and not the value
// itself. If we add that, all StackData objects will simply point to themselves.
if (parts[k].value as StackPointer)
;
else
t.addData(ptr, parts[k].value);
}
while (parts.count > src.variables.count)
parts.pop();
}
void traverse(World:Traversal t, unsafe:RawPtr object, Nat offset) : override {
for (k, v in src.variables) {
var ptr = unsafe:RawPtr(v.value);
parts[k].value.traverse(t, ptr, 0);
}
}
protected Data copyObject() : override {
Frame(this);
}
protected void putSummary(StrBuf to, SummaryData data) : override {
// Put the location first:
if (file = pos.file)
to << file.title << ":" << pos.start << "-" << pos.end << "@" << offset << ".";
super:putSummary(to, data);
}
}
}
|