Commit 456384d8 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Templatize generator.next

In theory should help with pyxl which throws a decent number
of StopIterations from calling generator.next() directly, but
pretty few of those calls actually make it into the llvm JIT
to benefit from this.
parent 9789073f
...@@ -117,19 +117,33 @@ Box* generatorIter(Box* s) { ...@@ -117,19 +117,33 @@ Box* generatorIter(Box* s) {
} }
// called from both generatorHasNext and generatorSend/generatorNext (but only if generatorHasNext hasn't been called) // called from both generatorHasNext and generatorSend/generatorNext (but only if generatorHasNext hasn't been called)
static void generatorSendInternal(BoxedGenerator* self, Box* v) { template <ExceptionStyle S> static bool generatorSendInternal(BoxedGenerator* self, Box* v) noexcept(S == CAPI) {
STAT_TIMER(t0, "us_timer_generator_switching", 0); STAT_TIMER(t0, "us_timer_generator_switching", 0);
if (!self->returnContext && v != None) if (!self->returnContext && v != None) {
raiseExcHelper(TypeError, "can't send non-None value to a just-started generator"); if (S == CAPI) {
PyErr_SetString(TypeError, "can't send non-None value to a just-started generator");
return true;
} else
raiseExcHelper(TypeError, "can't send non-None value to a just-started generator");
}
if (self->running) if (self->running) {
raiseExcHelper(ValueError, "generator already executing"); if (S == CAPI) {
PyErr_SetString(ValueError, "generator already executing");
return true;
} else
raiseExcHelper(ValueError, "generator already executing");
}
// check if the generator already exited // check if the generator already exited
if (self->entryExited) { if (self->entryExited) {
freeGeneratorStack(self); freeGeneratorStack(self);
raiseExcHelper(StopIteration, (const char*)nullptr); if (S == CAPI) {
PyErr_SetObject(StopIteration, None);
return true;
} else
raiseExcHelper(StopIteration, (const char*)nullptr);
} }
self->returnValue = v; self->returnValue = v;
...@@ -158,9 +172,14 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) { ...@@ -158,9 +172,14 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) {
if (self->exception.type) { if (self->exception.type) {
freeGeneratorStack(self); freeGeneratorStack(self);
// don't raise StopIteration exceptions because those are handled specially. // don't raise StopIteration exceptions because those are handled specially.
if (!self->exception.matches(StopIteration)) if (!self->exception.matches(StopIteration)) {
throw self->exception; if (S == CAPI) {
return; setCAPIException(self->exception);
return true;
} else
throw self->exception;
}
return false;
} }
if (self->entryExited) { if (self->entryExited) {
...@@ -169,18 +188,21 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) { ...@@ -169,18 +188,21 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) {
// We could directly create the StopIteration exception but we delay creating it because often the caller is not // We could directly create the StopIteration exception but we delay creating it because often the caller is not
// interested in the exception (=generatorHasnext). If we really need it we will create it inside generatorSend. // interested in the exception (=generatorHasnext). If we really need it we will create it inside generatorSend.
self->exception = ExcInfo(NULL, NULL, NULL); self->exception = ExcInfo(NULL, NULL, NULL);
return; return false;
} }
return false;
} }
Box* generatorSend(Box* s, Box* v) { template <ExceptionStyle S> static Box* generatorSend(Box* s, Box* v) 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);
if (self->iterated_from__hasnext__) if (self->iterated_from__hasnext__)
Py_FatalError(".throw called on generator last advanced with __hasnext__"); Py_FatalError(".throw called on generator last advanced with __hasnext__");
generatorSendInternal(self, v); bool exc = generatorSendInternal<S>(self, v);
if (S == CAPI && exc)
return NULL;
// throw StopIteration if the generator exited // throw StopIteration if the generator exited
if (self->entryExited) { if (self->entryExited) {
...@@ -195,9 +217,19 @@ Box* generatorSend(Box* s, Box* v) { ...@@ -195,9 +217,19 @@ Box* generatorSend(Box* s, Box* v) {
ExcInfo old_exc = self->exception; ExcInfo old_exc = self->exception;
// Clear the exception for GC purposes: // Clear the exception for GC purposes:
self->exception = ExcInfo(nullptr, nullptr, nullptr); self->exception = ExcInfo(nullptr, nullptr, nullptr);
if (old_exc.type == NULL) if (old_exc.type == NULL) {
raiseExcHelper(StopIteration, (const char*)nullptr); if (S == CAPI) {
throw old_exc; PyErr_SetObject(StopIteration, None);
return NULL;
} else
raiseExcHelper(StopIteration, (const char*)nullptr);
} else {
if (S == CAPI) {
setCAPIException(old_exc);
return NULL;
} else
throw old_exc;
}
} }
return self->returnValue; return self->returnValue;
...@@ -223,7 +255,7 @@ Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** a ...@@ -223,7 +255,7 @@ Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** a
throw exc_info; throw exc_info;
self->exception = exc_info; self->exception = exc_info;
return generatorSend(self, None); return generatorSend<CXX>(self, None);
} }
Box* generatorClose(Box* s) { Box* generatorClose(Box* s) {
...@@ -245,7 +277,7 @@ Box* generatorClose(Box* s) { ...@@ -245,7 +277,7 @@ Box* generatorClose(Box* s) {
assert(0); // unreachable assert(0); // unreachable
} }
Box* generatorNext(Box* s) { template <ExceptionStyle S> static Box* generatorNext(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);
...@@ -254,7 +286,7 @@ Box* generatorNext(Box* s) { ...@@ -254,7 +286,7 @@ Box* generatorNext(Box* s) {
return self->returnValue; return self->returnValue;
} }
return generatorSend(s, None); return generatorSend<S>(s, None);
} }
i1 generatorHasnextUnboxed(Box* s) { i1 generatorHasnextUnboxed(Box* s) {
...@@ -262,7 +294,7 @@ i1 generatorHasnextUnboxed(Box* s) { ...@@ -262,7 +294,7 @@ i1 generatorHasnextUnboxed(Box* s) {
BoxedGenerator* self = static_cast<BoxedGenerator*>(s); BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
if (!self->iterated_from__hasnext__) { if (!self->iterated_from__hasnext__) {
generatorSendInternal(self, None); generatorSendInternal<CXX>(self, None);
self->iterated_from__hasnext__ = true; self->iterated_from__hasnext__ = true;
} }
...@@ -455,13 +487,16 @@ void setupGenerator() { ...@@ -455,13 +487,16 @@ void setupGenerator() {
new BoxedFunction(boxRTFunction((void*)generatorIter, typeFromClass(generator_cls), 1))); new BoxedFunction(boxRTFunction((void*)generatorIter, typeFromClass(generator_cls), 1)));
generator_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)generatorClose, UNKNOWN, 1))); generator_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)generatorClose, UNKNOWN, 1)));
generator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)generatorNext, UNKNOWN, 1)));
auto generator_next = boxRTFunction((void*)generatorNext<CXX>, UNKNOWN, 1, ParamNames::empty(), CXX);
addRTFunction(generator_next, (void*)generatorNext<CAPI>, UNKNOWN, CAPI);
generator_cls->giveAttr("next", new BoxedFunction(generator_next));
CLFunction* hasnext = boxRTFunction((void*)generatorHasnextUnboxed, BOOL, 1); CLFunction* hasnext = boxRTFunction((void*)generatorHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)generatorHasnext, BOXED_BOOL); addRTFunction(hasnext, (void*)generatorHasnext, BOXED_BOOL);
generator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext)); generator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext));
generator_cls->giveAttr("send", new BoxedFunction(boxRTFunction((void*)generatorSend, UNKNOWN, 2))); generator_cls->giveAttr("send", new BoxedFunction(boxRTFunction((void*)generatorSend<CXX>, UNKNOWN, 2)));
auto gthrow = new BoxedFunction(boxRTFunction((void*)generatorThrow, UNKNOWN, 4, 2, false, false), { NULL, NULL }); auto gthrow = new BoxedFunction(boxRTFunction((void*)generatorThrow, UNKNOWN, 4, 2, false, false), { NULL, NULL });
generator_cls->giveAttr("throw", gthrow); generator_cls->giveAttr("throw", gthrow);
......
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