Skip to content

Commit cf5f44c

Browse files
author
raymond.hettinger
committed
Give meaning to the oparg for BUILD_MAP: estimated size of the dictionary.
Allows dictionaries to be pre-sized (upto 255 elements) saving time lost to re-sizes with their attendant mallocs and re-insertions. Has zero effect on small dictionaries (5 elements or fewer), a slight benefit for dicts upto 22 elements (because they had to resize once anyway), and more benefit for dicts upto 255 elements (saving multiple resizes during the build-up and reducing the number of collisions on the first insertions). Beyond 255 elements, there is no addional benefit. git-svn-id: http://svn.python.org/projects/python/trunk@59553 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 195b7e1 commit cf5f44c

6 files changed

Lines changed: 26 additions & 6 deletions

File tree

Include/dictobject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ PyAPI_FUNC(Py_ssize_t) PyDict_Size(PyObject *mp);
110110
PyAPI_FUNC(PyObject *) PyDict_Copy(PyObject *mp);
111111
PyAPI_FUNC(int) PyDict_Contains(PyObject *mp, PyObject *key);
112112
PyAPI_FUNC(int) _PyDict_Contains(PyObject *mp, PyObject *key, long hash);
113+
PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused);
113114

114115
/* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */
115116
PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other);

Lib/opcode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def jabs_op(name, op):
139139
name_op('LOAD_NAME', 101) # Index in name list
140140
def_op('BUILD_TUPLE', 102) # Number of tuple items
141141
def_op('BUILD_LIST', 103) # Number of list items
142-
def_op('BUILD_MAP', 104) # Always zero for now
142+
def_op('BUILD_MAP', 104) # Number of dict entries (upto 255)
143143
name_op('LOAD_ATTR', 105) # Index in name list
144144
def_op('COMPARE_OP', 106) # Comparison operator
145145
hascompare.append(106)

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 1?
1212
Core and builtins
1313
-----------------
1414

15+
- Compiler now generates simpler and faster code for dictionary literals.
16+
The oparg for BUILD_MAP now indicates an estimated dictionary size.
17+
There is a new opcode, STORE_MAP, for adding entries to the dictionary.
18+
1519
- Issue #1638: %zd configure test fails on Linux
1620

1721
- Issue #1620: New property decorator syntax was modifying the decorator

Objects/dictobject.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,23 @@ dictresize(PyDictObject *mp, Py_ssize_t minused)
549549
return 0;
550550
}
551551

552+
/* Create a new dictionary pre-sized to hold an estimated number of elements.
553+
Underestimates are okay because the dictionary will resize as necessary.
554+
Overestimates just mean the dictionary will be more sparse than usual.
555+
*/
556+
557+
PyObject *
558+
_PyDict_NewPresized(Py_ssize_t minused)
559+
{
560+
PyObject *op = PyDict_New();
561+
562+
if (minused>5 && op != NULL && dictresize((PyDictObject *)op, minused) == -1) {
563+
Py_DECREF(op);
564+
return NULL;
565+
}
566+
return op;
567+
}
568+
552569
/* Note that, for historical reasons, PyDict_GetItem() suppresses all errors
553570
* that may occur (originally dicts supported only string keys, and exceptions
554571
* weren't possible). So, while the original intent was that a NULL return

Python/ceval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1997,7 +1997,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
19971997
break;
19981998

19991999
case BUILD_MAP:
2000-
x = PyDict_New();
2000+
x = _PyDict_NewPresized((Py_ssize_t)oparg);
20012001
PUSH(x);
20022002
if (x != NULL) continue;
20032003
break;

Python/compile.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,11 +2922,9 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
29222922
case IfExp_kind:
29232923
return compiler_ifexp(c, e);
29242924
case Dict_kind:
2925-
/* XXX get rid of arg? */
2926-
ADDOP_I(c, BUILD_MAP, 0);
29272925
n = asdl_seq_LEN(e->v.Dict.values);
2928-
/* We must arrange things just right for STORE_SUBSCR.
2929-
It wants the stack to look like (value) (dict) (key) */
2926+
ADDOP_I(c, BUILD_MAP, (n>255 ? 255 : n));
2927+
n = asdl_seq_LEN(e->v.Dict.values);
29302928
for (i = 0; i < n; i++) {
29312929
VISIT(c, expr,
29322930
(expr_ty)asdl_seq_GET(e->v.Dict.values, i));

0 commit comments

Comments
 (0)