Skip to content

Commit

Permalink
[rt] Add NativeStackWalker for applications to walk stack
Browse files Browse the repository at this point in the history
  • Loading branch information
titzer committed Jul 10, 2023
1 parent e0ab636 commit 6204a8f
Show file tree
Hide file tree
Showing 12 changed files with 144 additions and 13 deletions.
21 changes: 21 additions & 0 deletions rt/gc/RiGc.v3
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,27 @@ component RiGc {
System.error("GcError", "Invalid object header");
return 0;
}
// scan references in a frame and return the size in bytes
def scanStackFrame(sp: Pointer, stackMap: int) -> int {
if ((stackMap & 0x80000) != 0) {
// extended entry
var vmap_p = CiRuntime.GC_EXTMAPS + (RiGc.INT_SIZE * (stackMap & 0x7FFFF));
return scanExtMap(vmap_p, sp);
} else {
// normal entry
return scanRefMap(stackMap, sp);
}
}
def stackmapSize(stackMap: int) -> int {
if ((stackMap & 0x80000) != 0) {
// extended entry
var vmap_p = CiRuntime.GC_EXTMAPS + (RiGc.INT_SIZE * (stackMap & 0x7FFFF));
return extmapSize(vmap_p);
} else {
// normal entry
return refmapSize(stackMap);
}
}
// scan the references at the given start address, returning the size
def scanRefMap(v: int, start: Pointer) -> int {
var vmap = v;
Expand Down
15 changes: 2 additions & 13 deletions rt/native/NativeStackScanner.v3
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ component NativeStackScanner {
}
return;
}
var frameSize = scanStackFrame(sp, stackmapEntry);
var stackMap = stackmapEntry.load<int>() >>> RiTables.PAGE_SHIFT;
var frameSize = RiGc.scanStackFrame(sp, stackMap);
if (RiGc.debug && frameSize != frameWords * RiGc.REF_SIZE) {
D.puts("\n\n!GcError: mismatch between source frame size ")
.puti(frameWords * RiGc.REF_SIZE)
Expand All @@ -56,16 +57,4 @@ component NativeStackScanner {
ip = t.0; sp = t.1;
}
}
// scan a single stack frame
def scanStackFrame(sp: Pointer, stackmapEntry: Pointer) -> int {
var stackMap = stackmapEntry.load<int>() >>> RiTables.PAGE_SHIFT;
if ((stackMap & 0x80000) != 0) {
// extended entry
var vmap_p = CiRuntime.GC_EXTMAPS + (RiGc.INT_SIZE * (stackMap & 0x7FFFF));
return RiGc.scanExtMap(vmap_p, sp);
} else {
// normal entry
return RiGc.scanRefMap(stackMap, sp);
}
}
}
44 changes: 44 additions & 0 deletions rt/native/NativeStackWalker.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2019 Google Inc. All rights reserved.
// See LICENSE for details of Apache 2.0 license.

