Commit c40fc9ac authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge commit 'pr/426' into getframe_merge

Conflicts:
	src/codegen/unwinding.cpp
	src/codegen/unwinding.h
parents a81ec92d f966a77e
...@@ -71,15 +71,9 @@ else: ...@@ -71,15 +71,9 @@ else:
_srcfile = __file__ _srcfile = __file__
_srcfile = os.path.normcase(_srcfile) _srcfile = os.path.normcase(_srcfile)
# next bit filched from 1.5.2's inspect.py # pyston changes: we don't support tb_frame or f_back, so always use sys._getframe
def currentframe(): currentframe = lambda: sys._getframe(4)
"""Return the frame object for the caller's stack frame.""" start_getframe = 4
try:
raise Exception
except:
return sys.exc_info()[2].tb_frame.f_back
if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)
# done filching # done filching
# _srcfile is only used in conjunction with sys._getframe(). # _srcfile is only used in conjunction with sys._getframe().
...@@ -1229,20 +1223,22 @@ class Logger(Filterer): ...@@ -1229,20 +1223,22 @@ class Logger(Filterer):
file name, line number and function name. file name, line number and function name.
""" """
# Pyston change:
return "(unknown file)", 0, "(unknown function)"
f = currentframe() f = currentframe()
# pyston change: we can't use f_back to walk back up the stack, so increment a counter of
# frames to skip and repeatedly call sys._getframe
fn = start_getframe
#On some versions of IronPython, currentframe() returns None if #On some versions of IronPython, currentframe() returns None if
#IronPython isn't run with -X:Frames. #IronPython isn't run with -X:Frames.
if f is not None: #if f is not None:
f = f.f_back # f = f.f_back
rv = "(unknown file)", 0, "(unknown function)" rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"): while hasattr(f, "f_code"):
co = f.f_code co = f.f_code
filename = os.path.normcase(co.co_filename) filename = os.path.normcase(co.co_filename)
if filename == _srcfile: if filename == _srcfile:
f = f.f_back fn += 1
f = sys._getframe(fn);
#f = f.f_back
continue continue
rv = (co.co_filename, f.f_lineno, co.co_name) rv = (co.co_filename, f.f_lineno, co.co_name)
break break
......
...@@ -99,6 +99,22 @@ Box* getSysStdout() { ...@@ -99,6 +99,22 @@ Box* getSysStdout() {
return sys_stdout; return sys_stdout;
} }
Box* sysGetFrame(Box* val) {
int depth = 0;
if (val) {
if (!isSubclass(val->cls, int_cls)) {
raiseExcHelper(TypeError, "TypeError: an integer is required");
}
depth = static_cast<BoxedInt*>(val)->n;
}
Box* frame = getFrame(depth);
if (!frame) {
raiseExcHelper(ValueError, "call stack is not deep enough");
}
return frame;
}
Box* sysGetDefaultEncoding() { Box* sysGetDefaultEncoding() {
return boxStrConstant(PyUnicode_GetDefaultEncoding()); return boxStrConstant(PyUnicode_GetDefaultEncoding());
} }
...@@ -281,6 +297,8 @@ void setupSys() { ...@@ -281,6 +297,8 @@ void setupSys() {
main_fn = llvm::sys::fs::getMainExecutable(NULL, NULL); main_fn = llvm::sys::fs::getMainExecutable(NULL, NULL);
sys_module->giveAttr("executable", boxString(main_fn.str())); sys_module->giveAttr("executable", boxString(main_fn.str()));
sys_module->giveAttr("_getframe",
new BoxedFunction(boxRTFunction((void*)sysGetFrame, UNKNOWN, 1, 1, false, false), { NULL }));
sys_module->giveAttr( sys_module->giveAttr(
"getdefaultencoding", "getdefaultencoding",
new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)sysGetDefaultEncoding, STR, 0), "getdefaultencoding")); new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)sysGetDefaultEncoding, STR, 0), "getdefaultencoding"));
......
...@@ -39,6 +39,16 @@ public: ...@@ -39,6 +39,16 @@ public:
boxGCHandler(v, b); boxGCHandler(v, b);
} }
static Box* name(Box* b, void*) {
RELEASE_ASSERT(b->cls == code_cls, "");
return boxString(static_cast<BoxedCode*>(b)->f->source->getName());
}
static Box* filename(Box* b, void*) {
RELEASE_ASSERT(b->cls == code_cls, "");
return boxString(static_cast<BoxedCode*>(b)->f->source->parent_module->fn);
}
static Box* argcount(Box* b, void*) { static Box* argcount(Box* b, void*) {
RELEASE_ASSERT(b->cls == code_cls, ""); RELEASE_ASSERT(b->cls == code_cls, "");
...@@ -80,12 +90,18 @@ Box* codeForFunction(BoxedFunction* f) { ...@@ -80,12 +90,18 @@ Box* codeForFunction(BoxedFunction* f) {
return new BoxedCode(f->f); return new BoxedCode(f->f);
} }
Box* codeForCLFunction(CLFunction* f) {
return new BoxedCode(f);
}
void setupCode() { void setupCode() {
code_cls code_cls
= BoxedHeapClass::create(type_cls, object_cls, &BoxedCode::gcHandler, 0, 0, sizeof(BoxedCode), false, "code"); = BoxedHeapClass::create(type_cls, object_cls, &BoxedCode::gcHandler, 0, 0, sizeof(BoxedCode), false, "code");
code_cls->giveAttr("__new__", None); // Hacky way of preventing users from instantiating this code_cls->giveAttr("__new__", None); // Hacky way of preventing users from instantiating this
code_cls->giveAttr("co_name", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::name, NULL, NULL));
code_cls->giveAttr("co_filename", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::filename, NULL, NULL));
code_cls->giveAttr("co_argcount", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::argcount, NULL, NULL)); code_cls->giveAttr("co_argcount", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::argcount, NULL, NULL));
code_cls->giveAttr("co_varnames", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::varnames, NULL, NULL)); code_cls->giveAttr("co_varnames", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::varnames, NULL, NULL));
code_cls->giveAttr("co_flags", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::flags, NULL, NULL)); code_cls->giveAttr("co_flags", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::flags, NULL, NULL));
......
// Copyright (c) 2014-2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "codegen/unwinding.h"
#include "runtime/types.h"
namespace pyston {
BoxedClass* frame_cls;
class BoxedFrame : public Box {
public:
BoxedFrame() __attribute__((visibility("default"))) {}
Box* _locals;
Box* _globals;
Box* _code;
uint32_t _lineno;
// cpython frame objects have the following attributes
// read-only attributes
//
// f_back[*] : previous stack frame (toward caller)
// f_code : code object being executed in this frame
// f_locals : dictionary used to look up local variables in this frame
// f_globals : dictionary used to look up global variables in this frame
// f_builtins[*] : dictionary to look up built-in (intrinsic) names
// f_restricted[*] : whether this function is executing in restricted execution mode
// f_lasti[*] : precise instruction (this is an index into the bytecode string of the code object)
// writable attributes
//
// f_trace[*] : if not None, is a function called at the start of each source code line (used by debugger)
// f_exc_type[*], : represent the last exception raised in the parent frame provided another exception was
// f_exc_value[*], : ever raised in the current frame (in all other cases they are None).
// f_exc_traceback[*] :
// f_lineno[**] : the current line number of the frame -- writing to this from within a trace function jumps
// to
// : the given line (only for the bottom-most frame). A debugger can implement a Jump command
// (aka
// : Set Next Statement) by writing to f_lineno
//
// * = unsupported in Pyston
// ** = getter supported, but setter unsupported
static void gchandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
auto f = static_cast<BoxedFrame*>(b);
v->visit(f->_code);
v->visit(f->_locals);
v->visit(f->_globals);
}
static Box* code(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj);
return f->_code;
}
static Box* locals(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj);
return f->_locals;
}
static Box* globals(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj);
return f->_globals;
}
static Box* lineno(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj);
return boxInt(f->_lineno);
}
DEFAULT_CLASS(frame_cls);
};
Box* getFrame(int depth) {
std::unique_ptr<ExecutionPoint> fr = getExecutionPoint(depth);
if (!fr)
return NULL;
Box* locals = fastLocalsToBoxedLocals(depth);
BoxedFrame* rtn = new BoxedFrame();
rtn->_locals = locals;
// basically the same as builtin globals()
// q: TODO is it ok that we don't return a real dict here?
rtn->_globals = makeAttrWrapper(fr->cf->clfunc->source->parent_module);
rtn->_code = codeForCLFunction(fr->cf->clfunc);
rtn->_lineno = fr->current_stmt->lineno;
return rtn;
}
void setupFrame() {
frame_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false,
"frame");
frame_cls->giveAttr("f_code", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::code, NULL, NULL));
// until we can determine if there's code in the wild that depends
// on f_locals boxing up fast locals when it's called, add methods
// getLocals() and getLineno() that we can modify code to use.
#ifdef expose_f_locals
frame_cls->giveAttr("f_locals", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::locals, NULL, NULL));
frame_cls->giveAttr("f_lineno", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::lineno, NULL, NULL));
#else
frame_cls->giveAttr("getLocals", new BoxedFunction(boxRTFunction((void*)BoxedFrame::locals, UNKNOWN, 1)));
frame_cls->giveAttr("getLineno", new BoxedFunction(boxRTFunction((void*)BoxedFrame::lineno, BOXED_INT, 1)));
#endif
frame_cls->giveAttr("f_globals", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::globals, NULL, NULL));
frame_cls->freeze();
}
}
...@@ -2146,6 +2146,7 @@ void setupRuntime() { ...@@ -2146,6 +2146,7 @@ void setupRuntime() {
setupDescr(); setupDescr();
setupTraceback(); setupTraceback();
setupCode(); setupCode();
setupFrame();
function_cls->giveAttr("__dict__", dict_descr); function_cls->giveAttr("__dict__", dict_descr);
function_cls->giveAttr("__name__", new (pyston_getset_cls) BoxedGetsetDescriptor(funcName, funcSetName, NULL)); function_cls->giveAttr("__name__", new (pyston_getset_cls) BoxedGetsetDescriptor(funcName, funcSetName, NULL));
......
...@@ -68,6 +68,7 @@ void setupGenerator(); ...@@ -68,6 +68,7 @@ void setupGenerator();
void setupDescr(); void setupDescr();
void teardownDescr(); void teardownDescr();
void setupCode(); void setupCode();
void setupFrame();
void setupSys(); void setupSys();
void setupBuiltins(); void setupBuiltins();
...@@ -815,6 +816,9 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems) ...@@ -815,6 +816,9 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
extern Box* dict_descr; extern Box* dict_descr;
Box* codeForFunction(BoxedFunction*); Box* codeForFunction(BoxedFunction*);
Box* codeForCLFunction(CLFunction*);
Box* getFrame(int depth);
} }
#endif #endif
import logging
import warnings
# output something using the root logger
def foo():
logging.warning("Houston, we have a %s", "bit of a problem")
foo()
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")
# Trigger a warning.
fxn()
# Verify some things
assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning)
assert "deprecated" in str(w[-1].message)
print "warnings module works"
"""
Frame Hack Recipe #1: Ruby-style string interpolation (version 1)
"""
# from http://farmdev.com/src/secrets/framehack/interpolate/solutions/interpolate1.py
import sys
from string import Template
def getLocals(frame):
try:
return frame.f_locals
except AttributeError:
return frame.getLocals()
def interpolate(templateStr):
frame = sys._getframe(1)
framedict = getLocals(frame)
t = Template(templateStr)
return t.substitute(**framedict)
name = 'Feihong'
place = 'Chicago'
print interpolate("My name is ${name}. I work in ${place}.")
import sys
def sysframetest():
return sys._getframe(0)
def sysframetestwrapper():
return sysframetest()
fr = sysframetest()
print sysframetest.__name__
print fr.f_code.co_name
print fr.f_code.co_filename
fr = sysframetestwrapper()
print sysframetestwrapper.__name__
print fr.f_code.co_name
print fr.f_code.co_filename
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