Commit 929e154f authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #296 from undingen/gen_traceback

Generator tracebacks
parents cdbf91f6 be3e46f6
...@@ -372,6 +372,7 @@ private: ...@@ -372,6 +372,7 @@ private:
return UNKNOWN; return UNKNOWN;
case AST_LangPrimitive::NONE: case AST_LangPrimitive::NONE:
case AST_LangPrimitive::SET_EXC_INFO: case AST_LangPrimitive::SET_EXC_INFO:
case AST_LangPrimitive::UNCACHE_EXC_INFO:
return NONE; return NONE;
case AST_LangPrimitive::NONZERO: case AST_LangPrimitive::NONZERO:
return BOOL; return BOOL;
......
...@@ -562,6 +562,10 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) { ...@@ -562,6 +562,10 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
getFrameInfo()->exc = ExcInfo(type.o, value.o, traceback.o); getFrameInfo()->exc = ExcInfo(type.o, value.o, traceback.o);
v = None; v = None;
} else if (node->opcode == AST_LangPrimitive::UNCACHE_EXC_INFO) {
assert(node->args.empty());
getFrameInfo()->exc = ExcInfo(NULL, NULL, NULL);
v = None;
} else } else
RELEASE_ASSERT(0, "not implemented"); RELEASE_ASSERT(0, "not implemented");
return v; return v;
......
...@@ -638,6 +638,22 @@ private: ...@@ -638,6 +638,22 @@ private:
return getNone(); return getNone();
} }
case AST_LangPrimitive::UNCACHE_EXC_INFO: {
assert(node->args.empty());
auto* builder = emitter.getBuilder();
llvm::Value* frame_info = irstate->getFrameInfoVar();
llvm::Value* exc_info = builder->CreateConstInBoundsGEP2_32(frame_info, 0, 0);
assert(exc_info->getType() == g.llvm_excinfo_type->getPointerTo());
llvm::Constant* v = embedConstantPtr(0, g.llvm_value_type_ptr);
builder->CreateStore(v, builder->CreateConstInBoundsGEP2_32(exc_info, 0, 0));
builder->CreateStore(v, builder->CreateConstInBoundsGEP2_32(exc_info, 0, 1));
builder->CreateStore(v, builder->CreateConstInBoundsGEP2_32(exc_info, 0, 2));
return getNone();
}
default: default:
RELEASE_ASSERT(0, "%d", node->opcode); RELEASE_ASSERT(0, "%d", node->opcode);
} }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "codegen/irgen/hooks.h" #include "codegen/irgen/hooks.h"
#include "codegen/stackmaps.h" #include "codegen/stackmaps.h"
#include "core/util.h" #include "core/util.h"
#include "runtime/generator.h"
#include "runtime/traceback.h" #include "runtime/traceback.h"
#include "runtime/types.h" #include "runtime/types.h"
...@@ -328,25 +329,17 @@ public: ...@@ -328,25 +329,17 @@ public:
return rtn; return rtn;
} }
bool isMainInterpreterFunc(unw_word_t ip) { unw_word_t getFunctionEnd(unw_word_t ip) {
// Remember the addr of the end of the interpreter function because unw_get_proc_info is slow and if we know
// the bounds we can replace it with pointer comparisons.
static intptr_t interpreter_instr_end = 0; // first ip NOT covered by interpreter func
if (interpreter_instr_end == 0) {
unw_proc_info_t pip; unw_proc_info_t pip;
int code = unw_get_proc_info(&this->cursor, &pip); int ret = unw_get_proc_info_by_ip(unw_local_addr_space, ip, &pip, NULL);
RELEASE_ASSERT(code == 0, "%d", code); RELEASE_ASSERT(ret == 0 && pip.end_ip, "");
if (pip.start_ip == (intptr_t)interpreter_instr_addr) { return pip.end_ip;
interpreter_instr_end = pip.end_ip;
return true;
}
} else if (ip >= (intptr_t)interpreter_instr_addr && ip < interpreter_instr_end) {
return true;
}
return false;
} }
bool incr() { bool incr() {
static unw_word_t interpreter_instr_end = getFunctionEnd((unw_word_t)interpreter_instr_addr);
static unw_word_t generator_entry_end = getFunctionEnd((unw_word_t)generatorEntry);
bool was_osr = cur_is_osr; bool was_osr = cur_is_osr;
while (true) { while (true) {
...@@ -377,7 +370,7 @@ public: ...@@ -377,7 +370,7 @@ public:
return true; return true;
} }
if (isMainInterpreterFunc(ip)) { if ((unw_word_t)interpreter_instr_addr <= ip && ip < interpreter_instr_end) {
unw_word_t bp; unw_word_t bp;
unw_get_reg(&this->cursor, UNW_TDEP_BP, &bp); unw_get_reg(&this->cursor, UNW_TDEP_BP, &bp);
...@@ -395,6 +388,15 @@ public: ...@@ -395,6 +388,15 @@ public:
return true; return true;
} }
if ((unw_word_t)generatorEntry <= ip && ip < generator_entry_end) {
// for generators continue unwinding in the context in which the generator got called
static_assert(sizeof(ucontext_t) == sizeof(unw_context_t), "");
unw_word_t bp;
unw_get_reg(&this->cursor, UNW_TDEP_BP, &bp);
ucontext_t* remote_ctx = getReturnContextForGeneratorFrame((void*)bp);
unw_init_local(&cursor, remote_ctx);
}
// keep unwinding // keep unwinding
} }
} }
......
...@@ -1454,6 +1454,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) { ...@@ -1454,6 +1454,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
case AST_LangPrimitive::SET_EXC_INFO: case AST_LangPrimitive::SET_EXC_INFO:
printf("SET_EXC_INFO"); printf("SET_EXC_INFO");
break; break;
case AST_LangPrimitive::UNCACHE_EXC_INFO:
printf("UNCACHE_EXC_INFO");
break;
default: default:
RELEASE_ASSERT(0, "%d", node->opcode); RELEASE_ASSERT(0, "%d", node->opcode);
} }
......
...@@ -997,6 +997,7 @@ public: ...@@ -997,6 +997,7 @@ public:
NONE, NONE,
NONZERO, NONZERO,
SET_EXC_INFO, SET_EXC_INFO,
UNCACHE_EXC_INFO,
} opcode; } opcode;
std::vector<AST_expr*> args; std::vector<AST_expr*> args;
......
...@@ -1006,7 +1006,13 @@ private: ...@@ -1006,7 +1006,13 @@ private:
rtn->lineno = node->lineno; rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset; rtn->col_offset = node->col_offset;
rtn->value = remapExpr(node->value); rtn->value = remapExpr(node->value);
return rtn;
InternedString node_name(nodeName(rtn));
pushAssign(node_name, rtn);
push_back(makeExpr(new AST_LangPrimitive(AST_LangPrimitive::UNCACHE_EXC_INFO)));
return makeName(node_name, AST_TYPE::Load, node->lineno);
} }
AST_expr* remapExpr(AST_expr* node, bool wrap_with_assign = true) { AST_expr* remapExpr(AST_expr* node, bool wrap_with_assign = true) {
......
...@@ -41,13 +41,38 @@ static std::vector<uint64_t> available_addrs; ...@@ -41,13 +41,38 @@ static std::vector<uint64_t> available_addrs;
#define STACK_REDZONE_SIZE PAGE_SIZE #define STACK_REDZONE_SIZE PAGE_SIZE
#define MAX_STACK_SIZE (4 * 1024 * 1024) #define MAX_STACK_SIZE (4 * 1024 * 1024)
static void generatorEntry(BoxedGenerator* g) { static std::unordered_map<void*, BoxedGenerator*> s_generator_map;
static_assert(THREADING_USE_GIL, "have to make the generator map thread safe!");
class RegisterHelper {
private:
void* frame_addr;
public:
RegisterHelper(BoxedGenerator* generator, void* frame_addr) : frame_addr(frame_addr) {
s_generator_map[frame_addr] = generator;
}
~RegisterHelper() {
assert(s_generator_map.count(frame_addr));
s_generator_map.erase(frame_addr);
}
};
ucontext* getReturnContextForGeneratorFrame(void* frame_addr) {
BoxedGenerator* generator = s_generator_map[frame_addr];
assert(generator);
return &generator->returnContext;
}
void generatorEntry(BoxedGenerator* g) {
assert(g->cls == generator_cls); assert(g->cls == generator_cls);
assert(g->function->cls == function_cls); assert(g->function->cls == function_cls);
threading::pushGenerator(g, g->stack_begin, (void*)g->returnContext.uc_mcontext.gregs[REG_RSP]); threading::pushGenerator(g, g->stack_begin, (void*)g->returnContext.uc_mcontext.gregs[REG_RSP]);
try { try {
RegisterHelper context_registerer(g, __builtin_frame_address(0));
// call body of the generator // call body of the generator
BoxedFunctionBase* func = g->function; BoxedFunctionBase* func = g->function;
......
...@@ -18,11 +18,15 @@ ...@@ -18,11 +18,15 @@
#include "core/types.h" #include "core/types.h"
#include "runtime/types.h" #include "runtime/types.h"
struct ucontext;
namespace pyston { namespace pyston {
extern BoxedClass* generator_cls; extern BoxedClass* generator_cls;
void setupGenerator(); void setupGenerator();
void generatorEntry(BoxedGenerator* g);
ucontext* getReturnContextForGeneratorFrame(void* frame_addr);
extern "C" Box* yield(BoxedGenerator* obj, Box* value); extern "C" Box* yield(BoxedGenerator* obj, Box* value);
extern "C" BoxedGenerator* createGenerator(BoxedFunctionBase* function, Box* arg1, Box* arg2, Box* arg3, Box** args); extern "C" BoxedGenerator* createGenerator(BoxedFunctionBase* function, Box* arg1, Box* arg2, Box* arg3, Box** args);
......
# expected: fail
# - wip
# Generators participate in the notional Python stack just like normal function calls do, # Generators participate in the notional Python stack just like normal function calls do,
# even if we implement them using separate C stacks. # even if we implement them using separate C stacks.
# #
...@@ -8,6 +5,7 @@ ...@@ -8,6 +5,7 @@
# get inherited when we go into a generator # get inherited when we go into a generator
# exc_info gets passed into generators (at both begin and send()) and cleared like normal on the way out: # exc_info gets passed into generators (at both begin and send()) and cleared like normal on the way out:
import sys
def f12(): def f12():
print print
print "f12" print "f12"
...@@ -25,6 +23,7 @@ def f12(): ...@@ -25,6 +23,7 @@ def f12():
print "after KeyError:", sys.exc_info()[0] print "after KeyError:", sys.exc_info()[0]
yield 2 yield 2
print list(g())
try: try:
raise AttributeError() raise AttributeError()
except: except:
...@@ -32,6 +31,7 @@ def f12(): ...@@ -32,6 +31,7 @@ def f12():
i = g() i = g()
i.next() i.next()
print list(g())
try: try:
1/0 1/0
except: except:
......
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