mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
Changes to speed up local variables enormously, by avoiding dictionary
lookup (opcode.h, ceval.[ch], compile.c, frameobject.[ch], pythonrun.c, import.c). The .pyc MAGIC number is changed again. Added get_menu_text to flmodule.
This commit is contained in:
parent
0023078a0b
commit
8b17d6bd89
9 changed files with 245 additions and 71 deletions
|
@ -28,6 +28,7 @@ object *call_object PROTO((object *, object *));
|
||||||
|
|
||||||
object *getglobals PROTO((void));
|
object *getglobals PROTO((void));
|
||||||
object *getlocals PROTO((void));
|
object *getlocals PROTO((void));
|
||||||
|
void mergelocals PROTO((void));
|
||||||
|
|
||||||
void printtraceback PROTO((object *));
|
void printtraceback PROTO((object *));
|
||||||
void flushline PROTO((void));
|
void flushline PROTO((void));
|
||||||
|
|
|
@ -36,6 +36,8 @@ typedef struct _frame {
|
||||||
codeobject *f_code; /* code segment */
|
codeobject *f_code; /* code segment */
|
||||||
object *f_globals; /* global symbol table (dictobject) */
|
object *f_globals; /* global symbol table (dictobject) */
|
||||||
object *f_locals; /* local symbol table (dictobject) */
|
object *f_locals; /* local symbol table (dictobject) */
|
||||||
|
object *f_fastlocals; /* fast local variables (listobject) */
|
||||||
|
object *f_localmap; /* local variable names (dictobject) */
|
||||||
object **f_valuestack; /* malloc'ed array */
|
object **f_valuestack; /* malloc'ed array */
|
||||||
block *f_blockstack; /* malloc'ed array */
|
block *f_blockstack; /* malloc'ed array */
|
||||||
int f_nvalues; /* size of f_valuestack */
|
int f_nvalues; /* size of f_valuestack */
|
||||||
|
|
|
@ -72,10 +72,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#define RAISE_EXCEPTION 81
|
#define RAISE_EXCEPTION 81
|
||||||
#define LOAD_LOCALS 82
|
#define LOAD_LOCALS 82
|
||||||
#define RETURN_VALUE 83
|
#define RETURN_VALUE 83
|
||||||
/*
|
|
||||||
#define REQUIRE_ARGS 84
|
|
||||||
#define REFUSE_ARGS 85
|
|
||||||
*/
|
|
||||||
#define BUILD_FUNCTION 86
|
#define BUILD_FUNCTION 86
|
||||||
#define POP_BLOCK 87
|
#define POP_BLOCK 87
|
||||||
#define END_FINALLY 88
|
#define END_FINALLY 88
|
||||||
|
@ -113,14 +110,15 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#define LOAD_LOCAL 115 /* Index in name list */
|
#define LOAD_LOCAL 115 /* Index in name list */
|
||||||
#define LOAD_GLOBAL 116 /* Index in name list */
|
#define LOAD_GLOBAL 116 /* Index in name list */
|
||||||
|
|
||||||
#define LOAD_FAST 117 /* Local variable number */
|
|
||||||
#define STORE_FAST 118 /* Local variable number */
|
|
||||||
#define RESERVE_FAST 119 /* Number of local variables */
|
|
||||||
|
|
||||||
#define SETUP_LOOP 120 /* Target address (absolute) */
|
#define SETUP_LOOP 120 /* Target address (absolute) */
|
||||||
#define SETUP_EXCEPT 121 /* "" */
|
#define SETUP_EXCEPT 121 /* "" */
|
||||||
#define SETUP_FINALLY 122 /* "" */
|
#define SETUP_FINALLY 122 /* "" */
|
||||||
|
|
||||||
|
#define RESERVE_FAST 123 /* Number of local variables */
|
||||||
|
#define LOAD_FAST 124 /* Local variable number */
|
||||||
|
#define STORE_FAST 125 /* Local variable number */
|
||||||
|
#define DELETE_FAST 126 /* Local variable number */
|
||||||
|
|
||||||
#define SET_LINENO 127 /* Current line number */
|
#define SET_LINENO 127 /* Current line number */
|
||||||
|
|
||||||
/* Comparison operator codes (argument to COMPARE_OP) */
|
/* Comparison operator codes (argument to COMPARE_OP) */
|
||||||
|
|
|
@ -1200,6 +1200,14 @@ get_menu (g, args)
|
||||||
return call_forms_Ri (fl_get_menu, g-> ob_generic, args);
|
return call_forms_Ri (fl_get_menu, g-> ob_generic, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static object *
|
||||||
|
get_menu_text (g, args)
|
||||||
|
genericobject *g;
|
||||||
|
object *args;
|
||||||
|
{
|
||||||
|
return call_forms_Rstr (fl_get_menu_text, g-> ob_generic, args);
|
||||||
|
}
|
||||||
|
|
||||||
static object *
|
static object *
|
||||||
addto_menu (g, args)
|
addto_menu (g, args)
|
||||||
genericobject *g;
|
genericobject *g;
|
||||||
|
@ -1211,6 +1219,7 @@ addto_menu (g, args)
|
||||||
static struct methodlist menu_methods[] = {
|
static struct methodlist menu_methods[] = {
|
||||||
{"set_menu", set_menu},
|
{"set_menu", set_menu},
|
||||||
{"get_menu", get_menu},
|
{"get_menu", get_menu},
|
||||||
|
{"get_menu_text", get_menu_text},
|
||||||
{"addto_menu", addto_menu},
|
{"addto_menu", addto_menu},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,6 +38,8 @@ static struct memberlist frame_memberlist[] = {
|
||||||
{"f_code", T_OBJECT, OFF(f_code)},
|
{"f_code", T_OBJECT, OFF(f_code)},
|
||||||
{"f_globals", T_OBJECT, OFF(f_globals)},
|
{"f_globals", T_OBJECT, OFF(f_globals)},
|
||||||
{"f_locals", T_OBJECT, OFF(f_locals)},
|
{"f_locals", T_OBJECT, OFF(f_locals)},
|
||||||
|
{"f_fastlocals",T_OBJECT, OFF(f_fastlocals)},
|
||||||
|
{"f_localmap", T_OBJECT, OFF(f_localmap)},
|
||||||
{"f_lasti", T_INT, OFF(f_lasti)},
|
{"f_lasti", T_INT, OFF(f_lasti)},
|
||||||
{"f_lineno", T_INT, OFF(f_lineno)},
|
{"f_lineno", T_INT, OFF(f_lineno)},
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
|
@ -82,6 +84,8 @@ frame_dealloc(f)
|
||||||
XDECREF(f->f_code);
|
XDECREF(f->f_code);
|
||||||
XDECREF(f->f_globals);
|
XDECREF(f->f_globals);
|
||||||
XDECREF(f->f_locals);
|
XDECREF(f->f_locals);
|
||||||
|
XDECREF(f->f_fastlocals);
|
||||||
|
XDECREF(f->f_localmap);
|
||||||
f->f_back = free_list;
|
f->f_back = free_list;
|
||||||
free_list = f;
|
free_list = f;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +146,8 @@ newframeobject(back, code, globals, locals, nvalues, nblocks)
|
||||||
f->f_globals = globals;
|
f->f_globals = globals;
|
||||||
INCREF(locals);
|
INCREF(locals);
|
||||||
f->f_locals = locals;
|
f->f_locals = locals;
|
||||||
|
f->f_fastlocals = NULL;
|
||||||
|
f->f_localmap = NULL;
|
||||||
if (nvalues > f->f_nvalues || f->f_valuestack == NULL) {
|
if (nvalues > f->f_nvalues || f->f_valuestack == NULL) {
|
||||||
XDEL(f->f_valuestack);
|
XDEL(f->f_valuestack);
|
||||||
f->f_valuestack = NEW(object *, nvalues+1);
|
f->f_valuestack = NEW(object *, nvalues+1);
|
||||||
|
|
134
Python/ceval.c
134
Python/ceval.c
|
@ -81,6 +81,7 @@ static int cmp_member PROTO((object *, object *));
|
||||||
static object *cmp_outcome PROTO((int, object *, object *));
|
static object *cmp_outcome PROTO((int, object *, object *));
|
||||||
static int import_from PROTO((object *, object *, object *));
|
static int import_from PROTO((object *, object *, object *));
|
||||||
static object *build_class PROTO((object *, object *));
|
static object *build_class PROTO((object *, object *));
|
||||||
|
static void locals_2_fast PROTO((frameobject *, int));
|
||||||
|
|
||||||
|
|
||||||
/* Pointer to current frame, used to link new frames to */
|
/* Pointer to current frame, used to link new frames to */
|
||||||
|
@ -994,19 +995,51 @@ eval_code(co, globals, locals, arg)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RESERVE_FAST:
|
case RESERVE_FAST:
|
||||||
if (oparg > 0) {
|
x = GETCONST(oparg);
|
||||||
XDECREF(fastlocals);
|
if (x == None)
|
||||||
x = newlistobject(oparg);
|
break;
|
||||||
fastlocals = (listobject *) x;
|
if (x == NULL || !is_dictobject(x)) {
|
||||||
|
fatal("bad RESERVE_FAST");
|
||||||
|
err_setstr(SystemError, "bad RESERVE_FAST");
|
||||||
|
x = NULL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
XDECREF(f->f_fastlocals);
|
||||||
|
XDECREF(f->f_localmap);
|
||||||
|
INCREF(x);
|
||||||
|
f->f_localmap = x;
|
||||||
|
f->f_fastlocals = x = newlistobject(
|
||||||
|
x->ob_type->tp_as_mapping->mp_length(x));
|
||||||
|
fastlocals = (listobject *) x;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOAD_FAST:
|
case LOAD_FAST:
|
||||||
/* NYI */
|
x = GETLISTITEM(fastlocals, oparg);
|
||||||
|
if (x == NULL) {
|
||||||
|
err_setstr(NameError,
|
||||||
|
"undefined local variable");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
INCREF(x);
|
||||||
|
PUSH(x);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STORE_FAST:
|
case STORE_FAST:
|
||||||
/* NYI */
|
w = GETLISTITEM(fastlocals, oparg);
|
||||||
|
XDECREF(w);
|
||||||
|
w = POP();
|
||||||
|
GETLISTITEM(fastlocals, oparg) = w;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DELETE_FAST:
|
||||||
|
x = GETLISTITEM(fastlocals, oparg);
|
||||||
|
if (x == NULL) {
|
||||||
|
err_setstr(NameError,
|
||||||
|
"undefined local variable");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DECREF(x);
|
||||||
|
GETLISTITEM(fastlocals, oparg) = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUILD_TUPLE:
|
case BUILD_TUPLE:
|
||||||
|
@ -1068,6 +1101,7 @@ eval_code(co, globals, locals, arg)
|
||||||
w = GETNAMEV(oparg);
|
w = GETNAMEV(oparg);
|
||||||
v = TOP();
|
v = TOP();
|
||||||
err = import_from(f->f_locals, v, w);
|
err = import_from(f->f_locals, v, w);
|
||||||
|
locals_2_fast(f, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JUMP_FORWARD:
|
case JUMP_FORWARD:
|
||||||
|
@ -1300,8 +1334,6 @@ eval_code(co, globals, locals, arg)
|
||||||
current_frame = f->f_back;
|
current_frame = f->f_back;
|
||||||
DECREF(f);
|
DECREF(f);
|
||||||
|
|
||||||
XDECREF(fastlocals);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1418,10 +1450,92 @@ call_trace(p_trace, p_newtrace, f, msg, arg)
|
||||||
object *
|
object *
|
||||||
getlocals()
|
getlocals()
|
||||||
{
|
{
|
||||||
if (current_frame == NULL)
|
/* Merge f->f_fastlocals into f->f_locals, then return the latter */
|
||||||
|
frameobject *f;
|
||||||
|
object *locals, *fast, *map;
|
||||||
|
int i;
|
||||||
|
f = current_frame;
|
||||||
|
if (f == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
locals = f->f_locals;
|
||||||
|
fast = f->f_fastlocals;
|
||||||
|
map = f->f_localmap;
|
||||||
|
if (locals == NULL || fast == NULL || map == NULL)
|
||||||
|
return locals;
|
||||||
|
if (!is_dictobject(locals) || !is_listobject(fast) ||
|
||||||
|
!is_dictobject(map))
|
||||||
|
return locals;
|
||||||
|
i = getdictsize(map);
|
||||||
|
while (--i >= 0) {
|
||||||
|
object *key;
|
||||||
|
object *value;
|
||||||
|
int j;
|
||||||
|
key = getdict2key(map, i);
|
||||||
|
if (key == NULL)
|
||||||
|
continue;
|
||||||
|
value = dict2lookup(map, key);
|
||||||
|
if (value == NULL || !is_intobject(value))
|
||||||
|
continue;
|
||||||
|
j = getintvalue(value);
|
||||||
|
value = getlistitem(fast, j);
|
||||||
|
if (value == NULL) {
|
||||||
|
err_clear();
|
||||||
|
if (dict2remove(locals, key) != 0)
|
||||||
|
err_clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (dict2insert(locals, key, value) != 0)
|
||||||
|
err_clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return locals;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
locals_2_fast(f, clear)
|
||||||
|
frameobject *f;
|
||||||
|
int clear;
|
||||||
|
{
|
||||||
|
/* Merge f->f_locals into f->f_fastlocals */
|
||||||
|
object *locals, *fast, *map;
|
||||||
|
int i;
|
||||||
|
if (f == NULL)
|
||||||
|
return;
|
||||||
|
locals = f->f_locals;
|
||||||
|
fast = f->f_fastlocals;
|
||||||
|
map = f->f_localmap;
|
||||||
|
if (locals == NULL || fast == NULL || map == NULL)
|
||||||
|
return;
|
||||||
|
if (!is_dictobject(locals) || !is_listobject(fast) ||
|
||||||
|
!is_dictobject(map))
|
||||||
|
return;
|
||||||
|
i = getdictsize(map);
|
||||||
|
while (--i >= 0) {
|
||||||
|
object *key;
|
||||||
|
object *value;
|
||||||
|
int j;
|
||||||
|
key = getdict2key(map, i);
|
||||||
|
if (key == NULL)
|
||||||
|
continue;
|
||||||
|
value = dict2lookup(map, key);
|
||||||
|
if (value == NULL || !is_intobject(value))
|
||||||
|
continue;
|
||||||
|
j = getintvalue(value);
|
||||||
|
value = dict2lookup(locals, key);
|
||||||
|
if (value == NULL)
|
||||||
|
err_clear();
|
||||||
else
|
else
|
||||||
return current_frame->f_locals;
|
INCREF(value);
|
||||||
|
if (value != NULL || clear)
|
||||||
|
if (setlistitem(fast, j, value) != 0)
|
||||||
|
err_clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mergelocals()
|
||||||
|
{
|
||||||
|
locals_2_fast(current_frame, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
object *
|
object *
|
||||||
|
|
131
Python/compile.c
131
Python/compile.c
|
@ -27,7 +27,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
/* XXX TO DO:
|
/* XXX TO DO:
|
||||||
XXX Compute maximum needed stack sizes while compiling
|
XXX Compute maximum needed stack sizes while compiling
|
||||||
XXX Generate simple jump for break/return outside 'try...finally'
|
XXX Generate simple jump for break/return outside 'try...finally'
|
||||||
XXX Include function name in code (and module names?)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "allobjects.h"
|
#include "allobjects.h"
|
||||||
|
@ -2032,7 +2031,7 @@ compile_funcdef(c, n)
|
||||||
node *ch;
|
node *ch;
|
||||||
REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
|
REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
|
||||||
c->c_name = STR(CHILD(n, 1));
|
c->c_name = STR(CHILD(n, 1));
|
||||||
com_addoparg(c, RESERVE_FAST, 0); /* Patched up later */
|
com_addoparg(c, RESERVE_FAST, com_addconst(c, None)); /* Patched! */
|
||||||
ch = CHILD(n, 2); /* parameters: '(' [varargslist] ')' */
|
ch = CHILD(n, 2); /* parameters: '(' [varargslist] ')' */
|
||||||
ch = CHILD(ch, 1); /* ')' | varargslist */
|
ch = CHILD(ch, 1); /* ')' | varargslist */
|
||||||
if (TYPE(ch) == RPAR)
|
if (TYPE(ch) == RPAR)
|
||||||
|
@ -2100,79 +2099,95 @@ compile_node(c, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optimization for local and global variables.
|
/* Optimization for local variables in functions (and *only* functions).
|
||||||
|
|
||||||
XXX Need to update this text for LOAD_FAST stuff...
|
This replaces all LOAD_NAME, STORE_NAME and DELETE_NAME
|
||||||
|
instructions that refer to local variables with LOAD_FAST etc.
|
||||||
Attempt to replace all LOAD_NAME instructions that refer to a local
|
The latter instructions are much faster because they don't need to
|
||||||
variable with LOAD_LOCAL instructions, and all that refer to a global
|
look up the variable name in a dictionary.
|
||||||
variable with LOAD_GLOBAL instructions.
|
|
||||||
|
|
||||||
To find all local variables, we check all STORE_NAME and IMPORT_FROM
|
To find all local variables, we check all STORE_NAME and IMPORT_FROM
|
||||||
instructions. This yields all local variables, including arguments,
|
instructions. This yields all local variables, including arguments,
|
||||||
function definitions, class definitions and import statements.
|
function definitions, class definitions and import statements.
|
||||||
|
(We don't check DELETE_NAME instructions, since if there's no
|
||||||
|
STORE_NAME the DELETE_NAME will surely fail.)
|
||||||
|
|
||||||
There is one leak: 'from foo import *' introduces local variables
|
There is one problem: 'from foo import *' introduces local variables
|
||||||
that we can't know while compiling. If this is the case, LOAD_GLOBAL
|
that we can't know while compiling. If this is the case, wo don't
|
||||||
instructions are not generated -- LOAD_NAME is left in place for
|
optimize at all (this rarely happens, since import is mostly used
|
||||||
globals, since it first checks for globals (LOAD_LOCAL is still used
|
at the module level).
|
||||||
for recognized locals, since it doesn't hurt).
|
|
||||||
|
|
||||||
This optimization means that using the same name as a global and
|
Note that, because of this optimization, code like the following
|
||||||
as a local variable within the same scope is now illegal, which
|
won't work:
|
||||||
is a change to the language! Also using eval() to introduce new
|
eval('x = 1')
|
||||||
local variables won't work. But both were bad practice at best.
|
print x
|
||||||
|
|
||||||
The optimization doesn't save much: basically, it saves one
|
|
||||||
unsuccessful dictionary lookup per global (or built-in) variable
|
|
||||||
reference. On the (slow!) Mac Plus, with 4 local variables,
|
|
||||||
this saving was measured to be about 0.18 ms. We might save more
|
|
||||||
by using a different data structure to hold local variables, like
|
|
||||||
an array indexed by variable number.
|
|
||||||
|
|
||||||
NB: this modifies the string object co->co_code!
|
NB: this modifies the string object co->co_code!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
optimizer(co)
|
optimize(c)
|
||||||
codeobject *co;
|
struct compiling *c;
|
||||||
{
|
{
|
||||||
unsigned char *next_instr, *cur_instr;
|
unsigned char *next_instr, *cur_instr;
|
||||||
object *locals;
|
object *locals;
|
||||||
|
int nlocals;
|
||||||
int opcode;
|
int opcode;
|
||||||
int oparg;
|
int oparg;
|
||||||
object *name;
|
object *name;
|
||||||
int star_used;
|
int fast_reserved;
|
||||||
|
object *error_type, *error_value;
|
||||||
|
|
||||||
#define NEXTOP() (*next_instr++)
|
#define NEXTOP() (*next_instr++)
|
||||||
#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
|
#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
|
||||||
#define GETITEM(v, i) (getlistitem((v), (i)))
|
#define GETITEM(v, i) (getlistitem((v), (i)))
|
||||||
#define GETNAMEOBJ(i) (GETITEM(co->co_names, (i)))
|
#define GETNAMEOBJ(i) (GETITEM(c->c_names, (i)))
|
||||||
|
|
||||||
locals = newdictobject();
|
locals = newdictobject();
|
||||||
if (locals == NULL) {
|
if (locals == NULL) {
|
||||||
err_clear();
|
c->c_errors++;
|
||||||
return; /* For now, this is OK */
|
return;
|
||||||
}
|
}
|
||||||
|
nlocals = 0;
|
||||||
|
|
||||||
next_instr = (unsigned char *) GETSTRINGVALUE(co->co_code);
|
err_get(&error_type, &error_value);
|
||||||
|
|
||||||
|
next_instr = (unsigned char *) getstringvalue(c->c_code);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
opcode = NEXTOP();
|
opcode = NEXTOP();
|
||||||
if (opcode == STOP_CODE)
|
if (opcode == STOP_CODE)
|
||||||
break;
|
break;
|
||||||
if (HAS_ARG(opcode))
|
if (HAS_ARG(opcode))
|
||||||
oparg = NEXTARG();
|
oparg = NEXTARG();
|
||||||
if (opcode == STORE_NAME || opcode == IMPORT_FROM) {
|
if (opcode == STORE_NAME || opcode == DELETE_NAME ||
|
||||||
|
opcode == IMPORT_FROM) {
|
||||||
|
object *v;
|
||||||
name = GETNAMEOBJ(oparg);
|
name = GETNAMEOBJ(oparg);
|
||||||
if (dict2insert(locals, name, None) != 0) {
|
if (dict2lookup(locals, name) != NULL)
|
||||||
DECREF(locals);
|
continue;
|
||||||
return; /* Sorry */
|
err_clear();
|
||||||
|
v = newintobject(nlocals);
|
||||||
|
if (v == NULL) {
|
||||||
|
c->c_errors++;
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
nlocals++;
|
||||||
|
if (dict2insert(locals, name, v) != 0) {
|
||||||
|
DECREF(v);
|
||||||
|
c->c_errors++;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
DECREF(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
star_used = (dictlookup(locals, "*") != NULL);
|
if (nlocals == 0 || dictlookup(locals, "*") != NULL) {
|
||||||
next_instr = (unsigned char *) GETSTRINGVALUE(co->co_code);
|
/* Don't optimize anything */
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_instr = (unsigned char *) getstringvalue(c->c_code);
|
||||||
|
fast_reserved = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
cur_instr = next_instr;
|
cur_instr = next_instr;
|
||||||
opcode = NEXTOP();
|
opcode = NEXTOP();
|
||||||
|
@ -2180,18 +2195,40 @@ optimizer(co)
|
||||||
break;
|
break;
|
||||||
if (HAS_ARG(opcode))
|
if (HAS_ARG(opcode))
|
||||||
oparg = NEXTARG();
|
oparg = NEXTARG();
|
||||||
if (opcode == LOAD_NAME) {
|
if (opcode == RESERVE_FAST) {
|
||||||
name = GETNAMEOBJ(oparg);
|
int i = com_addconst(c, locals);
|
||||||
if (dict2lookup(locals, name) != NULL)
|
cur_instr[1] = i & 0xff;
|
||||||
*cur_instr = LOAD_LOCAL;
|
cur_instr[2] = (i>>8) & 0xff;
|
||||||
else {
|
fast_reserved = 1;
|
||||||
err_clear();
|
continue;
|
||||||
if (!star_used)
|
|
||||||
*cur_instr = LOAD_GLOBAL;
|
|
||||||
}
|
}
|
||||||
|
if (!fast_reserved)
|
||||||
|
continue;
|
||||||
|
if (opcode == LOAD_NAME ||
|
||||||
|
opcode == STORE_NAME ||
|
||||||
|
opcode == DELETE_NAME) {
|
||||||
|
object *v;
|
||||||
|
int i;
|
||||||
|
name = GETNAMEOBJ(oparg);
|
||||||
|
v = dict2lookup(locals, name);
|
||||||
|
if (v == NULL) {
|
||||||
|
err_clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i = getintvalue(v);
|
||||||
|
switch (opcode) {
|
||||||
|
case LOAD_NAME: cur_instr[0] = LOAD_FAST; break;
|
||||||
|
case STORE_NAME: cur_instr[0] = STORE_FAST; break;
|
||||||
|
case DELETE_NAME: cur_instr[0] = DELETE_FAST; break;
|
||||||
|
}
|
||||||
|
cur_instr[1] = i & 0xff;
|
||||||
|
cur_instr[2] = (i>>8) & 0xff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
err_setval(error_type, error_value);
|
||||||
|
err:
|
||||||
DECREF(locals);
|
DECREF(locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2206,6 +2243,8 @@ compile(n, filename)
|
||||||
return NULL;
|
return NULL;
|
||||||
compile_node(&sc, n);
|
compile_node(&sc, n);
|
||||||
com_done(&sc);
|
com_done(&sc);
|
||||||
|
if (TYPE(n) == funcdef && sc.c_errors == 0)
|
||||||
|
optimize(&sc);
|
||||||
co = NULL;
|
co = NULL;
|
||||||
if (sc.c_errors == 0) {
|
if (sc.c_errors == 0) {
|
||||||
object *v, *w;
|
object *v, *w;
|
||||||
|
@ -2218,7 +2257,5 @@ compile(n, filename)
|
||||||
XDECREF(w);
|
XDECREF(w);
|
||||||
}
|
}
|
||||||
com_free(&sc);
|
com_free(&sc);
|
||||||
if (co != NULL && filename[0] != '<')
|
|
||||||
optimizer(co);
|
|
||||||
return co;
|
return co;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ extern char *argv0;
|
||||||
|
|
||||||
/* Magic word to reject pre-0.9.9 .pyc files */
|
/* Magic word to reject pre-0.9.9 .pyc files */
|
||||||
|
|
||||||
#define MAGIC 0x99BE2AL
|
#define MAGIC 0x99BE3AL
|
||||||
|
|
||||||
static object *modules;
|
static object *modules;
|
||||||
|
|
||||||
|
|
|
@ -304,16 +304,23 @@ run_node(n, filename, globals, locals)
|
||||||
char *filename;
|
char *filename;
|
||||||
/*dict*/object *globals, *locals;
|
/*dict*/object *globals, *locals;
|
||||||
{
|
{
|
||||||
|
object *res;
|
||||||
|
int needmerge = 0;
|
||||||
if (globals == NULL) {
|
if (globals == NULL) {
|
||||||
globals = getglobals();
|
globals = getglobals();
|
||||||
if (locals == NULL)
|
if (locals == NULL) {
|
||||||
locals = getlocals();
|
locals = getlocals();
|
||||||
|
needmerge = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (locals == NULL)
|
if (locals == NULL)
|
||||||
locals = globals;
|
locals = globals;
|
||||||
}
|
}
|
||||||
return eval_node(n, filename, globals, locals);
|
res = eval_node(n, filename, globals, locals);
|
||||||
|
if (needmerge)
|
||||||
|
mergelocals();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
object *
|
object *
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue