Commit 524b9284 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add frame.f_back support

parent 4870b92b
......@@ -907,6 +907,29 @@ PythonFrameIterator PythonFrameIterator::getCurrentVersion() {
return PythonFrameIterator(std::move(rtn));
}
PythonFrameIterator PythonFrameIterator::back() {
// TODO this is ineffecient: the iterator is no longer valid for libunwind iteration, so
// we have to do a full stack crawl again.
// Hopefully examination of f_back is uncommon.
std::unique_ptr<PythonFrameIteratorImpl> rtn(nullptr);
auto& impl = this->impl;
bool found = false;
unwindPythonStack([&](std::unique_ptr<PythonFrameIteratorImpl> frame_iter) {
if (found) {
rtn = std::move(frame_iter);
return true;
}
if (frame_iter->pointsToTheSameAs(*impl.get()))
found = true;
return false;
});
RELEASE_ASSERT(found, "this wasn't a valid frame?");
return PythonFrameIterator(std::move(rtn));
}
llvm::JITEventListener* makeTracebacksListener() {
return new TracebacksEventListener();
}
......
......@@ -58,10 +58,14 @@ public:
// the iterator was obtained, the methods may return old values. This returns
// an updated copy that returns the updated values.
// The "current version" will live at the same stack location, but any other
// similarities need to be verified by the caller.
// similarities need to be verified by the caller, ie it is up to the caller
// to determine that we didn't leave and reenter the stack frame.
// This function can only be called from the thread that created this object.
PythonFrameIterator getCurrentVersion();
// Assuming this is a valid frame iterator, return the next frame back (ie older).
PythonFrameIterator back();
PythonFrameIterator(PythonFrameIterator&& rhs);
void operator=(PythonFrameIterator&& rhs);
PythonFrameIterator(std::unique_ptr<PythonFrameIteratorImpl> impl);
......
......@@ -27,10 +27,12 @@ BoxedClass* frame_cls;
// - breaks c++ exceptions
// - we never free the trampolines
class BoxedFrame : public Box {
public:
BoxedFrame(PythonFrameIterator&& it) __attribute__((visibility("default")))
private:
// Call boxFrame to get a BoxedFrame object.
BoxedFrame(PythonFrameIterator it) __attribute__((visibility("default")))
: it(std::move(it)), thread_id(PyThread_get_thread_ident()) {}
public:
PythonFrameIterator it;
long thread_id;
......@@ -105,6 +107,16 @@ public:
return f->_globals;
}
static Box* back(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj);
f->update();
PythonFrameIterator it = f->it.back();
if (!it.exists())
return None;
return BoxedFrame::boxFrame(std::move(it));
}
static Box* lineno(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj);
f->update();
......@@ -113,6 +125,19 @@ public:
}
DEFAULT_CLASS(frame_cls);
static Box* boxFrame(PythonFrameIterator it) {
FrameInfo* fi = it.getFrameInfo();
if (fi->frame_obj == NULL) {
auto cf = it.getCF();
BoxedFrame* f = fi->frame_obj = new BoxedFrame(std::move(it));
assert(cf->clfunc->source->scoping->areGlobalsFromModule());
f->_globals = cf->clfunc->source->parent_module->getAttrWrapper();
f->_code = codeForCLFunction(cf->clfunc);
}
return fi->frame_obj;
}
};
Box* getFrame(int depth) {
......@@ -120,19 +145,9 @@ Box* getFrame(int depth) {
if (!it.exists())
return NULL;
FrameInfo* fi = it.getFrameInfo();
if (fi->frame_obj == NULL) {
auto cf = it.getCF();
BoxedFrame* f = fi->frame_obj = new BoxedFrame(std::move(it));
assert(cf->clfunc->source->scoping->areGlobalsFromModule());
f->_globals = cf->clfunc->source->parent_module->getAttrWrapper();
f->_code = codeForCLFunction(cf->clfunc);
}
return fi->frame_obj;
return BoxedFrame::boxFrame(std::move(it));
}
void setupFrame() {
frame_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false,
"frame");
......@@ -143,6 +158,7 @@ void setupFrame() {
frame_cls->giveAttr("f_lineno", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::lineno, NULL, NULL));
frame_cls->giveAttr("f_globals", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::globals, NULL, NULL));
frame_cls->giveAttr("f_back", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::back, NULL, NULL));
frame_cls->freeze();
}
......
......@@ -72,3 +72,18 @@ assert sys._getframe(0).f_globals is globals()
def f5():
assert sys._getframe(0).f_globals is globals()
f5()
# A number of libraries have functions like this:
def get_main_module():
f = sys._getframe(1)
while f.f_locals is not globals():
print f.f_code.co_filename, f.f_lineno, sorted(f.f_locals.items())
f = f.f_back
print "Main module currently at:", f.f_code.co_filename, f.f_lineno
print "f_back:", f.f_back
def f6(n):
if n:
f6(n - 1)
else:
get_main_module()
f6(10)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment