luau/tools/stackdbg.py
Andy Friesen 8a64cb8b73
Sync to upstream/release/624 (#1245)
# What's changed?

* Optimize table.maxn.  This function is now 5-14x faster
* Reserve Luau stack space for error message.

## New Solver

* Globals can be type-stated, but only if they are already in scope
* Fix a stack overflow that could occur when normalizing certain kinds
of recursive unions of intersections (of unions of intersections...)
* Fix an assertion failure that would trigger when the __iter metamethod
has a bad signature

## Native Codegen

* Type propagation and temporary register type hints
* Direct vector property access should only happen for names of right
length
* BytecodeAnalysis will only predict that some of the vector value
fields are numbers

---

## Internal Contributors

Co-authored-by: Alexander McCord <amccord@roblox.com>
Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Aviral Goel <agoel@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-05-03 13:17:51 -07:00

94 lines
3.7 KiB
Python

#!usr/bin/python3
"""
To use this command, simply run the command:
`command script import /path/to/your/game-engine/Client/Luau/tools/stackdbg.py`
in the `lldb` interpreter. You can also add it to your .lldbinit file to have it be
automatically imported.
If using vscode, you can add the above command to your launch.json under `preRunCommands` for the appropriate target. For example:
{
"name": "Luau.UnitTest",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/ninja/common-tests/noopt/Luau/Luau.UnitTest",
"preRunCommands": [
"command script import ${workspaceFolder}/Client/Luau/tools/stackdbg.py"
],
}
Once this is loaded,
`(lldb) help stack`
or
`(lldb) stack -h
or
`(lldb) stack --help
can get you started
"""
import lldb
import functools
import argparse
import shlex
# Dumps the collected frame data
def dump(collected):
for (frame_name, size_in_kb, live_size_kb, variables) in collected:
print(f'{frame_name}, locals: {size_in_kb}kb, fp-sp: {live_size_kb}kb')
for (var_name, var_size, variable_obj) in variables:
print(f' {var_name}, {var_size} bytes')
def dbg_stack_pressure(frame, frames_to_show = 5, sort_frames = False, vars_to_show = 5, sort_vars = True):
totalKb = 0
collect = []
for f in frame.thread:
frame_name = f.GetFunctionName()
variables = [ (v.GetName(), v.GetByteSize(), v) for v in f.get_locals() ]
if sort_vars:
variables.sort(key = lambda x: x[1], reverse = True)
size_in_kb = functools.reduce(lambda x,y : x + y[1], variables, 0) / 1024
fp = f.GetFP()
sp = f.GetSP()
live_size_kb = round((fp - sp) / 1024, 2)
size_in_kb = round(size_in_kb, 2)
totalKb += size_in_kb
collect.append((frame_name, size_in_kb, live_size_kb, variables[:vars_to_show]))
if sort_frames:
collect.sort(key = lambda x: x[1], reverse = True)
print("******************** Report Stack Usage ********************")
totalMb = round(totalKb / 1024, 2)
print(f'{len(frame.thread)} stack frames used {totalMb}MB')
dump(collect[:frames_to_show])
def stack(debugger, command, result, internal_dict):
"""
usage: [-h] [-f FRAMES] [-fd] [-v VARS] [-vd]
optional arguments:
-h, --help show this help message and exit
-f FRAMES, --frames FRAMES
How many stack frames to display
-fd, --sort_frames Sort frames
-v VARS, --vars VARS How many variables per frame to display
-vd, --sort_vars Sort frames
"""
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
args = shlex.split(command)
argparser = argparse.ArgumentParser(allow_abbrev = True)
argparser.add_argument("-f", "--frames", required=False, help="How many stack frames to display", default=5, type=int)
argparser.add_argument("-fd", "--sort_frames", required=False, help="Sort frames in descending order of stack usage", action="store_true", default=False)
argparser.add_argument("-v", "--vars", required=False, help="How many variables per frame to display", default=5, type=int)
argparser.add_argument("-vd", "--sort_vars", required=False, help="Sort locals in descending order of stack usage ", action="store_true", default=False)
args = argparser.parse_args(args)
dbg_stack_pressure(frame, frames_to_show=args.frames, sort_frames=args.sort_frames, vars_to_show=args.vars, sort_vars=args.sort_vars)
# Initialization code to add commands
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand('command script add -f stackdbg.stack stack')
print("The 'stack' python command has been installed and is ready for use.")