"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