PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/objspace/flow/objspace.py

https://bitbucket.org/dac_io/pypy
Python | 506 lines | 389 code | 48 blank | 69 comment | 98 complexity | cb46d1495705d25e0f61e811b02d4b6f MD5 | raw file
  1. # ______________________________________________________________________
  2. import __builtin__
  3. import sys
  4. import operator
  5. import types
  6. from pypy.tool import error
  7. from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
  8. from pypy.interpreter.pycode import PyCode, cpython_code_signature
  9. from pypy.interpreter.module import Module
  10. from pypy.interpreter.error import OperationError
  11. from pypy.interpreter.astcompiler.consts import CO_GENERATOR
  12. from pypy.interpreter import pyframe, argument
  13. from pypy.objspace.flow.model import *
  14. from pypy.objspace.flow import flowcontext, operation, specialcase
  15. from pypy.rlib.unroll import unrolling_iterable, _unroller
  16. from pypy.rlib import rstackovf, rarithmetic
  17. from pypy.rlib.rarithmetic import is_valid_int
  18. # method-wrappers have not enough introspection in CPython
  19. if hasattr(complex.real.__get__, 'im_self'):
  20. type_with_bad_introspection = None # on top of PyPy
  21. else:
  22. type_with_bad_introspection = type(complex.real.__get__)
  23. # the following gives us easy access to declare more for applications:
  24. NOT_REALLY_CONST = {
  25. Constant(sys): {
  26. Constant('maxint'): True,
  27. Constant('maxunicode'): True,
  28. Constant('api_version'): True,
  29. Constant('exit'): True,
  30. Constant('exc_info'): True,
  31. Constant('getrefcount'): True,
  32. Constant('getdefaultencoding'): True,
  33. # this is an incomplete list of true constants.
  34. # if we add much more, a dedicated class
  35. # might be considered for special objects.
  36. }
  37. }
  38. # ______________________________________________________________________
  39. class FlowObjSpace(ObjSpace):
  40. """NOT_RPYTHON.
  41. The flow objspace space is used to produce a flow graph by recording
  42. the space operations that the interpreter generates when it interprets
  43. (the bytecode of) some function.
  44. """
  45. full_exceptions = False
  46. do_imports_immediately = True
  47. FrameClass = flowcontext.FlowSpaceFrame
  48. def initialize(self):
  49. self.concrete_mode = 1
  50. self.w_None = Constant(None)
  51. self.builtin = Module(self, Constant('__builtin__'),
  52. Constant(__builtin__.__dict__))
  53. def pick_builtin(w_globals):
  54. return self.builtin
  55. self.builtin.pick_builtin = pick_builtin
  56. self.sys = Module(self, Constant('sys'), Constant(sys.__dict__))
  57. self.sys.recursionlimit = 100
  58. self.w_False = Constant(False)
  59. self.w_True = Constant(True)
  60. self.w_type = Constant(type)
  61. self.w_tuple = Constant(tuple)
  62. self.concrete_mode = 0
  63. for exc in [KeyError, ValueError, IndexError, StopIteration,
  64. AssertionError, TypeError, AttributeError, ImportError]:
  65. clsname = exc.__name__
  66. setattr(self, 'w_'+clsname, Constant(exc))
  67. # the following exceptions are the ones that should not show up
  68. # during flow graph construction; they are triggered by
  69. # non-R-Pythonic constructs or real bugs like typos.
  70. for exc in [NameError, UnboundLocalError]:
  71. clsname = exc.__name__
  72. setattr(self, 'w_'+clsname, None)
  73. self.specialcases = {}
  74. #self.make_builtins()
  75. #self.make_sys()
  76. # w_str is needed because cmp_exc_match of frames checks against it,
  77. # as string exceptions are deprecated
  78. self.w_str = Constant(str)
  79. # objects which should keep their SomeObjectness
  80. self.not_really_const = NOT_REALLY_CONST
  81. def enter_cache_building_mode(self):
  82. # when populating the caches, the flow space switches to
  83. # "concrete mode". In this mode, only Constants are allowed
  84. # and no SpaceOperation is recorded.
  85. previous_recorder = self.executioncontext.recorder
  86. self.executioncontext.recorder = flowcontext.ConcreteNoOp()
  87. self.concrete_mode += 1
  88. return previous_recorder
  89. def leave_cache_building_mode(self, previous_recorder):
  90. self.executioncontext.recorder = previous_recorder
  91. self.concrete_mode -= 1
  92. def is_w(self, w_one, w_two):
  93. return self.is_true(self.is_(w_one, w_two))
  94. is_ = None # real version added by add_operations()
  95. id = None # real version added by add_operations()
  96. def newdict(self, module="ignored"):
  97. if self.concrete_mode:
  98. return Constant({})
  99. return self.do_operation('newdict')
  100. def newtuple(self, args_w):
  101. try:
  102. content = [self.unwrap(w_arg) for w_arg in args_w]
  103. except UnwrapException:
  104. return self.do_operation('newtuple', *args_w)
  105. else:
  106. return Constant(tuple(content))
  107. def newlist(self, args_w, sizehint=None):
  108. if self.concrete_mode:
  109. content = [self.unwrap(w_arg) for w_arg in args_w]
  110. return Constant(content)
  111. return self.do_operation('newlist', *args_w)
  112. def newslice(self, w_start, w_stop, w_step):
  113. if self.concrete_mode:
  114. return Constant(slice(self.unwrap(w_start),
  115. self.unwrap(w_stop),
  116. self.unwrap(w_step)))
  117. return self.do_operation('newslice', w_start, w_stop, w_step)
  118. def wrap(self, obj):
  119. if isinstance(obj, (Variable, Constant)):
  120. raise TypeError("already wrapped: " + repr(obj))
  121. # method-wrapper have ill-defined comparison and introspection
  122. # to appear in a flow graph
  123. if type(obj) is type_with_bad_introspection:
  124. raise WrapException
  125. return Constant(obj)
  126. def int_w(self, w_obj):
  127. if isinstance(w_obj, Constant):
  128. val = w_obj.value
  129. if not is_valid_int(val):
  130. raise TypeError("expected integer: " + repr(w_obj))
  131. return val
  132. return self.unwrap(w_obj)
  133. def uint_w(self, w_obj):
  134. if isinstance(w_obj, Constant):
  135. val = w_obj.value
  136. if type(val) is not rarithmetic.r_uint:
  137. raise TypeError("expected unsigned: " + repr(w_obj))
  138. return val
  139. return self.unwrap(w_obj)
  140. def str_w(self, w_obj):
  141. if isinstance(w_obj, Constant):
  142. val = w_obj.value
  143. if type(val) is not str:
  144. raise TypeError("expected string: " + repr(w_obj))
  145. return val
  146. return self.unwrap(w_obj)
  147. def float_w(self, w_obj):
  148. if isinstance(w_obj, Constant):
  149. val = w_obj.value
  150. if type(val) is not float:
  151. raise TypeError("expected float: " + repr(w_obj))
  152. return val
  153. return self.unwrap(w_obj)
  154. def unwrap(self, w_obj):
  155. if isinstance(w_obj, Variable):
  156. raise UnwrapException
  157. elif isinstance(w_obj, Constant):
  158. return w_obj.value
  159. else:
  160. raise TypeError("not wrapped: " + repr(w_obj))
  161. def unwrap_for_computation(self, w_obj):
  162. obj = self.unwrap(w_obj)
  163. to_check = obj
  164. if hasattr(to_check, 'im_self'):
  165. to_check = to_check.im_self
  166. if (not isinstance(to_check, (type, types.ClassType, types.ModuleType)) and
  167. # classes/types/modules are assumed immutable
  168. hasattr(to_check, '__class__') and to_check.__class__.__module__ != '__builtin__'):
  169. frozen = hasattr(to_check, '_freeze_') and to_check._freeze_()
  170. if not frozen:
  171. if self.concrete_mode:
  172. # xxx do we want some warning? notice that some stuff is harmless
  173. # like setitem(dict, 'n', mutable)
  174. pass
  175. else: # cannot count on it not mutating at runtime!
  176. raise UnwrapException
  177. return obj
  178. def interpclass_w(self, w_obj):
  179. obj = self.unwrap(w_obj)
  180. if isinstance(obj, Wrappable):
  181. return obj
  182. return None
  183. def getexecutioncontext(self):
  184. return getattr(self, 'executioncontext', None)
  185. def createcompiler(self):
  186. # no parser/compiler needed - don't build one, it takes too much time
  187. # because it is done each time a FlowExecutionContext is built
  188. return None
  189. def setup_executioncontext(self, ec):
  190. self.executioncontext = ec
  191. specialcase.setup(self)
  192. def exception_match(self, w_exc_type, w_check_class):
  193. try:
  194. check_class = self.unwrap(w_check_class)
  195. except UnwrapException:
  196. raise Exception, "non-constant except guard"
  197. if check_class in (NotImplementedError, AssertionError):
  198. raise error.FlowingError("Catching %s is not valid in RPython" %
  199. check_class.__name__)
  200. if not isinstance(check_class, tuple):
  201. # the simple case
  202. return ObjSpace.exception_match(self, w_exc_type, w_check_class)
  203. # special case for StackOverflow (see rlib/rstackovf.py)
  204. if check_class == rstackovf.StackOverflow:
  205. w_real_class = self.wrap(rstackovf._StackOverflow)
  206. return ObjSpace.exception_match(self, w_exc_type, w_real_class)
  207. # checking a tuple of classes
  208. for w_klass in self.fixedview(w_check_class):
  209. if self.exception_match(w_exc_type, w_klass):
  210. return True
  211. return False
  212. def getconstclass(space, w_cls):
  213. try:
  214. ecls = space.unwrap(w_cls)
  215. except UnwrapException:
  216. pass
  217. else:
  218. if isinstance(ecls, (type, types.ClassType)):
  219. return ecls
  220. return None
  221. def build_flow(self, func, constargs={}, tweak_for_generator=True):
  222. """
  223. """
  224. if func.func_doc and func.func_doc.lstrip().startswith('NOT_RPYTHON'):
  225. raise Exception, "%r is tagged as NOT_RPYTHON" % (func,)
  226. code = func.func_code
  227. is_generator = bool(code.co_flags & CO_GENERATOR)
  228. code = PyCode._from_code(self, code)
  229. if func.func_closure is None:
  230. cl = None
  231. else:
  232. cl = [extract_cell_content(c) for c in func.func_closure]
  233. # CallableFactory.pycall may add class_ to functions that are methods
  234. name = func.func_name
  235. class_ = getattr(func, 'class_', None)
  236. if class_ is not None:
  237. name = '%s.%s' % (class_.__name__, name)
  238. for c in "<>&!":
  239. name = name.replace(c, '_')
  240. class outerfunc: # hack
  241. closure = cl
  242. ec = flowcontext.FlowExecutionContext(self, code, func.func_globals,
  243. constargs, outerfunc, name,
  244. is_generator)
  245. graph = ec.graph
  246. graph.func = func
  247. # attach a signature and defaults to the graph
  248. # so that it becomes even more interchangeable with the function
  249. # itself
  250. graph.signature = cpython_code_signature(code)
  251. graph.defaults = func.func_defaults or ()
  252. self.setup_executioncontext(ec)
  253. try:
  254. ec.build_flow()
  255. except error.FlowingError, a:
  256. # attach additional source info to AnnotatorError
  257. _, _, tb = sys.exc_info()
  258. formated = error.format_global_error(ec.graph, ec.crnt_offset,
  259. str(a))
  260. e = error.FlowingError(formated)
  261. raise error.FlowingError, e, tb
  262. checkgraph(graph)
  263. #
  264. if is_generator and tweak_for_generator:
  265. from pypy.translator.generator import tweak_generator_graph
  266. tweak_generator_graph(graph)
  267. #
  268. return graph
  269. def fixedview(self, w_tuple, expected_length=None):
  270. return self.unpackiterable(w_tuple, expected_length)
  271. listview = fixedview
  272. def unpackiterable(self, w_iterable, expected_length=None):
  273. if not isinstance(w_iterable, Variable):
  274. l = list(self.unwrap(w_iterable))
  275. if expected_length is not None and len(l) != expected_length:
  276. raise ValueError
  277. return [self.wrap(x) for x in l]
  278. if isinstance(w_iterable, Variable) and expected_length is None:
  279. raise UnwrapException, ("cannot unpack a Variable iterable"
  280. "without knowing its length")
  281. elif expected_length is not None:
  282. w_len = self.len(w_iterable)
  283. w_correct = self.eq(w_len, self.wrap(expected_length))
  284. if not self.is_true(w_correct):
  285. e = OperationError(self.w_ValueError, self.w_None)
  286. e.normalize_exception(self)
  287. raise e
  288. return [self.do_operation('getitem', w_iterable, self.wrap(i))
  289. for i in range(expected_length)]
  290. return ObjSpace.unpackiterable(self, w_iterable, expected_length)
  291. # ____________________________________________________________
  292. def do_operation(self, name, *args_w):
  293. spaceop = SpaceOperation(name, args_w, Variable())
  294. if hasattr(self, 'executioncontext'): # not here during bootstrapping
  295. spaceop.offset = self.executioncontext.crnt_offset
  296. self.executioncontext.recorder.append(spaceop)
  297. return spaceop.result
  298. def do_operation_with_implicit_exceptions(self, name, *args_w):
  299. w_result = self.do_operation(name, *args_w)
  300. self.handle_implicit_exceptions(operation.implicit_exceptions.get(name))
  301. return w_result
  302. def is_true(self, w_obj):
  303. try:
  304. obj = self.unwrap_for_computation(w_obj)
  305. except UnwrapException:
  306. pass
  307. else:
  308. return bool(obj)
  309. w_truthvalue = self.do_operation('is_true', w_obj)
  310. context = self.getexecutioncontext()
  311. return context.guessbool(w_truthvalue)
  312. def iter(self, w_iterable):
  313. try:
  314. iterable = self.unwrap(w_iterable)
  315. except UnwrapException:
  316. pass
  317. else:
  318. if isinstance(iterable, unrolling_iterable):
  319. return self.wrap(iterable.get_unroller())
  320. w_iter = self.do_operation("iter", w_iterable)
  321. return w_iter
  322. def next(self, w_iter):
  323. context = self.getexecutioncontext()
  324. try:
  325. it = self.unwrap(w_iter)
  326. except UnwrapException:
  327. pass
  328. else:
  329. if isinstance(it, _unroller):
  330. try:
  331. v, next_unroller = it.step()
  332. except IndexError:
  333. raise OperationError(self.w_StopIteration, self.w_None)
  334. else:
  335. context.replace_in_stack(it, next_unroller)
  336. return self.wrap(v)
  337. w_item = self.do_operation("next", w_iter)
  338. outcome, w_exc_cls, w_exc_value = context.guessexception(StopIteration,
  339. RuntimeError)
  340. if outcome is StopIteration:
  341. raise OperationError(self.w_StopIteration, w_exc_value)
  342. elif outcome is RuntimeError:
  343. raise operation.ImplicitOperationError(Constant(RuntimeError),
  344. w_exc_value)
  345. else:
  346. return w_item
  347. def setitem(self, w_obj, w_key, w_val):
  348. if self.concrete_mode:
  349. try:
  350. obj = self.unwrap_for_computation(w_obj)
  351. key = self.unwrap_for_computation(w_key)
  352. val = self.unwrap_for_computation(w_val)
  353. operator.setitem(obj, key, val)
  354. return self.w_None
  355. except UnwrapException:
  356. pass
  357. return self.do_operation_with_implicit_exceptions('setitem', w_obj,
  358. w_key, w_val)
  359. def call_function(self, w_func, *args_w):
  360. nargs = len(args_w)
  361. args = argument.ArgumentsForTranslation(self, list(args_w))
  362. return self.call_args(w_func, args)
  363. def call_args(self, w_callable, args):
  364. try:
  365. fn = self.unwrap(w_callable)
  366. if hasattr(fn, "_flowspace_rewrite_directly_as_"):
  367. fn = fn._flowspace_rewrite_directly_as_
  368. w_callable = self.wrap(fn)
  369. sc = self.specialcases[fn] # TypeError if 'fn' not hashable
  370. except (UnwrapException, KeyError, TypeError):
  371. pass
  372. else:
  373. return sc(self, fn, args)
  374. try:
  375. args_w, kwds_w = args.copy().unpack()
  376. except UnwrapException:
  377. args_w, kwds_w = '?', '?'
  378. # NOTE: annrpython needs to know about the following two operations!
  379. if not kwds_w:
  380. # simple case
  381. w_res = self.do_operation('simple_call', w_callable, *args_w)
  382. else:
  383. # general case
  384. shape, args_w = args.flatten()
  385. w_res = self.do_operation('call_args', w_callable, Constant(shape),
  386. *args_w)
  387. # maybe the call has generated an exception (any one)
  388. # but, let's say, not if we are calling a built-in class or function
  389. # because this gets in the way of the special-casing of
  390. #
  391. # raise SomeError(x)
  392. #
  393. # as shown by test_objspace.test_raise3.
  394. exceptions = [Exception] # *any* exception by default
  395. if isinstance(w_callable, Constant):
  396. c = w_callable.value
  397. if (isinstance(c, (types.BuiltinFunctionType,
  398. types.BuiltinMethodType,
  399. types.ClassType,
  400. types.TypeType)) and
  401. c.__module__ in ['__builtin__', 'exceptions']):
  402. exceptions = operation.implicit_exceptions.get(c)
  403. self.handle_implicit_exceptions(exceptions)
  404. return w_res
  405. def handle_implicit_exceptions(self, exceptions):
  406. if not exceptions:
  407. return
  408. # catch possible exceptions implicitly. If the OperationError
  409. # below is not caught in the same function, it will produce an
  410. # exception-raising return block in the flow graph. Note that
  411. # even if the interpreter re-raises the exception, it will not
  412. # be the same ImplicitOperationError instance internally.
  413. context = self.getexecutioncontext()
  414. outcome, w_exc_cls, w_exc_value = context.guessexception(*exceptions)
  415. if outcome is not None:
  416. # we assume that the caught exc_cls will be exactly the
  417. # one specified by 'outcome', and not a subclass of it,
  418. # unless 'outcome' is Exception.
  419. #if outcome is not Exception:
  420. #w_exc_cls = Constant(outcome) Now done by guessexception itself
  421. #pass
  422. raise operation.ImplicitOperationError(w_exc_cls, w_exc_value)
  423. def w_KeyboardInterrupt(self):
  424. # the reason to do this is: if you interrupt the flowing of a function
  425. # with <Ctrl-C> the bytecode interpreter will raise an applevel
  426. # KeyboardInterrupt and you will get an AttributeError: space does not
  427. # have w_KeyboardInterrupt, which is not very helpful
  428. raise KeyboardInterrupt
  429. w_KeyboardInterrupt = property(w_KeyboardInterrupt)
  430. def w_RuntimeError(self):
  431. # XXX same as w_KeyboardInterrupt()
  432. raise RuntimeError("the interpreter raises RuntimeError during "
  433. "flow graph construction")
  434. w_RuntimeError = prebuilt_recursion_error = property(w_RuntimeError)
  435. operation.add_operations(FlowObjSpace)
  436. def extract_cell_content(c):
  437. """Get the value contained in a CPython 'cell', as read through
  438. the func_closure of a function object."""
  439. try:
  440. # This is simple on 2.5
  441. return getattr(c, "cell_contents")
  442. except AttributeError:
  443. class X(object):
  444. def __cmp__(self, other):
  445. self.other = other
  446. return 0
  447. def __eq__(self, other):
  448. self.other = other
  449. return True
  450. x = X()
  451. x_cell, = (lambda: x).func_closure
  452. x_cell == c
  453. try:
  454. return x.other # crashes if the cell is actually empty
  455. except AttributeError:
  456. raise ValueError("empty cell")
  457. # ______________________________________________________________________
  458. # End of objspace.py