PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/interpreter/pycode.py

https://bitbucket.org/pypy/pypy/
Python | 433 lines | 424 code | 4 blank | 5 comment | 3 complexity | c80500d96c49559dfe35414ce02f7391 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """
  2. Python-style code objects.
  3. PyCode instances have the same co_xxx arguments as CPython code objects.
  4. The bytecode interpreter itself is implemented by the PyFrame class.
  5. """
  6. import dis, imp, struct, types, new, sys, os
  7. from pypy.interpreter import eval
  8. from pypy.interpreter.signature import Signature
  9. from pypy.interpreter.error import OperationError, oefmt
  10. from pypy.interpreter.gateway import unwrap_spec
  11. from pypy.interpreter.astcompiler.consts import (
  12. CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED,
  13. CO_GENERATOR, CO_KILL_DOCSTRING, CO_YIELD_INSIDE_TRY)
  14. from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT
  15. from rpython.rlib.rarithmetic import intmask, r_longlong
  16. from rpython.rlib.objectmodel import compute_hash
  17. from rpython.rlib import jit
  18. from rpython.rlib.debug import debug_start, debug_stop, debug_print
  19. class BytecodeCorruption(Exception):
  20. """Detected bytecode corruption. Never caught; it's an error."""
  21. # helper
  22. def unpack_str_tuple(space,w_str_tuple):
  23. return [space.str_w(w_el) for w_el in space.unpackiterable(w_str_tuple)]
  24. # Magic numbers for the bytecode version in code objects.
  25. # See comments in pypy/module/imp/importing.
  26. cpython_magic, = struct.unpack("<i", imp.get_magic()) # host magic number
  27. default_magic = (0xf303 + 7) | 0x0a0d0000 # this PyPy's magic
  28. # (from CPython 2.7.0)
  29. # cpython_code_signature helper
  30. def cpython_code_signature(code):
  31. "([list-of-arg-names], vararg-name-or-None, kwarg-name-or-None)."
  32. argcount = code.co_argcount
  33. varnames = code.co_varnames
  34. assert argcount >= 0 # annotator hint
  35. argnames = list(varnames[:argcount])
  36. if code.co_flags & CO_VARARGS:
  37. varargname = varnames[argcount]
  38. argcount += 1
  39. else:
  40. varargname = None
  41. kwargname = varnames[argcount] if code.co_flags & CO_VARKEYWORDS else None
  42. return Signature(argnames, varargname, kwargname)
  43. class CodeHookCache(object):
  44. def __init__(self, space):
  45. self._code_hook = None
  46. class PyCode(eval.Code):
  47. "CPython-style code objects."
  48. _immutable_fields_ = ["_signature", "co_argcount", "co_cellvars[*]",
  49. "co_code", "co_consts_w[*]", "co_filename",
  50. "co_firstlineno", "co_flags", "co_freevars[*]",
  51. "co_lnotab", "co_names_w[*]", "co_nlocals",
  52. "co_stacksize", "co_varnames[*]",
  53. "_args_as_cellvars[*]", "w_globals?"]
  54. def __init__(self, space, argcount, nlocals, stacksize, flags,
  55. code, consts, names, varnames, filename,
  56. name, firstlineno, lnotab, freevars, cellvars,
  57. hidden_applevel=False, magic=default_magic):
  58. """Initialize a new code object from parameters given by
  59. the pypy compiler"""
  60. self.space = space
  61. eval.Code.__init__(self, name)
  62. assert nlocals >= 0
  63. self.co_argcount = argcount
  64. self.co_nlocals = nlocals
  65. self.co_stacksize = stacksize
  66. self.co_flags = flags
  67. self.co_code = code
  68. self.co_consts_w = consts
  69. self.co_names_w = [space.new_interned_str(aname) for aname in names]
  70. self.co_varnames = varnames
  71. self.co_freevars = freevars
  72. self.co_cellvars = cellvars
  73. self.co_filename = filename
  74. self.co_name = name
  75. self.co_firstlineno = firstlineno
  76. self.co_lnotab = lnotab
  77. # store the first globals object that the code object is run in in
  78. # here. if a frame is run in that globals object, it does not need to
  79. # store it at all
  80. self.w_globals = None
  81. self.hidden_applevel = hidden_applevel
  82. self.magic = magic
  83. self._signature = cpython_code_signature(self)
  84. self._initialize()
  85. self._init_ready()
  86. self.new_code_hook()
  87. def frame_stores_global(self, w_globals):
  88. if self.w_globals is None:
  89. self.w_globals = w_globals
  90. return False
  91. if self.w_globals is w_globals:
  92. return False
  93. return True
  94. def new_code_hook(self):
  95. code_hook = self.space.fromcache(CodeHookCache)._code_hook
  96. if code_hook is not None:
  97. try:
  98. self.space.call_function(code_hook, self)
  99. except OperationError as e:
  100. e.write_unraisable(self.space, "new_code_hook()")
  101. def _initialize(self):
  102. from pypy.objspace.std.mapdict import init_mapdict_cache
  103. if self.co_cellvars:
  104. argcount = self.co_argcount
  105. assert argcount >= 0 # annotator hint
  106. if self.co_flags & CO_VARARGS:
  107. argcount += 1
  108. if self.co_flags & CO_VARKEYWORDS:
  109. argcount += 1
  110. # Cell vars could shadow already-set arguments.
  111. # The compiler used to be clever about the order of
  112. # the variables in both co_varnames and co_cellvars, but
  113. # it no longer is for the sake of simplicity. Moreover
  114. # code objects loaded from CPython don't necessarily follow
  115. # an order, which could lead to strange bugs if .pyc files
  116. # produced by CPython are loaded by PyPy. Note that CPython
  117. # contains the following bad-looking nested loops at *every*
  118. # function call!
  119. # Precompute what arguments need to be copied into cellvars
  120. args_as_cellvars = []
  121. argvars = self.co_varnames
  122. cellvars = self.co_cellvars
  123. for i in range(len(cellvars)):
  124. cellname = cellvars[i]
  125. for j in range(argcount):
  126. if cellname == argvars[j]:
  127. # argument j has the same name as the cell var i
  128. while len(args_as_cellvars) <= i:
  129. args_as_cellvars.append(-1) # pad
  130. args_as_cellvars[i] = j
  131. self._args_as_cellvars = args_as_cellvars[:]
  132. else:
  133. self._args_as_cellvars = []
  134. self._compute_flatcall()
  135. init_mapdict_cache(self)
  136. def _init_ready(self):
  137. "This is a hook for the vmprof module, which overrides this method."
  138. def _cleanup_(self):
  139. if (self.magic == cpython_magic and
  140. '__pypy__' not in sys.builtin_module_names):
  141. raise Exception("CPython host codes should not be rendered")
  142. # When translating PyPy, freeze the file name
  143. # <builtin>/lastdirname/basename.py
  144. # instead of freezing the complete translation-time path.
  145. filename = self.co_filename
  146. if filename.startswith('<builtin>'):
  147. return
  148. filename = filename.lstrip('<').rstrip('>')
  149. if filename.lower().endswith('.pyc'):
  150. filename = filename[:-1]
  151. basename = os.path.basename(filename)
  152. lastdirname = os.path.basename(os.path.dirname(filename))
  153. if lastdirname:
  154. basename = '%s/%s' % (lastdirname, basename)
  155. self.co_filename = '<builtin>/%s' % (basename,)
  156. co_names = property(lambda self: [self.space.unwrap(w_name) for w_name in self.co_names_w]) # for trace
  157. def signature(self):
  158. return self._signature
  159. @classmethod
  160. def _from_code(cls, space, code, hidden_applevel=False, code_hook=None):
  161. """
  162. Hack to initialize the code object from a real (CPython) one.
  163. """
  164. assert isinstance(code, types.CodeType)
  165. newconsts_w = [None] * len(code.co_consts)
  166. num = 0
  167. if code_hook is None:
  168. code_hook = cls._from_code
  169. for const in code.co_consts:
  170. if isinstance(const, types.CodeType): # from stable compiler
  171. const = code_hook(space, const, hidden_applevel, code_hook)
  172. newconsts_w[num] = space.wrap(const)
  173. num += 1
  174. # stick the underlying CPython magic value, if the code object
  175. # comes from there
  176. return cls(space, code.co_argcount,
  177. code.co_nlocals,
  178. code.co_stacksize,
  179. code.co_flags,
  180. code.co_code,
  181. newconsts_w[:],
  182. list(code.co_names),
  183. list(code.co_varnames),
  184. code.co_filename,
  185. code.co_name,
  186. code.co_firstlineno,
  187. code.co_lnotab,
  188. list(code.co_freevars),
  189. list(code.co_cellvars),
  190. hidden_applevel, cpython_magic)
  191. def _compute_flatcall(self):
  192. # Speed hack!
  193. self.fast_natural_arity = eval.Code.HOPELESS
  194. if self.co_flags & (CO_VARARGS | CO_VARKEYWORDS):
  195. return
  196. if len(self._args_as_cellvars) > 0:
  197. return
  198. if self.co_argcount > 0xff:
  199. return
  200. self.fast_natural_arity = eval.Code.FLATPYCALL | self.co_argcount
  201. def funcrun(self, func, args):
  202. frame = self.space.createframe(self, func.w_func_globals,
  203. func)
  204. sig = self._signature
  205. # speed hack
  206. fresh_frame = jit.hint(frame, access_directly=True,
  207. fresh_virtualizable=True)
  208. args.parse_into_scope(None, fresh_frame.locals_cells_stack_w, func.name,
  209. sig, func.defs_w)
  210. fresh_frame.init_cells()
  211. return frame.run()
  212. def funcrun_obj(self, func, w_obj, args):
  213. frame = self.space.createframe(self, func.w_func_globals,
  214. func)
  215. sig = self._signature
  216. # speed hack
  217. fresh_frame = jit.hint(frame, access_directly=True,
  218. fresh_virtualizable=True)
  219. args.parse_into_scope(w_obj, fresh_frame.locals_cells_stack_w, func.name,
  220. sig, func.defs_w)
  221. fresh_frame.init_cells()
  222. return frame.run()
  223. def getvarnames(self):
  224. return self.co_varnames
  225. def getdocstring(self, space):
  226. if self.co_consts_w: # it is probably never empty
  227. w_first = self.co_consts_w[0]
  228. if space.isinstance_w(w_first, space.w_basestring):
  229. return w_first
  230. return space.w_None
  231. def remove_docstrings(self, space):
  232. if self.co_flags & CO_KILL_DOCSTRING:
  233. self.co_consts_w[0] = space.w_None
  234. for w_co in self.co_consts_w:
  235. if isinstance(w_co, PyCode):
  236. w_co.remove_docstrings(space)
  237. def _to_code(self):
  238. """For debugging only."""
  239. consts = [None] * len(self.co_consts_w)
  240. num = 0
  241. for w in self.co_consts_w:
  242. if isinstance(w, PyCode):
  243. consts[num] = w._to_code()
  244. else:
  245. consts[num] = self.space.unwrap(w)
  246. num += 1
  247. return new.code(self.co_argcount,
  248. self.co_nlocals,
  249. self.co_stacksize,
  250. self.co_flags,
  251. self.co_code,
  252. tuple(consts),
  253. tuple(self.co_names),
  254. tuple(self.co_varnames),
  255. self.co_filename,
  256. self.co_name,
  257. self.co_firstlineno,
  258. self.co_lnotab,
  259. tuple(self.co_freevars),
  260. tuple(self.co_cellvars))
  261. def exec_host_bytecode(self, w_globals, w_locals):
  262. if sys.version_info < (2, 7):
  263. raise Exception("PyPy no longer supports Python 2.6 or lower")
  264. frame = self.space.FrameClass(self.space, self, w_globals, None)
  265. frame.setdictscope(w_locals)
  266. return frame.run()
  267. def dump(self):
  268. """A dis.dis() dump of the code object."""
  269. co = self._to_code()
  270. dis.dis(co)
  271. def fget_co_consts(self, space):
  272. return space.newtuple(self.co_consts_w)
  273. def fget_co_names(self, space):
  274. return space.newtuple(self.co_names_w)
  275. def fget_co_varnames(self, space):
  276. return space.newtuple([space.wrap(name) for name in self.co_varnames])
  277. def fget_co_cellvars(self, space):
  278. return space.newtuple([space.wrap(name) for name in self.co_cellvars])
  279. def fget_co_freevars(self, space):
  280. return space.newtuple([space.wrap(name) for name in self.co_freevars])
  281. def descr_code__eq__(self, w_other):
  282. space = self.space
  283. if not isinstance(w_other, PyCode):
  284. return space.w_False
  285. areEqual = (self.co_name == w_other.co_name and
  286. self.co_argcount == w_other.co_argcount and
  287. self.co_nlocals == w_other.co_nlocals and
  288. self.co_flags == w_other.co_flags and
  289. self.co_firstlineno == w_other.co_firstlineno and
  290. self.co_code == w_other.co_code and
  291. len(self.co_consts_w) == len(w_other.co_consts_w) and
  292. len(self.co_names_w) == len(w_other.co_names_w) and
  293. self.co_varnames == w_other.co_varnames and
  294. self.co_freevars == w_other.co_freevars and
  295. self.co_cellvars == w_other.co_cellvars)
  296. if not areEqual:
  297. return space.w_False
  298. for i in range(len(self.co_names_w)):
  299. if not space.eq_w(self.co_names_w[i], w_other.co_names_w[i]):
  300. return space.w_False
  301. for i in range(len(self.co_consts_w)):
  302. if not space.eq_w(self.co_consts_w[i], w_other.co_consts_w[i]):
  303. return space.w_False
  304. return space.w_True
  305. def descr_code__hash__(self):
  306. space = self.space
  307. result = compute_hash(self.co_name)
  308. result ^= self.co_argcount
  309. result ^= self.co_nlocals
  310. result ^= self.co_flags
  311. result ^= self.co_firstlineno
  312. result ^= compute_hash(self.co_code)
  313. for name in self.co_varnames: result ^= compute_hash(name)
  314. for name in self.co_freevars: result ^= compute_hash(name)
  315. for name in self.co_cellvars: result ^= compute_hash(name)
  316. w_result = space.wrap(intmask(result))
  317. for w_name in self.co_names_w:
  318. w_result = space.xor(w_result, space.hash(w_name))
  319. for w_const in self.co_consts_w:
  320. w_result = space.xor(w_result, space.hash(w_const))
  321. return w_result
  322. @unwrap_spec(argcount=int, nlocals=int, stacksize=int, flags=int,
  323. codestring=str,
  324. filename=str, name=str, firstlineno=int,
  325. lnotab=str, magic=int)
  326. def descr_code__new__(space, w_subtype,
  327. argcount, nlocals, stacksize, flags,
  328. codestring, w_constants, w_names,
  329. w_varnames, filename, name, firstlineno,
  330. lnotab, w_freevars=None, w_cellvars=None,
  331. magic=default_magic):
  332. if argcount < 0:
  333. raise oefmt(space.w_ValueError,
  334. "code: argcount must not be negative")
  335. if nlocals < 0:
  336. raise oefmt(space.w_ValueError,
  337. "code: nlocals must not be negative")
  338. if not space.isinstance_w(w_constants, space.w_tuple):
  339. raise oefmt(space.w_TypeError, "Expected tuple for constants")
  340. consts_w = space.fixedview(w_constants)
  341. names = unpack_str_tuple(space, w_names)
  342. varnames = unpack_str_tuple(space, w_varnames)
  343. if w_freevars is not None:
  344. freevars = unpack_str_tuple(space, w_freevars)
  345. else:
  346. freevars = []
  347. if w_cellvars is not None:
  348. cellvars = unpack_str_tuple(space, w_cellvars)
  349. else:
  350. cellvars = []
  351. code = space.allocate_instance(PyCode, w_subtype)
  352. PyCode.__init__(code, space, argcount, nlocals, stacksize, flags, codestring, consts_w[:], names,
  353. varnames, filename, name, firstlineno, lnotab, freevars, cellvars, magic=magic)
  354. return space.wrap(code)
  355. def descr__reduce__(self, space):
  356. from pypy.interpreter.mixedmodule import MixedModule
  357. w_mod = space.getbuiltinmodule('_pickle_support')
  358. mod = space.interp_w(MixedModule, w_mod)
  359. new_inst = mod.get('code_new')
  360. w = space.wrap
  361. tup = [
  362. w(self.co_argcount),
  363. w(self.co_nlocals),
  364. w(self.co_stacksize),
  365. w(self.co_flags),
  366. space.newbytes(self.co_code),
  367. space.newtuple(self.co_consts_w),
  368. space.newtuple(self.co_names_w),
  369. space.newtuple([w(v) for v in self.co_varnames]),
  370. w(self.co_filename),
  371. w(self.co_name),
  372. w(self.co_firstlineno),
  373. space.newbytes(self.co_lnotab),
  374. space.newtuple([w(v) for v in self.co_freevars]),
  375. space.newtuple([w(v) for v in self.co_cellvars]),
  376. w(self.magic),
  377. ]
  378. return space.newtuple([new_inst, space.newtuple(tup)])
  379. def get_repr(self):
  380. return "<code object %s, file '%s', line %d>" % (
  381. self.co_name, self.co_filename, self.co_firstlineno)
  382. def __repr__(self):
  383. return self.get_repr()
  384. def repr(self, space):
  385. return space.wrap(self.get_repr())