Commit d4b8c35c authored by Marius Wachtler's avatar Marius Wachtler

EH: correctly deregister EH frames and cleanup the code

- previously we never deregistered the EH frame from libunwind (which exposed a bug)
- I removed the calls to register the EH info with gcc since we have our own unwinder which does not need this
- cleaned up the code and fixed some small memory leaks
parent 91aad8d4
...@@ -104,19 +104,12 @@ JitCodeBlock::JitCodeBlock(llvm::StringRef name) ...@@ -104,19 +104,12 @@ JitCodeBlock::JitCodeBlock(llvm::StringRef name)
entry_offset = a.bytesWritten(); entry_offset = a.bytesWritten();
// generate the eh frame... // generate the eh frame...
const int size = sizeof(eh_info); const int eh_frame_size = sizeof(eh_info);
void* eh_frame_addr = memory.get(); void* eh_frame_addr = memory.get();
memcpy(eh_frame_addr, eh_info, size); memcpy(eh_frame_addr, eh_info, eh_frame_size);
int32_t* offset_ptr = (int32_t*)((uint8_t*)eh_frame_addr + 0x20); register_eh_info.updateAndRegisterFrameFromTemplate((uint64_t)code, code_size, (uint64_t)eh_frame_addr,
int32_t* size_ptr = (int32_t*)((uint8_t*)eh_frame_addr + 0x24); eh_frame_size);
int64_t offset = (int8_t*)code - (int8_t*)offset_ptr;
assert(offset >= INT_MIN && offset <= INT_MAX);
*offset_ptr = offset;
*size_ptr = code_size;
registerDynamicEhFrame((uint64_t)code, code_size, (uint64_t)eh_frame_addr, size - 4);
registerEHFrames((uint8_t*)eh_frame_addr, (uint64_t)eh_frame_addr, size);
static int num_block = 0; static int num_block = 0;
auto unique_name = ("bjit_" + name + "_" + llvm::Twine(num_block++)).str(); auto unique_name = ("bjit_" + name + "_" + llvm::Twine(num_block++)).str();
......
...@@ -177,6 +177,7 @@ private: ...@@ -177,6 +177,7 @@ private:
// this contains all the decref infos the bjit generated inside the memory block, // this contains all the decref infos the bjit generated inside the memory block,
// this allows us to deregister them when we release the code // this allows us to deregister them when we release the code
std::vector<DecrefInfo> decref_infos; std::vector<DecrefInfo> decref_infos;
RegisterEHFrame register_eh_info;
public: public:
JitCodeBlock(llvm::StringRef name); JitCodeBlock(llvm::StringRef name);
......
...@@ -241,14 +241,4 @@ PystonMemoryManager::~PystonMemoryManager() { ...@@ -241,14 +241,4 @@ PystonMemoryManager::~PystonMemoryManager() {
std::unique_ptr<llvm::RTDyldMemoryManager> createMemoryManager() { std::unique_ptr<llvm::RTDyldMemoryManager> createMemoryManager() {
return std::unique_ptr<llvm::RTDyldMemoryManager>(new PystonMemoryManager()); return std::unique_ptr<llvm::RTDyldMemoryManager>(new PystonMemoryManager());
} }
// These functions exist as instance methods of the RTDyldMemoryManager class,
// but it's tricky to access them since the class has pure-virtual methods.
void registerEHFrames(uint8_t* addr, uint64_t load_addr, size_t size) {
PystonMemoryManager().registerEHFrames(addr, load_addr, size);
}
void deregisterEHFrames(uint8_t* addr, uint64_t load_addr, size_t size) {
PystonMemoryManager().deregisterEHFrames(addr, load_addr, size);
}
} }
...@@ -26,8 +26,6 @@ class RTDyldMemoryManager; ...@@ -26,8 +26,6 @@ class RTDyldMemoryManager;
namespace pyston { namespace pyston {
std::unique_ptr<llvm::RTDyldMemoryManager> createMemoryManager(); std::unique_ptr<llvm::RTDyldMemoryManager> createMemoryManager();
void registerEHFrames(uint8_t* addr, uint64_t load_addr, size_t size);
void deregisterEHFrames(uint8_t* addr, uint64_t load_addr, size_t size);
} }
#endif #endif
...@@ -94,7 +94,7 @@ void parseEhFrame(uint64_t start_addr, uint64_t size, uint64_t func_addr, uint64 ...@@ -94,7 +94,7 @@ void parseEhFrame(uint64_t start_addr, uint64_t size, uint64_t func_addr, uint64
*out_len = nentries; *out_len = nentries;
} }
void registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size) { void* registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size) {
unw_dyn_info_t* dyn_info = new unw_dyn_info_t(); unw_dyn_info_t* dyn_info = new unw_dyn_info_t();
dyn_info->start_ip = code_addr; dyn_info->start_ip = code_addr;
dyn_info->end_ip = code_addr + code_size; dyn_info->end_ip = code_addr + code_size;
...@@ -116,6 +116,42 @@ void registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_fr ...@@ -116,6 +116,42 @@ void registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_fr
// as opposed to the binary search it can do within a dyn_info. // as opposed to the binary search it can do within a dyn_info.
// If we're registering a lot of dyn_info's, it might make sense to coalesce them into a single // If we're registering a lot of dyn_info's, it might make sense to coalesce them into a single
// dyn_info that contains a binary search table. // dyn_info that contains a binary search table.
return dyn_info;
}
void deregisterDynamicEhFrame(void* _dyn_info) {
auto dyn_info = (unw_dyn_info_t*)_dyn_info;
_U_dyn_cancel(dyn_info);
delete (uw_table_entry*)dyn_info->u.rti.table_data;
delete dyn_info;
}
void RegisterEHFrame::updateAndRegisterFrameFromTemplate(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr,
size_t eh_frame_size) {
assert(eh_frame_size > 0x24);
int32_t* offset_ptr = (int32_t*)((uint8_t*)eh_frame_addr + 0x20);
int32_t* size_ptr = (int32_t*)((uint8_t*)eh_frame_addr + 0x24);
int64_t offset = (int8_t*)code_addr - (int8_t*)offset_ptr;
assert(offset >= INT_MIN && offset <= INT_MAX);
*offset_ptr = offset;
*size_ptr = code_size;
// (EH_FRAME_SIZE - 4) to omit the 4-byte null terminator, otherwise we trip an assert in parseEhFrame.
// TODO: can we omit the terminator in general?
registerFrame(code_addr, code_size, eh_frame_addr, eh_frame_size - 4);
}
void RegisterEHFrame::registerFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr,
size_t eh_frame_size) {
assert(!dyn_info);
dyn_info = registerDynamicEhFrame(code_addr, code_size, eh_frame_addr, eh_frame_size);
}
void RegisterEHFrame::deregisterFrame() {
if (dyn_info) {
deregisterDynamicEhFrame(dyn_info);
dyn_info = NULL;
}
} }
struct compare_cf { struct compare_cf {
......
...@@ -30,7 +30,24 @@ class BoxedDict; ...@@ -30,7 +30,24 @@ class BoxedDict;
class BoxedModule; class BoxedModule;
struct FrameInfo; struct FrameInfo;
void registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size); class RegisterEHFrame {
private:
void* dyn_info;
public:
RegisterEHFrame() : dyn_info(NULL) {}
~RegisterEHFrame() { deregisterFrame(); }
// updates the EH info at eh_frame_addr to reference the passed code addr and code size and registers it
void updateAndRegisterFrameFromTemplate(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr,
size_t eh_frame_size);
void registerFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size);
void deregisterFrame();
};
void* registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size);
void deregisterDynamicEhFrame(void* dyn_info);
uint64_t getCXXUnwindSymbolAddress(llvm::StringRef sym); uint64_t getCXXUnwindSymbolAddress(llvm::StringRef sym);
// use this instead of std::uncaught_exception. // use this instead of std::uncaught_exception.
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include "codegen/memmgr.h" #include "codegen/memmgr.h"
#include "codegen/patchpoints.h" #include "codegen/patchpoints.h"
#include "codegen/stackmaps.h" #include "codegen/stackmaps.h"
#include "codegen/unwinding.h" // registerDynamicEhFrame
#include "core/common.h" #include "core/common.h"
#include "core/options.h" #include "core/options.h"
#include "core/stats.h" #include "core/stats.h"
...@@ -161,23 +160,6 @@ static constexpr int _eh_frame_template_fp_size = sizeof(_eh_frame_template_fp) ...@@ -161,23 +160,6 @@ static constexpr int _eh_frame_template_fp_size = sizeof(_eh_frame_template_fp)
static_assert(sizeof("") == 1, "strings are null-terminated"); static_assert(sizeof("") == 1, "strings are null-terminated");
static void writeTrivialEhFrame(void* eh_frame_addr, void* func_addr, uint64_t func_size, bool omit_frame_pointer) {
if (omit_frame_pointer)
memcpy(eh_frame_addr, _eh_frame_template_ofp, _eh_frame_template_ofp_size);
else
memcpy(eh_frame_addr, _eh_frame_template_fp, _eh_frame_template_fp_size);
int32_t* offset_ptr = (int32_t*)((uint8_t*)eh_frame_addr + 0x20);
int32_t* size_ptr = (int32_t*)((uint8_t*)eh_frame_addr + 0x24);
int64_t offset = (int8_t*)func_addr - (int8_t*)offset_ptr;
RELEASE_ASSERT(offset >= INT_MIN && offset <= INT_MAX, "");
*offset_ptr = offset;
assert(func_size <= UINT_MAX);
*size_ptr = func_size;
}
#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)
...@@ -309,11 +291,13 @@ RuntimeIC::RuntimeIC(void* func_addr, int total_size) { ...@@ -309,11 +291,13 @@ RuntimeIC::RuntimeIC(void* func_addr, int total_size) {
assert(!epilogue_assem.hasFailed()); assert(!epilogue_assem.hasFailed());
assert(epilogue_assem.isExactlyFull()); assert(epilogue_assem.isExactlyFull());
writeTrivialEhFrame(eh_frame_addr, addr, total_code_size, RUNTIMEICS_OMIT_FRAME_PTR);
// (EH_FRAME_SIZE - 4) to omit the 4-byte null terminator, otherwise we trip an assert in parseEhFrame. if (RUNTIMEICS_OMIT_FRAME_PTR)
// TODO: can we omit the terminator in general? memcpy(eh_frame_addr, _eh_frame_template_ofp, _eh_frame_template_ofp_size);
registerDynamicEhFrame((uint64_t)addr, total_code_size, (uint64_t)eh_frame_addr, EH_FRAME_SIZE - 4); else
registerEHFrames((uint8_t*)eh_frame_addr, (uint64_t)eh_frame_addr, EH_FRAME_SIZE); memcpy(eh_frame_addr, _eh_frame_template_fp, _eh_frame_template_fp_size);
register_eh_frame.updateAndRegisterFrameFromTemplate((uint64_t)addr, total_code_size, (uint64_t)eh_frame_addr,
EH_FRAME_SIZE);
} else { } else {
addr = func_addr; addr = func_addr;
} }
...@@ -321,8 +305,8 @@ RuntimeIC::RuntimeIC(void* func_addr, int total_size) { ...@@ -321,8 +305,8 @@ RuntimeIC::RuntimeIC(void* func_addr, int total_size) {
RuntimeIC::~RuntimeIC() { RuntimeIC::~RuntimeIC() {
if (ENABLE_RUNTIME_ICS) { if (ENABLE_RUNTIME_ICS) {
register_eh_frame.deregisterFrame();
uint8_t* eh_frame_addr = (uint8_t*)addr - EH_FRAME_SIZE; uint8_t* eh_frame_addr = (uint8_t*)addr - EH_FRAME_SIZE;
deregisterEHFrames(eh_frame_addr, (uint64_t)eh_frame_addr, EH_FRAME_SIZE);
memory_manager_512b.dealloc(eh_frame_addr); memory_manager_512b.dealloc(eh_frame_addr);
} else { } else {
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#ifndef PYSTON_RUNTIME_ICS_H #ifndef PYSTON_RUNTIME_ICS_H
#define PYSTON_RUNTIME_ICS_H #define PYSTON_RUNTIME_ICS_H
#include "codegen/unwinding.h" // RegisterEHFrame
#include "core/common.h" #include "core/common.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
...@@ -26,6 +27,7 @@ class RuntimeIC { ...@@ -26,6 +27,7 @@ class RuntimeIC {
private: private:
void* addr; // points to function start not the start of the allocated memory block. void* addr; // points to function start not the start of the allocated memory block.
RegisterEHFrame register_eh_frame;
std::unique_ptr<ICInfo> icinfo; std::unique_ptr<ICInfo> icinfo;
RuntimeIC(const RuntimeIC&) = delete; RuntimeIC(const RuntimeIC&) = delete;
......
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