# PyPy[chained_getattr]

PyPy[chained_getattr]
news getting-started documentation svn issues contact EU/project

"chained getattr/module global lookup" optimization (discussion during trillke-sprint 2007, anto/holger, a bit of samuele and cf earlier on)

random example:

> code:
>   import os.path normed = [os.path.normpath(p) for p in somelist]
> bytecode:
>   [...]
>     LOAD_GLOBAL (os) LOAD_ATTR (path) LOAD_ATTR (normpath) LOAD_FAST (p) CALL_FUNCTION 1

> would be turned by pypy-compiler into:

> > LOAD_CHAINED_GLOBAL (os,path,normpath) LOAD_FAST (p) CALL_FUNCTION 1

> now for the LOAD_CHAINED_GLOBAL bytecode implementation:

> > Module dicts have a special implemnetation, providing:

> > - an extra "fastlookup" rpython-dict serving as a cache for LOAD_CHAINED_GLOBAL places within the modules:

> >   - keys are e.g. ('os', 'path', 'normpath')

> >   - values are tuples of the form: ([obj1, obj2, obj3], [ver1, ver2])

> >     > "ver1" refer to the version of the globals of "os" "ver2" refer to the version of the globals of "os.path" "obj3" is the resulting "normpath" function

> > - upon changes to the global dict, "fastlookup.clear()" is called

> > - after the fastlookup entry is filled for a given LOAD_CHAINED_GLOBAL index, the following checks need to be performed in the bytecode implementation:

> >         value = f_globals.fastlookup.get(key, None)
> >         if value is None:
> >            # fill entry
> >         else:
> >             # check that our cached lookups are still valid
> >             assert isinstance(value, tuple)
> >             objects, versions = value
> >             i = 0
> >             while i < len(versions):
> >                 lastversion = versions[i]
> >                 ver = getver_for_obj(objects[i])
> >                 if ver == -1 or ver != lastversion:
> >                    name = key[i]
> >                    objects[i] = space.getattr(curobj, name)
> >                    versions[i] = ver
> >                 curobj = objects[i]
> >                 i += 1
> >         return objects[i]

> >       def getver_for_obj(obj):
> >           if "obj is not Module":
> >               return -1
> >           return obj.w_dict.version