
Hi, 2016-01-10 6:23 GMT+01:00 Chris Angelico <rosuav@gmail.com>:
Consider:
def enumerate_classes(): return (cls.__name__ for cls in object.__subclasses__())
As long as nobody has *rebound* the name 'object', this will continue to work - and it'll pick up new subclasses, which means that something's mutable or non-pure in there. FAT Python should be able to handle this just as easily as it handles an immutable. The only part that has to be immutable is the string "len" or "object" that is used as the key.
FYI I implemented a "copy builtin to constant" optimization which replaces "LOAD_GLOBAL object" instruction with "LOAD_CONST <object function>": https://faster-cpython.readthedocs.org/fat_python.html#fat-copy-builtin-to-c... It uses a guard on the builtin and global namespaces to disable the optimization if object is replaced. If you want to make object.__subclasses__ constant, we need more guards: * guard on the object.__subclasses__ attribute * guard on the private tp_version_tag attribute of the object type * ... and it looks like object.__subclasses__ uses weak references, so I'm not sure that it's really possible to make object.__subclasses__() constant with guards. Is it really worth it? Is it a common case? Oh... I just remember that the "type" type already implements a version as I propose for dict. It's called "tp_version_tag" and it's private. It has the C type "unsigned int" and it's incremented at each modification.
And that's where it might be important to check more than just the identity of the object. If len were implemented in Python:
def len(x): ... l = 0 ... for l, _ in enumerate(x, 1): pass ... return l ... len("abc") 3 len <function len at 0x7fc6111769d8>
then it would be possible to keep the same len object but change its behaviour.
len.__code__ = (lambda x: 5).__code__ len <function len at 0x7fc6111769d8> len("abc") 5
Does anyone EVER do this?
FAT Python implements a fat.GuardFunc which checks if func.__code__ was replaced or not. It doesn't matter if replacing replacing func.__code__ is unlikely. An optimizer must not change the Python semantic, otherwise it will break some applications and cannot be used widely.
if FAT Python has an optimization flag that says "Assume no __code__ objects are ever replaced", most programs would have no problem with it. (Having it trigger an immediate exception would mean there's no "what the bleep is going on" moment, and I still doubt it'll ever happen.)
In my plan, I will add an option to skip guards if you are 100% sure that some things will never change. For example, if you control all code of your application (not only the app itself, all modules) and you know that func.__code__ is never replaced, you can skip fat.GuardFunc (not emit them).
I think there are some interesting possibilities here. Whether they actually result in real improvement I don't know; but if FAT Python is aiming to be fast at the "start program, do a tiny bit of work, and then terminate" execution model (where JIT compilation can't help), then it could potentially make Mercurial a *lot* faster to fiddle with.
FAT Python is designed to compile the code ahead of code. The installation can be pre-optimized in a package, or optimized at the installation, but it's not optimized when the program is started. If the optimization are efficient, the program will run faster, even for short living programs (yes, like Mercurial). Victor