Commit 5e64050e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #1082 from undingen/sass

Get libsass working by fixing c++ EH handling
parents 831c8d1a b28222dc
......@@ -16,13 +16,6 @@
#define PYSTON_NOEXCEPT
#endif
// HACK: we should set this manually rather than cluing off of the C++ version
#ifdef __cplusplus
#if __cplusplus > 199711L
#define _PYSTON_API
#endif
#endif
#define Py_PROTO(x) x
// Pyston change: these are just hard-coded for now:
......
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_FLAGS_DEBUG "-g -DBINARY_SUFFIX= -DBINARY_STRIPPED_SUFFIX=_stripped -DPy_BUILD_CORE")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fstrict-aliasing -enable-tbaa -DNVALGRIND -DBINARY_SUFFIX=_release -DBINARY_STRIPPED_SUFFIX= -DPy_BUILD_CORE")
set(CMAKE_CXX_FLAGS_DEBUG "-g -DBINARY_SUFFIX= -DBINARY_STRIPPED_SUFFIX=_stripped -DPy_BUILD_CORE -D_PYSTON_API")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fstrict-aliasing -enable-tbaa -DNVALGRIND -DBINARY_SUFFIX=_release -DBINARY_STRIPPED_SUFFIX= -DPy_BUILD_CORE -D_PYSTON_API")
execute_process(COMMAND git rev-parse HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GITREV OUTPUT_STRIP_TRAILING_WHITESPACE)
set_source_files_properties(jit.cpp PROPERTIES COMPILE_DEFINITIONS "GITREV=${GITREV}")
......
......@@ -21,6 +21,7 @@
#include "llvm/Support/Memory.h"
#include "codegen/irgen/util.h"
#include "codegen/unwinding.h"
#include "core/common.h"
#include "core/stats.h"
#include "core/util.h"
......@@ -211,6 +212,11 @@ uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) {
if (base)
return base;
// make sure our own c++ exc implementations symbols get used instead of gcc ones.
base = getCXXUnwindSymbolAddress(name);
if (base)
return base;
base = RTDyldMemoryManager::getSymbolAddress(name);
if (base)
return base;
......
......@@ -32,6 +32,8 @@ class BoxedTraceback;
struct FrameInfo;
void registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size);
uint64_t getCXXUnwindSymbolAddress(llvm::StringRef sym);
bool isUnwinding(); // use this instead of std::uncaught_exception
void setupUnwinding();
BoxedModule* getCurrentModule();
......
......@@ -22,6 +22,7 @@
#include "Python.h"
#include "analysis/scoping_analysis.h"
#include "codegen/unwinding.h"
#include "core/ast.h"
#include "core/options.h"
#include "core/types.h"
......@@ -197,8 +198,8 @@ public:
~CFGVisitor() {
// if we're being destroyed due to an exception, our internal invariants may be violated, but that's okay; the
// CFG isn't going to get used anyway. (Maybe we should check that it won't be used somehow?)
assert(continuations.size() == 0 || std::uncaught_exception());
assert(exc_handlers.size() == 0 || std::uncaught_exception());
assert(continuations.size() == 0 || isUnwinding());
assert(exc_handlers.size() == 0 || isUnwinding());
}
// ---------- private methods ----------
......
......@@ -35,6 +35,7 @@
#define PYSTON_CUSTOM_UNWINDER 1 // set to 0 to use C++ unwinder
#define NORETURN __attribute__((__noreturn__))
#define HIDDEN __attribute__((visibility("hidden")))
// An action of 0 in the LSDA action table indicates cleanup.
#define CLEANUP_ACTION 0
......@@ -62,7 +63,7 @@
#define DW_EH_PE_indirect 0x80
// end dwarf encoding modes
extern "C" void __gxx_personality_v0(); // wrong type signature, but that's ok, it's extern "C"
extern "C" HIDDEN void __gxx_personality_v0(); // wrong type signature, but that's ok, it's extern "C"
// check(EXPR) is like assert((EXPR) == 0), but evaluates EXPR even in debug mode.
template <typename T> static inline void check(T x) {
......@@ -94,6 +95,10 @@ static __thread bool in_cleanup_code = false;
#endif
static __thread bool is_unwinding = false;
bool isUnwinding() {
return is_unwinding;
}
extern "C" {
static NORETURN void panic(void) {
......@@ -612,16 +617,12 @@ void std::terminate() noexcept {
RELEASE_ASSERT(0, "std::terminate() called!");
}
bool std::uncaught_exception() noexcept {
return pyston::is_unwinding;
}
// wrong type signature, but that's okay, it's extern "C"
extern "C" void __gxx_personality_v0() {
extern "C" HIDDEN void __gxx_personality_v0() {
RELEASE_ASSERT(0, "__gxx_personality_v0 should never get called");
}
extern "C" void _Unwind_Resume(struct _Unwind_Exception* _exc) {
extern "C" HIDDEN void _Unwind_Resume(struct _Unwind_Exception* _exc) {
assert(pyston::in_cleanup_code);
#ifndef NDEBUG
pyston::in_cleanup_code = false;
......@@ -638,7 +639,7 @@ extern "C" void _Unwind_Resume(struct _Unwind_Exception* _exc) {
// C++ ABI functionality
namespace __cxxabiv1 {
extern "C" void* __cxa_allocate_exception(size_t size) noexcept {
extern "C" HIDDEN void* __cxa_allocate_exception(size_t size) noexcept {
// we should only ever be throwing ExcInfos
RELEASE_ASSERT(size == sizeof(pyston::ExcInfo), "allocating exception whose size doesn't match ExcInfo");
......@@ -650,7 +651,7 @@ extern "C" void* __cxa_allocate_exception(size_t size) noexcept {
// Takes the value that resume() sent us in RAX, and returns a pointer to the exception object actually thrown. In our
// case, these are the same, and should always be &pyston::exception_ferry.
extern "C" void* __cxa_begin_catch(void* exc_obj_in) noexcept {
extern "C" HIDDEN void* __cxa_begin_catch(void* exc_obj_in) noexcept {
assert(exc_obj_in);
pyston::us_unwind_resume_catch.log(pyston::per_thread_resume_catch_timer.end());
......@@ -662,7 +663,7 @@ extern "C" void* __cxa_begin_catch(void* exc_obj_in) noexcept {
return e;
}
extern "C" void __cxa_end_catch() {
extern "C" HIDDEN void __cxa_end_catch() {
if (VERBOSITY("cxx_unwind") >= 4)
printf("***** __cxa_end_catch() *****\n");
// See comment in __cxa_begin_catch for why we don't clear the exception ferry here.
......@@ -676,7 +677,7 @@ extern "C" std::type_info EXCINFO_TYPE_INFO;
static uint64_t* unwinding_stattimer = pyston::Stats::getStatCounter("us_timer_unwinding");
#endif
extern "C" void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(void*)) {
extern "C" HIDDEN void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(void*)) {
static pyston::StatCounter num_cxa_throw("num_cxa_throw");
num_cxa_throw.log();
......@@ -702,7 +703,7 @@ extern "C" void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(v
pyston::unwind(exc_data);
}
extern "C" void* __cxa_get_exception_ptr(void* exc_obj_in) noexcept {
extern "C" HIDDEN void* __cxa_get_exception_ptr(void* exc_obj_in) noexcept {
assert(exc_obj_in);
pyston::ExcInfo* e = (pyston::ExcInfo*)exc_obj_in;
checkExcInfo(e);
......@@ -718,9 +719,31 @@ extern "C" void* __cxa_get_exception_ptr(void* exc_obj_in) noexcept {
// throw e;
// }
//
extern "C" void __cxa_rethrow() {
extern "C" HIDDEN void __cxa_rethrow() {
RELEASE_ASSERT(0, "__cxa_rethrow() unimplemented; please don't use bare `throw' in Pyston!");
}
}
#endif // PYSTON_CUSTOM_UNWINDER
namespace pyston {
static llvm::StringMap<uint64_t> cxx_unwind_syms;
uint64_t getCXXUnwindSymbolAddress(llvm::StringRef sym) {
#if PYSTON_CUSTOM_UNWINDER
if (unlikely(cxx_unwind_syms.empty())) {
cxx_unwind_syms["_Unwind_Resume"] = (uint64_t)_Unwind_Resume;
cxx_unwind_syms["__gxx_personality_v0"] = (uint64_t)__gxx_personality_v0;
cxx_unwind_syms["__cxa_allocate_exception"] = (uint64_t)__cxxabiv1::__cxa_allocate_exception;
cxx_unwind_syms["__cxa_begin_catch"] = (uint64_t)__cxxabiv1::__cxa_begin_catch;
cxx_unwind_syms["__cxa_end_catch"] = (uint64_t)__cxxabiv1::__cxa_end_catch;
cxx_unwind_syms["__cxa_get_exception_ptr"] = (uint64_t)__cxxabiv1::__cxa_get_exception_ptr;
cxx_unwind_syms["__cxa_rethrow"] = (uint64_t)__cxxabiv1::__cxa_rethrow;
cxx_unwind_syms["__cxa_throw"] = (uint64_t)__cxxabiv1::__cxa_throw;
}
auto&& it = cxx_unwind_syms.find(sym);
if (it != cxx_unwind_syms.end())
return it->second;
#endif
return 0;
}
}
......@@ -16,6 +16,7 @@
#define PYSTON_RUNTIME_REWRITEARGS_H
#include "asm_writing/rewriter.h"
#include "codegen/unwinding.h"
namespace pyston {
......@@ -73,7 +74,7 @@ public:
#ifndef NDEBUG
~_ReturnConventionBase() {
if (out_success && !std::uncaught_exception())
if (out_success && !isUnwinding())
assert(return_convention_checked && "Didn't check the return convention of this rewrite...");
}
#endif
......
# skip-if: 'clang' in os.environ['CC']
# looks like libsass only builds using gcc...
import os, sys, subprocess
sys.path.append(os.path.dirname(__file__) + "/../lib")
from test_helper import create_virtenv, run_test
ENV_NAME = "sass_test_env_" + os.path.basename(sys.executable)
SRC_DIR = os.path.abspath(os.path.join(ENV_NAME, "src"))
PYTHON_EXE = os.path.abspath(os.path.join(ENV_NAME, "bin", "python"))
SASS_DIR = os.path.abspath(os.path.join(ENV_NAME, "src", "libsass"))
packages = ["six==1.10", "werkzeug==0.9"]
packages += ["-e", "git+https://github.com/dahlia/libsass-python@0.8.3#egg=libsass"]
create_virtenv(ENV_NAME, packages, force_create = True)
expected = [{'ran': 75}]
run_test([PYTHON_EXE, "setup.py", "test"], cwd=SASS_DIR, expected=expected)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-undef")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-undef -D_PYSTON_API")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_definitions(-DGTEST_HAS_RTTI=0 ${LLVM_DEFINITIONS})
......
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