Commit 6004bf9a authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #55 from undingen/iterable_min_max

Updated exception handling in:
	src/runtime/types.cpp
	src/runtime/builtin_modules/builtins.cpp
	src/runtime/builtin_modules/math.cpp
parents 18b34c5f 79150fed
......@@ -122,7 +122,7 @@ cd ~/pyston_deps
cp -rv libunwind-1.1 libunwind-1.1-debug
mkdir libunwind-1.1-debug-install
cd libunwind-1.1-debug
./configure --prefix=$HOME/pyston_deps/libunwind-1.1-debug-install --enable-shared=0 --enable-debug --enable-debug-frame
CFLAGS="-g -O0" CXXFLAGS="-g -O0" ./configure --prefix=$HOME/pyston_deps/libunwind-1.1-debug-install --enable-shared=0 --enable-debug --enable-debug-frame
make -j4
make install
echo "USE_DEBUG_LIBUNWIND := 1" >> ~/pyston/src/Makefile.local
......@@ -151,7 +151,7 @@ make -j4
```
### gdb
A new version of gdb is highly recommended since debugging a JIT tends to stress GDB:
A new version of gdb is highly recommended since debugging a JIT tends to use new features of GDB:
```
cd ~/pyston_deps
......@@ -161,9 +161,14 @@ cd gdb-7.6.2
./configure
make -j4
cd ~/pyston/src
echo "GDB := \$(HOME)/pyston_deps/gdb-7.6.2/gdb/gdb" >> Makefile.local
echo "GDB := \$(DEPS_DIR)/gdb-7.6.2/gdb/gdb --data-directory \$(DEPS_DIR)/gdb-7.6.2/gdb/data-directory" >> Makefile.local
```
<!---
TODO: GDB should be able to determine its data directory. maybe it should be installed rather that run
from inside the source dir?
--->
### gperftools (-lprofiler)
```
download from http://code.google.com/p/gperftools/downloads/list
......
def wrap(f, n):
if n:
wrap(f, n-1)
return f()
def throws():
raise AttributeError
for i in xrange(10000):
try:
wrap(throws, 500)
except AttributeError:
pass
......@@ -116,6 +116,7 @@ COMMON_CXXFLAGS := -g -Werror -Wreturn-type -Woverloaded-virtual -Wall -Wno-sign
COMMON_CXXFLAGS += -std=c++11
COMMON_CXXFLAGS += -Wextra -Wno-sign-compare
COMMON_CXXFLAGS += -Wno-unused-parameter # should use the "unused" attribute
COMMON_CXXFLAGS += -fexceptions -fno-rtti
ifeq ($(ENABLE_VALGRIND),0)
COMMON_CXXFLAGS += -DNVALGRIND
......@@ -283,7 +284,7 @@ $(UNITTEST_DIR)/$1: $(GTEST_DIR)/src/gtest-all.o $(NON_ENTRY_OBJS) $(BUILD_SYSTE
$(ECHO) Linking $$@
$(VERB) $(CXX) $(NON_ENTRY_OBJS) $(GTEST_DIR)/src/gtest-all.o $(GTEST_DIR)/src/gtest_main.o $(UNITTEST_DIR)/$1.o $(LDFLAGS) -o $$@
dbg_$1_unittests: $(UNITTEST_DIR)/$1
zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time gdb $(GDB_CMDS) --args ./$(UNITTEST_DIR)/$1 --gtest_break_on_failure $(ARGS)'
zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time $(GDB) $(GDB_CMDS) --args ./$(UNITTEST_DIR)/$1 --gtest_break_on_failure $(ARGS)'
run_$1_unittests: $(UNITTEST_DIR)/$1
zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time ./$(UNITTEST_DIR)/$1 $(ARGS)'
run_unittests:: run_$1_unittests
......@@ -538,6 +539,7 @@ PASS_OBJS := $(PASS_SRCS:.cpp=.standalone.o)
%.release.h.pch: CXXFLAGS := $(CXXFLAGS_RELEASE)
%.release.h.pch %.h.pch: %.h $(BUILD_SYSTEM_DEPS)
$(ECHO) Compiling $@
$(VERB) rm -f $@-*
$(VERB) $(CLANG_EXE) $(CXXFLAGS) -MMD -MP -MF $<.d -x c++-header $< -o $@
CODEGEN_SRCS := $(wildcard codegen/*.cpp) $(wildcard codegen/*/*.cpp)
......@@ -606,10 +608,10 @@ stdlib.release.unopt.bc: $(STDLIB_SRCS:.cpp=.release.o.pub.bc)
stdlib.bc: OPT_OPTIONS=-O3
stdlib.release.bc: OPT_OPTIONS=-O3 -strip-debug
%.bc: %.unopt.bc
$(ECHO) Optimizing $@
$(ECHO) Optimizing $< -> $@
$(VERB) $(LLVM_BIN)/opt $(OPT_OPTIONS) $< -o $@
%.stripped.bc: %.bc
$(ECHO) Optimizing $@
$(ECHO) Stripping $< -> $@
$(VERB) $(LLVM_BIN)/opt -strip-debug $< -o $@
# Then do "ld -b binary" to create a .o file for embedding into the executable
......@@ -787,7 +789,7 @@ watch_%:
TARGET=$(dir $@)$(patsubst watch_%,%,$(notdir $@)); \
clear; $(MAKE) $$TARGET; true; \
while inotifywait -q -e modify -e attrib -e move -e move_self -e create -e delete -e delete_self \
Makefile $$(find \( -name '*.cpp' -o -name '*.h' -o -name '*.py' \) ); do clear; $(MAKE) $$TARGET; done )
Makefile $$(find .. \( -name '*.cpp' -o -name '*.h' -o -name '*.py' \) ); do clear; $(MAKE) $$TARGET; done )
# Makefile $$(find \( -name '*.cpp' -o -name '*.h' -o -name '*.py' \) -o -type d ); do clear; $(MAKE) $(patsubst watch_%,%,$@); done )
# -r . ; do clear; $(MAKE) $(patsubst watch_%,%,$@); done
wdbg_%:
......@@ -795,14 +797,18 @@ wdbg_%:
.PHONY: test_asm test_cpp_asm
test_asm:
$(CLANG_EXE) tests/test.s -c -o test
$(CLANG_EXE) ../test/test.s -c -o test
objdump -d test | less
@ rm test
test_cpp_asm:
$(CLANG_EXE) tests/test.cpp -o test -c -O3
$(CLANG_EXE) ../test/test.cpp -o test -c -O3
# $(GPP) tests/test.cpp -o test -c -O3
objdump -d test | less
rm test
test_cpp_ll:
$(CLANG_EXE) ../test/test.cpp -o test.ll -c -O3 -emit-llvm -S
less test.ll
rm test.ll
.PHONY: ext
ext: ../test/test_extension/test.so
......
......@@ -177,9 +177,11 @@ public:
virtual bool visit_branch(AST_Branch* node) { return true; }
virtual bool visit_expr(AST_Expr* node) { return true; }
virtual bool visit_global(AST_Global* node) { return true; }
virtual bool visit_invoke(AST_Invoke* node) { return false; }
virtual bool visit_jump(AST_Jump* node) { return true; }
virtual bool visit_pass(AST_Pass* node) { return true; }
virtual bool visit_print(AST_Print* node) { return true; }
virtual bool visit_raise(AST_Raise* node) { return true; }
virtual bool visit_return(AST_Return* node) { return true; }
virtual bool visit_classdef(AST_ClassDef* node) {
......
......@@ -145,6 +145,7 @@ public:
}
virtual bool visit_arguments(AST_arguments* node) { return false; }
virtual bool visit_assert(AST_Assert* node) { return false; }
virtual bool visit_assign(AST_Assign* node) { return false; }
virtual bool visit_augassign(AST_AugAssign* node) { return false; }
virtual bool visit_attribute(AST_Attribute* node) { return false; }
......@@ -157,6 +158,7 @@ public:
// virtual bool visit_classdef(AST_ClassDef *node) { return false; }
virtual bool visit_continue(AST_Continue* node) { return false; }
virtual bool visit_dict(AST_Dict* node) { return false; }
virtual bool visit_excepthandler(AST_ExceptHandler* node) { return false; }
virtual bool visit_expr(AST_Expr* node) { return false; }
virtual bool visit_for(AST_For* node) { return false; }
// virtual bool visit_functiondef(AST_FunctionDef *node) { return false; }
......@@ -172,11 +174,14 @@ public:
virtual bool visit_num(AST_Num* node) { return false; }
virtual bool visit_pass(AST_Pass* node) { return false; }
virtual bool visit_print(AST_Print* node) { return false; }
virtual bool visit_raise(AST_Raise* node) { return false; }
virtual bool visit_repr(AST_Repr* node) { return false; }
virtual bool visit_return(AST_Return* node) { return false; }
virtual bool visit_slice(AST_Slice* node) { return false; }
virtual bool visit_str(AST_Str* node) { return false; }
virtual bool visit_subscript(AST_Subscript* node) { return false; }
virtual bool visit_tryexcept(AST_TryExcept* node) { return false; }
virtual bool visit_tryfinally(AST_TryFinally* node) { return false; }
virtual bool visit_tuple(AST_Tuple* node) { return false; }
virtual bool visit_unaryop(AST_UnaryOp* node) { return false; }
virtual bool visit_while(AST_While* node) { return false; }
......
......@@ -329,6 +329,17 @@ private:
virtual void* visit_index(AST_Index* node) { return getType(node->value); }
virtual void* visit_langprimitive(AST_LangPrimitive* node) {
switch (node->opcode) {
case AST_LangPrimitive::ISINSTANCE:
return BOOL;
case AST_LangPrimitive::LANDINGPAD:
return UNKNOWN;
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
}
virtual void* visit_list(AST_List* node) {
// Get all the sub-types, even though they're not necessary to
// determine the expression type, so that things like speculations
......@@ -459,6 +470,8 @@ private:
visit_alias(alias);
}
virtual void visit_invoke(AST_Invoke* node) { node->stmt->accept_stmt(this); }
virtual void visit_jump(AST_Jump* node) {}
virtual void visit_pass(AST_Pass* node) {}
......@@ -473,6 +486,17 @@ private:
}
}
virtual void visit_raise(AST_Raise* node) {
if (EXPAND_UNNEEDED) {
if (node->arg0)
getType(node->arg0);
if (node->arg1)
getType(node->arg1);
if (node->arg2)
getType(node->arg2);
}
}
virtual void visit_return(AST_Return* node) {
if (EXPAND_UNNEEDED) {
if (node->value != NULL)
......
This diff is collapsed.
......@@ -103,7 +103,7 @@ public:
printf("call not defined for %s\n", debugName().c_str());
abort();
}
virtual void print(IREmitter& emitter, VAR* value) {
virtual void print(IREmitter& emitter, const OpInfo& info, VAR* value) {
printf("print not defined for %s\n", debugName().c_str());
abort();
}
......@@ -219,7 +219,7 @@ public:
const std::vector<CompilerVariable*>& args) = 0;
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, const std::vector<CompilerVariable*>& args)
= 0;
virtual void print(IREmitter& emitter) = 0;
virtual void print(IREmitter& emitter, const OpInfo& info) = 0;
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info) = 0;
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable*) = 0;
};
......@@ -283,7 +283,7 @@ public:
const std::vector<CompilerVariable*>& args) override {
return type->call(emitter, info, this, args);
}
void print(IREmitter& emitter) override { type->print(emitter, this); }
void print(IREmitter& emitter, const OpInfo& info) override { type->print(emitter, info, this); }
ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info) override {
return type->len(emitter, info, this);
}
......
......@@ -144,6 +144,7 @@ void PystonJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
code = I->getName(name);
assert(!code);
uint64_t address, size;
const char* type = "unknown";
bool b;
code = I->isText(b);
......@@ -162,7 +163,11 @@ void PystonJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
assert(!code);
if (b)
type = "rodata";
printf("Section: %s %s\n", name.data(), type);
code = I->getAddress(address);
assert(!code);
code = I->getSize(size);
assert(!code);
printf("Section: %s %s (%lx %lx)\n", name.data(), type, address, size);
#if LLVMREV < 200442
I = I.increment(code);
......@@ -173,7 +178,7 @@ void PystonJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
for (llvm::object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E;) {
llvm::StringRef name;
uint64_t addr, size, offset=0;
uint64_t addr, size, offset = 0;
code = I->getName(name);
assert(!code);
code = I->getAddress(addr);
......
......@@ -317,10 +317,10 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
SymbolTable* initial_syms = new SymbolTable();
// llvm::BranchInst::Create(llvm_entry_blocks[entry_descriptor->backedge->target->idx], entry_block);
std::unique_ptr<IREmitter> entry_emitter(createIREmitter(irstate));
entry_emitter->getBuilder()->SetInsertPoint(osr_entry_block);
std::unique_ptr<IREmitter> unbox_emitter(createIREmitter(irstate));
unbox_emitter->getBuilder()->SetInsertPoint(osr_unbox_block);
llvm::BasicBlock* osr_entry_block_end = osr_entry_block;
llvm::BasicBlock* osr_unbox_block_end = osr_unbox_block;
std::unique_ptr<IREmitter> entry_emitter(createIREmitter(irstate, osr_entry_block_end));
std::unique_ptr<IREmitter> unbox_emitter(createIREmitter(irstate, osr_unbox_block_end));
CFGBlock* target_block = entry_descriptor->backedge->target;
......@@ -493,8 +493,8 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
std::unique_ptr<IRGenerator> generator(
createIRGenerator(irstate, llvm_entry_blocks, block, types, out_guards, in_guards, is_partial));
std::unique_ptr<IREmitter> emitter(createIREmitter(irstate));
emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[block]);
llvm::BasicBlock* entry_block_end = llvm_entry_blocks[block];
std::unique_ptr<IREmitter> emitter(createIREmitter(irstate, entry_block_end));
PHITable* phis = NULL;
if (!is_partial) {
......@@ -703,8 +703,8 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
llvm::BasicBlock* off_ramp = llvm::BasicBlock::Create(g.context, "deopt_ramp", irstate->getLLVMFunction());
offramps.push_back(off_ramp);
IREmitter* emitter = createIREmitter(irstate);
emitter->getBuilder()->SetInsertPoint(off_ramp);
llvm::BasicBlock* off_ramp_end = off_ramp;
IREmitter* emitter = createIREmitter(irstate, off_ramp_end);
emitters.push_back(emitter);
block_guards[i]->branch->setSuccessor(1, off_ramp);
......
......@@ -15,6 +15,7 @@
#ifndef PYSTON_CODEGEN_IRGEN_H
#define PYSTON_CODEGEN_IRGEN_H
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IRBuilder.h"
......@@ -30,6 +31,18 @@ class AST_expr;
class GCBuilder;
class IREmitter;
struct ExcInfo {
public:
llvm::BasicBlock* exc_dest;
bool needsInvoke() { return exc_dest != NULL; }
ExcInfo(llvm::BasicBlock* exc_dest) : exc_dest(exc_dest) {}
static ExcInfo none() { return ExcInfo(NULL); }
};
// TODO get rid of this
class MyInserter : public llvm::IRBuilderDefaultInserter<true> {
private:
IREmitter* emitter;
......@@ -55,8 +68,14 @@ public:
virtual CompiledFunction* currentFunction() = 0;
virtual llvm::Function* getIntrinsic(llvm::Intrinsic::ID) = 0;
virtual llvm::Value* createPatchpoint(const PatchpointSetupInfo* pp, void* func_addr,
const std::vector<llvm::Value*>& args) = 0;
virtual llvm::CallSite createCall(ExcInfo exc_info, llvm::Value* callee, const std::vector<llvm::Value*>& args) = 0;
virtual llvm::CallSite createCall(ExcInfo exc_info, llvm::Value* callee, llvm::Value* arg1) = 0;
virtual llvm::CallSite createCall2(ExcInfo exc_info, llvm::Value* callee, llvm::Value* arg1, llvm::Value* arg2) = 0;
virtual llvm::CallSite createCall3(ExcInfo exc_info, llvm::Value* callee, llvm::Value* arg1, llvm::Value* arg2,
llvm::Value* arg3) = 0;
virtual llvm::CallSite createPatchpoint(const PatchpointSetupInfo* pp, void* func_addr,
const std::vector<llvm::Value*>& args, ExcInfo exc_info) = 0;
};
CompiledFunction* compileFunction(SourceInfo* source, const OSREntryDescriptor* entry_descriptor,
......@@ -70,8 +89,10 @@ private:
TypeRecorder* const type_recorder;
public:
OpInfo(EffortLevel::EffortLevel effort, TypeRecorder* type_recorder)
: effort(effort), type_recorder(type_recorder) {}
const ExcInfo exc_info;
OpInfo(EffortLevel::EffortLevel effort, TypeRecorder* type_recorder, ExcInfo exc_info)
: effort(effort), type_recorder(type_recorder), exc_info(exc_info) {}
bool isInterpreted() const { return effort == EffortLevel::INTERPRETED; }
TypeRecorder* getTypeRecorder() const { return type_recorder; }
......
This diff is collapsed.
......@@ -190,7 +190,7 @@ public:
virtual EndingState getEndingSymbolTable() = 0;
};
IREmitter* createIREmitter(IRGenState* irstate);
IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock);
IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks,
CFGBlock* myblock, TypeAnalysis* types, GuardList& out_guards,
const GuardList& in_guards, bool is_partial);
......
This diff is collapsed.
......@@ -104,9 +104,9 @@ private:
continue;
}
if (CallInst* si = dyn_cast<CallInst>(user)) {
if (llvm::isa<CallInst>(user) || llvm::isa<InvokeInst>(user)) {
if (VERBOSITY() >= 2)
errs() << "Not dead; used here: " << *si << '\n';
errs() << "Not dead; used here: " << *user << '\n';
return true;
}
......
......@@ -132,10 +132,10 @@ bool EscapeAnalysis::runOnFunction(Function& F) {
continue;
}
if (CallInst* si = dyn_cast<CallInst>(user)) {
if (llvm::isa<CallInst>(user) || llvm::isa<InvokeInst>(user)) {
if (VERBOSITY() >= 2)
errs() << "Escapes here: " << *si << '\n';
chain->escape_points.insert(si);
errs() << "Escapes here: " << *user << '\n';
chain->escape_points.insert(dyn_cast<Instruction>(user));
continue;
}
......
......@@ -790,12 +790,27 @@ AST* readASTMisc(BufferedReader* reader) {
}
}
static std::string getParserCommandLine(const char* fn) {
llvm::SmallString<128> parse_ast_fn;
// TODO supposed to pass argv0, main_addr to this function:
parse_ast_fn = llvm::sys::fs::getMainExecutable(NULL, NULL);
assert(parse_ast_fn.size() && "could not find the path to the pyston src dir");
// Start by removing the binary name, because the "pyston" binary will break the logic below
llvm::sys::path::remove_filename(parse_ast_fn);
while (llvm::sys::path::filename(parse_ast_fn) != "pyston") {
llvm::sys::path::remove_filename(parse_ast_fn);
}
llvm::sys::path::append(parse_ast_fn, "src/codegen/parse_ast.py");
return std::string("python -S ") + parse_ast_fn.str().str() + " " + fn;
}
AST_Module* parse(const char* fn) {
Timer _t("parsing");
std::string cmdline = "python codegen/parse_ast.py ";
cmdline += fn;
FILE* fp = popen(cmdline.c_str(), "r");
FILE* fp = popen(getParserCommandLine(fn).c_str(), "r");
BufferedReader* reader = new BufferedReader(fp);
AST* rtn = readASTMisc(reader);
......@@ -820,15 +835,7 @@ AST_Module* parse(const char* fn) {
#define LENGTH_SUFFIX_LENGTH 4
static void _reparse(const char* fn, const std::string& cache_fn) {
llvm::SmallString<128> parse_ast_fn;
// TODO supposed to pass argv0, main_addr to this function:
parse_ast_fn = llvm::sys::fs::getMainExecutable(NULL, NULL);
assert(parse_ast_fn.size() && "could not find the path to the pyston src dir");
llvm::sys::path::remove_filename(parse_ast_fn);
llvm::sys::path::append(parse_ast_fn, "codegen/parse_ast.py");
std::string cmdline = std::string("python -S ") + parse_ast_fn.str().str() + " " + fn;
FILE* parser = popen(cmdline.c_str(), "r");
FILE* parser = popen(getParserCommandLine(fn).c_str(), "r");
FILE* cache_fp = fopen(cache_fn.c_str(), "w");
assert(cache_fp);
......
......@@ -40,6 +40,11 @@
#include "runtime/inline/boxing.h"
extern "C" void* __cxa_begin_catch(void*);
extern "C" void __cxa_end_catch();
extern "C" void* __cxa_allocate_exception(size_t);
extern "C" void __cxa_throw(void*, void*, void (*)(void*));
namespace pyston {
static llvm::Function* lookupFunction(const std::string& name) {
......@@ -168,6 +173,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(unaryop);
GET(import);
GET(repr);
GET(isinstance);
GET(checkUnpackingLength);
GET(raiseAttributeError);
......@@ -203,6 +209,11 @@ void initGlobalFuncs(GlobalState& g) {
g.funcs.reoptCompiledFunc = addFunc((void*)reoptCompiledFunc, g.i8_ptr, g.i8_ptr);
g.funcs.compilePartialFunc = addFunc((void*)compilePartialFunc, g.i8_ptr, g.i8_ptr);
GET(__cxa_begin_catch);
g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_);
g.funcs.__cxa_allocate_exception = addFunc((void*)__cxa_allocate_exception, g.i8_ptr, g.i64);
g.funcs.__cxa_throw = addFunc((void*)__cxa_throw, g.void_, g.i8_ptr, g.i8_ptr, g.i8_ptr);
g.funcs.div_i64_i64 = getFunc((void*)div_i64_i64, "div_i64_i64");
g.funcs.mod_i64_i64 = getFunc((void*)mod_i64_i64, "mod_i64_i64");
g.funcs.pow_i64_i64 = getFunc((void*)pow_i64_i64, "pow_i64_i64");
......
......@@ -23,7 +23,7 @@ struct GlobalFuncs {
llvm::Value* boxInt, *unboxInt, *boxFloat, *unboxFloat, *boxStringPtr, *boxCLFunction, *unboxCLFunction,
*boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *createClass;
llvm::Value* getattr, *setattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem, *getclsattr,
*getGlobal, *setitem, *unaryop, *import, *repr;
*getGlobal, *setitem, *unaryop, *import, *repr, *isinstance;
llvm::Value* checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail;
llvm::Value* printFloat, *listAppendInternal;
......@@ -32,6 +32,8 @@ struct GlobalFuncs {
llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr;
llvm::Value* reoptCompiledFunc, *compilePartialFunc;
llvm::Value* __cxa_begin_catch, *__cxa_end_catch, *__cxa_allocate_exception, *__cxa_throw;
llvm::Value* div_i64_i64, *mod_i64_i64, *pow_i64_i64;
llvm::Value* div_float_float, *mod_float_float, *pow_float_float;
};
......
......@@ -46,6 +46,17 @@ public:
virtual void NotifyObjectEmitted(const llvm::ObjectImage&);
};
// LLVM will silently not register the eh frames with libgcc if these functions don't exist;
// make sure that these functions exist.
// TODO I think this breaks it for windows, which apparently loads these dynamically?
// see llvm/lib/ExecutionEngine/RTDyldMemoryManager.cpp
extern "C" void __register_frame(void*);
extern "C" void __deregister_frame(void*);
extern void _force_link() {
__register_frame(nullptr);
__deregister_frame(nullptr);
}
void StackmapJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
// llvm::outs() << "An object has been emitted:\n";
......
......@@ -23,8 +23,54 @@
#include "codegen/codegen.h"
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#ifndef LIBUNWIND_PYSTON_PATCH_VERSION
#error "Please use a patched version of libunwind; see docs/INSTALLING.md"
#elif LIBUNWIND_PYSTON_PATCH_VERSION != 0x01
#error "Please repatch your version of libunwind; see docs/INSTALLING.md"
#endif
// Definition from libunwind, but standardized I suppose by the format of the .eh_frame_hdr section:
struct uw_table_entry {
int32_t start_ip_offset;
int32_t fde_offset;
};
namespace pyston {
// Parse an .eh_frame section, and construct a "binary search table" such as you would find in a .eh_frame_hdr section.
// Currently only supports .eh_frame sections with exactly one fde.
void parseEhFrame(uint64_t start_addr, uint64_t size, uint64_t* out_data, uint64_t* out_len) {
union {
uint8_t* u8;
uint32_t* u32;
};
u32 = (uint32_t*)start_addr;
int cie_length = *u32;
*u32++;
assert(*u32 == 0); // CIE ID
u8 += cie_length;
int fde_length = *u32;
u32++;
assert(cie_length + fde_length + 8 == size && "more than one fde! (supportable, but not implemented)");
int nentries = 1;
uw_table_entry* table_data = new uw_table_entry[nentries];
table_data->start_ip_offset = 0;
table_data->fde_offset = 4 + cie_length;
*out_data = (uintptr_t)table_data;
*out_len = nentries;
}
class TracebacksEventListener : public llvm::JITEventListener {
public:
void NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
......@@ -56,6 +102,62 @@ public:
}
}
}
// Currently-unused libunwind support:
llvm::error_code code;
bool found_text = false, found_eh_frame = false;
uint64_t text_addr, text_size;
uint64_t eh_frame_addr, eh_frame_size;
for (llvm::object::section_iterator I = Obj.begin_sections(), E = Obj.end_sections(); I != E; ++I) {
llvm::StringRef name;
code = I->getName(name);
assert(!code);
uint64_t addr, size;
if (name == ".eh_frame") {
assert(!found_eh_frame);
found_eh_frame = true;
if (I->getAddress(eh_frame_addr))
continue;
if (I->getSize(eh_frame_size))
continue;
if (VERBOSITY())
printf("eh_frame: %lx %lx\n", eh_frame_addr, eh_frame_size);
} else if (name == ".text") {
assert(!found_text);
found_text = true;
if (I->getAddress(text_addr))
continue;
if (I->getSize(text_size))
continue;
if (VERBOSITY())
printf("text: %lx %lx\n", text_addr, text_size);
}
}
assert(found_text);
assert(found_eh_frame);
unw_dyn_info_t* dyn_info = new unw_dyn_info_t();
dyn_info->start_ip = text_addr;
dyn_info->end_ip = text_addr + text_size;
dyn_info->format = UNW_INFO_FORMAT_REMOTE_TABLE;
dyn_info->u.rti.name_ptr = 0;
dyn_info->u.rti.segbase = eh_frame_addr;
parseEhFrame(eh_frame_addr, eh_frame_size, &dyn_info->u.rti.table_data, &dyn_info->u.rti.table_len);
if (VERBOSITY())
printf("dyn_info = %p, table_data = %p\n", dyn_info, (void*)dyn_info->u.rti.table_data);
_U_dyn_register(dyn_info);
// TODO: it looks like libunwind does a linear search over anything dynamically registered,
// 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
// dyn_info that contains a binary search table.
}
};
......
......@@ -25,7 +25,7 @@
namespace pyston {
std::string getOpSymbol(int op_type) {
llvm::StringRef getOpSymbol(int op_type) {
switch (op_type) {
case AST_TYPE::Add:
return "+";
......@@ -86,7 +86,7 @@ std::string getOpSymbol(int op_type) {
}
std::string getInplaceOpSymbol(int op_type) {
return getOpSymbol(op_type) + '=';
return std::string(getOpSymbol(op_type)) + '=';
}
std::string getOpName(int op_type) {
......@@ -513,6 +513,18 @@ void* AST_Index::accept_expr(ExprVisitor* v) {
return v->visit_index(this);
}
void AST_Invoke::accept(ASTVisitor* v) {
bool skip = v->visit_invoke(this);
if (skip)
return;
this->stmt->accept(v);
}
void AST_Invoke::accept_stmt(StmtVisitor* v) {
return v->visit_invoke(this);
}
void AST_keyword::accept(ASTVisitor* v) {
bool skip = v->visit_keyword(this);
if (skip)
......@@ -521,6 +533,18 @@ void AST_keyword::accept(ASTVisitor* v) {
value->accept(v);
}
void AST_LangPrimitive::accept(ASTVisitor* v) {
bool skip = v->visit_langprimitive(this);
if (skip)
return;
visitVector(args, v);
}
void* AST_LangPrimitive::accept_expr(ExprVisitor* v) {
return v->visit_langprimitive(this);
}
void AST_List::accept(ASTVisitor* v) {
bool skip = v->visit_list(this);
if (skip)
......@@ -1175,6 +1199,34 @@ bool PrintVisitor::visit_index(AST_Index* node) {
return false;
}
bool PrintVisitor::visit_invoke(AST_Invoke* node) {
printf("invoke %d %d: ", node->normal_dest->idx, node->exc_dest->idx);
node->stmt->accept(this);
return true;
}
bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
printf(":");
switch (node->opcode) {
case AST_LangPrimitive::ISINSTANCE:
printf("isinstance");
break;
case AST_LangPrimitive::LANDINGPAD:
printf("landingpad");
break;
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
printf("(");
for (int i = 0, n = node->args.size(); i < n; ++i) {
if (i > 0)
printf(", ");
node->args[i]->accept(this);
}
printf(")");
return true;
}
bool PrintVisitor::visit_list(AST_List* node) {
printf("[");
for (int i = 0, n = node->elts.size(); i < n; ++i) {
......@@ -1548,6 +1600,10 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_excepthandler(AST_ExceptHandler* node) {
output->push_back(node);
return false;
}
virtual bool visit_expr(AST_Expr* node) {
output->push_back(node);
return false;
......@@ -1588,6 +1644,10 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_langprimitive(AST_LangPrimitive* node) {
output->push_back(node);
return false;
}
virtual bool visit_list(AST_List* node) {
output->push_back(node);
return false;
......@@ -1616,6 +1676,10 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_raise(AST_Raise* node) {
output->push_back(node);
return false;
}
virtual bool visit_repr(AST_Repr* node) {
output->push_back(node);
return false;
......@@ -1636,6 +1700,14 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_tryexcept(AST_TryExcept* node) {
output->push_back(node);
return false;
}
virtual bool visit_tryfinally(AST_TryFinally* node) {
output->push_back(node);
return false;
}
virtual bool visit_tuple(AST_Tuple* node) {
output->push_back(node);
return false;
......
......@@ -23,6 +23,8 @@
#include <vector>
#include <string>
#include "llvm/ADT/StringRef.h"
namespace pyston {
namespace AST_TYPE {
......@@ -120,6 +122,8 @@ enum AST_TYPE {
Jump = 201,
ClsAttribute = 202,
AugBinOp = 203,
Invoke = 204,
LangPrimitive = 205,
};
};
......@@ -620,7 +624,7 @@ public:
virtual void accept(ASTVisitor* v);
virtual void accept_stmt(StmtVisitor* v);
AST_Raise() : AST_stmt(AST_TYPE::Raise) {}
AST_Raise() : AST_stmt(AST_TYPE::Raise), arg0(NULL), arg1(NULL), arg2(NULL) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Raise;
};
......@@ -795,6 +799,41 @@ public:
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::ClsAttribute;
};
class AST_Invoke : public AST_stmt {
public:
AST_stmt* stmt;
CFGBlock* normal_dest, *exc_dest;
virtual void accept(ASTVisitor* v);
virtual void accept_stmt(StmtVisitor* v);
AST_Invoke(AST_stmt* stmt) : AST_stmt(AST_TYPE::Invoke), stmt(stmt) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Invoke;
};
// "LangPrimitive" represents operations that "primitive" to the language,
// but aren't directly *exactly* representable as normal Python.
// ClsAttribute would fall into this category, as would isinstance (which
// is not the same as the "isinstance" name since that could get redefined).
class AST_LangPrimitive : public AST_expr {
public:
enum Opcodes {
ISINSTANCE,
LANDINGPAD,
} opcode;
std::vector<AST_expr*> args;
virtual void accept(ASTVisitor* v);
virtual void* accept_expr(ExprVisitor* v);
AST_LangPrimitive(Opcodes opcode) : AST_expr(AST_TYPE::LangPrimitive), opcode(opcode) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::LangPrimitive;
};
template <typename T> T* ast_cast(AST* node) {
assert(node->type == T::TYPE);
return static_cast<T*>(node);
......@@ -834,7 +873,9 @@ public:
virtual bool visit_import(AST_Import* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_importfrom(AST_ImportFrom* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_index(AST_Index* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_invoke(AST_Invoke* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_keyword(AST_keyword* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_langprimitive(AST_LangPrimitive* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_list(AST_List* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_listcomp(AST_ListComp* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_module(AST_Module* node) { RELEASE_ASSERT(0, ""); }
......@@ -891,7 +932,9 @@ public:
virtual bool visit_import(AST_Import* node) { return false; }
virtual bool visit_importfrom(AST_ImportFrom* node) { return false; }
virtual bool visit_index(AST_Index* node) { return false; }
virtual bool visit_invoke(AST_Invoke* node) { return false; }
virtual bool visit_keyword(AST_keyword* node) { return false; }
virtual bool visit_langprimitive(AST_LangPrimitive* node) { return false; }
virtual bool visit_list(AST_List* node) { return false; }
virtual bool visit_listcomp(AST_ListComp* node) { return false; }
virtual bool visit_module(AST_Module* node) { return false; }
......@@ -931,6 +974,7 @@ public:
virtual void* visit_dict(AST_Dict* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_ifexp(AST_IfExp* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_index(AST_Index* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_langprimitive(AST_LangPrimitive* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_list(AST_List* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_listcomp(AST_ListComp* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_name(AST_Name* node) { RELEASE_ASSERT(0, ""); }
......@@ -961,6 +1005,7 @@ public:
virtual void visit_if(AST_If* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_import(AST_Import* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_importfrom(AST_ImportFrom* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_invoke(AST_Invoke* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_pass(AST_Pass* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_print(AST_Print* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_raise(AST_Raise* node) { RELEASE_ASSERT(0, ""); }
......@@ -1011,7 +1056,9 @@ public:
virtual bool visit_import(AST_Import* node);
virtual bool visit_importfrom(AST_ImportFrom* node);
virtual bool visit_index(AST_Index* node);
virtual bool visit_invoke(AST_Invoke* node);
virtual bool visit_keyword(AST_keyword* node);
virtual bool visit_langprimitive(AST_LangPrimitive* node);
virtual bool visit_list(AST_List* node);
virtual bool visit_listcomp(AST_ListComp* node);
virtual bool visit_module(AST_Module* node);
......@@ -1050,6 +1097,8 @@ template <class T, class R> void findNodes(const R& roots, std::vector<T*>& outp
output.push_back(reinterpret_cast<T*>(n));
}
}
llvm::StringRef getOpSymbol(int op_type);
};
#endif
This diff is collapsed.
......@@ -230,7 +230,6 @@ extern "C" Box* callCompiledFunc(CompiledFunction* cf, int64_t nargs, Box* arg1,
std::string getOpName(int op_type);
std::string getReverseOpName(int op_type);
std::string getInplaceOpName(int op_type);
std::string getOpSymbol(int op_type);
std::string getInplaceOpSymbol(int op_type);
typedef bool i1;
......@@ -400,6 +399,8 @@ std::string getPythonFuncAt(void* ip, void* sp);
// TODO where to put this
void addToSysPath(const std::string& path);
void addToSysArgv(const char* str);
std::string formatException(Box* e);
}
#endif
......@@ -143,7 +143,14 @@ int main(int argc, char** argv) {
fprintf(stderr, "==============\n");
}
compileAndRunModule(m, main);
try {
compileAndRunModule(m, main);
}
catch (Box* b) {
std::string msg = formatException(b);
fprintf(stderr, "%s\n", msg.c_str());
exit(1);
}
}
}
......@@ -179,7 +186,8 @@ int main(int argc, char** argv) {
}
if (repl) {
printf("Pyston v0.1, rev " STRINGIFY(GITREV) "\n");
printf("Pyston v0.1 (rev " STRINGIFY(GITREV) ")");
printf(", targeting Python %d.%d.%d\n", PYTHON_VERSION_MAJOR, PYTHON_VERSION_MINOR, PYTHON_VERSION_MICRO);
BoxedModule* main = createModule("__main__", "<stdin>");
......@@ -193,8 +201,7 @@ int main(int argc, char** argv) {
if ((read = getline(&line, &size, stdin)) == -1) {
repl = false;
} else {
timeval start, end;
gettimeofday(&start, NULL);
Timer _t("repl");
char buf[] = "pystontmp_XXXXXX";
char* tmpdir = mkdtemp(buf);
......@@ -221,12 +228,6 @@ int main(int argc, char** argv) {
}
compileAndRunModule(m, main);
if (VERBOSITY() >= 1) {
gettimeofday(&end, NULL);
long ms = 1000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000;
printf("%ldms\n", ms);
}
}
}
}
......
......@@ -81,8 +81,7 @@ extern "C" Box* min1(Box* container) {
}
if (!minElement) {
fprintf(stderr, "ValueError: min() arg is an empty sequence\n");
raiseExc();
raiseExcHelper(ValueError, "min() arg is an empty sequence");
}
return minElement;
}
......@@ -110,8 +109,7 @@ extern "C" Box* max1(Box* container) {
}
if (!maxElement) {
fprintf(stderr, "ValueError: max() arg is an empty sequence\n");
raiseExc();
raiseExcHelper(ValueError, "max() arg is an empty sequence");
}
return maxElement;
}
......@@ -129,12 +127,12 @@ extern "C" Box* open2(Box* arg1, Box* arg2) {
if (arg1->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n",
getTypeName(arg1)->c_str());
raiseExc();
raiseExcHelper(TypeError, "");
}
if (arg2->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n",
getTypeName(arg2)->c_str());
raiseExc();
raiseExcHelper(TypeError, "");
}
const std::string& fn = static_cast<BoxedString*>(arg1)->s;
......@@ -155,7 +153,7 @@ extern "C" Box* open1(Box* arg) {
extern "C" Box* chr(Box* arg) {
if (arg->cls != int_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(arg)->c_str());
raiseExc();
raiseExcHelper(TypeError, "");
}
i64 n = static_cast<BoxedInt*>(arg)->n;
RELEASE_ASSERT(n >= 0 && n < 256, "");
......@@ -240,27 +238,23 @@ Box* sorted(Box* obj) {
return rtn;
}
Box* isinstance(Box* obj, Box* cls) {
Box* isinstance_func(Box* obj, Box* cls) {
assert(cls->cls == type_cls);
BoxedClass* ccls = static_cast<BoxedClass*>(cls);
// TODO need to check if it's a subclass, or if subclasshook exists
return boxBool(obj->cls == cls);
return boxBool(isinstance(obj, cls, 0));
}
Box* getattr2(Box* obj, Box* _str) {
if (_str->cls != str_cls) {
fprintf(stderr, "TypeError: getattr(): attribute name must be string\n");
raiseExc();
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
}
BoxedString* str = static_cast<BoxedString*>(_str);
Box* rtn = getattr_internal(obj, str->s, true, true, NULL, NULL);
if (!rtn) {
fprintf(stderr, "AttributeError: '%s' object has no attribute '%s'\n", getTypeName(obj)->c_str(),
str->s.c_str());
raiseExc();
raiseExcHelper(AttributeError, "'%s' object has no attribute '%s'", getTypeName(obj)->c_str(), str->s.c_str());
}
return rtn;
......@@ -268,8 +262,7 @@ Box* getattr2(Box* obj, Box* _str) {
Box* getattr3(Box* obj, Box* _str, Box* default_value) {
if (_str->cls != str_cls) {
fprintf(stderr, "TypeError: getattr(): attribute name must be string\n");
raiseExc();
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
}
BoxedString* str = static_cast<BoxedString*>(_str);
......@@ -294,6 +287,60 @@ extern "C" const ObjectFlavor notimplemented_flavor(&boxGCHandler, NULL);
BoxedClass* notimplemented_cls;
BoxedModule* builtins_module;
// TODO looks like CPython and pypy put this into an "exceptions" module:
BoxedClass* Exception, *AssertionError, *AttributeError, *TypeError, *NameError, *KeyError, *IndexError, *IOError,
*OSError, *ZeroDivisionError, *ValueError, *UnboundLocalError, *RuntimeError, *ImportError;
const ObjectFlavor exception_flavor(&boxGCHandler, NULL);
Box* exceptionNew1(BoxedClass* cls) {
return exceptionNew2(cls, boxStrConstant(""));
}
Box* exceptionNew2(BoxedClass* cls, Box* message) {
HCBox* r = new HCBox(&exception_flavor, cls);
r->giveAttr("message", message);
return r;
}
Box* exceptionStr(Box* b) {
HCBox* hcb = static_cast<HCBox*>(b);
// TODO In CPython __str__ and __repr__ pull from an internalized message field, but for now do this:
Box* message = hcb->peekattr("message");
assert(message);
message = str(message);
assert(message->cls == str_cls);
return message;
}
Box* exceptionRepr(Box* b) {
HCBox* hcb = static_cast<HCBox*>(b);
// TODO In CPython __str__ and __repr__ pull from an internalized message field, but for now do this:
Box* message = hcb->peekattr("message");
assert(message);
message = repr(message);
assert(message->cls == str_cls);
BoxedString* message_s = static_cast<BoxedString*>(message);
return boxString(*getTypeName(b) + "(" + message_s->s + ",)");
}
static BoxedClass* makeBuiltinException(const char* name) {
BoxedClass* cls = new BoxedClass(true, NULL);
cls->giveAttr("__name__", boxStrConstant(name));
// TODO these should be on the base Exception class:
cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)exceptionNew1, NULL, 1, false)));
cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)exceptionStr, NULL, 1, false)));
cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)exceptionRepr, NULL, 1, false)));
cls->freeze();
builtins_module->giveAttr(name, cls);
return cls;
}
void setupBuiltins() {
builtins_module = createModule("__builtin__", "__builtin__");
......@@ -313,6 +360,21 @@ void setupBuiltins() {
builtins_module->giveAttr("all", new BoxedFunction(boxRTFunction((void*)all, BOXED_BOOL, 1, false)));
builtins_module->giveAttr("any", new BoxedFunction(boxRTFunction((void*)any, BOXED_BOOL, 1, false)));
Exception = makeBuiltinException("Exception");
AssertionError = makeBuiltinException("AssertionError");
AttributeError = makeBuiltinException("AttributeError");
TypeError = makeBuiltinException("TypeError");
NameError = makeBuiltinException("NameError");
KeyError = makeBuiltinException("KeyError");
IndexError = makeBuiltinException("IndexError");
IOError = makeBuiltinException("IOError");
OSError = makeBuiltinException("OSError");
ZeroDivisionError = makeBuiltinException("ZeroDivisionError");
ValueError = makeBuiltinException("ValueError");
UnboundLocalError = makeBuiltinException("UnboundLocalError");
RuntimeError = makeBuiltinException("RuntimeError");
ImportError = makeBuiltinException("ImportError");
repr_obj = new BoxedFunction(boxRTFunction((void*)repr, NULL, 1, false));
builtins_module->giveAttr("repr", repr_obj);
len_obj = new BoxedFunction(boxRTFunction((void*)len, NULL, 1, false));
......@@ -341,7 +403,7 @@ void setupBuiltins() {
addRTFunction(getattr_func, (void*)getattr3, NULL, 3, false);
builtins_module->giveAttr("getattr", new BoxedFunction(getattr_func));
Box* isinstance_obj = new BoxedFunction(boxRTFunction((void*)isinstance, NULL, 2, false));
Box* isinstance_obj = new BoxedFunction(boxRTFunction((void*)isinstance_func, NULL, 2, false));
builtins_module->giveAttr("isinstance", isinstance_obj);
builtins_module->giveAttr("sorted", new BoxedFunction(boxRTFunction((void*)sorted, NULL, 1, false)));
......
......@@ -30,8 +30,7 @@ BoxedModule* math_module;
static double _extractFloat(Box* b) {
if (b->cls != int_cls && b->cls != float_cls) {
fprintf(stderr, "TypeError: a float is required\n");
raiseExc();
raiseExcHelper(TypeError, "a float is required");
}
if (b->cls == int_cls)
......@@ -44,8 +43,7 @@ Box* mathSqrtFloat(Box* b) {
assert(b->cls == float_cls);
double d = static_cast<BoxedFloat*>(b)->d;
if (d < 0) {
fprintf(stderr, "ValueError: math domain error\n");
raiseExc();
raiseExcHelper(ValueError, "math domain error");
}
return boxFloat(sqrt(d));
}
......@@ -54,8 +52,7 @@ Box* mathSqrtInt(Box* b) {
assert(b->cls == int_cls);
double d = static_cast<BoxedInt*>(b)->n;
if (d < 0) {
fprintf(stderr, "ValueError: math domain error\n");
raiseExc();
raiseExcHelper(ValueError, "math domain error");
}
return boxFloat(sqrt(d));
}
......@@ -64,8 +61,7 @@ Box* mathSqrtInt(Box* b) {
Box* mathSqrt(Box* b) {
double d = _extractFloat(b);
if (d < 0) {
fprintf(stderr, "ValueError: math domain error\n");
raiseExc();
raiseExcHelper(ValueError, "math domain error");
}
return boxFloat(sqrt(d));
}
......
......@@ -46,7 +46,7 @@ BoxedList* getSysPath() {
if (_sys_path->cls != list_cls) {
fprintf(stderr, "RuntimeError: sys.path must be a list of directory name\n");
raiseExc();
raiseExcHelper(RuntimeError, "");
}
assert(_sys_path->cls == list_cls);
......
......@@ -81,7 +81,7 @@ Box* dictGetitem(BoxedDict* self, Box* k) {
if (pos == NULL) {
BoxedString* s = static_cast<BoxedString*>(repr(k));
fprintf(stderr, "KeyError: %s\n", s->s.c_str());
raiseExc();
raiseExcHelper(KeyError, "");
}
return pos;
......
......@@ -36,7 +36,7 @@ Box* fileRepr(BoxedFile* self) {
static Box* _fileRead(BoxedFile* self, i64 size) {
if (self->closed) {
fprintf(stderr, "IOError: file not open for reading\n");
raiseExc();
raiseExcHelper(IOError, "");
}
std::ostringstream os("");
......@@ -88,7 +88,7 @@ Box* fileRead2(BoxedFile* self, Box* size) {
assert(self->cls == file_cls);
if (size->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n");
raiseExc();
raiseExcHelper(TypeError, "");
}
return _fileRead(self, static_cast<BoxedInt*>(size)->n);
}
......@@ -98,7 +98,7 @@ Box* fileWrite(BoxedFile* self, Box* val) {
if (self->closed) {
fprintf(stderr, "IOError: file is closed\n");
raiseExc();
raiseExcHelper(IOError, "");
}
......@@ -119,7 +119,7 @@ Box* fileWrite(BoxedFile* self, Box* val) {
if (!new_written) {
int error = ferror(self->f);
fprintf(stderr, "IOError %d\n", error);
raiseExc();
raiseExcHelper(IOError, "");
}
written += new_written;
......@@ -127,8 +127,8 @@ Box* fileWrite(BoxedFile* self, Box* val) {
return None;
} else {
fprintf(stderr, "str expected\n");
raiseExc();
fprintf(stderr, "TypeError: expected a character buffer object\n");
raiseExcHelper(TypeError, "");
}
}
......@@ -136,7 +136,7 @@ Box* fileClose(BoxedFile* self) {
assert(self->cls == file_cls);
if (self->closed) {
fprintf(stderr, "IOError: file is closed\n");
raiseExc();
raiseExcHelper(IOError, "");
}
fclose(self->f);
......
......@@ -30,8 +30,7 @@ namespace pyston {
template <typename T> static inline void raiseDivZeroExcIfZero(T var) {
if (var == 0) {
fprintf(stderr, "float divide by zero\n");
raiseExc();
raiseExcHelper(ZeroDivisionError, "float divide by zero");
}
}
......
......@@ -34,6 +34,11 @@ static void forceLink(void* x) {
printf("%p\n", x);
}
extern "C" void __py_personality_v0() {
RELEASE_ASSERT(0, "not used");
}
namespace _force {
#define FORCE(name) forceLink((void*)name)
......@@ -71,6 +76,7 @@ void force() {
FORCE(unaryop);
FORCE(import);
FORCE(repr);
FORCE(isinstance);
FORCE(checkUnpackingLength);
FORCE(raiseAttributeError);
......
......@@ -48,8 +48,7 @@ extern "C" i64 sub_i64_i64(i64 lhs, i64 rhs) {
extern "C" i64 div_i64_i64(i64 lhs, i64 rhs) {
if (rhs == 0) {
fprintf(stderr, "ZeroDivisionError: integer division or modulo by zero\n");
raiseExc();
raiseExcHelper(ZeroDivisionError, "integer division or modulo by zero");
}
if (lhs < 0 && rhs > 0)
return (lhs - rhs + 1) / rhs;
......@@ -60,8 +59,7 @@ extern "C" i64 div_i64_i64(i64 lhs, i64 rhs) {
extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs) {
if (rhs == 0) {
fprintf(stderr, "ZeroDivisionError: integer division or modulo by zero\n");
raiseExc();
raiseExcHelper(ZeroDivisionError, "integer division or modulo by zero");
}
if (lhs < 0 && rhs > 0)
return ((lhs + 1) % rhs) + (rhs - 1);
......@@ -163,8 +161,7 @@ extern "C" Box* intDivFloat(BoxedInt* lhs, BoxedFloat* rhs) {
assert(rhs->cls == float_cls);
if (rhs->d == 0) {
fprintf(stderr, "float divide by zero\n");
raiseExc();
raiseExcHelper(ZeroDivisionError, "float divide by zero");
}
return boxFloat(lhs->n / rhs->d);
}
......@@ -300,6 +297,25 @@ extern "C" Box* intMod(BoxedInt* lhs, Box* rhs) {
return boxInt(mod_i64_i64(lhs->n, rhs_int->n));
}
extern "C" Box* intDivmod(BoxedInt* lhs, Box* rhs) {
assert(lhs->cls == int_cls);
Box* divResult = intDiv(lhs, rhs);
if (divResult == NotImplemented) {
return NotImplemented;
}
Box* modResult = intMod(lhs, rhs);
if (modResult == NotImplemented) {
return NotImplemented;
}
Box* arg[2] = { divResult, modResult };
return createTuple(2, arg);
}
extern "C" Box* intMulInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(lhs->cls == int_cls);
assert(rhs->cls == int_cls);
......@@ -445,8 +461,9 @@ extern "C" Box* intNew2(Box* cls, Box* val) {
return boxInt(d);
} else {
fprintf(stderr, "int() argument must be a string or a number, not '%s'\n", getTypeName(val)->c_str());
raiseExc();
fprintf(stderr, "TypeError: int() argument must be a string or a number, not '%s'\n",
getTypeName(val)->c_str());
raiseExcHelper(TypeError, "");
}
}
......@@ -521,6 +538,7 @@ void setupInt() {
int_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)intRepr, STR, 1, false)));
int_cls->setattr("__str__", int_cls->peekattr("__repr__"), NULL, NULL);
int_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)intHash, BOXED_INT, 1, false)));
int_cls->giveAttr("__divmod__", new BoxedFunction(boxRTFunction((void*)intDivmod, BOXED_TUPLE, 2, false)));
CLFunction* __new__ = boxRTFunction((void*)intNew1, NULL, 1, false);
addRTFunction(__new__, (void*)intNew2, NULL, 2, false);
......
......@@ -54,8 +54,7 @@ extern "C" Box* listNonzero(BoxedList* self) {
extern "C" Box* listPop1(BoxedList* self) {
if (self->size == 0) {
fprintf(stderr, "IndexError: pop from empty list\n");
raiseExc();
raiseExcHelper(IndexError, "pop from empty list");
}
self->size--;
......@@ -65,8 +64,7 @@ extern "C" Box* listPop1(BoxedList* self) {
extern "C" Box* listPop2(BoxedList* self, Box* idx) {
if (idx->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n");
raiseExc();
raiseExcHelper(TypeError, "an integer is required");
}
int64_t n = static_cast<BoxedInt*>(idx)->n;
......@@ -78,7 +76,7 @@ extern "C" Box* listPop2(BoxedList* self, Box* idx) {
fprintf(stderr, "IndexError: pop from empty list\n");
else
fprintf(stderr, "IndexError: pop index out of range\n");
raiseExc();
raiseExcHelper(IndexError, "");
}
Box* rtn = self->elts->elts[n];
......@@ -126,8 +124,7 @@ extern "C" Box* listGetitemInt(BoxedList* self, BoxedInt* slice) {
n = self->size + n;
if (n < 0 || n >= self->size) {
fprintf(stderr, "IndexError: list index out of range\n");
raiseExc();
raiseExcHelper(IndexError, "list index out of range");
}
Box* rtn = self->elts->elts[n];
return rtn;
......@@ -148,8 +145,7 @@ extern "C" Box* listGetitem(BoxedList* self, Box* slice) {
} else if (slice->cls == slice_cls) {
return listGetitemSlice(self, static_cast<BoxedSlice*>(slice));
} else {
fprintf(stderr, "TypeError: list indices must be integers, not %s\n", getTypeName(slice)->c_str());
raiseExc();
raiseExcHelper(TypeError, "list indices must be integers, not %s", getTypeName(slice)->c_str());
}
}
......@@ -162,8 +158,7 @@ extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) {
n = self->size + n;
if (n < 0 || n >= self->size) {
fprintf(stderr, "IndexError: list index out of range\n");
raiseExc();
raiseExcHelper(IndexError, "list index out of range");
}
self->elts->elts[n] = v;
......@@ -206,15 +201,13 @@ extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) {
} else if (slice->cls == slice_cls) {
return listSetitemSlice(self, static_cast<BoxedSlice*>(slice), v);
} else {
fprintf(stderr, "TypeError: list indices must be integers, not %s\n", getTypeName(slice)->c_str());
raiseExc();
raiseExcHelper(TypeError, "list indices must be integers, not %s", getTypeName(slice)->c_str());
}
}
extern "C" Box* listInsert(BoxedList* self, Box* idx, Box* v) {
if (idx->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n");
raiseExc();
raiseExcHelper(TypeError, "an integer is required");
}
int64_t n = static_cast<BoxedInt*>(idx)->n;
......@@ -240,8 +233,7 @@ extern "C" Box* listInsert(BoxedList* self, Box* idx, Box* v) {
Box* listMul(BoxedList* self, Box* rhs) {
if (rhs->cls != int_cls) {
fprintf(stderr, "TypeError: can't multiply sequence by non-int of type '%s'\n", getTypeName(rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "can't multiply sequence by non-int of type '%s'", getTypeName(rhs)->c_str());
}
int n = static_cast<BoxedInt*>(rhs)->n;
......@@ -264,8 +256,7 @@ Box* listMul(BoxedList* self, Box* rhs) {
Box* listIAdd(BoxedList* self, Box* _rhs) {
if (_rhs->cls != list_cls) {
fprintf(stderr, "TypeError: can only concatenate list (not \"%s\") to list\n", getTypeName(_rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "can only concatenate list (not \"%s\") to list", getTypeName(_rhs)->c_str());
}
BoxedList* rhs = static_cast<BoxedList*>(_rhs);
......@@ -281,8 +272,7 @@ Box* listIAdd(BoxedList* self, Box* _rhs) {
Box* listAdd(BoxedList* self, Box* _rhs) {
if (_rhs->cls != list_cls) {
fprintf(stderr, "TypeError: can only concatenate list (not \"%s\") to list\n", getTypeName(_rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "can only concatenate list (not \"%s\") to list", getTypeName(_rhs)->c_str());
}
BoxedList* rhs = static_cast<BoxedList*>(_rhs);
......
This diff is collapsed.
......@@ -28,6 +28,9 @@ class BoxedInt;
class BoxedList;
class BoxedString;
void raiseExc(Box*) __attribute__((__noreturn__));
void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__));
extern "C" const std::string* getTypeName(Box* o);
extern "C" const std::string* getNameOfClass(BoxedClass* cls);
......@@ -40,6 +43,7 @@ extern "C" Box* runtimeCall(Box*, int64_t, Box*, Box*, Box*, Box**);
extern "C" Box* callattr(Box*, std::string*, bool, int64_t, Box*, Box*, Box*, Box**);
extern "C" BoxedString* str(Box* obj);
extern "C" Box* repr(Box* obj);
extern "C" bool isinstance(Box* obj, Box* cls, int64_t flags);
extern "C" BoxedInt* hash(Box* obj);
// extern "C" Box* abs_(Box* obj);
extern "C" Box* open1(Box* arg);
......
......@@ -22,11 +22,14 @@
#endif
#include "core/options.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
#include "core/options.h"
#include <stdarg.h>
namespace pyston {
// from http://www.nongnu.org/libunwind/man/libunwind(3).html
......@@ -50,12 +53,102 @@ void showBacktrace() {
}
}
void raiseExc() {
if (VERBOSITY())
showBacktrace();
// if (VERBOSITY()) raise(SIGTRAP);
if (VERBOSITY())
abort();
exit(1);
// Currently-unused libunwind-based unwinding:
void unwindExc(Box* exc_obj) __attribute__((noreturn));
void unwindExc(Box* exc_obj) {
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
int code;
unw_proc_info_t pip;
while (unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
printf("ip = %lx, sp = %lx\n", (long)ip, (long)sp);
code = unw_get_proc_info(&cursor, &pip);
RELEASE_ASSERT(code == 0, "");
// printf("%lx %lx %lx %lx %lx %lx %d %d %p\n", pip.start_ip, pip.end_ip, pip.lsda, pip.handler, pip.gp,
// pip.flags, pip.format, pip.unwind_info_size, pip.unwind_info);
assert((pip.lsda == 0) == (pip.handler == 0));
assert(pip.flags == 0);
if (pip.handler == 0) {
if (VERBOSITY())
printf("Skipping frame without handler\n");
continue;
}
printf("%lx %lx %lx\n", pip.lsda, pip.handler, pip.flags);
// assert(pip.handler == (uintptr_t)__gxx_personality_v0 || pip.handler == (uintptr_t)__py_personality_v0);
// auto handler_fn = (int (*)(int, int, uint64_t, void*, void*))pip.handler;
////handler_fn(1, 1 /* _UA_SEARCH_PHASE */, 0 /* exc_class */, NULL, NULL);
// handler_fn(2, 2 /* _UA_SEARCH_PHASE */, 0 /* exc_class */, NULL, NULL);
unw_set_reg(&cursor, UNW_REG_IP, 1);
// TODO testing:
// unw_resume(&cursor);
}
abort();
}
void raiseExc(Box* exc_obj) {
// Using libgcc:
throw exc_obj;
// Using libunwind
// unwindExc(exc_obj);
abort();
}
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) {
if (msg != NULL) {
va_list ap;
va_start(ap, msg);
char buf[1024];
vsnprintf(buf, sizeof(buf), msg, ap);
va_end(ap);
BoxedString* message = boxStrConstant(buf);
Box* exc_obj = exceptionNew2(cls, message);
raiseExc(exc_obj);
} else {
Box* exc_obj = exceptionNew1(cls);
raiseExc(exc_obj);
}
}
std::string formatException(Box* b) {
const std::string* name = getTypeName(b);
HCBox* hcb = static_cast<HCBox*>(b);
Box* attr = hcb->peekattr("message");
if (attr == nullptr)
return *name;
Box* r;
try {
r = str(attr);
}
catch (Box* b) {
return *name;
}
assert(r->cls == str_cls);
const std::string* msg = &static_cast<BoxedString*>(r)->s;
return *name + ": " + *msg;
}
}
......@@ -37,8 +37,7 @@ extern "C" BoxedString* strAdd(BoxedString* lhs, Box* _rhs) {
assert(lhs->cls == str_cls);
if (_rhs->cls != str_cls) {
fprintf(stderr, "TypeError: cannot concatenate 'str' and '%s' objects", getTypeName(_rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "cannot concatenate 'str' and '%s' objects", getTypeName(_rhs)->c_str());
}
BoxedString* rhs = static_cast<BoxedString*>(_rhs);
......@@ -336,8 +335,7 @@ Box* strJoin(BoxedString* self, Box* rhs) {
}
return boxString(os.str());
} else {
fprintf(stderr, "TypeError\n");
raiseExc();
raiseExcHelper(TypeError, "");
}
}
......@@ -376,14 +374,12 @@ Box* strSplit2(BoxedString* self, BoxedString* sep) {
listAppendInternal(rtn, boxString(s.str()));
return rtn;
} else {
fprintf(stderr, "ValueError: empty separator\n");
raiseExc();
raiseExcHelper(ValueError, "empty separator");
}
} else if (sep->cls == none_cls) {
return strSplit1(self);
} else {
fprintf(stderr, "TypeError: expected a character buffer object\n");
raiseExc();
raiseExcHelper(TypeError, "expected a character buffer object");
}
}
......@@ -397,8 +393,7 @@ extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
n = size + n;
if (n < 0 || n >= size) {
fprintf(stderr, "IndexError: string index out of range\n");
raiseExc();
raiseExcHelper(IndexError, "string index out of range");
}
char c = self->s[n];
......@@ -410,8 +405,7 @@ extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
parseSlice(sslice, self->s.size(), &start, &stop, &step);
return _strSlice(self, start, stop, step);
} else {
fprintf(stderr, "TypeError: string indices must be integers, not %s\n", getTypeName(slice)->c_str());
raiseExc();
raiseExcHelper(TypeError, "string indices must be integers, not %s", getTypeName(slice)->c_str());
}
}
......
......@@ -47,8 +47,8 @@ Box* tupleGetitem(BoxedTuple* self, Box* slice) {
if (n < 0)
n = size - n;
if (n < 0 || n >= size) {
fprintf(stderr, "indexerror\n");
raiseExc();
fprintf(stderr, "IndexError: tuple index out of range\n");
raiseExcHelper(IndexError, "");
}
Box* rtn = self->elts[n];
......
......@@ -57,7 +57,8 @@ llvm::iterator_range<BoxIterator> Box::pyElements() {
if (iter) {
return llvm::iterator_range<BoxIterator>(++BoxIterator(iter), BoxIterator(nullptr));
}
return llvm::iterator_range<BoxIterator>(BoxIterator(nullptr), BoxIterator(nullptr));
raiseExcHelper(TypeError, "'%s' object is not iterable", getTypeName(this)->c_str());
}
extern "C" BoxedFunction::BoxedFunction(CLFunction* f) : HCBox(&function_flavor, function_cls), f(f) {
......
......@@ -136,7 +136,7 @@ public:
class BoxedList : public Box {
public:
class ElementArray : GCObject {
class ElementArray : public GCObject {
public:
Box* elts[0];
......@@ -272,5 +272,11 @@ public:
};
extern "C" void boxGCHandler(GCVisitor* v, void* p);
Box* exceptionNew1(BoxedClass* cls);
Box* exceptionNew2(BoxedClass* cls, Box* message);
extern BoxedClass* Exception, *AssertionError, *AttributeError, *TypeError, *NameError, *KeyError, *IndexError,
*IOError, *OSError, *ZeroDivisionError, *ValueError, *UnboundLocalError, *RuntimeError, *ImportError;
}
#endif
......@@ -14,6 +14,7 @@
#include "core/options.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -64,7 +65,7 @@ void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64*
if (istep == 0) {
fprintf(stderr, "ValueError: slice step cannot be zero\n");
raiseExc();
raiseExcHelper(ValueError, "");
}
if (istep > 0) {
......
......@@ -22,7 +22,5 @@ namespace pyston {
class BoxedSlice;
void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64* out_end);
void raiseExc() __attribute__((__noreturn__));
}
#endif
......@@ -10,6 +10,14 @@ void set64full(int64_t* ptr) {
*ptr = 0x1234567890;
}
void set32(int64_t* ptr) {
*(int32_t*)ptr = 0x1234;
namespace pyston {
class Box {};
int throw_catch(Box* b) {
try {
throw b;
} catch (int e) {
return e;
}
}
}
# expected: fail
# - exceptions
class TestException(Exception):
pass
class ExpectationFailedException(Exception):
pass
class ExpectedException(object):
def __init__(self, excs):
if isinstance(excs, BaseException):
excs = (excs,)
self.excs = excs
def __enter__(self):
pass
def __exit__(self, type, val, tback):
if not val:
raise ExpectationFailedException("Didn't raise any exception")
if not isinstance(val, self.excs):
raise ExpectationFailedException("Raised %s instead of %s" % (val, self.excs))
print "Caught", type.__name__
return True
expected_exception = ExpectedException
# Test the expected_exception manager:
with expected_exception(Exception):
raise Exception()
try:
with expected_exception(Exception):
pass
raise Exception("shouldn't get here")
except ExpectationFailedException:
print "good"
# The inner one will fail, which the outer one should catch:
with expected_exception(ExpectationFailedException):
with expected_exception(Exception):
pass
def throw(x):
try:
raise x
......@@ -59,3 +100,223 @@ def f2(throw):
f2(True)
f2(False)
def f3():
# Finally blocks are actually somewhat complicated, because
# you need to catch not just exceptions, but also continue/break/return's
print "f3"
for i in xrange(5):
try:
if i == 3:
break
continue
finally:
print "finally", i
try:
# Looks like this returns from the function, but it needs to go to the finally block
return
finally:
print "in finally"
f3()
def f4():
# Make sure that simply accessing a name can throw exceptions as expected
print "f4"
with expected_exception(NameError):
print doesnt_exist
global doesnt_exist2
with expected_exception(NameError):
print doesnt_exist2
f4()
def f5():
# Make sure that we don't accidentally set 'x' here;
# the exception prevents the assignment from happening
print "f5"
try:
try:
x = doesnt_exist
except NameError:
print "inner except"
print x
except NameError:
print "outer except"
# Similar test, except now the reference to 'y' *does* come from
# the line that will end up throwing, but from a previous iteration
# that didn't throw.
def inner(i):
if i == 1:
raise AttributeError
for i in xrange(5):
try:
y = inner(i)
except AttributeError:
print y
f5()
def f6():
print "f6"
a = 0
with expected_exception(AttributeError):
a.x = 0
with expected_exception(TypeError):
a[0] = 0
# Tricky!
# Note: a multiple-assignment statement like this is processed by setting the targets one by one, left-to-right.
# So the assignment to "x" should succeed, but then the assignment to x.a will fail.
# In the exception handler we should be able to see a value for x, but accessing y should fail.
try:
x = x.a = y = 1
raise Exception("shouldn't get here")
except AttributeError:
print "caught, as expected"
print "x = ", x
try:
print "y = ", y
raise Exception("shouldn't get here")
except UnboundLocalError:
print "caught, as expected"
f6()
def f7():
print "f7"
# Make sure that desugaring produces exception handling as expected:
class NonIterable(object):
pass
with expected_exception(TypeError):
for i in NonIterable():
pass
class BadIterable(object):
def __iter__(self):
return self
def next(self):
raise NotImplementedError()
with expected_exception(NotImplementedError):
for i in BadIterable():
print i
class ExceptionRaiser(object):
def __nonzero__(self):
raise TestException()
def __repr__(self):
raise TestException()
with expected_exception(TestException):
while ExceptionRaiser():
pass
with expected_exception(TestException):
print ExceptionRaiser()
with expected_exception(TestException):
assert ExceptionRaiser()
with expected_exception(AssertionError):
assert 0
def throw():
raise TestException()
with expected_exception(TestException):
def f(x=throw()):
pass
with expected_exception(TestException):
class C(object):
throw()
with expected_exception(ImportError):
import hopefully_this_package_doesnt_exist
hopefully_this_package_doesnt_exist # to silence pyflakes
with expected_exception(ImportError):
from hopefully_this_package_doesnt_exist import a
a # to silence pyflakes
with expected_exception(TestException):
print 1 if throw() else 0
with expected_exception(TestException):
print ExceptionRaiser() and 1
with expected_exception(TestException):
if throw():
pass
with expected_exception(TestException):
if ExceptionRaiser():
pass
try:
# Imports also need to be broken into separate parts:
from sys import path, doesnt_exist
except ImportError:
print type(path)
with expected_exception(NameError):
print doesnt_exist
f7()
def f8():
print "f8"
def f(exc):
print "evaluating except type;", exc.__name__
return exc
try:
raise AttributeError()
except f(TypeError):
print "shouldn't be here 1"
except f(AttributeError):
print "should hit this"
except f(NotImplementedError):
print "shouldn't be here"
f8()
def f9():
print "f9"
# arithmetic
with expected_exception(ZeroDivisionError):
1/0
with expected_exception(ZeroDivisionError):
1.0/0
with expected_exception(ZeroDivisionError):
1/0.0
with expected_exception(ZeroDivisionError):
1 % 0
with expected_exception(ZeroDivisionError):
1 % 0.0
with expected_exception(ZeroDivisionError):
1.0 % 0
with expected_exception(AttributeError):
(1).a
f9()
def f10():
print "f10"
try:
raise ZeroDivisionError()
except:
with expected_exception(ZeroDivisionError):
raise
f10()
def f(x):
print x
try:
if x == 2:
raise AttributeError()
assert x
except AssertionError:
print "is assert"
except:
print "not an assert"
else:
print "no exception"
f(0)
f(1)
f(2)
# You can set attributes on exception objects:
e = Exception()
e.n = 1
print e.n
try:
1/0
except ZeroDivisionError, e:
print e.message
print str(e), repr(e)
print e
......@@ -158,3 +158,125 @@ def f5():
except AttributeError:
print sys.exc_info()[0].__name__
f5()
def f6():
print
print "f6"
# A finally block must somehow track how it was entered, because it's not based
# on the value of sys.exc_info at the end of the finally block:
def inner(nested_throw, reraise):
try:
pass
finally:
if nested_throw:
try:
raise AttributeError()
except:
pass
print sys.exc_info()
if reraise:
raise
inner(False, False) # no exception raised
inner(True, False) # no exception raised
try:
inner(True, True)
# Shouldn't get here
raise Exception()
except AttributeError:
print "the thrown AttributeError raised as expected"
# Have to call this, because the inner throw can reraise the out-of-except
# exception from this scope!
sys.exc_clear()
try:
inner(False, True)
# Shouldn't get here
raise Exception()
except TypeError:
print "Got TypeError as expected, since exc_info was None"
f6()
def f7():
print
print "f7"
# Similar test to f6, but this time with an exception propagating
# up through a finally block.
# An exception thrown inside that finally shouldn't change the exception
# that will end up getting propagated
def inner():
try:
raise AttributeError()
finally:
try:
raise NotImplementedError()
except:
pass
print sys.exc_info()[0].__name__
try:
inner()
except:
print sys.exc_info()[0].__name__
f7()
def f8():
print
print "f8"
try:
raise AttributeError()
except:
pass
def reraise():
raise
try:
reraise()
raise Exception()
except AttributeError:
print "reraised correctly"
f8()
def f9():
print
print "f9"
# Exceptions thrown inside a catch block should still go through the finally,
# but not other catch blocks.
try:
try:
raise Exception()
except Exception:
print "here"
raise AttributeError()
except AttributeError:
print "shouldn't get here"
finally:
print "in finally"
except AttributeError:
pass
f9()
def f10():
print "f10"
x = 1
try:
try:
y = 2
raise AttributeError()
x = 3
except NotImplementedError:
print "shouldn't be here"
except AttributeError:
print x, y
print "here"
f10()
# expected: fail
# - inheritance
class BadException(Exception):
def __str__(self):
print "str"
raise NotImplementedError()
try:
# This will raise:
print BadException()
assert 0
except NotImplementedError:
pass
raise BadException()
# can't try large numbers yet due to lack of long
for i in xrange(1, 100):
for j in xrange(1, 100):
print i.__divmod__(j)
......@@ -10,6 +10,8 @@ n = 0
while n < 100000:
setattr(c, "a" + str(n), n)
n = n + 1
if n % 1000 == 0:
print n
def f(o):
print o.a1
......
......@@ -79,11 +79,20 @@ bool makeVisible(llvm::GlobalValue* gv) {
changed = true;
}
//llvm::GlobalValue::VisibilityTypes visibility = gv->getVisibility();
//if (visibility == llvm::GlobalValue::HiddenVisibility) {
//gv->setVisibility(llvm::GlobalValue::ProtectedVisibility);
//changed = true;
//}
// Hidden symbols won't end up as globals.
// Worse, a hidden symbol, when linked with a default-visibility symbol,
// will result in a non-visible symbol.
// So it's not enough to just set the visibility here; instead we have to
// set it to protected *and* change the name.
// The only thing affected by this that I know about is __clang_call_terminate.
llvm::GlobalValue::VisibilityTypes visibility = gv->getVisibility();
if (visibility == llvm::GlobalValue::HiddenVisibility) {
gv->setVisibility(llvm::GlobalValue::ProtectedVisibility);
//gv->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
gv->setName(gv->getName() + "_protected");
changed = true;
}
return changed;
}
......
......@@ -37,6 +37,12 @@ FN_JUST_SIZE = 20
EXTRA_JIT_ARGS = []
TIME_LIMIT = 2
# For fun, can test pypy.
# Tough because the tester will check to see if the error messages are exactly the
# same as the system CPython, but the error messages change over micro CPython versions.
# Pyston compile-time checks the system CPython version to try to give compatible error messages.
TEST_PYPY = 0
def set_ulimits():
# Guard the process from running too long with a hard rlimit.
# But first try to kill it after a second with a SIGALRM, though that's catchable/clearable by the program:
......@@ -77,7 +83,7 @@ def run_test(fn, check_stats, run_memcheck):
r = fn.rjust(FN_JUST_SIZE)
statchecks = []
jit_args = ["-csr"] + EXTRA_JIT_ARGS
jit_args = ["-csrq"] + EXTRA_JIT_ARGS
expected = "success"
for l in open(fn):
if not l.startswith("#"):
......@@ -93,7 +99,12 @@ def run_test(fn, check_stats, run_memcheck):
assert expected in ("success", "fail", "statfail"), expected
run_args = ["./%s" % IMAGE] + jit_args + ["-q", fn]
if TEST_PYPY:
jit_args = []
check_stats = False
expected = "success"
run_args = [os.path.abspath(IMAGE)] + jit_args + [fn]
start = time.time()
p = subprocess.Popen(run_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=open("/dev/null"), preexec_fn=set_ulimits)
out, err = p.communicate()
......@@ -104,7 +115,7 @@ def run_test(fn, check_stats, run_memcheck):
elapsed = time.time() - start
stats = {}
if code == 0:
if code == 0 and not TEST_PYPY:
assert out.count("Stats:") == 1
out, stats_str = out.split("Stats:")
for l in stats_str.strip().split('\n'):
......@@ -153,7 +164,7 @@ def run_test(fn, check_stats, run_memcheck):
diff = p.stdout.read()
assert p.wait() in (0, 1)
raise Exception("Failed on %s:\n%s" % (fn, diff))
elif err != expected_err:
elif not TEST_PYPY and err != expected_err:
if KEEP_GOING:
r += " \033[31mFAILED\033[0m (bad stderr)"
failed.append(fn)
......@@ -357,10 +368,14 @@ if __name__ == "__main__":
FN_JUST_SIZE = max(20, 2 + max(map(len, tests)))
print "Building...",
sys.stdout.flush()
subprocess.check_call(["make", "-j4", IMAGE], stdout=open("/dev/null", 'w'), stderr=subprocess.PIPE)
print "done"
if not TEST_PYPY:
print "Building...",
sys.stdout.flush()
subprocess.check_call(["make", "-j4", IMAGE], stdout=open("/dev/null", 'w'), stderr=subprocess.PIPE)
print "done"
if TEST_PYPY:
IMAGE = '/usr/local/bin/pypy'
if not patterns:
tests.sort(key=fileSize)
......
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