Added error checking for numeric constants; added local/global variable
optimization.
This commit is contained in:
parent
572fd57b5a
commit
282914b7b0
116
Python/compile.c
116
Python/compile.c
|
@ -41,6 +41,8 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#include <ctype.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
#define OFF(x) offsetof(codeobject, x)
|
||||
|
||||
static struct memberlist code_memberlist[] = {
|
||||
|
@ -349,14 +351,28 @@ parsenumber(s)
|
|||
char *s;
|
||||
{
|
||||
extern long strtol();
|
||||
extern double atof();
|
||||
extern double strtod();
|
||||
char *end = s;
|
||||
long x;
|
||||
double xx;
|
||||
errno = 0;
|
||||
x = strtol(s, &end, 0);
|
||||
if (*end == '\0')
|
||||
if (*end == '\0') {
|
||||
if (errno != 0) {
|
||||
err_setstr(RuntimeError, "integer constant too large");
|
||||
return NULL;
|
||||
}
|
||||
return newintobject(x);
|
||||
if (*end == '.' || *end == 'e' || *end == 'E')
|
||||
return newfloatobject(atof(s));
|
||||
}
|
||||
errno = 0;
|
||||
xx = strtod(s, &end);
|
||||
if (*end == '\0') {
|
||||
if (errno != 0) {
|
||||
err_setstr(RuntimeError, "float constant too large");
|
||||
return NULL;
|
||||
}
|
||||
return newfloatobject(xx);
|
||||
}
|
||||
err_setstr(RuntimeError, "bad number syntax");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1752,6 +1768,96 @@ compile_node(c, n)
|
|||
}
|
||||
}
|
||||
|
||||
/* Optimization for local and global variables.
|
||||
|
||||
Attempt to replace all LOAD_NAME instructions that refer to a local
|
||||
variable with LOAD_LOCAL instructions, and all that refer to a global
|
||||
variable with LOAD_GLOBAL instructions.
|
||||
|
||||
To find all local variables, we check all STORE_NAME and IMPORT_FROM
|
||||
instructions. This yields all local variables, including arguments,
|
||||
function definitions, class definitions and import statements.
|
||||
|
||||
There is one leak: 'from foo import *' introduces local variables
|
||||
that we can't know while compiling. If this is the case, LOAD_GLOBAL
|
||||
instructions are not generated -- LOAD_NAME is left in place for
|
||||
globals, since it first checks for globals (LOAD_LOCAL is still used
|
||||
for recognized locals, since it doesn't hurt).
|
||||
|
||||
This optimization means that using the same name as a global and
|
||||
as a local variable within the same scope is now illegal, which
|
||||
is a change to the language! Also using eval() to introduce new
|
||||
local variables won't work. But both were bad practice at best.
|
||||
|
||||
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!
|
||||
*/
|
||||
|
||||
static void
|
||||
optimizer(co)
|
||||
codeobject *co;
|
||||
{
|
||||
char *next_instr, *cur_instr;
|
||||
object *locals;
|
||||
int opcode;
|
||||
int oparg;
|
||||
object *name;
|
||||
int star_used;
|
||||
|
||||
#define NEXTOP() (*next_instr++)
|
||||
#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
|
||||
#define GETITEM(v, i) (getlistitem((v), (i)))
|
||||
#define GETNAMEOBJ(i) (GETITEM(co->co_names, (i)))
|
||||
|
||||
locals = newdictobject();
|
||||
if (locals == NULL) {
|
||||
err_clear();
|
||||
return; /* For now, this is OK */
|
||||
}
|
||||
|
||||
next_instr = GETSTRINGVALUE(co->co_code);
|
||||
for (;;) {
|
||||
opcode = NEXTOP();
|
||||
if (opcode == STOP_CODE)
|
||||
break;
|
||||
if (HAS_ARG(opcode))
|
||||
oparg = NEXTARG();
|
||||
if (opcode == STORE_NAME || opcode == IMPORT_FROM) {
|
||||
name = GETNAMEOBJ(oparg);
|
||||
if (dict2insert(locals, name, None) != 0) {
|
||||
DECREF(locals);
|
||||
return; /* Sorry */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
star_used = (dictlookup(locals, "*") != NULL);
|
||||
next_instr = GETSTRINGVALUE(co->co_code);
|
||||
for (;;) {
|
||||
cur_instr = next_instr;
|
||||
opcode = NEXTOP();
|
||||
if (opcode == STOP_CODE)
|
||||
break;
|
||||
if (HAS_ARG(opcode))
|
||||
oparg = NEXTARG();
|
||||
if (opcode == LOAD_NAME) {
|
||||
name = GETNAMEOBJ(oparg);
|
||||
if (dictlookup(locals, getstringvalue(name)) != NULL)
|
||||
*cur_instr = LOAD_LOCAL;
|
||||
else if (!star_used)
|
||||
*cur_instr = LOAD_GLOBAL;
|
||||
}
|
||||
}
|
||||
|
||||
DECREF(locals);
|
||||
}
|
||||
|
||||
codeobject *
|
||||
compile(n, filename)
|
||||
node *n;
|
||||
|
@ -1768,5 +1874,7 @@ compile(n, filename)
|
|||
else
|
||||
co = NULL;
|
||||
com_free(&sc);
|
||||
if (co != NULL)
|
||||
optimizer(co);
|
||||
return co;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue