Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup of Python Stack Access #81

Open
saulshanabrook opened this issue Sep 7, 2020 · 2 comments
Open

Cleanup of Python Stack Access #81

saulshanabrook opened this issue Sep 7, 2020 · 2 comments

Comments

@saulshanabrook
Copy link
Contributor

There were some comments here by @Caagr98 on how we can clean up our ability to access the Python stack, that we could try to incorporate. I haven't looked into them yet.

@Kyuuhachi
Copy link

Here's the simplified code I ended up with.

import sys
import ctypes as c

__all__ = ("get_stack",)

class Frame(c.Structure):
	_fields_ = (
		*(
			("_ob_next", c.POINTER(c.py_object)),
			("_ob_prev", c.POINTER(c.py_object)),
		) * sys.flags.debug,
		("ob_refcnt", c.c_ssize_t),
		("ob_type", c.py_object),
		("ob_size", c.c_ssize_t),
		("f_back", c.py_object), # c.POINTER(Frame)
		("f_code", c.py_object),
		("f_builtins", c.py_object),
		("f_globals", c.py_object),
		("f_locals", c.py_object),
		# The two fields below are pointers to PyObject arrays, but ctypes is
		# kinda weird so it's easier to just use them as void pointers
		("f_valuestack", c.c_void_p),
		("f_stacktop", c.c_void_p),
	)

def get_stack(frame):
	PTR_SIZE = c.sizeof(c.POINTER(c.py_object))
	_frame = Frame.from_address(id(frame))

	return tuple(
		c.py_object.from_address(addr).value
		for addr in range(_frame.f_valuestack, _frame.f_stacktop, PTR_SIZE)
	)

I'm not 100% certain I don't need to do anything about refcounts, but py_object probably deals with that automatically.

@saulshanabrook
Copy link
Contributor Author

@Caagr98 Awesome, thank you for this!

If anyone feels like updating our stack functionality to use this logic, you can edit the record_api/get_stack.py file.

In our usage we just need to be able to look at the ith item from the top of the stack, we never need to iterate through it all. So all we really need is the __getitem__ function to work on that OpStack class with negative indexes. Since performance is a concern here, we don't have any bounds checks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants