Commit 79ad8be8 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'getframe_merge'

parents 62794865 45225091
...@@ -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
......
...@@ -54,6 +54,12 @@ const int dwarf_to_gp[] = { ...@@ -54,6 +54,12 @@ const int dwarf_to_gp[] = {
// 17-32: xmm0-xmm15 // 17-32: xmm0-xmm15
}; };
Register Register::fromDwarf(int dwarf_regnum) {
assert(dwarf_regnum >= 0 && dwarf_regnum <= 16);
return Register(dwarf_to_gp[dwarf_regnum]);
}
GenericRegister GenericRegister::fromDwarf(int dwarf_regnum) { GenericRegister GenericRegister::fromDwarf(int dwarf_regnum) {
assert(dwarf_regnum >= 0); assert(dwarf_regnum >= 0);
...@@ -856,6 +862,20 @@ void Assembler::je(JumpDestination dest) { ...@@ -856,6 +862,20 @@ void Assembler::je(JumpDestination dest) {
jmp_cond(dest, COND_EQUAL); jmp_cond(dest, COND_EQUAL);
} }
void Assembler::jmpq(Register dest) {
int reg_idx = dest.regnum;
if (reg_idx >= 8) {
emitRex(REX_B);
reg_idx -= 8;
}
assert(0 <= reg_idx && reg_idx < 8);
emitByte(0xff);
emitModRM(0b11, 0b100, reg_idx);
}
void Assembler::set_cond(Register reg, ConditionCode condition) { void Assembler::set_cond(Register reg, ConditionCode condition) {
......
...@@ -140,6 +140,7 @@ public: ...@@ -140,6 +140,7 @@ public:
void jmp_cond(JumpDestination dest, ConditionCode condition); void jmp_cond(JumpDestination dest, ConditionCode condition);
void jmp(JumpDestination dest); void jmp(JumpDestination dest);
void jmpq(Register dest);
void je(JumpDestination dest); void je(JumpDestination dest);
void jne(JumpDestination dest); void jne(JumpDestination dest);
......
...@@ -45,6 +45,8 @@ struct Register { ...@@ -45,6 +45,8 @@ struct Register {
bool operator!=(const Register& rhs) const { return !(*this == rhs); } bool operator!=(const Register& rhs) const { return !(*this == rhs); }
void dump() const; void dump() const;
static Register fromDwarf(int dwarf_regnum);
}; };
const Register RAX(0); const Register RAX(0);
......
...@@ -469,8 +469,8 @@ extern "C" PyObject* PyObject_CallObject(PyObject* obj, PyObject* args) noexcept ...@@ -469,8 +469,8 @@ extern "C" PyObject* PyObject_CallObject(PyObject* obj, PyObject* args) noexcept
r = runtimeCall(obj, ArgPassSpec(0, 0, false, false), NULL, NULL, NULL, NULL, NULL); r = runtimeCall(obj, ArgPassSpec(0, 0, false, false), NULL, NULL, NULL, NULL, NULL);
return r; return r;
} catch (ExcInfo e) { } catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); setCAPIException(e);
return nullptr; return NULL;
} }
} }
......
...@@ -100,6 +100,16 @@ static llvm::Value* getExcinfoGep(llvm::IRBuilder<true>& builder, llvm::Value* v ...@@ -100,6 +100,16 @@ static llvm::Value* getExcinfoGep(llvm::IRBuilder<true>& builder, llvm::Value* v
return builder.CreateConstInBoundsGEP2_32(builder.CreateConstInBoundsGEP2_32(v, 0, 0), 0, 0); return builder.CreateConstInBoundsGEP2_32(builder.CreateConstInBoundsGEP2_32(v, 0, 0), 0, 0);
} }
static llvm::Value* getFrameObjGep(llvm::IRBuilder<true>& builder, llvm::Value* v) {
static_assert(offsetof(FrameInfo, exc) == 0, "");
static_assert(sizeof(ExcInfo) == 24, "");
static_assert(sizeof(Box*) == 8, "");
static_assert(offsetof(FrameInfo, frame_obj) == 32, "");
return builder.CreateConstInBoundsGEP2_32(v, 0, 2);
// TODO: this could be made more resilient by doing something like
// gep->accumulateConstantOffset(g.tm->getDataLayout(), ap_offset)
}
llvm::Value* IRGenState::getFrameInfoVar() { llvm::Value* IRGenState::getFrameInfoVar() {
/* /*
There is a matrix of possibilities here. There is a matrix of possibilities here.
...@@ -162,6 +172,11 @@ llvm::Value* IRGenState::getFrameInfoVar() { ...@@ -162,6 +172,11 @@ llvm::Value* IRGenState::getFrameInfoVar() {
builder.CreateStore(this->boxed_locals, boxed_locals_gep); builder.CreateStore(this->boxed_locals, boxed_locals_gep);
} }
// frame_info.frame_obj = NULL
static llvm::Type* llvm_frame_obj_type_ptr
= llvm::cast<llvm::StructType>(g.llvm_frame_info_type)->getElementType(2);
builder.CreateStore(embedConstantPtr(NULL, llvm_frame_obj_type_ptr), getFrameObjGep(builder, al));
this->frame_info = al; this->frame_info = al;
} }
} }
......
This diff is collapsed.
...@@ -33,19 +33,47 @@ Box* getGlobalsDict(); // always returns a dict-like object ...@@ -33,19 +33,47 @@ Box* getGlobalsDict(); // always returns a dict-like object
BoxedTraceback* getTraceback(); BoxedTraceback* getTraceback();
struct ExecutionPoint {
CompiledFunction* cf;
AST_stmt* current_stmt;
};
ExecutionPoint getExecutionPoint();
// Adds stack locals and closure locals into the locals dict, and returns it. // Adds stack locals and closure locals into the locals dict, and returns it.
Box* fastLocalsToBoxedLocals(); Box* fastLocalsToBoxedLocals();
class PythonFrameIteratorImpl;
class PythonFrameIterator {
private:
std::unique_ptr<PythonFrameIteratorImpl> impl;
public:
CompiledFunction* getCF();
FrameInfo* getFrameInfo();
bool exists() { return impl.get() != NULL; }
std::unique_ptr<ExecutionPoint> getExecutionPoint();
Box* fastLocalsToBoxedLocals();
// Gets the "current version" of this frame: if the frame has executed since
// 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.
// This function can only be called from the thread that created this object.
PythonFrameIterator getCurrentVersion();
PythonFrameIterator(PythonFrameIterator&& rhs);
void operator=(PythonFrameIterator&& rhs);
PythonFrameIterator(std::unique_ptr<PythonFrameIteratorImpl>&& impl);
~PythonFrameIterator();
};
PythonFrameIterator getPythonFrame(int depth);
// Fetches a writeable pointer to the frame-local excinfo object, // Fetches a writeable pointer to the frame-local excinfo object,
// calculating it if necessary (from previous frames). // calculating it if necessary (from previous frames).
ExcInfo* getFrameExcInfo(); ExcInfo* getFrameExcInfo();
struct ExecutionPoint {
CompiledFunction* cf;
AST_stmt* current_stmt;
};
ExecutionPoint getExecutionPoint();
struct FrameStackState { struct FrameStackState {
// This includes all # variables (but not the ! ones). // This includes all # variables (but not the ! ones).
// Therefore, it's not the same as the BoxedLocals. // Therefore, it's not the same as the BoxedLocals.
......
...@@ -561,16 +561,29 @@ struct ExcInfo { ...@@ -561,16 +561,29 @@ struct ExcInfo {
void printExcAndTraceback() const; void printExcAndTraceback() const;
}; };
class BoxedFrame;
struct FrameInfo { struct FrameInfo {
// Note(kmod): we have a number of fields here that all have independent
// initialization rules. We could potentially save time on every function-entry
// by having an "initialized" variable (or condition) that guards all of them.
// *Not the same semantics as CPython's frame->f_exc* // *Not the same semantics as CPython's frame->f_exc*
// In CPython, f_exc is the saved exc_info from the previous frame. // In CPython, f_exc is the saved exc_info from the previous frame.
// In Pyston, exc is the frame-local value of sys.exc_info. // In Pyston, exc is the frame-local value of sys.exc_info.
// - This makes frame entering+leaving faster at the expense of slower exceptions. // - This makes frame entering+leaving faster at the expense of slower exceptions.
//
// exc.type is initialized to NULL at function entry, and exc.value and exc.tb are left
// uninitialized. When one wants to access any of the values, you need to check if exc.type
// is NULL, and if so crawl up the stack looking for the first frame with a non-null exc.type
// and copy that.
ExcInfo exc; ExcInfo exc;
// This field is always initialized:
Box* boxedLocals; Box* boxedLocals;
FrameInfo(ExcInfo exc) : exc(exc), boxedLocals(NULL) {} BoxedFrame* frame_obj;
FrameInfo(ExcInfo exc) : exc(exc), boxedLocals(NULL), frame_obj(0) {}
}; };
struct CallattrFlags { struct CallattrFlags {
......
...@@ -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 "Python.h"
#include "pythread.h"
#include "codegen/unwinding.h"
#include "runtime/types.h"
namespace pyston {
BoxedClass* frame_cls;
// Issues:
// - breaks gdb backtraces
// - breaks c++ exceptions
// - we never free the trampolines
class BoxedFrame : public Box {
public:
BoxedFrame(PythonFrameIterator&& it) __attribute__((visibility("default")))
: it(std::move(it)), thread_id(PyThread_get_thread_ident()) {}
PythonFrameIterator it;
long thread_id;
Box* _globals;
Box* _code;
void update() {
// This makes sense as an exception, but who knows how the user program would react
// (it might swallow it and do something different)
RELEASE_ASSERT(thread_id == PyThread_get_thread_ident(),
"frame objects can only be accessed from the same thread");
PythonFrameIterator new_it = it.getCurrentVersion();
RELEASE_ASSERT(new_it.exists() && new_it.getFrameInfo()->frame_obj == this, "frame has exited");
it = std::move(new_it);
}
// 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->_globals);
}
static void simpleDestructor(Box* b) {
auto f = static_cast<BoxedFrame*>(b);
f->it.~PythonFrameIterator();
}
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);
f->update();
return f->it.fastLocalsToBoxedLocals();
}
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);
f->update();
std::unique_ptr<ExecutionPoint> fr = f->it.getExecutionPoint();
return boxInt(fr->current_stmt->lineno);
}
DEFAULT_CLASS(frame_cls);
};
Box* getFrame(int depth) {
auto it = getPythonFrame(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 = makeAttrWrapper(cf->clfunc->source->parent_module);
f->_code = codeForCLFunction(cf->clfunc);
}
return fi->frame_obj;
}
void setupFrame() {
frame_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedFrame::gchandler, 0, 0, sizeof(BoxedFrame), false,
"frame");
frame_cls->simple_destructor = BoxedFrame::simpleDestructor;
frame_cls->giveAttr("f_code", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::code, NULL, NULL));
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));
frame_cls->giveAttr("f_globals", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedFrame::globals, NULL, NULL));
frame_cls->freeze();
}
}
...@@ -158,6 +158,20 @@ static void writeTrivialEhFrame(void* eh_frame_addr, void* func_addr, uint64_t f ...@@ -158,6 +158,20 @@ static void writeTrivialEhFrame(void* eh_frame_addr, void* func_addr, uint64_t f
*size_ptr = func_size; *size_ptr = func_size;
} }
void EHFrameManager::writeAndRegister(void* func_addr, uint64_t func_size) {
assert(eh_frame_addr == NULL);
eh_frame_addr = malloc(EH_FRAME_SIZE);
writeTrivialEhFrame(eh_frame_addr, func_addr, func_size);
registerEHFrames((uint8_t*)eh_frame_addr, (uint64_t)eh_frame_addr, EH_FRAME_SIZE);
}
EHFrameManager::~EHFrameManager() {
if (eh_frame_addr) {
deregisterEHFrames((uint8_t*)eh_frame_addr, (uint64_t)eh_frame_addr, EH_FRAME_SIZE);
free(eh_frame_addr);
}
}
#if RUNTIMEICS_OMIT_FRAME_PTR #if RUNTIMEICS_OMIT_FRAME_PTR
// If you change this, you *must* update the value in _eh_frame_template // If you change this, you *must* update the value in _eh_frame_template
// (set the -9'th byte to this value plus 8) // (set the -9'th byte to this value plus 8)
...@@ -256,10 +270,7 @@ RuntimeIC::RuntimeIC(void* func_addr, int num_slots, int slot_size) { ...@@ -256,10 +270,7 @@ RuntimeIC::RuntimeIC(void* func_addr, int num_slots, int slot_size) {
// TODO: ideally would be more intelligent about allocation strategies. // TODO: ideally would be more intelligent about allocation strategies.
// The code sections should be together and the eh sections together // The code sections should be together and the eh sections together
eh_frame_addr = malloc(EH_FRAME_SIZE); eh_frame.writeAndRegister(addr, total_size);
writeTrivialEhFrame(eh_frame_addr, addr, total_size);
registerEHFrames((uint8_t*)eh_frame_addr, (uint64_t)eh_frame_addr, EH_FRAME_SIZE);
} else { } else {
addr = func_addr; addr = func_addr;
} }
...@@ -268,9 +279,7 @@ RuntimeIC::RuntimeIC(void* func_addr, int num_slots, int slot_size) { ...@@ -268,9 +279,7 @@ RuntimeIC::RuntimeIC(void* func_addr, int num_slots, int slot_size) {
RuntimeIC::~RuntimeIC() { RuntimeIC::~RuntimeIC() {
if (ENABLE_RUNTIME_ICS) { if (ENABLE_RUNTIME_ICS) {
deregisterCompiledPatchpoint(icinfo.get()); deregisterCompiledPatchpoint(icinfo.get());
deregisterEHFrames((uint8_t*)eh_frame_addr, (uint64_t)eh_frame_addr, EH_FRAME_SIZE);
free(addr); free(addr);
free(eh_frame_addr);
} else { } else {
} }
} }
......
...@@ -22,10 +22,20 @@ namespace pyston { ...@@ -22,10 +22,20 @@ namespace pyston {
class ICInfo; class ICInfo;
class EHFrameManager {
private:
void* eh_frame_addr;
public:
EHFrameManager() : eh_frame_addr(NULL) {}
~EHFrameManager();
void writeAndRegister(void* func_addr, uint64_t func_size);
};
class RuntimeIC { class RuntimeIC {
private: private:
void* addr; void* addr;
void* eh_frame_addr; EHFrameManager eh_frame;
std::unique_ptr<ICInfo> icinfo; std::unique_ptr<ICInfo> icinfo;
......
...@@ -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
...@@ -15,7 +15,7 @@ d[2].append(3) ...@@ -15,7 +15,7 @@ d[2].append(3)
print sorted(d.items()) print sorted(d.items())
NT = collections.namedtuple("NT", ["field1", "field2"]) NT = collections.namedtuple("NT", ["field1", "field2"])
print NT.__name__ print NT.__name__, NT
n = NT(1, "hi") n = NT(1, "hi")
print n.field1, n.field2, len(n), list(n), n[0], n[-1] print n.field1, n.field2, len(n), list(n), n[0], n[-1]
print n print n
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"
# expected: fail
# - needs sys._getframe
import collections
NT = collections.namedtuple("NT", ["field1", "field2"])
print NT
"""
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 interpolate(templateStr):
frame = sys._getframe(1)
framedict = frame.f_locals
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
import sys
def f():
fr = sys._getframe(0)
print fr.f_lineno
print fr.f_lineno
print sorted(fr.f_locals.keys())
a = 1
print sorted(fr.f_locals.keys())
f()
assert sys._getframe(0) is sys._getframe(0)
def f2():
f1 = sys._getframe(0)
# trigger osr:
for i in xrange(20000):
pass
assert f1 is sys._getframe(0)
f2()
# Make sure we can throw exceptions through frame we called _getframe
import sys
def g():
sys._getframe(1)
1/0
def f():
g()
try:
f()
except Exception as e:
print e
# expected: fail
# - we don't (yet?) support looking at frame objects after
# their frame has exited
import sys
def f():
return sys._getframe(0)
fr = f()
print fr.f_locals
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