PageRenderTime 56ms CodeModel.GetById 20ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/JIT/opcodes/block.cc

http://unladen-swallow.googlecode.com/
C++ | 362 lines | 271 code | 37 blank | 54 comment | 0 complexity | 05a86164922dd7140712c7832b2d3834 MD5 | raw file
  1#include "Python.h"
  2#include "opcode.h"
  3
  4#include "JIT/opcodes/block.h"
  5#include "JIT/llvm_fbuilder.h"
  6
  7#include "llvm/ADT/STLExtras.h"
  8#include "llvm/BasicBlock.h"
  9#include "llvm/Function.h"
 10#include "llvm/Instructions.h"
 11
 12using llvm::BasicBlock;
 13using llvm::ConstantInt;
 14using llvm::Function;
 15using llvm::Type;
 16using llvm::Value;
 17using llvm::array_endof;
 18
 19// Use like "this->GET_GLOBAL_VARIABLE(Type, variable)".
 20#define GET_GLOBAL_VARIABLE(TYPE, VARIABLE) \
 21    GetGlobalVariable<TYPE>(&VARIABLE, #VARIABLE)
 22
 23namespace py {
 24
 25OpcodeBlock::OpcodeBlock(LlvmFunctionBuilder *fbuilder) :
 26    fbuilder_(fbuilder),
 27    state_(fbuilder->state()),
 28    builder_(fbuilder->builder()),
 29    llvm_data_(fbuilder->llvm_data())
 30{
 31}
 32
 33void
 34OpcodeBlock::SETUP_LOOP(llvm::BasicBlock *target,
 35                        int target_opindex,
 36                        llvm::BasicBlock *fallthrough)
 37{
 38    this->CallBlockSetup(::SETUP_LOOP, target, target_opindex);
 39}
 40
 41void
 42OpcodeBlock::POP_BLOCK()
 43{
 44    Value *block_info = this->state_->CreateCall(
 45        this->state_->GetGlobalFunction<PyTryBlock *(PyTryBlock *, char *)>(
 46            "_PyLlvm_Frame_BlockPop"),
 47        this->fbuilder_->blockstack_addr(),
 48        this->fbuilder_->num_blocks_addr());
 49    Value *pop_to_level = this->builder_.CreateLoad(
 50        PyTypeBuilder<PyTryBlock>::b_level(this->builder_, block_info));
 51    Value *pop_to_addr =
 52        this->builder_.CreateGEP(this->fbuilder_->stack_bottom(), pop_to_level);
 53    this->fbuilder_->PopAndDecrefTo(pop_to_addr);
 54}
 55
 56void
 57OpcodeBlock::SETUP_EXCEPT(llvm::BasicBlock *target,
 58                          int target_opindex,
 59                          llvm::BasicBlock *fallthrough)
 60{
 61    this->CallBlockSetup(::SETUP_EXCEPT, target, target_opindex);
 62    llvm::BasicBlock *block = this->builder_.GetInsertBlock();
 63    this->builder_.SetInsertPoint(target);
 64    this->fbuilder_->PushException();
 65    this->builder_.SetInsertPoint(block);
 66}
 67
 68void
 69OpcodeBlock::SETUP_FINALLY(llvm::BasicBlock *target,
 70                           int target_opindex,
 71                           llvm::BasicBlock *fallthrough)
 72{
 73    BasicBlock *unwind =
 74        this->state_->CreateBasicBlock("SETUP_FINALLY_unwind");
 75    this->CallBlockSetup(::SETUP_FINALLY, unwind, target_opindex);
 76    llvm::BasicBlock *block = this->builder_.GetInsertBlock();
 77    this->builder_.SetInsertPoint(unwind);
 78    this->fbuilder_->PushException();
 79    this->builder_.CreateBr(target);
 80    this->builder_.SetInsertPoint(block);
 81}
 82
 83void
 84OpcodeBlock::CallBlockSetup(int block_type, llvm::BasicBlock *handler,
 85                            int handler_opindex)
 86{
 87    Value *stack_level = this->fbuilder_->GetStackLevel();
 88    Value *unwind_target_index =
 89        this->fbuilder_->AddUnwindTarget(handler, handler_opindex);
 90    Function *blocksetup =
 91        this->state_->GetGlobalFunction<void(PyTryBlock *, char *, int, int, int)>(
 92            "_PyLlvm_Frame_BlockSetup");
 93    Value *args[] = {
 94        this->fbuilder_->blockstack_addr(), this->fbuilder_->num_blocks_addr(),
 95        ConstantInt::get(PyTypeBuilder<int>::get(this->fbuilder_->context()),
 96                         block_type),
 97        unwind_target_index,
 98        stack_level
 99    };
100    this->state_->CreateCall(blocksetup, args, array_endof(args));
101}
102
103void
104OpcodeBlock::END_FINALLY()
105{
106    Value *finally_discriminator = this->fbuilder_->Pop();
107    Value *second = this->fbuilder_->Pop();
108    Value *third = this->fbuilder_->Pop();
109    // END_FINALLY is fairly complicated. It decides what to do based
110    // on the top value in the stack.  If that value is an int, it's
111    // interpreted as one of the unwind reasons.  If it's an exception
112    // type, the next two stack values are the rest of the exception,
113    // and it's re-raised.  Otherwise, it's supposed to be None,
114    // indicating that the finally was entered through normal control
115    // flow.
116
117    BasicBlock *unwind_code =
118        this->state_->CreateBasicBlock("unwind_code");
119    BasicBlock *test_exception =
120        this->state_->CreateBasicBlock("test_exception");
121    BasicBlock *reraise_exception =
122        this->state_->CreateBasicBlock("reraise_exception");
123    BasicBlock *check_none = this->state_->CreateBasicBlock("check_none");
124    BasicBlock *not_none = this->state_->CreateBasicBlock("not_none");
125    BasicBlock *finally_fallthrough =
126        this->state_->CreateBasicBlock("finally_fallthrough");
127
128    this->builder_.CreateCondBr(
129        this->state_->IsInstanceOfFlagClass(finally_discriminator,
130                                            Py_TPFLAGS_INT_SUBCLASS),
131        unwind_code, test_exception);
132
133    this->builder_.SetInsertPoint(unwind_code);
134    // The top of the stack was an int, interpreted as an unwind code.
135    // If we're resuming a return or continue, the return value or
136    // loop target (respectively) is now on top of the stack and needs
137    // to be popped off.
138    Value *unwind_reason = this->builder_.CreateTrunc(
139        this->state_->CreateCall(
140            this->state_->GetGlobalFunction<long(PyObject *)>("PyInt_AsLong"),
141            finally_discriminator),
142        Type::getInt8Ty(this->fbuilder_->context()),
143        "unwind_reason");
144    this->state_->DecRef(finally_discriminator);
145    this->state_->DecRef(third);
146    // Save the unwind reason for when we jump to the unwind block.
147    this->builder_.CreateStore(unwind_reason,
148                               this->fbuilder_->unwind_reason_addr());
149    // Check if we need to pop the return value or loop target.
150    BasicBlock *store_retval = this->state_->CreateBasicBlock("store_retval");
151    BasicBlock *decref_second = this->state_->CreateBasicBlock("decref_second");
152    llvm::SwitchInst *should_store_retval =
153        this->builder_.CreateSwitch(unwind_reason, decref_second, 2);
154    should_store_retval->addCase(
155        ConstantInt::get(Type::getInt8Ty(this->fbuilder_->context()),
156                         UNWIND_RETURN),
157        store_retval);
158    should_store_retval->addCase(
159        ConstantInt::get(Type::getInt8Ty(this->fbuilder_->context()),
160                         UNWIND_CONTINUE),
161        store_retval);
162
163    this->builder_.SetInsertPoint(store_retval);
164    // We're continuing a return or continue.  Retrieve its argument.
165    this->builder_.CreateStore(second, this->fbuilder_->retval_addr());
166    this->builder_.CreateBr(this->fbuilder_->unwind_block());
167
168    this->builder_.SetInsertPoint(decref_second);
169    this->state_->DecRef(second);
170    this->builder_.CreateBr(this->fbuilder_->unwind_block());
171
172    this->builder_.SetInsertPoint(test_exception);
173    Value *is_exception_or_string = this->state_->CreateCall(
174        this->state_->GetGlobalFunction<int(PyObject *)>(
175            "_PyLlvm_WrapIsExceptionOrString"),
176        finally_discriminator);
177    this->builder_.CreateCondBr(
178        this->state_->IsNonZero(is_exception_or_string),
179        reraise_exception, check_none);
180
181    this->builder_.SetInsertPoint(reraise_exception);
182    Value *err_type = finally_discriminator;
183    Value *err_value = second;
184    Value *err_traceback = third;
185    this->state_->CreateCall(
186        this->state_->GetGlobalFunction<
187            void(PyObject *, PyObject *, PyObject *)>("PyErr_Restore"),
188        err_type, err_value, err_traceback);
189    // This is a "re-raise" rather than a new exception, so we don't
190    // jump to the propagate_exception_block_.
191    this->builder_.CreateStore(this->state_->GetNull<PyObject*>(),
192                               this->fbuilder_->retval_addr());
193    this->builder_.CreateStore(
194        ConstantInt::get(Type::getInt8Ty(this->fbuilder_->context()),
195                         UNWIND_EXCEPTION),
196        this->fbuilder_->unwind_reason_addr());
197    this->builder_.CreateBr(this->fbuilder_->unwind_block());
198
199    this->builder_.SetInsertPoint(check_none);
200    // The contents of the try block push None onto the stack just
201    // before falling through to the finally block.  If we didn't get
202    // an unwind reason or an exception, we expect to fall through,
203    // but for sanity we also double-check that the None is present.
204    Value *is_none = this->builder_.CreateICmpEQ(
205        finally_discriminator,
206        this->state_->GetGlobalVariableFor(&_Py_NoneStruct));
207    this->state_->DecRef(finally_discriminator);
208    this->state_->DecRef(second);
209    this->state_->DecRef(third);
210    this->builder_.CreateCondBr(is_none, finally_fallthrough, not_none);
211
212    this->builder_.SetInsertPoint(not_none);
213    // If we didn't get a None, raise a SystemError.
214    Value *system_error = this->builder_.CreateLoad(
215        this->state_->GET_GLOBAL_VARIABLE(PyObject *, PyExc_SystemError));
216    Value *err_msg = llvm_data_->GetGlobalStringPtr(
217        "'finally' pops bad exception");
218    this->state_->CreateCall(
219        this->state_->GetGlobalFunction<void(PyObject *, const char *)>(
220            "PyErr_SetString"),
221        system_error, err_msg);
222    this->builder_.CreateStore(
223        ConstantInt::get(Type::getInt8Ty(this->fbuilder_->context()),
224                         UNWIND_EXCEPTION),
225        this->fbuilder_->unwind_reason_addr());
226    this->builder_.CreateBr(this->fbuilder_->unwind_block());
227
228    // After falling through into a finally block, we also fall
229    // through out of the block.  This has the nice side-effect of
230    // avoiding jumps and switch instructions in the common case,
231    // although returning out of a finally may still be slower than
232    // ideal.
233    this->builder_.SetInsertPoint(finally_fallthrough);
234}
235
236void
237OpcodeBlock::WITH_CLEANUP()
238{
239    /* At the top of the stack are 3 values indicating
240       how/why we entered the finally clause:
241       - (TOP, SECOND, THIRD) = None, None, None
242       - (TOP, SECOND, THIRD) = (UNWIND_{RETURN,CONTINUE}), retval, None
243       - (TOP, SECOND, THIRD) = UNWIND_*, None, None
244       - (TOP, SECOND, THIRD) = exc_info()
245       Below them is EXIT, the context.__exit__ bound method.
246       In the last case, we must call
247       EXIT(TOP, SECOND, THIRD)
248       otherwise we must call
249       EXIT(None, None, None)
250
251       In all cases, we remove EXIT from the stack, leaving
252       the rest in the same order.
253
254       In addition, if the stack represents an exception,
255       *and* the function call returns a 'true' value, we
256       "zap" this information, to prevent END_FINALLY from
257       re-raising the exception. (But non-local gotos
258       should still be resumed.)
259    */
260
261    Value *exc_type = this->state_->CreateAllocaInEntryBlock(
262        PyTypeBuilder<PyObject*>::get(this->fbuilder_->context()),
263        NULL, "WITH_CLEANUP_exc_type");
264    Value *exc_value = this->state_->CreateAllocaInEntryBlock(
265        PyTypeBuilder<PyObject*>::get(this->fbuilder_->context()),
266        NULL, "WITH_CLEANUP_exc_value");
267    Value *exc_traceback = this->state_->CreateAllocaInEntryBlock(
268        PyTypeBuilder<PyObject*>::get(this->fbuilder_->context()),
269        NULL, "WITH_CLEANUP_exc_traceback");
270    Value *exit_func = this->state_->CreateAllocaInEntryBlock(
271        PyTypeBuilder<PyObject*>::get(this->fbuilder_->context()),
272        NULL, "WITH_CLEANUP_exit_func");
273
274    BasicBlock *handle_int =
275        this->state_->CreateBasicBlock("WITH_CLEANUP_handle_int");
276    BasicBlock *main_block =
277        this->state_->CreateBasicBlock("WITH_CLEANUP_main_block");
278
279    Value *none = this->state_->GetGlobalVariableFor(&_Py_NoneStruct);
280
281    this->builder_.CreateStore(this->fbuilder_->Pop(), exc_type);
282    this->builder_.CreateStore(this->fbuilder_->Pop(), exc_value);
283    this->builder_.CreateStore(this->fbuilder_->Pop(), exc_traceback);
284    this->builder_.CreateStore(this->fbuilder_->Pop(), exit_func);
285    this->fbuilder_->Push(this->builder_.CreateLoad(exc_traceback));
286    this->fbuilder_->Push(this->builder_.CreateLoad(exc_value));
287    this->fbuilder_->Push(this->builder_.CreateLoad(exc_type));
288
289    Value *is_int = this->state_->CreateCall(
290        this->state_->
291            GetGlobalFunction<int(PyObject *)>("_PyLlvm_WrapIntCheck"),
292        this->builder_.CreateLoad(exc_type),
293        "WITH_CLEANUP_pyint_check");
294    this->builder_.CreateCondBr(this->state_->IsNonZero(is_int),
295                                handle_int, main_block);
296
297    this->builder_.SetInsertPoint(handle_int);
298    this->builder_.CreateStore(none, exc_type);
299    this->builder_.CreateStore(none, exc_value);
300    this->builder_.CreateStore(none, exc_traceback);
301
302    this->fbuilder_->FallThroughTo(main_block);
303    // Build a vector because there is no CreateCall5().
304    // This is easier than building the tuple ourselves, but doing so would
305    // probably be faster.
306    std::vector<Value*> args;
307    args.push_back(this->builder_.CreateLoad(exit_func));
308    args.push_back(this->builder_.CreateLoad(exc_type));
309    args.push_back(this->builder_.CreateLoad(exc_value));
310    args.push_back(this->builder_.CreateLoad(exc_traceback));
311    args.push_back(this->state_->GetNull<PyObject*>());
312    Value *ret = this->state_->CreateCall(
313        this->state_->GetGlobalFunction<PyObject *(PyObject *, ...)>(
314            "PyObject_CallFunctionObjArgs"),
315        args.begin(), args.end());
316    this->state_->DecRef(this->builder_.CreateLoad(exit_func));
317    this->fbuilder_->PropagateExceptionOnNull(ret);
318
319    BasicBlock *check_silence =
320        this->state_->CreateBasicBlock("WITH_CLEANUP_check_silence");
321    BasicBlock *no_silence =
322        this->state_->CreateBasicBlock("WITH_CLEANUP_no_silence");
323    BasicBlock *cleanup =
324        this->state_->CreateBasicBlock("WITH_CLEANUP_cleanup");
325    BasicBlock *next =
326        this->state_->CreateBasicBlock("WITH_CLEANUP_next");
327
328    // Don't bother checking whether to silence the exception if there's
329    // no exception to silence.
330    this->builder_.CreateCondBr(
331        this->builder_.CreateICmpEQ(
332            this->builder_.CreateLoad(exc_type), none),
333        no_silence, check_silence);
334
335    this->builder_.SetInsertPoint(no_silence);
336    this->state_->DecRef(ret);
337    this->builder_.CreateBr(next);
338
339    this->builder_.SetInsertPoint(check_silence);
340    this->builder_.CreateCondBr(this->fbuilder_->IsPythonTrue(ret),
341                                cleanup, next);
342
343    this->builder_.SetInsertPoint(cleanup);
344    // There was an exception and a true return. Swallow the exception.
345    this->fbuilder_->Pop();
346    this->fbuilder_->Pop();
347    this->fbuilder_->Pop();
348    this->state_->IncRef(none);
349    this->fbuilder_->Push(none);
350    this->state_->IncRef(none);
351    this->fbuilder_->Push(none);
352    this->state_->IncRef(none);
353    this->fbuilder_->Push(none);
354    this->state_->DecRef(this->builder_.CreateLoad(exc_type));
355    this->state_->DecRef(this->builder_.CreateLoad(exc_value));
356    this->state_->DecRef(this->builder_.CreateLoad(exc_traceback));
357    this->builder_.CreateBr(next);
358
359    this->builder_.SetInsertPoint(next);
360}
361
362}