[Python-Dev] Re: Code Generation Idea Was: Bytecode idea
Ludovic Aubry
Ludovic.Aubry@logilab.fr
Wed, 26 Feb 2003 19:56:46 +0100
On Wed, Feb 26, 2003 at 01:06:44PM -0500, Terry Reedy wrote:
>
> "Skip Montanaro" <skip@pobox.com> wrote in message
> news:15964.59840.342254.176499@montanaro.dyndns.org...
> > For code that wants to cleanly cross the boundary between Python
> with no
> > boolean type and Python with a boolean type, you sometimes see
> >
> > True = 1==1
> > False = 1==0
> >
> > You get True and False if it didn't exist before and have the added
> benefit
> > that if it does exist, it gets found in globals() or locals()
> instead of in
> > __builtins__ and has the right type.
>
> This suggests a more radical optimization that might do more speedup
> than all the byte-code fiddling currently proposed: automatically
> localize, at definition time, builtins used within a function. This
> would be like giving each function a customized implicit set of
> default args: True=True, None=None, len=len, ...etc.
> If a program alters __builtins__, def statement placement would
> determine which version gets used.
>
Hi,
I have a piece of code that does (almost) exactly that, except at
runtime.
It's purpose is to optimize access to globals used as constants by
replacing the LOAD_GLOBAL opcode by a LOAD_CONST.
It does that by creating a new code object for the function you provide
and using a list of symbols to consider constant.
I called it bind, because it works like the postscript bind operator
the code for the main function is below, you can find the full module
at ftp://ftp.logilab.org/pub/tmp/bind.py
it can provide a 10% speedup although most of the time it is around 3% to 5%
regards,
Ludovic
from dis import HAVE_ARGUMENT
from new import code as make_code, function as make_function
import inspect
LOAD_GLOBAL = 116
LOAD_CONST = 100
EXTENDED_ARG = 143
STORE_GLOBAL = 97
def bind_code(co,globals):
"""Take a code object and a dictionnary and returns a
new code object where the opcodes LOAD_GLOBAL are replaced
by LOAD_CONST whenever the global's name appear in the
dictionnary"""
consts = list(co.co_consts)
assigned = {}
code = co.co_code
new_code=""
n = len(code)
i = 0
while i < n:
c = code[i]
op = ord(c)
i+=1
if op >= HAVE_ARGUMENT:
oparg = ord(code[i]) + ord(code[i+1])*256
i += 2
else:
oparg=None
if op == LOAD_GLOBAL:
name = co.co_names[oparg]
if globals.has_key(name):
k = assigned.get(name,None)
if k==None:
k=len(consts)
assigned[name]=len(consts)
consts.append(globals[name])
op = LOAD_CONST
oparg=k
new_code+=chr(op)
if oparg is not None:
new_code += chr(oparg & 255)
new_code += chr( (oparg>>8) & 255 )
return make_code(co.co_argcount,
co.co_nlocals,
co.co_stacksize,
co.co_flags,
new_code,
tuple(consts),
co.co_names,
co.co_varnames,
co.co_filename,
co.co_name,
co.co_firstlineno,
co.co_lnotab )
def bind(f,globals):
"""Returns a new function whose code object has been
bound by bind_code()"""
newcode = bind_code(f.func_code,globals)
defaults = f.func_defaults or ()
return make_function(newcode,f.func_globals,f.func_name,defaults)
--
Ludovic Aubry LOGILAB, Paris (France).
http://www.logilab.com http://www.logilab.fr http://www.logilab.org