[Python-Dev] Accessing globals without dict lookup (original) (raw)
Tim Peters tim.one@comcast.net
Mon, 11 Feb 2002 04:27:27 -0500
- Previous message: [Python-Dev] Accessing globals without dict lookup
- Next message: [Python-Dev] Accessing globals without dict lookup
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
[Jeremy Hylton]
Here's a brief review of the example function.
def mylen(s): return len(s) LOADBUILTIN 0 (len) LOADFAST 0 (s) CALLFUNCTION 1 RETURNVALUE The interpreter has a dlict for all the builtins. The details don't matter here.
Actually, the details are everything here .
Let's say that len is at index 4.
The function mylen has an array: funcbuiltinindex = [4] # an index for each builtin used in mylen The entry at index 0 of funcbuiltinindex is the index of len in the interpreter's builtin dlict. It is either initialized when the function is created or on first use of len.
All clear except for the referent of "It" (the subject of the preceding sentence is "The entry at index 0", but that doesn't seem to make much sense as a referent).
(It doesn't matter for the mechanism and there's no need to decide which is better yet.)
The module has an mdglobalsdirty flag. If it is true, then a global was introduced dynamically, i.e. a name binding op occurred that the compiler did not detect statically.
Once it becomes true, can md_globals_dirty ever become false again?
The code object has a cobuiltinnames that is like conames except that it only contains the names of builtins used by LOADBUILTIN. It's there to get the correct behavior when shadowing of a builtin by a local occurs at runtime. ^^^^^
Can that happen? Or did you mean when shadowing of a builtin by a global occurs at runtime? The LOAD_BUILTIN code below seems most consistent with the "global" rewording.
The frame grows a bunch of pointers --
fmodule from the function (which stores it instead of funcglobals) fbuiltinnames from the code object fbuiltins from the interpreter The implementation of LOADBUILTIN 0 is straightforward -- in pidgin C: case LOADBUILTIN: if (f->fmodule->mdglobalsdirty) { PyObject *w = PyTupleGETITEM(f->fbuiltinnames);
Presumably this is missing an ", oparg" argument.
... /* rest is just like current LOADGLOBAL except that is used PyDLictGetItem() */ } else { int builtinindex = f->fbuiltinindex[oparg]; PyObject *x = f->fbuiltins[builtinindex]; if (x == NULL) raise NameError PyINCREF(x); PUSH(x); }
OK, that's the gritty detail I was looking for. When it comes time to code, note that it's better to negate the test and swap the "if" branches (a not-taken branch is usually quicker than a taken branch, and you want to favor the expected case).
Question: couldn't the LOAD_BUILTIN opcode use builtin_index directly as its argument (and so skip one level of indirection)? We know which builtins the interpreter supplies, and the compiler could be taught a fixed correspondence between builtin names and little integers. There are only 114 keys in builtin.dict today, so there's plenty of room in an instruction to hold the index. A tuple of std builtin names could also be a C extern shared by everyone, eliminating the need for f_builtin_names.
The LOADGLOBAL opcode ends up looking basically the same, except that it doesn't need to check mdglobalsdirty.
case LOADGLOBAL: int globalindex = f->fglobalindex[oparg]; PyObject *x = f->fmodule->mdglobals[globalindex]; if (x == NULL) { check for dynamically introduced builtin } PyINCREF(x); PUSH(x);
f_global_index wasn't mentioned before its appearance in this code block. I can guess what it is. Again I wonder whether it's possible to snip a layer of indirection (for a fixed function and fixed oparg, can f->f_global_index[oparg] change across invocations of LOAD_GLOBAL? I'm guessing "no", in which case a third of the normal-case code is burning cycles without real need).
In the x == NULL case above, we need to take extra care for a builtin that the compiler didn't expect. It's an odd case. There is a global for the module named spam
The module is named spam, or the global is named spam? I think the latter was intended.
that hasn't yet been assigned to in the module and there's also a builtin named spam that will be hidden once spam is bound in the module.
And can also be revealed again if someone reaches into the module and del's spam again, right?
This looks fast, provided it works , and is along the lines of what I had in mind when I first tortured Guido with the idea of dlicts way back when. One major correction: you pronounce it "dee-likt". That's a travesty. I picked the name dlict because it's unpronounceable in any human language -- as befits an unthinkable idea .
- Previous message: [Python-Dev] Accessing globals without dict lookup
- Next message: [Python-Dev] Accessing globals without dict lookup
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]