// Encapsulates logic relating to walking the stack to be exposed to (power user) applications.
component NativeStackWalker {
def iterateFrames(i: Pointer, s: Pointer, callback: (Pointer, Pointer, RiUserCode, int) -> bool) {
var ip = i, sp = s;
while (true) {
// Try looking up a GC stackmap entry first.
var stackmapEntry = RiTables.exactMatch(RiTables.searchTable(CiRuntime.GC_STACKMAP_PAGES,
CiRuntime.GC_STACKMAP_TABLE, ip));
if (stackmapEntry != Pointer.NULL) { // found a (GC) stackmap entry.
var stackMap = stackmapEntry.load<int>() >>> RiTables.PAGE_SHIFT;
var frameSize = RiGc.stackmapSize(stackMap);
callback(ip, sp, null, frameSize);
var t = RiOs.callerFrame(ip, sp, frameSize / RiGc.REF_SIZE);
ip = t.0; sp = t.1;
continue;
}

//
/* TODO: try using a source entry if no GC entry.
var sourceEntry = RiTables.findSource(ip);
if (sourceEntry != Pointer.NULL) { // found a source entry.
var frameWords = printSourceEntry(ip, sourceEntry);
var t = RiOs.callerFrame(ip, sp, frameWords);
ip = t.0; sp = t.1;
continue;
}
*/

// Search for user code.
if (RiRuntime.userCodeList != null) {
var userCode = RiRuntime.findUserCode(ip);
if (userCode == null) return; // no user code found
callback(ip, sp, userCode, 0);
var t = userCode.nextFrame(ip, sp);
ip = t.0; sp = t.1;
continue;
}
return; // unknown frame; assume finished
}
}
}
14 changes: 14 additions & 0 deletions test/rt/x86-64-darwin/stackwalk0.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def main() -> int {
foo(Array<byte>.new(4));
foo(Array<int>.new(8));
return 33;
}
def foo<T>(x: Array<T>) -> int {
NativeStackWalker.iterateFrames(CiRuntime.callerIp() + -1, CiRuntime.callerSp(), printFrame);
return x.length;
}
def printFrame(ip: Pointer, sp: Pointer, code: RiUserCode, size: int) -> bool {
if (code == null) System.puts("--{virgil frame}--\n");
else System.puts("--{user frame}--\n");
return true;
}
2 changes: 2 additions & 0 deletions test/rt/x86-64-darwin/stackwalk0.v3.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--{virgil frame}--
--{virgil frame}--
14 changes: 14 additions & 0 deletions test/rt/x86-64-linux/stackwalk0.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def main() -> int {
foo(Array<byte>.new(4));
foo(Array<int>.new(8));
return 33;
}
def foo<T>(x: Array<T>) -> int {
NativeStackWalker.iterateFrames(CiRuntime.callerIp() + -1, CiRuntime.callerSp(), printFrame);
return x.length;
}
def printFrame(ip: Pointer, sp: Pointer, code: RiUserCode, size: int) -> bool {
if (code == null) System.puts("--{virgil frame}--\n");
else System.puts("--{user frame}--\n");
return true;
}
2 changes: 2 additions & 0 deletions test/rt/x86-64-linux/stackwalk0.v3.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--{virgil frame}--
--{virgil frame}--
13 changes: 13 additions & 0 deletions test/rt/x86-64-linux/stackwalk1.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
def main() -> int {
foo(Array<byte>.new(4));
foo(Array<int>.new(8));
return 33;
}
def foo<T>(x: Array<T>) -> int {
NativeStackWalker.iterateFrames(CiRuntime.callerIp() + -1, CiRuntime.callerSp(), printFrame);
return x.length;
}
def printFrame(ip: Pointer, sp: Pointer, code: RiUserCode, size: int) -> bool {
System.puts("--{user frame}--\n");
return true;
}
14 changes: 14 additions & 0 deletions test/rt/x86-darwin/stackwalk0.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def main() -> int {
foo(Array<byte>.new(4));
foo(Array<int>.new(8));
return 33;
}
def foo<T>(x: Array<T>) -> int {
NativeStackWalker.iterateFrames(CiRuntime.callerIp() + -1, CiRuntime.callerSp(), printFrame);
return x.length;
}
def printFrame(ip: Pointer, sp: Pointer, code: RiUserCode, size: int) -> bool {
if (code == null) System.puts("--{virgil frame}--\n");
else System.puts("--{user frame}--\n");
return true;
}
2 changes: 2 additions & 0 deletions test/rt/x86-darwin/stackwalk0.v3.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--{virgil frame}--
--{virgil frame}--
14 changes: 14 additions & 0 deletions test/rt/x86-linux/stackwalk0.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def main() -> int {
foo(Array<byte>.new(4));
foo(Array<int>.new(8));
return 33;
}
def foo<T>(x: Array<T>) -> int {
NativeStackWalker.iterateFrames(CiRuntime.callerIp() + -1, CiRuntime.callerSp(), printFrame);
return x.length;
}
def printFrame(ip: Pointer, sp: Pointer, code: RiUserCode, size: int) -> bool {
if (code == null) System.puts("--{virgil frame}--\n");
else System.puts("--{user frame}--\n");
return true;
}
2 changes: 2 additions & 0 deletions test/rt/x86-linux/stackwalk0.v3.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--{virgil frame}--
--{virgil frame}--

0 comments on commit 6204a8f

Please sign in to comment.