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