Index: Python/ceval.c
===================================================================
--- Python/ceval.c (revision 59259)
+++ Python/ceval.c (working copy)
@@ -492,12 +492,27 @@
PyObject *
PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
{
- return PyEval_EvalCodeEx(co,
- globals, locals,
+ PyObject *fastglobals;
+ PyObject *res;
+
+ if (globals == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "PyEval_EvalCode: NULL globals");
+ return NULL;
+ }
+
+ fastglobals = PyFastGlobals_New(globals, co->co_names);
+ if (fastglobals == NULL)
+ return NULL;
+
+ res = PyEval_EvalCodeEx(co,
+ fastglobals, locals,
(PyObject **)NULL, 0,
(PyObject **)NULL, 0,
(PyObject **)NULL, 0,
NULL);
+ Py_DECREF(fastglobals);
+ return res;
}
@@ -762,7 +777,8 @@
f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */
#ifdef LLTRACE
- lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL;
+ lltrace = PyDict_GetItemString(
+ PyFrame_GET_GLOBALS(f), "__lltrace__") != NULL;
#endif
#if defined(Py_DEBUG) || defined(LLTRACE)
filename = PyString_AsString(co->co_filename);
@@ -1814,16 +1830,17 @@
break;
case STORE_GLOBAL:
- w = GETITEM(names, oparg);
v = POP();
- err = PyDict_SetItem(f->f_globals, w, v);
- Py_DECREF(v);
+ /* steals a reference */
+ err = PyFastGlobals_SetItem(
+ f->f_fastglobals, oparg, v);
if (err == 0) continue;
break;
case DELETE_GLOBAL:
w = GETITEM(names, oparg);
- if ((err = PyDict_DelItem(f->f_globals, w)) != 0)
+ if ((err = PyDict_DelItem(
+ PyFrame_GET_GLOBALS(f), w)) != 0)
format_exc_check_arg(
PyExc_NameError, GLOBAL_NAME_ERROR_MSG, w);
break;
@@ -1850,15 +1867,13 @@
}
}
if (x == NULL) {
- x = PyDict_GetItem(f->f_globals, w);
+ PyFastGlobals_GET_ITEM_INPLACE(
+ x, f->f_fastglobals, oparg);
if (x == NULL) {
- x = PyDict_GetItem(f->f_builtins, w);
- if (x == NULL) {
- format_exc_check_arg(
- PyExc_NameError,
- NAME_ERROR_MSG, w);
- break;
- }
+ format_exc_check_arg(
+ PyExc_NameError,
+ NAME_ERROR_MSG, w);
+ break;
}
Py_INCREF(x);
}
@@ -1866,53 +1881,14 @@
continue;
case LOAD_GLOBAL:
- w = GETITEM(names, oparg);
- if (PyString_CheckExact(w)) {
- /* Inline the PyDict_GetItem() calls.
- WARNING: this is an extreme speed hack.
- Do not try this at home. */
- long hash = ((PyStringObject *)w)->ob_shash;
- if (hash != -1) {
- PyDictObject *d;
- PyDictEntry *e;
- d = (PyDictObject *)(f->f_globals);
- e = d->ma_lookup(d, w, hash);
- if (e == NULL) {
- x = NULL;
- break;
- }
- x = e->me_value;
- if (x != NULL) {
- Py_INCREF(x);
- PUSH(x);
- continue;
- }
- d = (PyDictObject *)(f->f_builtins);
- e = d->ma_lookup(d, w, hash);
- if (e == NULL) {
- x = NULL;
- break;
- }
- x = e->me_value;
- if (x != NULL) {
- Py_INCREF(x);
- PUSH(x);
- continue;
- }
- goto load_global_error;
- }
- }
- /* This is the un-inlined version of the code above */
- x = PyDict_GetItem(f->f_globals, w);
+ PyFastGlobals_GET_ITEM_INPLACE(
+ x, f->f_fastglobals, oparg);
if (x == NULL) {
- x = PyDict_GetItem(f->f_builtins, w);
- if (x == NULL) {
- load_global_error:
- format_exc_check_arg(
- PyExc_NameError,
- GLOBAL_NAME_ERROR_MSG, w);
- break;
- }
+ w = GETITEM(names, oparg);
+ format_exc_check_arg(
+ PyExc_NameError,
+ GLOBAL_NAME_ERROR_MSG, w);
+ break;
}
Py_INCREF(x);
PUSH(x);
@@ -2047,7 +2023,8 @@
case IMPORT_NAME:
w = GETITEM(names, oparg);
- x = PyDict_GetItemString(f->f_builtins, "__import__");
+ x = PyDict_GetItemString(PyFrame_GET_BUILTINS(f),
+ "__import__");
if (x == NULL) {
PyErr_SetString(PyExc_ImportError,
"__import__ not found");
@@ -2058,7 +2035,7 @@
if (PyInt_AsLong(u) != -1 || PyErr_Occurred())
w = PyTuple_Pack(5,
w,
- f->f_globals,
+ PyFrame_GET_GLOBALS(f),
f->f_locals == NULL ?
Py_None : f->f_locals,
v,
@@ -2066,7 +2043,7 @@
else
w = PyTuple_Pack(4,
w,
- f->f_globals,
+ PyFrame_GET_GLOBALS(f),
f->f_locals == NULL ?
Py_None : f->f_locals,
v);
@@ -2353,7 +2330,7 @@
case MAKE_FUNCTION:
v = POP(); /* code object */
- x = PyFunction_New(v, f->f_globals);
+ x = PyFunction_New(v, PyFrame_GET_GLOBALS(f));
Py_DECREF(v);
/* XXX Maybe this should be a separate opcode? */
if (x != NULL && oparg > 0) {
@@ -2376,7 +2353,7 @@
case MAKE_CLOSURE:
{
v = POP(); /* code object */
- x = PyFunction_New(v, f->f_globals);
+ x = PyFunction_New(v, PyFrame_GET_GLOBALS(f));
Py_DECREF(v);
if (x != NULL) {
v = POP();
@@ -2637,7 +2614,7 @@
the test in the if statements in Misc/gdbinit (pystack and pystackv). */
PyObject *
-PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
+PyEval_EvalCodeEx(PyCodeObject *co, PyObject *fastglobals, PyObject *locals,
PyObject **args, int argcount, PyObject **kws, int kwcount,
PyObject **defs, int defcount, PyObject *closure)
{
@@ -2647,15 +2624,14 @@
PyThreadState *tstate = PyThreadState_GET();
PyObject *x, *u;
- if (globals == NULL) {
+ if (fastglobals == NULL) {
PyErr_SetString(PyExc_SystemError,
- "PyEval_EvalCodeEx: NULL globals");
+ "PyEval_EvalCodeEx: NULL fastglobals");
return NULL;
}
assert(tstate != NULL);
- assert(globals != NULL);
- f = PyFrame_New(tstate, co, globals, locals);
+ f = PyFrame_New(tstate, co, fastglobals, locals);
if (f == NULL)
return NULL;
@@ -3346,7 +3322,7 @@
if (current_frame == NULL)
return PyThreadState_GET()->interp->builtins;
else
- return current_frame->f_builtins;
+ return PyFrame_GET_BUILTINS(current_frame);
}
PyObject *
@@ -3366,7 +3342,7 @@
if (current_frame == NULL)
return NULL;
else
- return current_frame->f_globals;
+ return PyFrame_GET_GLOBALS(current_frame);
}
PyFrameObject *
@@ -3641,7 +3617,7 @@
fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
{
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
- PyObject *globals = PyFunction_GET_GLOBALS(func);
+ PyObject *fastglobals = PyFunction_GET_FASTGLOBALS(func);
PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
PyObject **d = NULL;
int nd = 0;
@@ -3657,13 +3633,13 @@
int i;
PCALL(PCALL_FASTER_FUNCTION);
- assert(globals != NULL);
+ assert(fastglobals != NULL);
/* XXX Perhaps we should create a specialized
PyFrame_New() that doesn't take locals, but does
take builtins without sanity checking them.
*/
assert(tstate != NULL);
- f = PyFrame_New(tstate, co, globals, NULL);
+ f = PyFrame_New(tstate, co, fastglobals, NULL);
if (f == NULL)
return NULL;
@@ -3684,7 +3660,7 @@
d = &PyTuple_GET_ITEM(argdefs, 0);
nd = Py_Size(argdefs);
}
- return PyEval_EvalCodeEx(co, globals,
+ return PyEval_EvalCodeEx(co, fastglobals,
(PyObject *)NULL, (*pp_stack)-n, na,
(*pp_stack)-2*nk, nk, d, nd,
PyFunction_GET_CLOSURE(func));
@@ -4233,7 +4209,8 @@
return -1;
}
if (PyDict_GetItemString(globals, "__builtins__") == NULL)
- PyDict_SetItemString(globals, "__builtins__", f->f_builtins);
+ PyDict_SetItemString(globals, "__builtins__",
+ PyFrame_GET_BUILTINS(f));
if (PyCode_Check(prog)) {
if (PyCode_GetNumFree((PyCodeObject *)prog) > 0) {
PyErr_SetString(PyExc_TypeError,
Index: PCbuild/pythoncore.vcproj
===================================================================
--- PCbuild/pythoncore.vcproj (revision 59259)
+++ PCbuild/pythoncore.vcproj (working copy)
@@ -785,6 +785,9 @@
RelativePath="..\Objects\weakrefobject.c">
+
+
ma_entryversion)
+PyAPI_FUNC(PyDictEntry *) PyDict_GetEntry(PyObject *op, PyObject *key);
+
/* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */
PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other);
Index: Include/Python.h
===================================================================
--- Include/Python.h (revision 59259)
+++ Include/Python.h (working copy)
@@ -109,6 +109,7 @@
#include "genobject.h"
#include "descrobject.h"
#include "weakrefobject.h"
+#include "fastglobals.h"
#include "codecs.h"
#include "pyerrors.h"
Index: Include/funcobject.h
===================================================================
--- Include/funcobject.h (revision 59259)
+++ Include/funcobject.h (working copy)
@@ -21,7 +21,7 @@
typedef struct {
PyObject_HEAD
PyObject *func_code; /* A code object */
- PyObject *func_globals; /* A dictionary (other mappings won't do) */
+ PyObject *func_fastglobals; /* A PyFastGlobalsObject */
PyObject *func_defaults; /* NULL or a tuple */
PyObject *func_closure; /* NULL or a tuple of cell objects */
PyObject *func_doc; /* The __doc__ attribute, can be anything */
@@ -54,8 +54,10 @@
done, so use with care. */
#define PyFunction_GET_CODE(func) \
(((PyFunctionObject *)func) -> func_code)
+#define PyFunction_GET_FASTGLOBALS(func) \
+ (((PyFunctionObject *)func) -> func_fastglobals)
#define PyFunction_GET_GLOBALS(func) \
- (((PyFunctionObject *)func) -> func_globals)
+ (PyFastGlobals_GLOBALS(PyFunction_GET_FASTGLOBALS(func)))
#define PyFunction_GET_MODULE(func) \
(((PyFunctionObject *)func) -> func_module)
#define PyFunction_GET_DEFAULTS(func) \
Index: Include/fastglobals.h
===================================================================
--- Include/fastglobals.h (revision 0)
+++ Include/fastglobals.h (revision 0)
@@ -0,0 +1,109 @@
+
+/* Fast globals dictionary adapter interface */
+
+#ifndef Py_FASTGLOBALS_H
+#define Py_FASTGLOBALS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+PyFastGlobalsObject
+
+These objects hold pointers directly into globals and builtins dict tables
+for very fast access. Every function has one of these adapters, which is
+passed to the function's frame when it's called. It enables ceval.c to get
+globals and builtins almost as fast as it gets locals.
+
+Changes to globals and builtins DO NOT have to be reported to an object
+of this type in any way. PyDictObject keeps a "version" that is
+incremented whenever at least one entry becomes invalid (not safe to
+keep a pointer to). PyFastGlobalObject uses this to make sure its entry
+pointers are valid before dereferencing them. The rest of the codebase
+can happily believe that nothing magical is going on and interact with
+globals and builtins dicts as they always have.
+
+The dictionary versioning mechanism might be used to accelerate dictionary
+access in other contexts. It could be appropriate any time get/set (non-
+inserting) with a static set of keys dominates access.
+*/
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *names; /* Tuple of names from co->co_code */
+ Py_ssize_t num_entries; /* == len(names) */
+
+ PyObject *globals; /* PyDictObject only */
+ PyObject *builtins; /* PyDictObject only */
+
+ PyDictEntry **entries; /* PyDictEntry*'s into ma_table */
+ int *isbuiltin; /* For each pointer, whether it points
+ into the builtins dict (boolean) */
+ /* We don't keep track of two sets of entries (one for globals and
+ one for builtins) because we want to make the common case, a GET,
+ as fast as possible. (See PyFastGlobals_GET_ITEM_INPLACE.) */
+ PY_LONG_LONG entryversion; /* == globals + builtins after update */
+ PyDictEntry *builtins_entry; /* entry for __builtins__ */
+ PyObject *old_builtins; /* used to detect __builtins__ changes */
+} PyFastGlobalsObject;
+
+PyAPI_DATA(PyTypeObject) PyFastGlobals_Type;
+
+#define PyFastGlobals_Check(op) (Py_Type(op) == &PyFastGlobals_Type)
+
+#define PyFastGlobals_NAMES(op) \
+ (((PyFastGlobalsObject *)(op))->names)
+
+#define PyFastGlobals_SIZE(op) \
+ (((PyFastGlobalsObject *)(op))->num_entries)
+
+#define PyFastGlobals_GLOBALS(op) \
+ (((PyFastGlobalsObject *)(op))->globals)
+
+#define PyFastGlobals_BUILTINS(op) \
+ (((PyFastGlobalsObject *)(op))->builtins)
+
+#define PyFastGlobals_ENTRY(op, index) \
+ (((PyFastGlobalsObject *)(op))->entries[index])
+
+#define PyFastGlobals_IS_BUILTIN(op, index) \
+ (((PyFastGlobalsObject *)(op))->isbuiltin[index])
+
+#define PyFastGlobals_ENTRYVERSION(op) \
+ (((PyFastGlobalsObject *)(op))->entryversion)
+
+#define PyFastGlobals_IS_UPDATED(op)\
+ (PyFastGlobals_ENTRYVERSION(op) ==\
+ PyDict_ENTRYVERSION(PyFastGlobals_GLOBALS(op)) +\
+ PyDict_ENTRYVERSION(PyFastGlobals_BUILTINS(op)))
+
+#define PyFastGlobals_BUILTINS_CHANGED(op) \
+ (((PyFastGlobalsObject *)(op))->builtins_entry == NULL ||\
+ ((PyFastGlobalsObject *)(op))->builtins_entry->me_value !=\
+ ((PyFastGlobalsObject *)(op))->old_builtins)
+
+PyAPI_FUNC(PyObject *) PyFastGlobals_New(PyObject *globals, PyObject *names);
+/* The following do no run-time error checking except asserts */
+PyAPI_FUNC(int) PyFastGlobals_Update(PyObject *op);
+PyAPI_FUNC(int) PyFastGlobals_CheckBuiltins(PyObject *op);
+PyAPI_FUNC(PyObject *) PyFastGlobals_GetItem(PyObject *op, Py_ssize_t index);
+PyAPI_FUNC(int) PyFastGlobals_SetItem(
+ PyObject *op, Py_ssize_t index, PyObject *item);
+
+/* The following returns NULL on errors and suppresses exceptions just
+like PyDict_GetItem - it's intended as a replacement */
+#define PyFastGlobals_GET_ITEM_INPLACE(x, op, index) do {\
+ if (!PyFastGlobals_IS_UPDATED(op) &&\
+ PyFastGlobals_Update(op) < 0) {\
+ PyErr_Clear();\
+ (x) = NULL;\
+ }\
+ else\
+ (x) = PyFastGlobals_ENTRY(op, index) == NULL ? NULL :\
+ PyFastGlobals_ENTRY(op, index)->me_value;\
+} while (0)
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_FASTGLOBALS_H */
Index: Include/pythonrun.h
===================================================================
--- Include/pythonrun.h (revision 59259)
+++ Include/pythonrun.h (working copy)
@@ -137,6 +137,7 @@
PyAPI_FUNC(void) PyInt_Fini(void);
PyAPI_FUNC(void) PyFloat_Fini(void);
PyAPI_FUNC(void) PyOS_FiniInterrupts(void);
+PyAPI_FUNC(void) PyFastGlobals_Fini(void);
/* Stuff with no proper home (yet) */
PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *);
Index: Include/frameobject.h
===================================================================
--- Include/frameobject.h (revision 59259)
+++ Include/frameobject.h (working copy)
@@ -17,8 +17,8 @@
PyObject_VAR_HEAD
struct _frame *f_back; /* previous frame, or NULL */
PyCodeObject *f_code; /* code segment */
- PyObject *f_builtins; /* builtin symbol table (PyDictObject) */
- PyObject *f_globals; /* global symbol table (PyDictObject) */
+ PyObject *f_fastglobals; /* globals and builtins symbol tables
+ (PyFastGlobalsObject) */
PyObject *f_locals; /* local symbol table (any mapping) */
PyObject **f_valuestack; /* points after the last local */
/* Next free slot in f_valuestack. Frame creation sets to f_valuestack.
@@ -52,8 +52,12 @@
PyAPI_DATA(PyTypeObject) PyFrame_Type;
#define PyFrame_Check(op) ((op)->ob_type == &PyFrame_Type)
-#define PyFrame_IsRestricted(f) \
- ((f)->f_builtins != (f)->f_tstate->interp->builtins)
+#define PyFrame_GET_GLOBALS(op) \
+ (((PyFastGlobalsObject *)(op)->f_fastglobals)->globals)
+#define PyFrame_GET_BUILTINS(op) \
+ (((PyFastGlobalsObject *)(op)->f_fastglobals)->builtins)
+#define PyFrame_IsRestricted(op) \
+ (PyFrame_GET_BUILTINS(op) != (op)->f_tstate->interp->builtins)
PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
PyObject *, PyObject *);
Index: Include/eval.h
===================================================================
--- Include/eval.h (revision 59259)
+++ Include/eval.h (working copy)
@@ -10,7 +10,7 @@
PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyCodeObject *, PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
- PyObject *globals,
+ PyObject *fastglobals,
PyObject *locals,
PyObject **args, int argc,
PyObject **kwds, int kwdc,
Index: fastglobals_test.py
===================================================================
--- fastglobals_test.py (revision 0)
+++ fastglobals_test.py (revision 0)
@@ -0,0 +1,416 @@
+#!/usr/bin/python
+
+import timeit, random, time
+
+
+MULTIPLIER = 1
+
+
+def test_local_get():
+ x = 0
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+
+
+def test_local_set():
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+
+
+x = 0
+def test_global_get():
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+ x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x; x
+
+
+def test_global_set():
+ global x
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+ x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0; x = 0
+
+
+def test_builtin_get():
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+ len; len; len; len; len; len; len; len; len; len;
+
+
+lists = [[x for x in xrange(y)] for y in xrange(1, 1000)]
+def test_listcomp():
+ [set(sub) for sub in lists if len(sub) <= 5]
+
+
+def test_func_call():
+ def inner_function():
+ pass
+ for i in xrange(1000):
+ inner_function();
+
+
+dict_range = ['%i' % i for i in range(1000)]
+def test_dict_insert_del():
+ d = {}
+ for i in dict_range:
+ d[i] = i
+ for i in dict_range:
+ del d[i]
+
+test_dict = dict((i, i) for i in dict_range)
+def test_dict_set():
+ d = test_dict
+ for i in dict_range:
+ d[i] = i
+
+def test_dict_get():
+ d = test_dict
+ for i in dict_range:
+ d[i]
+
+
+cfg = {
+ 'S': ['NP VP'],
+ 'NP': ['CN', 'CN PP'],
+ 'VP': ['CV', 'CV PP'],
+ 'PP': ['P CN'],
+ 'CN': ['A N'],
+ 'CV': ['V', 'V NP'],
+ 'A': ['a', 'the'],
+ 'N': ['knight', 'king', 'shrubbery', 'castle', 'python', 'trojan rabbit'],
+ 'V': ['eats', 'likes', 'sees', 'decapitates', 'smells', 'throws'],
+ 'P': ['with', 'without', 'behind', 'above', 'below', 'on top of', 'under'],
+}
+
+cfg = dict(
+ (rule, [string.split() for string in stringlist])
+ for rule, stringlist in cfg.items())
+
+def produce(rule):
+ try:
+ rulelist = random.choice(cfg[rule])
+ except KeyError:
+ return [rule] # a terminal
+ return sum([produce(rule) for rule in rulelist], [])
+
+def produce2(rule):
+ d = []
+ d.append(rule)
+ result = []
+ while len(d) > 0:
+ rule = d.pop()
+ try:
+ rulelist = random.choice(cfg[rule])
+ except KeyError:
+ result.append(rule)
+ else:
+ d += rulelist
+ result.reverse()
+ return result
+
+def matches_rule(rule, wordlist):
+ '''A very naive top-down parser.'''
+ try:
+ rulelists = cfg[rule]
+ except KeyError:
+ return False # a terminal
+ if wordlist in rulelists:
+ return True # word list matches the rule exactly
+ for rulelist in rulelists:
+ if matches_rulelist(rulelist, wordlist):
+ return True
+ return False
+
+def matches_rulelist(rulelist, wordlist):
+ if len(rulelist) == 0:
+ if len(wordlist) == 0:
+ return True
+ return False
+ for i in xrange(1, len(wordlist) + 1):
+ if matches_rule(rulelist[0], wordlist[:i]):
+ if matches_rulelist(rulelist[1:], wordlist[i:]):
+ return True
+ return False
+
+def test_grammar():
+ produce('S')
+
+def test_grammar2():
+ produce2('S')
+
+cfg_strings = [
+ 'the trojan rabbit without the castle eats the knight on top of a python',
+ 'a knight under the python decapitates on top of the trojan rabbit',
+ 'the shrubbery on top of a castle smells without the king',
+ 'a shrubbery decapitates',
+ 'the python below a castle throws the shrubbery',
+ 'the python decapitates below a knight',
+ 'a trojan rabbit under a shrubbery sees behind a python',
+ 'a castle smells',
+ 'the castle with a knight eats the shrubbery on top of a knight below the castle',
+ 'a python behind a king likes the knight on top of a trojan rabbit',
+ 'the shrubbery with a shrubbery sees',
+ 'a castle behind a python likes a python on top of a castle without a trojan rabbit',
+ 'a shrubbery below the trojan rabbit decapitates the king without a castle above the castle',
+ 'a shrubbery above the knight sees the castle with the python',
+ 'a knight eats the shrubbery behind a shrubbery',
+ 'a trojan rabbit decapitates the python on top of a knight',
+ 'a castle behind the king smells',
+ 'a castle throws without a trojan rabbit',
+ 'a shrubbery under a king throws with a trojan rabbit',
+ 'a knight decapitates',
+ 'a knight eats below the shrubbery',
+ 'a castle throws above a castle',
+ 'the trojan rabbit with the castle likes',
+ 'a trojan rabbit above a shrubbery smells the king',
+ 'the castle below a trojan rabbit throws',
+ 'a castle smells a trojan rabbit without the shrubbery',
+ 'the trojan rabbit above a castle smells a king behind the trojan rabbit',
+ 'a trojan rabbit sees',
+ 'the castle eats',
+ 'the castle throws',
+ 'a python throws a castle with a castle below a trojan rabbit',
+ 'a king eats a knight without the python',
+ 'a python below a shrubbery likes a castle with the shrubbery',
+ 'the trojan rabbit eats the shrubbery behind the king below the python',
+ 'the python likes',
+ 'a knight behind the king decapitates the knight on top of the python',
+ 'the castle decapitates the knight under the trojan rabbit',
+ 'a shrubbery below a shrubbery sees',
+ 'a shrubbery on top of a trojan rabbit likes',
+ 'the python behind a trojan rabbit decapitates behind a castle',
+ 'a castle under a castle smells the trojan rabbit below a trojan rabbit with the king',
+ 'the knight likes',
+ 'the king without a shrubbery eats with a python',
+ 'a king smells',
+ 'the python throws a castle with a shrubbery on top of the python',
+ 'the castle under a knight likes a trojan rabbit under the king',
+ 'a trojan rabbit decapitates on top of a shrubbery',
+ 'the python decapitates the shrubbery behind the shrubbery',
+ 'the shrubbery likes the knight with the castle',
+ 'the shrubbery likes the python without the king'
+]
+
+cfg_wordlists = [string.split() for string in cfg_strings]
+
+def test_grammar3():
+ for wordlist in cfg_wordlists:
+ assert matches_rule('S', wordlist)
+
+
+def qsort(lst):
+ if len(lst) <= 1:
+ return lst
+ else:
+ pivot = lst[0]
+ lesser = qsort([l for l in lst[1:] if l < pivot])
+ greater = qsort([l for l in lst[1:] if l >= pivot])
+ return lesser + [pivot] + greater
+
+def test_qsort():
+ lst = range(500)
+ random.shuffle(lst)
+ qsort(lst)
+
+
+def fib(n):
+ if (n < 2):
+ return 1
+ return fib(n - 1) + fib(n - 2)
+
+def test_fib():
+ fib(10)
+
+
+if __name__ == '__main__':
+ print 'Recursion:', timeit.Timer('test_fib()',
+ 'from __main__ import test_fib').timeit(number=20000 * MULTIPLIER)
+
+ print 'Grammar:', timeit.Timer('test_grammar()',
+ 'from __main__ import test_grammar').timeit(number=20000 * MULTIPLIER)
+
+ print 'Grammar (stack):', timeit.Timer('test_grammar2()',
+ 'from __main__ import test_grammar2').timeit(number=20000 * MULTIPLIER)
+
+ print 'Grammar (parse):', timeit.Timer('test_grammar3()',
+ 'from __main__ import test_grammar3').timeit(number=1 * MULTIPLIER)
+
+ print 'Quicksort:', timeit.Timer('test_qsort()',
+ 'from __main__ import test_qsort').timeit(number=500 * MULTIPLIER)
+
+ print 'Dict insert/del:', timeit.Timer('test_dict_insert_del()',
+ 'from __main__ import test_dict_insert_del').timeit(number=10000 * MULTIPLIER)
+
+ print 'Dict get:', timeit.Timer('test_dict_get()',
+ 'from __main__ import test_dict_get').timeit(number=10000 * MULTIPLIER)
+
+ print 'Dict set:', timeit.Timer('test_dict_set()',
+ 'from __main__ import test_dict_set').timeit(number=10000 * MULTIPLIER)
+
+ print 'Local get:', timeit.Timer('test_local_get()',
+ 'from __main__ import test_local_get').timeit(number=100000 * MULTIPLIER)
+
+ print 'Local set:', timeit.Timer('test_local_set()',
+ 'from __main__ import test_local_set').timeit(number=100000 * MULTIPLIER)
+
+ print 'Global get:', timeit.Timer('test_global_get()',
+ 'from __main__ import test_global_get').timeit(number=100000 * MULTIPLIER)
+
+ print 'Global set:', timeit.Timer('test_global_set()',
+ 'from __main__ import test_global_set').timeit(number=100000 * MULTIPLIER)
+
+ print 'Builtin get:', timeit.Timer('test_builtin_get()',
+ 'from __main__ import test_builtin_get').timeit(number=100000 * MULTIPLIER)
+
+ print 'Function call:', timeit.Timer('test_func_call()',
+ 'from __main__ import test_func_call').timeit(number=10000 * MULTIPLIER)
+
+ print 'List comp:', timeit.Timer('test_listcomp()',
+ 'from __main__ import test_listcomp').timeit(number=10000 * MULTIPLIER)
Property changes on: fastglobals_test.py
___________________________________________________________________
Name: svn:executable
+ *
Index: Objects/fastglobals.c
===================================================================
--- Objects/fastglobals.c (revision 0)
+++ Objects/fastglobals.c (revision 0)
@@ -0,0 +1,376 @@
+
+/* Fast globals dictionary adapter implementation */
+
+#include "Python.h"
+#include "structmember.h"
+
+#define PyFastGlobals_VERSION_SET(op) \
+ (PyFastGlobals_ENTRYVERSION(op) =\
+ PyDict_ENTRYVERSION(PyFastGlobals_GLOBALS(op)) +\
+ PyDict_ENTRYVERSION(PyFastGlobals_BUILTINS(op)))
+
+static PyObject *__builtins__ = NULL;
+
+/* Request entry pointers from globals and builtins for every name if one
+of them has invalidated any entries. Returns 0 on success, -1 on failure
+with an exception set. */
+static int
+fg_update(PyFastGlobalsObject *fg)
+{
+ Py_ssize_t i;
+ PyObject *key;
+ PyDictEntry *entry;
+ /* This loop SHOULD only get executed once, though it may loop if a
+ key comparison alters the underlying dictionary. */
+ while (!PyFastGlobals_IS_UPDATED(fg)) {
+ PyFastGlobals_VERSION_SET(fg);
+ /* Store the entries in the same order as the names */
+ for (i = 0; i < fg->num_entries; i++) {
+ key = PyTuple_GET_ITEM(fg->names, i);
+ entry = PyDict_GetEntry(fg->globals, key);
+ if (entry != NULL) {
+ fg->entries[i] = entry;
+ fg->isbuiltin[i] = 0;
+ }
+ else {
+ if (PyErr_Occurred()) return -1;
+ entry = PyDict_GetEntry(fg->builtins, key);
+ if (entry != NULL) {
+ fg->entries[i] = entry;
+ fg->isbuiltin[i] = 1;
+ }
+ else {
+ if (PyErr_Occurred()) return -1;
+ fg->entries[i] = NULL;
+ fg->isbuiltin[i] = 0;
+ }
+ }
+ }
+ }
+ /* XXX A clever adversary could prevent this from terminating */
+
+ /* For convenience later */
+ fg->builtins_entry = fg->entries[fg->num_entries - 1];
+ return 0;
+}
+
+/* Public wrapper for fg_update with minimal error checking. */
+int
+PyFastGlobals_Update(PyObject *op)
+{
+ assert(op != NULL && PyFastGlobals_Check(op));
+ return fg_update((PyFastGlobalsObject *)op);
+}
+
+/* This finds the __builtins__ of a global dict and tracks its value.
+It also detects when __builtins__ changes. If __builtins__ does not exist
+in globals, it creates one consisting of just {'None': None}. Unlike
+the the previous code in PyFrame_New, this actually inserts __builtins__
+into the globals dictionary. Returns 0 on success, -1 on failure with an
+exception set. */
+static int
+fg_check_builtins(PyFastGlobalsObject *fg)
+{
+ PyObject *builtins, *old_builtins;
+ /* This loop SHOULD only get executed once, though it may loop if a
+ key comparison alters the underlying dictionary. */
+ while (PyFastGlobals_BUILTINS_CHANGED(fg)) {
+ builtins = PyDict_GetItem(fg->globals, __builtins__);
+ if (builtins != NULL) {
+ /* Get the actual dict if it's a module */
+ if (PyModule_Check(builtins)) {
+ builtins = PyModule_GetDict(builtins);
+ assert(!builtins || PyDict_Check(builtins));
+ }
+ else if (!PyDict_Check(builtins))
+ builtins = NULL;
+ }
+
+ if (builtins != NULL)
+ Py_INCREF(builtins);
+ else {
+ /* No builtins! Create a minimal one */
+ builtins = PyDict_New();
+ if (builtins == NULL)
+ return -1;
+ if (PyDict_SetItemString(
+ builtins, "None", Py_None) < 0) {
+ Py_DECREF(builtins);
+ return -1;
+ }
+ /* Make it available */
+ if (PyDict_SetItem(fg->globals,
+ __builtins__, builtins) < 0) {
+ Py_DECREF(builtins);
+ return -1;
+ }
+ }
+
+ old_builtins = fg->builtins;
+ fg->builtins = builtins;
+ Py_XDECREF(old_builtins);
+
+ if (fg_update(fg) < 0) /* Get fresh entries */
+ return -1;
+
+ if (fg->builtins_entry != NULL)
+ fg->old_builtins = fg->builtins_entry->me_value;
+ else
+ fg->old_builtins = NULL;
+ }
+ return 0;
+}
+
+/* Public wrapper for fg_check_builtins with minimal error checking. */
+int
+PyFastGlobals_CheckBuiltins(PyObject *op)
+{
+ PyFastGlobalsObject *fg;
+ assert(op != NULL && PyFastGlobals_Check(op));
+ fg = (PyFastGlobalsObject *)op;
+
+ /* Make sure fg->builtins_entry is updated first */
+ if (fg_update(fg) < 0)
+ return -1;
+
+ return fg_check_builtins(fg);
+}
+
+PyObject *
+PyFastGlobals_New(PyObject *globals, PyObject *names)
+{
+ PyObject *newnames;
+ Py_ssize_t i, num_entries;
+ PyDictEntry **entries;
+ int *isbuiltin;
+ PyFastGlobalsObject *fg;
+
+ if (globals == NULL || !PyDict_Check(globals)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ if (names == NULL || !PyTuple_Check(names)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ if (__builtins__ == NULL) {
+ __builtins__ = PyString_InternFromString("__builtins__");
+ if (__builtins__ == NULL)
+ return NULL; /* shouldn't happen */
+ }
+
+ /* Append '__builtins__' to names */
+ num_entries = PyTuple_GET_SIZE(names);
+ newnames = PyTuple_New(num_entries + 1);
+ if (newnames == NULL)
+ return NULL;
+ for (i = 0; i < num_entries; i++) {
+ PyObject *name = PyTuple_GET_ITEM(names, i);
+ Py_INCREF(name);
+ PyTuple_SET_ITEM(newnames, i, name);
+ }
+ Py_INCREF(__builtins__);
+ PyTuple_SET_ITEM(newnames, i, __builtins__);
+ num_entries++;
+
+ entries = PyMem_NEW(PyDictEntry *, num_entries);
+ if (entries == NULL) {
+ PyErr_NoMemory();
+ Py_DECREF(newnames);
+ return NULL;
+ }
+
+ isbuiltin = PyMem_NEW(int, num_entries);
+ if (isbuiltin == NULL) {
+ PyErr_NoMemory();
+ Py_DECREF(newnames);
+ PyMem_FREE(isbuiltin);
+ return NULL;
+ }
+
+ fg = PyObject_GC_New(PyFastGlobalsObject, &PyFastGlobals_Type);
+ if (fg == NULL) {
+ Py_DECREF(newnames);
+ PyMem_FREE(entries);
+ PyMem_FREE(isbuiltin);
+ return NULL;
+ }
+
+ fg->names = newnames;
+ fg->num_entries = num_entries;
+ /* The following will be initialized in fg_check_builtins */
+ fg->entries = entries;
+ fg->isbuiltin = isbuiltin;
+
+ Py_INCREF(globals);
+ fg->globals = globals;
+ /* Force fg_update to update entries */
+ fg->entryversion = PyDict_ENTRYVERSION(fg->globals) - 1;
+
+ fg->builtins = NULL;
+ /* Force fg_check_builtins to set up builtins */
+ fg->builtins_entry = NULL;
+ if (fg_check_builtins(fg) == -1) {
+ _PyObject_GC_TRACK(fg);
+ Py_DECREF(fg);
+ return NULL;
+ }
+
+ _PyObject_GC_TRACK(fg);
+ return (PyObject *)fg;
+}
+
+/* Returns a borrowed reference to the item at index. Returns NULL on
+failure or missing key, with an exception set. */
+PyObject *
+PyFastGlobals_GetItem(PyObject *op, register Py_ssize_t index)
+{
+ register PyFastGlobalsObject *fg;
+ register PyDictEntry *entry;
+
+ assert(op != NULL && PyFastGlobals_Check(op));
+ fg = (PyFastGlobalsObject *)op;
+ assert(index >= 0 && index < fg->num_entries);
+
+ /* Version check here almost always saves a function call */
+ if (!PyFastGlobals_IS_UPDATED(fg))
+ if (fg_update(fg) < 0) {
+ return NULL;
+ }
+
+ entry = fg->entries[index];
+ if (entry == NULL) {
+ PyErr_Format(PyExc_KeyError,
+ "fastglobals: no value for index %d", index);
+ return NULL;
+ }
+ assert(entry->me_value != NULL);
+ return entry->me_value;
+}
+
+/* Sets the item at index to item. This "steals" a reference to item and
+discards a reference to the item already at index, if any. Returns 0 on
+success, -1 on failure with an exception. (This only happens when the item
+must be inserted but PyDict_SetItem fails.) */
+int
+PyFastGlobals_SetItem(PyObject *op, Py_ssize_t index, PyObject *item)
+{
+ PyObject *old_value;
+ PyDictEntry *entry;
+ PyFastGlobalsObject *fg;
+
+ assert(item != NULL);
+ assert(op != NULL && PyFastGlobals_Check(op));
+ fg = (PyFastGlobalsObject *)op;
+ assert(index >= 0 && index < fg->num_entries);
+
+ /* Version check here almost always saves a function call */
+ if (!PyFastGlobals_IS_UPDATED(fg))
+ if (fg_update(fg) < 0) {
+ return -1;
+ }
+
+ entry = fg->entries[index];
+ if (entry == NULL || fg->isbuiltin[index]) {
+ /* Not already there or a builtin - insert it into globals */
+ PyObject *key = PyTuple_GET_ITEM(fg->names, index);
+ int ret = PyDict_SetItem(fg->globals, key, item);
+ /* Can't guarantee that only the missing entry will be changed,
+ so we wait for the next get/set to update. */
+ Py_DECREF(item); /* steal a reference */
+ return ret;
+ }
+
+ old_value = entry->me_value;
+ entry->me_value = item; /* steal a reference */
+ assert(old_value != NULL); /* dict enforces this */
+ Py_DECREF(old_value);
+ return 0;
+}
+
+static int
+fg_clear(PyFastGlobalsObject *fg)
+{
+ Py_CLEAR(fg->globals);
+ Py_CLEAR(fg->builtins);
+ Py_CLEAR(fg->names);
+ if (fg->entries != NULL) {
+ PyMem_FREE(fg->entries);
+ fg->entries = NULL;
+ }
+ if (fg->isbuiltin != NULL) {
+ PyMem_FREE(fg->isbuiltin);
+ fg->isbuiltin = NULL;
+ }
+ return 0;
+}
+
+static void
+fg_dealloc(PyFastGlobalsObject *fg)
+{
+ _PyObject_GC_UNTRACK(fg);
+ fg_clear(fg);
+ PyObject_GC_Del(fg);
+}
+
+static int
+fg_traverse(PyFastGlobalsObject *fg, visitproc visit, void *arg)
+{
+ Py_VISIT(fg->globals);
+ Py_VISIT(fg->builtins);
+ Py_VISIT(fg->names);
+ /* Traversing entries will be done in dict traversal */
+ return 0;
+}
+
+PyTypeObject PyFastGlobals_Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "fastglobals",
+ sizeof(PyFastGlobalsObject),
+ 0,
+ (destructor)fg_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT |
+ Py_TPFLAGS_HAVE_GC, /* tp_flags */
+ 0, /* tp_doc */
+ (traverseproc)fg_traverse, /* tp_traverse */
+ (inquiry)fg_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+};
+
+
+void
+PyFastGlobals_Fini(void)
+{
+ Py_XDECREF(__builtins__);
+}
Index: Objects/dictobject.c
===================================================================
--- Objects/dictobject.c (revision 59259)
+++ Objects/dictobject.c (working copy)
@@ -207,6 +207,7 @@
if (mp->ma_fill) {
EMPTY_TO_MINSIZE(mp);
}
+ mp->ma_entryversion = 0;
assert (mp->ma_used == 0);
assert (mp->ma_table == mp->ma_smalltable);
assert (mp->ma_mask == PyDict_MINSIZE - 1);
@@ -215,6 +216,7 @@
if (mp == NULL)
return NULL;
EMPTY_TO_MINSIZE(mp);
+ mp->ma_entryversion = 0;
}
mp->ma_lookup = lookdict_string;
#ifdef SHOW_CONVERSION_COUNTS
@@ -425,6 +427,7 @@
ep->me_hash = (Py_ssize_t)hash;
ep->me_value = value;
mp->ma_used++;
+ mp->ma_entryversion++; /* key insert invalidates */
}
return 0;
}
@@ -546,6 +549,7 @@
if (is_oldtable_malloced)
PyMem_DEL(oldtable);
+ mp->ma_entryversion++; /* table resize invalidates */
return 0;
}
@@ -602,6 +606,42 @@
return ep->me_value;
}
+/* Like PyDict_GetItem, but retrieves a PyDictEntry pointer. This is NOT
+safe to use unless you VERY carefully keep track of the dictionary's
+entries version and update your entries pointers when it changes. This is
+a little tricker than it sounds because key comparisons can change a
+dictionary's entries. See fastglobals.h/fastglobals.c for examples of how
+to use it safely.
+
+Returns NULL with an exception set if an error occurred, or NULL without
+an exception set if the key is not in the dictionary. ??? Is there a
+better way to do this? */
+PyDictEntry *
+PyDict_GetEntry(PyObject *op, PyObject *key)
+{
+ PyDictObject *mp;
+ long hash;
+ PyDictEntry *ep;
+
+ if (!PyDict_Check(op)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ assert(key != NULL);
+ mp = (PyDictObject *)op;
+
+ if (!PyString_CheckExact(key) ||
+ (hash = ((PyStringObject *)key)->ob_shash) == -1) {
+ if ((hash = PyObject_Hash(key)) == -1)
+ return NULL;
+ }
+
+ ep = (mp->ma_lookup)(mp, key, hash);
+ if (ep == NULL || ep->me_value == NULL)
+ return NULL;
+ return ep;
+}
+
/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
* dictionary if it's merely replacing the value for an existing key.
* This means that it's safe to loop over a dictionary with PyDict_Next()
@@ -690,6 +730,7 @@
old_value = ep->me_value;
ep->me_value = NULL;
mp->ma_used--;
+ mp->ma_entryversion++; /* deleting invalidates */
Py_DECREF(old_value);
Py_DECREF(old_key);
return 0;
@@ -762,6 +803,7 @@
if (table_is_malloced)
PyMem_DEL(table);
+ mp->ma_entryversion++; /* clear invalidates */
}
/*
@@ -1862,6 +1904,7 @@
old_value = ep->me_value;
ep->me_value = NULL;
mp->ma_used--;
+ mp->ma_entryversion++; /* deleting invalidates */
Py_DECREF(old_key);
return old_value;
}
@@ -1921,6 +1964,7 @@
mp->ma_used--;
assert(mp->ma_table[0].me_value == NULL);
mp->ma_table[0].me_hash = i + 1; /* next place to start */
+ mp->ma_entryversion++; /* deleting invalidates */
return res;
}
Index: Objects/frameobject.c
===================================================================
--- Objects/frameobject.c (revision 59259)
+++ Objects/frameobject.c (working copy)
@@ -17,8 +17,6 @@
static PyMemberDef frame_memberlist[] = {
{"f_back", T_OBJECT, OFF(f_back), RO},
{"f_code", T_OBJECT, OFF(f_code), RO},
- {"f_builtins", T_OBJECT, OFF(f_builtins),RO},
- {"f_globals", T_OBJECT, OFF(f_globals), RO},
{"f_lasti", T_INT, OFF(f_lasti), RO},
{"f_exc_type", T_OBJECT, OFF(f_exc_type)},
{"f_exc_value", T_OBJECT, OFF(f_exc_value)},
@@ -35,6 +33,22 @@
}
static PyObject *
+frame_getglobals(PyFrameObject *f, void *closure)
+{
+ PyObject *globals = PyFrame_GET_GLOBALS(f);
+ Py_INCREF(globals);
+ return globals;
+}
+
+static PyObject *
+frame_getbuiltins(PyFrameObject *f, void *closure)
+{
+ PyObject *builtins = PyFrame_GET_BUILTINS(f);
+ Py_INCREF(builtins);
+ return builtins;
+}
+
+static PyObject *
frame_getlineno(PyFrameObject *f, void *closure)
{
int lineno;
@@ -348,6 +362,8 @@
static PyGetSetDef frame_getsetlist[] = {
{"f_locals", (getter)frame_getlocals, NULL, NULL},
+ {"f_globals", (getter)frame_getglobals, NULL, NULL},
+ {"f_builtins", (getter)frame_getbuiltins, NULL, NULL},
{"f_lineno", (getter)frame_getlineno,
(setter)frame_setlineno, NULL},
{"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL},
@@ -422,8 +438,7 @@
}
Py_XDECREF(f->f_back);
- Py_DECREF(f->f_builtins);
- Py_DECREF(f->f_globals);
+ Py_CLEAR(f->f_fastglobals);
Py_CLEAR(f->f_locals);
Py_CLEAR(f->f_trace);
Py_CLEAR(f->f_exc_type);
@@ -453,8 +468,14 @@
Py_VISIT(f->f_back);
Py_VISIT(f->f_code);
- Py_VISIT(f->f_builtins);
- Py_VISIT(f->f_globals);
+ /* This is a bad idea now: if gc breaks a cycle by clearing
+ f_fastglobals, when a generator is finally collected it does this
+ sequence of calls: gen_del->gen_close->gen_send_ex->
+ PyEval_EvalFrameEx. But PyEval_EvalFrameEx references
+ f_fastglobals->globals, which will be cleared by then, resuling
+ in a segfault.
+ ??? Is there a way to preserve this traversal? */
+ /* Py_VISIT(f->f_fastglobals); */
Py_VISIT(f->f_locals);
Py_VISIT(f->f_trace);
Py_VISIT(f->f_exc_type);
@@ -543,60 +564,33 @@
0, /* tp_dict */
};
-static PyObject *builtin_object;
-
int _PyFrame_Init()
{
- builtin_object = PyString_InternFromString("__builtins__");
- return (builtin_object != NULL);
+ return 1;
}
PyFrameObject *
-PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
- PyObject *locals)
+PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
+ PyObject *fastglobals, PyObject *locals)
{
PyFrameObject *back = tstate->frame;
PyFrameObject *f;
- PyObject *builtins;
Py_ssize_t i;
#ifdef Py_DEBUG
- if (code == NULL || globals == NULL || !PyDict_Check(globals) ||
+ if (code == NULL || fastglobals == NULL ||
+ !PyFastGlobals_Check(fastglobals) ||
(locals != NULL && !PyMapping_Check(locals))) {
PyErr_BadInternalCall();
return NULL;
}
#endif
- if (back == NULL || back->f_globals != globals) {
- builtins = PyDict_GetItem(globals, builtin_object);
- if (builtins) {
- if (PyModule_Check(builtins)) {
- builtins = PyModule_GetDict(builtins);
- assert(!builtins || PyDict_Check(builtins));
- }
- else if (!PyDict_Check(builtins))
- builtins = NULL;
- }
- if (builtins == NULL) {
- /* No builtins! Make up a minimal one
- Give them 'None', at least. */
- builtins = PyDict_New();
- if (builtins == NULL ||
- PyDict_SetItemString(
- builtins, "None", Py_None) < 0)
- return NULL;
- }
- else
- Py_INCREF(builtins);
-
- }
- else {
- /* If we share the globals, we share the builtins.
- Save a lookup and a call. */
- builtins = back->f_builtins;
- assert(builtins != NULL && PyDict_Check(builtins));
- Py_INCREF(builtins);
- }
+ /* Superfluous checks here almost always save a function call */
+ if (!PyFastGlobals_IS_UPDATED(fastglobals) ||
+ PyFastGlobals_BUILTINS_CHANGED(fastglobals))
+ if (PyFastGlobals_CheckBuiltins(fastglobals) < 0)
+ return NULL;
+
if (code->co_zombieframe != NULL) {
f = code->co_zombieframe;
code->co_zombieframe = NULL;
@@ -613,7 +607,6 @@
f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type,
extras);
if (f == NULL) {
- Py_DECREF(builtins);
return NULL;
}
}
@@ -625,7 +618,6 @@
if (Py_Size(f) < extras) {
f = PyObject_GC_Resize(PyFrameObject, f, extras);
if (f == NULL) {
- Py_DECREF(builtins);
return NULL;
}
}
@@ -642,12 +634,11 @@
f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL;
}
f->f_stacktop = f->f_valuestack;
- f->f_builtins = builtins;
Py_XINCREF(back);
f->f_back = back;
Py_INCREF(code);
- Py_INCREF(globals);
- f->f_globals = globals;
+ Py_INCREF(fastglobals);
+ f->f_fastglobals = fastglobals;
/* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */
if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) ==
(CO_NEWLOCALS | CO_OPTIMIZED))
@@ -662,7 +653,7 @@
}
else {
if (locals == NULL)
- locals = globals;
+ locals = PyFastGlobals_GLOBALS(fastglobals);
Py_INCREF(locals);
f->f_locals = locals;
}
@@ -899,6 +890,4 @@
--numfree;
}
assert(numfree == 0);
- Py_XDECREF(builtin_object);
- builtin_object = NULL;
}
Index: Objects/funcobject.c
===================================================================
--- Objects/funcobject.c (revision 59259)
+++ Objects/funcobject.c (working copy)
@@ -9,9 +9,16 @@
PyObject *
PyFunction_New(PyObject *code, PyObject *globals)
{
- PyFunctionObject *op = PyObject_GC_New(PyFunctionObject,
- &PyFunction_Type);
static PyObject *__name__ = 0;
+ PyFunctionObject *op;
+ PyObject *fastglobals;
+
+ fastglobals = PyFastGlobals_New(globals,
+ ((PyCodeObject*)code)->co_names);
+ if (fastglobals == NULL)
+ return NULL;
+
+ op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
if (op != NULL) {
PyObject *doc;
PyObject *consts;
@@ -19,8 +26,7 @@
op->func_weakreflist = NULL;
Py_INCREF(code);
op->func_code = code;
- Py_INCREF(globals);
- op->func_globals = globals;
+ op->func_fastglobals = fastglobals;
op->func_name = ((PyCodeObject *)code)->co_name;
Py_INCREF(op->func_name);
op->func_defaults = NULL; /* No default arguments */
@@ -54,8 +60,10 @@
op->func_module = module;
}
}
- else
+ else {
+ Py_DECREF(fastglobals);
return NULL;
+ }
_PyObject_GC_TRACK(op);
return (PyObject *)op;
}
@@ -77,7 +85,7 @@
PyErr_BadInternalCall();
return NULL;
}
- return ((PyFunctionObject *) op) -> func_globals;
+ return PyFunction_GET_GLOBALS(op);
}
PyObject *
@@ -165,10 +173,6 @@
RESTRICTED|READONLY},
{"func_doc", T_OBJECT, OFF(func_doc), PY_WRITE_RESTRICTED},
{"__doc__", T_OBJECT, OFF(func_doc), PY_WRITE_RESTRICTED},
- {"func_globals", T_OBJECT, OFF(func_globals),
- RESTRICTED|READONLY},
- {"__globals__", T_OBJECT, OFF(func_globals),
- RESTRICTED|READONLY},
{"__module__", T_OBJECT, OFF(func_module), PY_WRITE_RESTRICTED},
{NULL} /* Sentinel */
};
@@ -329,6 +333,15 @@
return 0;
}
+static PyObject *
+func_get_globals(PyFunctionObject *op)
+{
+ if (restricted())
+ return NULL;
+ Py_INCREF(PyFunction_GET_GLOBALS(op));
+ return PyFunction_GET_GLOBALS(op);
+}
+
static PyGetSetDef func_getsetlist[] = {
{"func_code", (getter)func_get_code, (setter)func_set_code},
{"__code__", (getter)func_get_code, (setter)func_set_code},
@@ -340,6 +353,8 @@
{"__dict__", (getter)func_get_dict, (setter)func_set_dict},
{"func_name", (getter)func_get_name, (setter)func_set_name},
{"__name__", (getter)func_get_name, (setter)func_set_name},
+ {"func_globals", (getter)func_get_globals, NULL},
+ {"__globals__", (getter)func_get_globals, NULL},
{NULL} /* Sentinel */
};
@@ -452,7 +467,7 @@
if (op->func_weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) op);
Py_DECREF(op->func_code);
- Py_DECREF(op->func_globals);
+ Py_DECREF(op->func_fastglobals);
Py_XDECREF(op->func_module);
Py_DECREF(op->func_name);
Py_XDECREF(op->func_defaults);
@@ -474,7 +489,7 @@
func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
{
Py_VISIT(f->func_code);
- Py_VISIT(f->func_globals);
+ Py_VISIT(f->func_fastglobals);
Py_VISIT(f->func_module);
Py_VISIT(f->func_defaults);
Py_VISIT(f->func_doc);
@@ -523,7 +538,7 @@
result = PyEval_EvalCodeEx(
(PyCodeObject *)PyFunction_GET_CODE(func),
- PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
+ PyFunction_GET_FASTGLOBALS(func), (PyObject *)NULL,
&PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
k, nk, d, nd,
PyFunction_GET_CLOSURE(func));
Index: PC/os2emx/Makefile
===================================================================
--- PC/os2emx/Makefile (revision 59259)
+++ PC/os2emx/Makefile (working copy)
@@ -405,7 +405,8 @@
Objects/typeobject.c \
Objects/unicodeobject.c \
Objects/unicodectype.c \
- Objects/weakrefobject.c)
+ Objects/weakrefobject.c \
+ Objects/fastglobals.c)
SRC.LIB= $(SRC.OS2EMX) \
$(SRC.MAIN) \
Index: PC/VC6/pythoncore.dsp
===================================================================
--- PC/VC6/pythoncore.dsp (revision 59259)
+++ PC/VC6/pythoncore.dsp (working copy)
@@ -687,6 +687,10 @@
# End Source File
# Begin Source File
+SOURCE=..\..\Objects\fastglobals.c
+# End Source File
+# Begin Source File
+
SOURCE=..\..\Modules\xxsubtype.c
# End Source File
# Begin Source File
Index: Lib/test/test_gc.py
===================================================================
--- Lib/test/test_gc.py (revision 59259)
+++ Lib/test/test_gc.py (working copy)
@@ -173,7 +173,7 @@
exec("def f(): pass\n") in d
gc.collect()
del d
- self.assertEqual(gc.collect(), 2)
+ self.assertEqual(gc.collect(), 4)
def test_frame(self):
def f():
Index: Makefile.pre.in
===================================================================
--- Makefile.pre.in (revision 59259)
+++ Makefile.pre.in (working copy)
@@ -306,6 +306,7 @@
Objects/listobject.o \
Objects/longobject.o \
Objects/dictobject.o \
+ Objects/fastglobals.o \
Objects/methodobject.o \
Objects/moduleobject.o \
Objects/object.o \
@@ -529,6 +530,7 @@
Include/complexobject.h \
Include/descrobject.h \
Include/dictobject.h \
+ Include/fastglobals.h \
Include/enumobject.h \
Include/genobject.h \
Include/fileobject.h \
Index: Modules/_ctypes/callbacks.c
===================================================================
--- Modules/_ctypes/callbacks.c (revision 59259)
+++ Modules/_ctypes/callbacks.c (working copy)
@@ -34,6 +34,7 @@
PyObject *py_srcfile = 0;
PyObject *py_funcname = 0;
PyObject *py_globals = 0;
+ PyObject *py_fastglobals = 0;
PyObject *empty_tuple = 0;
PyObject *empty_string = 0;
PyCodeObject *py_code = 0;
@@ -47,6 +48,8 @@
if (!py_globals) goto bad;
empty_tuple = PyTuple_New(0);
if (!empty_tuple) goto bad;
+ py_fastglobals = PyFastGlobals_New(py_globals, empty_tuple);
+ if (!py_fastglobals) goto bad;
empty_string = PyString_FromString("");
if (!empty_string) goto bad;
py_code = PyCode_New(
@@ -69,7 +72,7 @@
py_frame = PyFrame_New(
PyThreadState_Get(), /*PyThreadState *tstate,*/
py_code, /*PyCodeObject *code,*/
- py_globals, /*PyObject *globals,*/
+ py_fastglobals, /*PyObject *fastglobals,*/
0 /*PyObject *locals*/
);
if (!py_frame) goto bad;
@@ -77,6 +80,7 @@
PyTraceBack_Here(py_frame);
bad:
Py_XDECREF(py_globals);
+ Py_XDECREF(py_fastglobals);
Py_XDECREF(py_srcfile);
Py_XDECREF(py_funcname);
Py_XDECREF(empty_tuple);
Index: Modules/pyexpat.c
===================================================================
--- Modules/pyexpat.c (revision 59259)
+++ Modules/pyexpat.c (working copy)
@@ -380,11 +380,16 @@
PyThreadState *tstate = PyThreadState_GET();
PyFrameObject *f;
PyObject *res;
+ PyObject *fastglobals;
if (c == NULL)
return NULL;
- f = PyFrame_New(tstate, c, PyEval_GetGlobals(), NULL);
+ fastglobals = PyFastGlobals_New(PyEval_GetGlobals(), c->co_names);
+ if (fastglobals == NULL)
+ return NULL;
+ f = PyFrame_New(tstate, c, fastglobals, NULL);
+ Py_CLEAR(fastglobals); /* Don't need this anymore */
if (f == NULL)
return NULL;
tstate->frame = f;
Index: PCbuild8/pythoncore/pythoncore.vcproj
===================================================================
--- PCbuild8/pythoncore/pythoncore.vcproj (revision 59259)
+++ PCbuild8/pythoncore/pythoncore.vcproj (working copy)
@@ -935,6 +935,10 @@
RelativePath="..\..\Objects\weakrefobject.c"
>
+
+
+
+
+
+