@@ -41,6 +41,8 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4141
4242#include <ctype.h>
4343
44+ extern int errno ;
45+
4446#define OFF (x ) offsetof(codeobject, x)
4547
4648static struct memberlist code_memberlist [] = {
@@ -349,14 +351,28 @@ parsenumber(s)
349351 char * s ;
350352{
351353 extern long strtol ();
352- extern double atof ();
354+ extern double strtod ();
353355 char * end = s ;
354356 long x ;
357+ double xx ;
358+ errno = 0 ;
355359 x = strtol (s , & end , 0 );
356- if (* end == '\0' )
360+ if (* end == '\0' ) {
361+ if (errno != 0 ) {
362+ err_setstr (RuntimeError , "integer constant too large" );
363+ return NULL ;
364+ }
357365 return newintobject (x );
358- if (* end == '.' || * end == 'e' || * end == 'E' )
359- return newfloatobject (atof (s ));
366+ }
367+ errno = 0 ;
368+ xx = strtod (s , & end );
369+ if (* end == '\0' ) {
370+ if (errno != 0 ) {
371+ err_setstr (RuntimeError , "float constant too large" );
372+ return NULL ;
373+ }
374+ return newfloatobject (xx );
375+ }
360376 err_setstr (RuntimeError , "bad number syntax" );
361377 return NULL ;
362378}
@@ -1752,6 +1768,96 @@ compile_node(c, n)
17521768 }
17531769}
17541770
1771+ /* Optimization for local and global variables.
1772+
1773+ Attempt to replace all LOAD_NAME instructions that refer to a local
1774+ variable with LOAD_LOCAL instructions, and all that refer to a global
1775+ variable with LOAD_GLOBAL instructions.
1776+
1777+ To find all local variables, we check all STORE_NAME and IMPORT_FROM
1778+ instructions. This yields all local variables, including arguments,
1779+ function definitions, class definitions and import statements.
1780+
1781+ There is one leak: 'from foo import *' introduces local variables
1782+ that we can't know while compiling. If this is the case, LOAD_GLOBAL
1783+ instructions are not generated -- LOAD_NAME is left in place for
1784+ globals, since it first checks for globals (LOAD_LOCAL is still used
1785+ for recognized locals, since it doesn't hurt).
1786+
1787+ This optimization means that using the same name as a global and
1788+ as a local variable within the same scope is now illegal, which
1789+ is a change to the language! Also using eval() to introduce new
1790+ local variables won't work. But both were bad practice at best.
1791+
1792+ The optimization doesn't save much: basically, it saves one
1793+ unsuccessful dictionary lookup per global (or built-in) variable
1794+ reference. On the (slow!) Mac Plus, with 4 local variables,
1795+ this saving was measured to be about 0.18 ms. We might save more
1796+ by using a different data structure to hold local variables, like
1797+ an array indexed by variable number.
1798+
1799+ NB: this modifies the string object co->co_code!
1800+ */
1801+
1802+ static void
1803+ optimizer (co )
1804+ codeobject * co ;
1805+ {
1806+ char * next_instr , * cur_instr ;
1807+ object * locals ;
1808+ int opcode ;
1809+ int oparg ;
1810+ object * name ;
1811+ int star_used ;
1812+
1813+ #define NEXTOP () (*next_instr++)
1814+ #define NEXTARG () (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
1815+ #define GETITEM (v , i ) (getlistitem((v), (i)))
1816+ #define GETNAMEOBJ (i ) (GETITEM(co->co_names, (i)))
1817+
1818+ locals = newdictobject ();
1819+ if (locals == NULL ) {
1820+ err_clear ();
1821+ return ; /* For now, this is OK */
1822+ }
1823+
1824+ next_instr = GETSTRINGVALUE (co -> co_code );
1825+ for (;;) {
1826+ opcode = NEXTOP ();
1827+ if (opcode == STOP_CODE )
1828+ break ;
1829+ if (HAS_ARG (opcode ))
1830+ oparg = NEXTARG ();
1831+ if (opcode == STORE_NAME || opcode == IMPORT_FROM ) {
1832+ name = GETNAMEOBJ (oparg );
1833+ if (dict2insert (locals , name , None ) != 0 ) {
1834+ DECREF (locals );
1835+ return ; /* Sorry */
1836+ }
1837+ }
1838+ }
1839+
1840+ star_used = (dictlookup (locals , "*" ) != NULL );
1841+ next_instr = GETSTRINGVALUE (co -> co_code );
1842+ for (;;) {
1843+ cur_instr = next_instr ;
1844+ opcode = NEXTOP ();
1845+ if (opcode == STOP_CODE )
1846+ break ;
1847+ if (HAS_ARG (opcode ))
1848+ oparg = NEXTARG ();
1849+ if (opcode == LOAD_NAME ) {
1850+ name = GETNAMEOBJ (oparg );
1851+ if (dictlookup (locals , getstringvalue (name )) != NULL )
1852+ * cur_instr = LOAD_LOCAL ;
1853+ else if (!star_used )
1854+ * cur_instr = LOAD_GLOBAL ;
1855+ }
1856+ }
1857+
1858+ DECREF (locals );
1859+ }
1860+
17551861codeobject *
17561862compile (n , filename )
17571863 node * n ;
@@ -1768,5 +1874,7 @@ compile(n, filename)
17681874 else
17691875 co = NULL ;
17701876 com_free (& sc );
1877+ if (co != NULL )
1878+ optimizer (co );
17711879 return co ;
17721880}
0 commit comments