[unladen-swallow] r1166 committed - Change the WITH_CLEANUP opcode to have a deterministic effect on the s...

4 views
Skip to first unread message

unladen...@googlecode.com

unread,
Jul 30, 2010, 2:34:39 AM7/30/10
to unladen...@googlegroups.com
Revision: 1166
Author: e...@4geeks.de
Date: Thu Jul 29 23:33:28 2010
Log: Change the WITH_CLEANUP opcode to have a deterministic effect on the
stack.


http://code.google.com/p/unladen-swallow/source/detail?r=1166

Modified:
/trunk/JIT/llvm_fbuilder.cc
/trunk/JIT/opcodes/block.cc
/trunk/Lib/compiler/pycodegen.py
/trunk/Python/compile.c
/trunk/Python/eval.cc
/trunk/Python/import.c

=======================================
--- /trunk/JIT/llvm_fbuilder.cc Wed Jul 28 23:50:04 2010
+++ /trunk/JIT/llvm_fbuilder.cc Thu Jul 29 23:33:28 2010
@@ -517,17 +517,30 @@
// Jump to the finally block, with the stack prepared for
// END_FINALLY to continue unwinding.

+ BasicBlock *push_pseudo_exception =
+ this->state()->CreateBasicBlock("push_pseudo_exception");
BasicBlock *push_retval =
this->state()->CreateBasicBlock("push_retval");
+ BasicBlock *push_no_retval =
+ this->state()->CreateBasicBlock("push_no_retval");
BasicBlock *handle_finally_end =
this->state()->CreateBasicBlock("handle_finally_end");
- llvm::SwitchInst *should_push_retval = this->builder_.CreateSwitch(
- unwind_reason, handle_finally_end, 2);
// When unwinding for an exception, we have to save the
// exception onto the stack.
- should_push_retval->addCase(
- ConstantInt::get(Type::getInt8Ty(this->context_),
UNWIND_EXCEPTION),
- push_exception);
+ Value *unwinding_exception2 = this->builder_.CreateICmpEQ(
+ unwind_reason,
ConstantInt::get(Type::getInt8Ty(this->context_),
+ UNWIND_EXCEPTION),
+ "currently_unwinding_exception");
+ this->builder_.CreateCondBr(unwinding_exception2,
+ push_exception, push_pseudo_exception);
+
+ this->builder_.SetInsertPoint(push_pseudo_exception);
+ Value *none = this->state()->GetGlobalVariableFor(&_Py_NoneStruct);
+ this->state()->IncRef(none);
+ this->Push(none);
+
+ llvm::SwitchInst *should_push_retval = this->builder_.CreateSwitch(
+ unwind_reason, push_no_retval, 2);
// When unwinding for a return or continue, we have to save
// the return value or continue target onto the stack.
should_push_retval->addCase(
@@ -539,6 +552,11 @@

this->builder_.SetInsertPoint(push_retval);

this->Push(this->builder_.CreateLoad(this->retval_addr_, "retval"));
+ this->builder_.CreateBr(handle_finally_end);
+
+ this->builder_.SetInsertPoint(push_no_retval);
+ this->state()->IncRef(none);
+ this->Push(none);

this->FallThroughTo(handle_finally_end);
// END_FINALLY expects to find the unwind reason on the top of
=======================================
--- /trunk/JIT/opcodes/block.cc Wed Jul 28 23:50:04 2010
+++ /trunk/JIT/opcodes/block.cc Thu Jul 29 23:33:28 2010
@@ -93,6 +93,8 @@
OpcodeBlock::END_FINALLY()
{
Value *finally_discriminator = this->fbuilder_->Pop();
+ Value *second = this->fbuilder_->Pop();
+ Value *third = this->fbuilder_->Pop();
// END_FINALLY is fairly complicated. It decides what to do based
// on the top value in the stack. If that value is an int, it's
// interpreted as one of the unwind reasons. If it's an exception
@@ -129,29 +131,33 @@
Type::getInt8Ty(this->fbuilder_->context()),
"unwind_reason");
this->state_->DecRef(finally_discriminator);
+ this->state_->DecRef(third);
// Save the unwind reason for when we jump to the unwind block.
this->builder_.CreateStore(unwind_reason,
this->fbuilder_->unwind_reason_addr());
// Check if we need to pop the return value or loop target.
- BasicBlock *pop_retval = this->state_->CreateBasicBlock("pop_retval");
- llvm::SwitchInst *should_pop_retval =
- this->builder_.CreateSwitch(unwind_reason,
- this->fbuilder_->unwind_block(), 2);
- should_pop_retval->addCase(
+ BasicBlock *store_retval =
this->state_->CreateBasicBlock("store_retval");
+ BasicBlock *decref_second =
this->state_->CreateBasicBlock("decref_second");
+ llvm::SwitchInst *should_store_retval =
+ this->builder_.CreateSwitch(unwind_reason, decref_second, 2);
+ should_store_retval->addCase(
ConstantInt::get(Type::getInt8Ty(this->fbuilder_->context()),
UNWIND_RETURN),
- pop_retval);
- should_pop_retval->addCase(
+ store_retval);
+ should_store_retval->addCase(
ConstantInt::get(Type::getInt8Ty(this->fbuilder_->context()),
UNWIND_CONTINUE),
- pop_retval);
-
- this->builder_.SetInsertPoint(pop_retval);
+ store_retval);
+
+ this->builder_.SetInsertPoint(store_retval);
// We're continuing a return or continue. Retrieve its argument.
- this->builder_.CreateStore(this->fbuilder_->Pop(),
- this->fbuilder_->retval_addr());
+ this->builder_.CreateStore(second, this->fbuilder_->retval_addr());
this->builder_.CreateBr(this->fbuilder_->unwind_block());

+ this->builder_.SetInsertPoint(decref_second);
+ this->state_->DecRef(second);
+ this->builder_.CreateBr(this->fbuilder_->unwind_block());
+
this->builder_.SetInsertPoint(test_exception);
Value *is_exception_or_string = this->state_->CreateCall(
this->state_->GetGlobalFunction<int(PyObject *)>(
@@ -163,8 +169,8 @@

this->builder_.SetInsertPoint(reraise_exception);
Value *err_type = finally_discriminator;
- Value *err_value = this->fbuilder_->Pop();
- Value *err_traceback = this->fbuilder_->Pop();
+ Value *err_value = second;
+ Value *err_traceback = third;
this->state_->CreateCall(
this->state_->GetGlobalFunction<
void(PyObject *, PyObject *, PyObject *)>("PyErr_Restore"),
@@ -188,6 +194,8 @@
finally_discriminator,
this->state_->GetGlobalVariableFor(&_Py_NoneStruct));
this->state_->DecRef(finally_discriminator);
+ this->state_->DecRef(second);
+ this->state_->DecRef(third);
this->builder_.CreateCondBr(is_none, finally_fallthrough, not_none);

this->builder_.SetInsertPoint(not_none);
@@ -217,11 +225,11 @@
void
OpcodeBlock::WITH_CLEANUP()
{
- /* At the top of the stack are 1-3 values indicating
+ /* At the top of the stack are 3 values indicating
how/why we entered the finally clause:
- - TOP = None
- - (TOP, SECOND) = (WHY_{RETURN,CONTINUE}), retval
- - TOP = WHY_*; no retval below it
+ - (TOP, SECOND, THIRD) = None, None, None
+ - (TOP, SECOND, THIRD) = (UNWIND_{RETURN,CONTINUE}), retval, None
+ - (TOP, SECOND, THIRD) = UNWIND_*, None, None
- (TOP, SECOND, THIRD) = exc_info()
Below them is EXIT, the context.__exit__ bound method.
In the last case, we must call
@@ -252,98 +260,35 @@
PyTypeBuilder<PyObject*>::get(this->fbuilder_->context()),
NULL, "WITH_CLEANUP_exit_func");

- BasicBlock *handle_none =
- this->state_->CreateBasicBlock("WITH_CLEANUP_handle_none");
- BasicBlock *check_int =
- this->state_->CreateBasicBlock("WITH_CLEANUP_check_int");
BasicBlock *handle_int =
this->state_->CreateBasicBlock("WITH_CLEANUP_handle_int");
- BasicBlock *handle_ret_cont =
- this->state_->CreateBasicBlock("WITH_CLEANUP_handle_ret_cont");
- BasicBlock *handle_default =
- this->state_->CreateBasicBlock("WITH_CLEANUP_handle_default");
- BasicBlock *handle_else =
- this->state_->CreateBasicBlock("WITH_CLEANUP_handle_else");
BasicBlock *main_block =
this->state_->CreateBasicBlock("WITH_CLEANUP_main_block");

Value *none = this->state_->GetGlobalVariableFor(&_Py_NoneStruct);
- this->builder_.CreateStore(this->fbuilder_->Pop(), exc_type);
-
- Value *is_none = this->builder_.CreateICmpEQ(
- this->builder_.CreateLoad(exc_type), none,
- "reason_is_none");
- this->builder_.CreateCondBr(is_none, handle_none, check_int);
-
- this->builder_.SetInsertPoint(handle_none);
+
+ this->builder_.CreateStore(this->fbuilder_->Pop(), exc_type);
+ this->builder_.CreateStore(this->fbuilder_->Pop(), exc_value);
+ this->builder_.CreateStore(this->fbuilder_->Pop(), exc_traceback);
this->builder_.CreateStore(this->fbuilder_->Pop(), exit_func);
+ this->fbuilder_->Push(this->builder_.CreateLoad(exc_traceback));
+ this->fbuilder_->Push(this->builder_.CreateLoad(exc_value));
this->fbuilder_->Push(this->builder_.CreateLoad(exc_type));
- this->builder_.CreateStore(none, exc_value);
- this->builder_.CreateStore(none, exc_traceback);
- this->builder_.CreateBr(main_block);
-
- this->builder_.SetInsertPoint(check_int);
+
Value *is_int = this->state_->CreateCall(
- this->state_->GetGlobalFunction<int(PyObject *)>(
- "_PyLlvm_WrapIntCheck"),
+ this->state_->
+ GetGlobalFunction<int(PyObject *)>("_PyLlvm_WrapIntCheck"),
this->builder_.CreateLoad(exc_type),
"WITH_CLEANUP_pyint_check");
this->builder_.CreateCondBr(this->state_->IsNonZero(is_int),
- handle_int, handle_else);
+ handle_int, main_block);

this->builder_.SetInsertPoint(handle_int);
- Value *unboxed = this->builder_.CreateTrunc(
- this->state_->CreateCall(
- this->state_->GetGlobalFunction<long(PyObject
*)>("PyInt_AsLong"),
- this->builder_.CreateLoad(exc_type)),
- Type::getInt8Ty(this->fbuilder_->context()),
- "unboxed_unwind_reason");
- // The LLVM equivalent of
- // switch (reason)
- // case UNWIND_RETURN:
- // case UNWIND_CONTINUE:
- // ...
- // break;
- // default:
- // break;
- llvm::SwitchInst *unwind_kind =
- this->builder_.CreateSwitch(unboxed, handle_default, 2);
- unwind_kind->addCase(
- ConstantInt::get(Type::getInt8Ty(this->fbuilder_->context()),
- UNWIND_RETURN), handle_ret_cont);
- unwind_kind->addCase(
- ConstantInt::get(Type::getInt8Ty(this->fbuilder_->context()),
- UNWIND_CONTINUE), handle_ret_cont);
-
- this->builder_.SetInsertPoint(handle_ret_cont);
- Value *retval = this->fbuilder_->Pop();
- this->builder_.CreateStore(this->fbuilder_->Pop(), exit_func);
- this->fbuilder_->Push(retval);
- this->fbuilder_->Push(this->builder_.CreateLoad(exc_type));
this->builder_.CreateStore(none, exc_type);
this->builder_.CreateStore(none, exc_value);
this->builder_.CreateStore(none, exc_traceback);
- this->builder_.CreateBr(main_block);
-
- this->builder_.SetInsertPoint(handle_default);
- this->builder_.CreateStore(this->fbuilder_->Pop(), exit_func);
- this->fbuilder_->Push(this->builder_.CreateLoad(exc_type));
- this->builder_.CreateStore(none, exc_type);
- this->builder_.CreateStore(none, exc_value);
- this->builder_.CreateStore(none, exc_traceback);
- this->builder_.CreateBr(main_block);
-
- // This is the (TOP, SECOND, THIRD) = exc_info() case above.
- this->builder_.SetInsertPoint(handle_else);
- this->builder_.CreateStore(this->fbuilder_->Pop(), exc_value);
- this->builder_.CreateStore(this->fbuilder_->Pop(), exc_traceback);
- this->builder_.CreateStore(this->fbuilder_->Pop(), exit_func);
- this->fbuilder_->Push(this->builder_.CreateLoad(exc_traceback));
- this->fbuilder_->Push(this->builder_.CreateLoad(exc_value));
- this->fbuilder_->Push(this->builder_.CreateLoad(exc_type));
- this->builder_.CreateBr(main_block);
-
- this->builder_.SetInsertPoint(main_block);
+
+ this->fbuilder_->FallThroughTo(main_block);
// Build a vector because there is no CreateCall5().
// This is easier than building the tuple ourselves, but doing so would
// probably be faster.
@@ -389,6 +334,10 @@
this->fbuilder_->Pop();
this->fbuilder_->Pop();
this->fbuilder_->Pop();
+ this->state_->IncRef(none);
+ this->fbuilder_->Push(none);
+ this->state_->IncRef(none);
+ this->fbuilder_->Push(none);
this->state_->IncRef(none);
this->fbuilder_->Push(none);
this->state_->DecRef(this->builder_.CreateLoad(exc_type));
=======================================
--- /trunk/Lib/compiler/pycodegen.py Fri Nov 13 17:46:58 2009
+++ /trunk/Lib/compiler/pycodegen.py Thu Jul 29 23:33:28 2010
@@ -787,6 +787,8 @@
self.emit('POP_BLOCK')
self.setups.pop()
self.emit('LOAD_CONST', None)
+ self.emit('DUP_TOP')
+ self.emit('DUP_TOP')
self.nextBlock(final)
self.setups.push((END_FINALLY, final))
self.visit(node.final)
@@ -822,6 +824,8 @@
self.emit('POP_BLOCK')
self.setups.pop()
self.emit('LOAD_CONST', None)
+ self.emit('DUP_TOP')
+ self.emit('DUP_TOP')
self.nextBlock(final)
self.setups.push((END_FINALLY, final))
self.emit('WITH_CLEANUP')
=======================================
--- /trunk/Python/compile.c Mon Jan 25 16:39:14 2010
+++ /trunk/Python/compile.c Thu Jul 29 23:33:28 2010
@@ -773,7 +773,7 @@
case BREAK_LOOP:
return 0;
case WITH_CLEANUP:
- return -1; /* XXX Sometimes more */
+ return -1;
case RETURN_VALUE:
return -1;
case YIELD_VALUE:
@@ -782,7 +782,7 @@
case POP_BLOCK:
return 0;
case END_FINALLY:
- return -1; /* or -2 or -3 if exception occurred */
+ return -3;

case STORE_NAME:
return -1;
@@ -1862,6 +1862,8 @@
compiler_pop_fblock(c, FINALLY_TRY, body, end);

ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ ADDOP(c, DUP_TOP);
+ ADDOP(c, DUP_TOP);
compiler_use_next_block(c, end);
if (!compiler_push_fblock(c, FINALLY_END, end, NULL))
return 0;
@@ -3023,6 +3025,8 @@
compiler_pop_fblock(c, FINALLY_TRY, block, finally);

ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ ADDOP(c, DUP_TOP);
+ ADDOP(c, DUP_TOP);
compiler_use_next_block(c, finally);
if (!compiler_push_fblock(c, FINALLY_END, finally, NULL))
return 0;
=======================================
--- /trunk/Python/eval.cc Thu Apr 1 17:29:10 2010
+++ /trunk/Python/eval.cc Thu Jul 29 23:33:28 2010
@@ -2173,17 +2173,19 @@
PREDICTED(END_FINALLY);
TARGET(END_FINALLY)
v = POP();
+ w = POP();
+ u = POP();
if (PyInt_Check(v)) {
why = (enum _PyUnwindReason) PyInt_AS_LONG(v);
assert(why != UNWIND_YIELD);
if (why == UNWIND_RETURN ||
why == UNWIND_CONTINUE)
- retval = POP();
+ retval = w;
+ else
+ Py_DECREF(w);
}
else if (PyExceptionClass_Check(v) ||
PyString_Check(v)) {
- w = POP();
- u = POP();
PyErr_Restore(v, w, u);
why = UNWIND_RERAISE;
break;
@@ -2192,8 +2194,10 @@
PyErr_SetString(PyExc_SystemError,
"'finally' pops bad exception");
why = UNWIND_EXCEPTION;
+ Py_DECREF(w);
}
Py_DECREF(v);
+ Py_DECREF(u);
break;

TARGET(STORE_NAME)
@@ -2726,11 +2730,12 @@

TARGET(WITH_CLEANUP)
{
- /* At the top of the stack are 1-3 values indicating
+ /* At the top of the stack are 3 values indicating
how/why we entered the finally clause:
- - TOP = None
- - (TOP, SECOND) = (UNWIND_{RETURN,CONTINUE}), retval
- - TOP = UNWIND_*; no retval below it
+ - (TOP, SECOND, THIRD) = None, None, None
+ - (TOP, SECOND, THIRD) = (UNWIND_{RETURN,CONTINUE}),
+ retval, None
+ - (TOP, SECOND, THIRD) = UNWIND_*, None, None
- (TOP, SECOND, THIRD) = exc_info()
Below them is EXIT, the context.__exit__ bound method.
In the last case, we must call
@@ -2751,35 +2756,14 @@
PyObject *exit_func;

u = POP();
- if (u == Py_None) {
- exit_func = TOP();
- SET_TOP(u);
- v = w = Py_None;
- }
- else if (PyInt_Check(u)) {
- switch(PyInt_AS_LONG(u)) {
- case UNWIND_RETURN:
- case UNWIND_CONTINUE:
- /* Retval in TOP. */
- exit_func = SECOND();
- SET_SECOND(TOP());
- SET_TOP(u);
- break;
- default:
- exit_func = TOP();
- SET_TOP(u);
- break;
- }
+ v = TOP();
+ w = SECOND();
+ exit_func = THIRD();
+ SET_TOP(u);
+ SET_SECOND(v);
+ SET_THIRD(w);
+ if (PyInt_Check(u))
u = v = w = Py_None;
- }
- else {
- v = TOP();
- w = SECOND();
- exit_func = THIRD();
- SET_TOP(u);
- SET_SECOND(v);
- SET_THIRD(w);
- }
/* XXX Not the fastest way to call it... */
x = PyObject_CallFunctionObjArgs(exit_func, u, v, w,
NULL);
@@ -2801,9 +2785,12 @@
}
else if (err > 0) {
/* There was an exception and a true return */
- STACKADJ(-2);
Py_INCREF(Py_None);
SET_TOP(Py_None);
+ Py_INCREF(Py_None);
+ SET_SECOND(Py_None);
+ Py_INCREF(Py_None);
+ SET_THIRD(Py_None);
Py_DECREF(u);
Py_DECREF(v);
Py_DECREF(w);
@@ -3129,8 +3116,16 @@
PyErr_Clear();
}
else {
+ Py_INCREF(Py_None);
+ PUSH(Py_None);
if (why & (UNWIND_RETURN | UNWIND_CONTINUE))
+ {
PUSH(retval);
+ }
+ else {
+ Py_INCREF(Py_None);
+ PUSH(Py_None);
+ }
v = PyInt_FromLong((long)why);
PUSH(v);
}
=======================================
--- /trunk/Python/import.c Tue Jan 12 14:13:47 2010
+++ /trunk/Python/import.c Thu Jul 29 23:33:28 2010
@@ -82,9 +82,10 @@
Unladen Swallow 2009Q2: 62211 (undo vmgen-based opcodes)
Unladen Swallow 2009Q3: 62221 (add CO_USES_EXEC flag)
Unladen Swallow 2009Q4: 62231 (add IMPORT_NAME opcode back)
+ Unladen Swallow 2009Q4: 62241 (END_FINALLY always pops 3 values)
.
*/
-#define MAGIC (62231 | ((long)'\r'<<16) | ((long)'\n'<<24))
+#define MAGIC (62241 | ((long)'\r'<<16) | ((long)'\n'<<24))

/* Magic word as global; note that _PyImport_Init() can change the
value of this global to accommodate for alterations of how the

Reply all
Reply to author
Forward
0 new messages