PyPy has lots of documents but some of them are not easy to read because it deals with PyPy internal architecture as well as PyPy usage, several comments are only for implementing Python on Python, while others are more generic and for every RPython scripts, and there are lots of levels of things, CPython v.s. RPython, application level objects v.s. interpreter level objects ... so I will suggest in what order you read PyPy documents.
The order I recommend is, you first read getting-started just briefly ignoring every stuff you cannot understand, then architecture then coding-guide then translation. Do not read documents regarding new features such as What PyPy can do for your objects first, though it's the first thing you see in the PyPy documentation list.
Here I will make some more comments on different PyPy topics randomly.
One good thing about outputting llvm code is that it can take advantage of llvm's powerful optimization, both llvm bit code level and processor dependent. From the llvm point of view, PyPy is a llvm Python front end(more precisely RPython frontend). I haven't tested a lot but it's definitely a cool topic.
PyPy translates RPython into other languages from a Python object, not the script directly. It means what you pass to the translator is your function object, not a string nor a file path that contains RPython script.
They have added some to PyPy that doesn't exist in CPython such as optional stackless features. Lazy computed objects is another.
Talking about PyPy implementation, "object space" is interesting. PyPy uses a "standard object space" to execute Python scripts. When it generates a control flow graph (which is used when it translates RPython into another language), it just replaces the standard object space with "flow object space", so for the rest of PyPy, it looks as if the script is executed but the result is a control flow graph, not script execution. I'm not interested in the details but understanding the concept made it easier to read the document.
I just found a tiny bug.
for a in [1, 2, 3]:
1 2 3
f() prints nothing after it is c-compiled. It works as expected if I remove comma after "print a".