Commit d9b5310f authored by Marius Wachtler's avatar Marius Wachtler

generator: reduce number of c++ exceptions

Adds a few C API paths plus sets tp_iternext and tpp_hasnext
parent 40fa7ef7
...@@ -84,7 +84,7 @@ Context* getReturnContextForGeneratorFrame(void* frame_addr) { ...@@ -84,7 +84,7 @@ Context* getReturnContextForGeneratorFrame(void* frame_addr) {
return generator->returnContext; return generator->returnContext;
} }
void generatorEntry(BoxedGenerator* g) { void generatorEntry(BoxedGenerator* g) noexcept {
{ {
assert(g->cls == generator_cls); assert(g->cls == generator_cls);
assert(g->function->cls == function_cls); assert(g->function->cls == function_cls);
...@@ -92,7 +92,7 @@ void generatorEntry(BoxedGenerator* g) { ...@@ -92,7 +92,7 @@ void generatorEntry(BoxedGenerator* g) {
assert(g->returnValue == Py_None); assert(g->returnValue == Py_None);
Py_CLEAR(g->returnValue); Py_CLEAR(g->returnValue);
try { {
RegisterHelper context_registerer(g, __builtin_frame_address(0)); RegisterHelper context_registerer(g, __builtin_frame_address(0));
g->top_caller_frame_info = (FrameInfo*)cur_thread_state.frame_info; g->top_caller_frame_info = (FrameInfo*)cur_thread_state.frame_info;
...@@ -103,13 +103,16 @@ void generatorEntry(BoxedGenerator* g) { ...@@ -103,13 +103,16 @@ void generatorEntry(BoxedGenerator* g) {
// KEEP_ALIVE(func); // KEEP_ALIVE(func);
Box** args = g->args ? &g->args->elts[0] : nullptr; Box** args = g->args ? &g->args->elts[0] : nullptr;
auto r = callCLFunc<ExceptionStyle::CXX, NOT_REWRITABLE>(func->md, nullptr, func->md->numReceivedArgs(), auto r = callCLFunc<ExceptionStyle::CAPI, NOT_REWRITABLE>(func->md, nullptr, func->md->numReceivedArgs(),
func->closure, g, func->globals, g->arg1, g->arg2, func->closure, g, func->globals, g->arg1, g->arg2,
g->arg3, args); g->arg3, args);
Py_DECREF(r); if (r)
} catch (ExcInfo e) { Py_DECREF(r);
// unhandled exception: propagate the exception to the caller else {
g->exception = e; // unhandled exception: propagate the exception to the caller
PyErr_Fetch(&g->exception.type, &g->exception.value, &g->exception.traceback);
PyErr_Clear();
}
} }
// we returned from the body of the generator. next/send/throw will notify the caller // we returned from the body of the generator. next/send/throw will notify the caller
...@@ -254,7 +257,8 @@ template <ExceptionStyle S> static Box* generatorSend(Box* s, Box* v) noexcept(S ...@@ -254,7 +257,8 @@ template <ExceptionStyle S> static Box* generatorSend(Box* s, Box* v) noexcept(S
return rtn; return rtn;
} }
Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** args = nullptr) { template <ExceptionStyle S>
Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** args = nullptr) noexcept(S == CAPI) {
assert(s->cls == generator_cls); assert(s->cls == generator_cls);
BoxedGenerator* self = static_cast<BoxedGenerator*>(s); BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
...@@ -262,22 +266,32 @@ Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** a ...@@ -262,22 +266,32 @@ Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** a
Py_FatalError(".throw called on generator last advanced with __hasnext__"); Py_FatalError(".throw called on generator last advanced with __hasnext__");
Box* exc_tb = args ? args[0] : nullptr; Box* exc_tb = args ? args[0] : nullptr;
if (exc_tb && exc_tb != Py_None && !PyTraceBack_Check(exc_tb)) if (exc_tb && exc_tb != Py_None && !PyTraceBack_Check(exc_tb)) {
if (S == CAPI) {
PyErr_SetString(TypeError, "throw() third argument must be a traceback object");
return NULL;
}
raiseExcHelper(TypeError, "throw() third argument must be a traceback object"); raiseExcHelper(TypeError, "throw() third argument must be a traceback object");
}
if (!exc_val) if (!exc_val)
exc_val = Py_None; exc_val = Py_None;
if (!exc_tb) if (!exc_tb)
exc_tb = Py_None; exc_tb = Py_None;
ExcInfo exc_info = excInfoForRaise(incref(exc_cls), incref(exc_val), incref(exc_tb)); ExcInfo exc_info = excInfoForRaise(incref(exc_cls), incref(exc_val), incref(exc_tb));
if (self->entryExited) if (self->entryExited) {
if (S == CAPI) {
setCAPIException(exc_info);
return NULL;
}
throw exc_info; throw exc_info;
}
self->exception = exc_info; self->exception = exc_info;
return generatorSend<CXX>(self, Py_None); return generatorSend<S>(self, Py_None);
} }
Box* generatorClose(Box* s) { template <ExceptionStyle S> Box* generatorClose(Box* s) noexcept(S == CAPI) {
assert(s->cls == generator_cls); assert(s->cls == generator_cls);
BoxedGenerator* self = static_cast<BoxedGenerator*>(s); BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
...@@ -285,15 +299,28 @@ Box* generatorClose(Box* s) { ...@@ -285,15 +299,28 @@ Box* generatorClose(Box* s) {
if (self->entryExited) if (self->entryExited)
return incref(Py_None); return incref(Py_None);
try { if (S == CAPI) {
autoDecref(generatorThrow(self, GeneratorExit, nullptr, nullptr)); Box* rtn = generatorThrow<S>(self, GeneratorExit, nullptr, nullptr);
raiseExcHelper(RuntimeError, "generator ignored GeneratorExit"); if (rtn) {
} catch (ExcInfo e) { PyErr_SetString(RuntimeError, "generator ignored GeneratorExit");
if (e.matches(StopIteration) || e.matches(GeneratorExit)) { return NULL;
e.clear(); }
if (PyErr_ExceptionMatches(PyExc_StopIteration) || PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
PyErr_Clear();
return incref(Py_None); return incref(Py_None);
} }
throw e; return NULL;
} else {
try {
autoDecref(generatorThrow<S>(self, GeneratorExit, nullptr, nullptr));
raiseExcHelper(RuntimeError, "generator ignored GeneratorExit");
} catch (ExcInfo e) {
if (e.matches(StopIteration) || e.matches(GeneratorExit)) {
e.clear();
return incref(Py_None);
}
throw e;
}
} }
assert(0); // unreachable assert(0); // unreachable
} }
...@@ -329,24 +356,9 @@ Box* generatorHasnext(Box* s) { ...@@ -329,24 +356,9 @@ Box* generatorHasnext(Box* s) {
return boxBool(generatorHasnextUnboxed(s)); return boxBool(generatorHasnextUnboxed(s));
} }
extern "C" Box* yield_capi(BoxedGenerator* obj, STOLEN(Box*) value, int num_live_values, ...) noexcept { template <ExceptionStyle S>
try { static Box* yieldInternal(BoxedGenerator* obj, STOLEN(Box*) value,
Box** live_values = (Box**)alloca(sizeof(Box*) * num_live_values); llvm::ArrayRef<Box*> live_values) noexcept(S == CAPI) {
va_list ap;
va_start(ap, num_live_values);
for (int i = 0; i < num_live_values; ++i) {
live_values[i] = va_arg(ap, Box*);
}
va_end(ap);
return yield(obj, value, llvm::makeArrayRef(live_values, num_live_values));
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
extern "C" Box* yield(BoxedGenerator* obj, STOLEN(Box*) value, llvm::ArrayRef<Box*> live_values) {
STAT_TIMER(t0, "us_timer_generator_switching", 0); STAT_TIMER(t0, "us_timer_generator_switching", 0);
assert(obj->cls == generator_cls); assert(obj->cls == generator_cls);
...@@ -384,6 +396,10 @@ extern "C" Box* yield(BoxedGenerator* obj, STOLEN(Box*) value, llvm::ArrayRef<Bo ...@@ -384,6 +396,10 @@ extern "C" Box* yield(BoxedGenerator* obj, STOLEN(Box*) value, llvm::ArrayRef<Bo
ExcInfo e = self->exception; ExcInfo e = self->exception;
self->exception = ExcInfo(NULL, NULL, NULL); self->exception = ExcInfo(NULL, NULL, NULL);
Py_CLEAR(self->returnValue); Py_CLEAR(self->returnValue);
if (S == CAPI) {
setCAPIException(e);
return NULL;
}
throw e; throw e;
} }
...@@ -392,6 +408,22 @@ extern "C" Box* yield(BoxedGenerator* obj, STOLEN(Box*) value, llvm::ArrayRef<Bo ...@@ -392,6 +408,22 @@ extern "C" Box* yield(BoxedGenerator* obj, STOLEN(Box*) value, llvm::ArrayRef<Bo
return r; return r;
} }
extern "C" Box* yield_capi(BoxedGenerator* obj, STOLEN(Box*) value, int num_live_values, ...) noexcept {
Box** live_values = (Box**)alloca(sizeof(Box*) * num_live_values);
va_list ap;
va_start(ap, num_live_values);
for (int i = 0; i < num_live_values; ++i) {
live_values[i] = va_arg(ap, Box*);
}
va_end(ap);
return yieldInternal<CAPI>(obj, value, llvm::makeArrayRef(live_values, num_live_values));
}
extern "C" Box* yield(BoxedGenerator* obj, STOLEN(Box*) value, llvm::ArrayRef<Box*> live_values) {
return yieldInternal<CXX>(obj, value, live_values);
}
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) {
assert(function); assert(function);
assert(function->cls == function_cls); assert(function->cls == function_cls);
...@@ -531,15 +563,6 @@ extern "C" int PyGen_NeedsFinalizing(PyGenObject* gen) noexcept { ...@@ -531,15 +563,6 @@ extern "C" int PyGen_NeedsFinalizing(PyGenObject* gen) noexcept {
#endif #endif
} }
static PyObject* generator_close(PyGenObject* gen, PyObject* args) noexcept {
try {
return generatorClose((Box*)gen);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
static void generator_del(PyObject* self) noexcept { static void generator_del(PyObject* self) noexcept {
PyObject* res; PyObject* res;
PyObject* error_type, *error_value, *error_traceback; PyObject* error_type, *error_value, *error_traceback;
...@@ -560,7 +583,7 @@ static void generator_del(PyObject* self) noexcept { ...@@ -560,7 +583,7 @@ static void generator_del(PyObject* self) noexcept {
// Pyston change: // Pyston change:
// res = gen_close(gen, NULL); // res = gen_close(gen, NULL);
res = generator_close((PyGenObject*)gen, NULL); res = generatorClose<CAPI>((Box*)gen);
if (res == NULL) if (res == NULL)
PyErr_WriteUnraisable(self); PyErr_WriteUnraisable(self);
...@@ -693,7 +716,9 @@ void setupGenerator() { ...@@ -693,7 +716,9 @@ void setupGenerator() {
generator_cls->giveAttr( generator_cls->giveAttr(
"__iter__", new BoxedFunction(FunctionMetadata::create((void*)generatorIter, typeFromClass(generator_cls), 1))); "__iter__", new BoxedFunction(FunctionMetadata::create((void*)generatorIter, typeFromClass(generator_cls), 1)));
generator_cls->giveAttr("close", new BoxedFunction(FunctionMetadata::create((void*)generatorClose, UNKNOWN, 1))); auto generator_close = FunctionMetadata::create((void*)generatorClose<CXX>, UNKNOWN, 1);
generator_close->addVersion((void*)generatorClose<CAPI>, UNKNOWN, CAPI);
generator_cls->giveAttr("close", new BoxedFunction(generator_close));
auto generator_next = FunctionMetadata::create((void*)generatorNext<CXX>, UNKNOWN, 1, ParamNames::empty(), CXX); auto generator_next = FunctionMetadata::create((void*)generatorNext<CXX>, UNKNOWN, 1, ParamNames::empty(), CXX);
generator_next->addVersion((void*)generatorNext<CAPI>, UNKNOWN, CAPI); generator_next->addVersion((void*)generatorNext<CAPI>, UNKNOWN, CAPI);
...@@ -703,15 +728,20 @@ void setupGenerator() { ...@@ -703,15 +728,20 @@ void setupGenerator() {
hasnext->addVersion((void*)generatorHasnext, BOXED_BOOL); hasnext->addVersion((void*)generatorHasnext, BOXED_BOOL);
generator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext)); generator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext));
generator_cls->giveAttr("send", new BoxedFunction(FunctionMetadata::create((void*)generatorSend<CXX>, UNKNOWN, 2))); auto generator_send = FunctionMetadata::create((void*)generatorSend<CXX>, UNKNOWN, 2);
auto gthrow generator_send->addVersion((void*)generatorSend<CAPI>, UNKNOWN, CAPI);
= new BoxedFunction(FunctionMetadata::create((void*)generatorThrow, UNKNOWN, 4, false, false), { NULL, NULL }); generator_cls->giveAttr("send", new BoxedFunction(generator_send));
generator_cls->giveAttr("throw", gthrow);
auto generator_throw = FunctionMetadata::create((void*)generatorThrow<CXX>, UNKNOWN, 4, false, false);
generator_throw->addVersion((void*)generatorThrow<CAPI>, UNKNOWN, CAPI);
generator_cls->giveAttr("throw", new BoxedFunction(generator_throw, { NULL, NULL }));
generator_cls->giveAttrDescriptor("__name__", generator_name, NULL); generator_cls->giveAttrDescriptor("__name__", generator_name, NULL);
generator_cls->freeze(); generator_cls->freeze();
generator_cls->tp_iter = PyObject_SelfIter; generator_cls->tp_iter = PyObject_SelfIter;
generator_cls->tp_del = generator_del; // don't do giveAttr("__del__") because it should not be visible from python generator_cls->tp_del = generator_del; // don't do giveAttr("__del__") because it should not be visible from python
generator_cls->tpp_hasnext = generatorHasnextUnboxed;
generator_cls->tp_iternext = generatorNext<CAPI>;
} }
} }
...@@ -26,7 +26,7 @@ struct Context; ...@@ -26,7 +26,7 @@ struct Context;
extern BoxedClass* generator_cls; extern BoxedClass* generator_cls;
void setupGenerator(); void setupGenerator();
void generatorEntry(BoxedGenerator* g); void generatorEntry(BoxedGenerator* g) noexcept;
Context* getReturnContextForGeneratorFrame(void* frame_addr); Context* getReturnContextForGeneratorFrame(void* frame_addr);
extern "C" Box* yield(BoxedGenerator* obj, STOLEN(Box*) value, llvm::ArrayRef<Box*> live_values = {}); extern "C" Box* yield(BoxedGenerator* obj, STOLEN(Box*) value, llvm::ArrayRef<Box*> live_values = {});
......
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