Commit d55d8e07 authored by Marius Wachtler's avatar Marius Wachtler

Unwind generator stacks correctly

before we stopped at the generatorEntry func and did not unwind
into the caller.
parent 5a680f65
...@@ -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 unw_proc_info_t pip;
// the bounds we can replace it with pointer comparisons. int ret = unw_get_proc_info_by_ip(unw_local_addr_space, ip, &pip, NULL);
static intptr_t interpreter_instr_end = 0; // first ip NOT covered by interpreter func RELEASE_ASSERT(ret == 0 && pip.end_ip, "");
if (interpreter_instr_end == 0) { return pip.end_ip;
unw_proc_info_t pip;
int code = unw_get_proc_info(&this->cursor, &pip);
RELEASE_ASSERT(code == 0, "%d", code);
if (pip.start_ip == (intptr_t)interpreter_instr_addr) {
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
} }
} }
......
...@@ -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);
......
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