Skip to content

Commit

Permalink
Merge commit '5825f5e7b67b' from swift/release/6.1 into stable/20240723
Browse files Browse the repository at this point in the history
  • Loading branch information
git apple-llvm automerger committed Jan 30, 2025
2 parents fe24ba0 + 5825f5e commit 6a23220
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2321,6 +2321,21 @@ static llvm::Expected<addr_t> GetCFA(Process &process, RegisterContext &regctx,
cfa_loc.GetValueType());
}

static UnwindPlanSP GetUnwindPlanForAsyncRegister(FuncUnwinders &unwinders,
Target &target,
Thread &thread) {
// We cannot trust compiler emitted unwind plans, as they respect the
// swifttail calling convention, which assumes the async register is _not_
// restored and therefore it is not tracked by compiler plans. If LLDB uses
// those plans, it may take "no info" to mean "register not clobbered". For
// those reasons, always favour the assembly plan first, it will try to track
// the async register by assuming the usual arm calling conventions.
if (UnwindPlanSP asm_plan = unwinders.GetAssemblyUnwindPlan(target, thread))
return asm_plan;
// In the unlikely case the assembly plan is not available, try all others.
return unwinders.GetUnwindPlanAtNonCallSite(target, thread);
}

/// Attempts to use UnwindPlans that inspect assembly to recover the entry value
/// of the async context register. This is a simplified version of the methods
/// in RegisterContextUnwind, since plumbing access to those here would be
Expand All @@ -2338,7 +2353,7 @@ static llvm::Expected<addr_t> ReadAsyncContextRegisterFromUnwind(

Target &target = process.GetTarget();
UnwindPlanSP unwind_plan =
unwinders->GetUnwindPlanAtNonCallSite(target, regctx.GetThread());
GetUnwindPlanForAsyncRegister(*unwinders, target, regctx.GetThread());
if (!unwind_plan)
return llvm::createStringError(
"SwiftLanguageRuntime: Failed to find non call site unwind plan at "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SWIFT_SOURCES := main.swift
SWIFTFLAGS_EXTRAS := -parse-as-library -Xfrontend -Xllvm -Xfrontend --emit-dwarf-unwind=always
include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import lldb
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbtest as lldbtest
import lldbsuite.test.lldbutil as lldbutil


# This test is a best effort attempt at creating a program with high register
# pressure while also making the linker avoid compact unwind.
class TestCase(lldbtest.TestBase):

mydir = lldbtest.TestBase.compute_mydir(__file__)

def set_breakpoints_all_instructions(self, target):
funclet_name = "$s1a12ASYNC___1___SiyYaFTY0_"
breakpoints = set()

sym_ctx_list = target.FindFunctions(funclet_name)
self.assertEqual(
sym_ctx_list.GetSize(),
1,
f"failed to get symbol context for {funclet_name}",
)
function = sym_ctx_list[0].function

instructions = list(function.GetInstructions(target))
self.assertGreater(len(instructions), 0)
for instruction in instructions:
bp = target.BreakpointCreateBySBAddress(instruction.GetAddress())
self.assertTrue(
bp.IsValid(), f"failed to set bp inside funclet {funclet_name}"
)
breakpoints.add(bp.GetID())
return breakpoints

def check_unwind_ok(self, thread):
# Check that we see the virtual backtrace:
expected_funcnames = [
"ASYNC___1___",
"ASYNC___2___",
"ASYNC___3___",
"ASYNC___4___",
"ASYNC___5___",
]
frames = thread.frames
self.assertGreater(
len(frames), len(expected_funcnames), f"Invalid backtrace for {frames}"
)
actual_funcnames = [
frame.GetFunctionName() for frame in frames[: len(expected_funcnames)]
]
for expected_name, actual_name in zip(expected_funcnames, actual_funcnames):
self.assertIn(expected_name, actual_name, f"Unexpected backtrace: {frames}")

@swiftTest
@skipIf(oslist=["windows", "linux"])
def test(self):
"""Test that the debugger can unwind at all instructions of all funclets"""
self.build()

source_file = lldb.SBFileSpec("main.swift")
target, process, _, bp = lldbutil.run_to_source_breakpoint(
self, "BREAK HERE", source_file
)
target.DeleteAllBreakpoints()

breakpoints = self.set_breakpoints_all_instructions(target)
num_breakpoints = len(breakpoints)

# Reach most breakpoints and ensure we can unwind in that position.
while True:
process.Continue()
if process.GetState() == lldb.eStateExited:
break
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
self.assertTrue(thread.IsValid())
bpid = thread.GetStopReasonDataAtIndex(0)
breakpoints.remove(bpid)
target.FindBreakpointByID(bpid).SetEnabled(False)

self.check_unwind_ok(thread)

# We will never hit all breakpoints we set, because of things like
# overflow handling or other unreachable traps. However, it's good to
# have some sanity check that we have hit at least a decent chunk of
# them.
breakpoints_not_hit = len(breakpoints)
self.assertLess(breakpoints_not_hit / num_breakpoints, 0.25)
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
func work(_ objects: Any...) {
for object in objects {
print("Processing object of type: \(type(of: object))")
}
}

func use(_ x: Int, _ y: Int) -> Int {
return x &* y &+ x &- y
}

var arr: [Int] = []

func ASYNC___1___() async -> Int {
var a1 = 1, a2 = 2, a3 = 3, a4 = 4, a5 = 5
print("BREAK HERE")
var a6 = 6, a7 = 7, a8 = 8, a9 = 9, a10 = 10
var a11 = 11, a12 = 12, a13 = 13, a14 = 14, a15 = 15
var a16 = 16, a17 = 17, a18 = 18, a19 = 19, a20 = 20
var a21 = 21, a22 = 22, a23 = 23, a24 = 24, a25 = 25
var a26 = 26, a27 = 27, a28 = 28, a29 = 29, a30 = 30
a1 = use(a1, a2)
a3 = use(a3, a4)
a5 = use(a5, a6)
a7 = use(a7, a8)
a9 = use(a9, a10)
a11 = use(a11, a12)
a13 = use(a13, a14)
a15 = use(a15, a16)
a17 = use(a17, a18)
a19 = use(a19, a20)
a21 = use(a21, a22)
a23 = use(a23, a24)
a25 = use(a25, a26)
a27 = use(a27, a28)
a29 = use(a29, a30)
work(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24,a25, a26,a27, a28, a29, a30)
arr = [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24,a25, a26,a27, a28, a29, a30]
return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19
}

func ASYNC___2___() async -> Int {
let result = await ASYNC___1___()
return result
}

func ASYNC___3___() async -> Int {
let result = await ASYNC___2___()
return result
}

func ASYNC___4___() async -> Int {
let result = await ASYNC___3___()
return result
}

func ASYNC___5___() async -> Int {
let result = await ASYNC___4___()
return result
}

@main struct Main {
static func main() async {
let result = await ASYNC___5___()
print(result)
}
}

0 comments on commit 6a23220

Please sign in to comment.