Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d2a915d

Browse files
author
Victor Stinner
committed
ceval.c: restore str+=str optimization
1 parent a3be613 commit d2a915d

1 file changed

Lines changed: 73 additions & 3 deletions

File tree

Python/ceval.c

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ static PyObject * import_from(PyObject *, PyObject *);
136136
static int import_all_from(PyObject *, PyObject *);
137137
static void format_exc_check_arg(PyObject *, const char *, PyObject *);
138138
static void format_exc_unbound(PyCodeObject *co, int oparg);
139+
static PyObject * unicode_concatenate(PyObject *, PyObject *,
140+
PyFrameObject *, unsigned char *);
139141
static PyObject * special_lookup(PyObject *, char *, PyObject **);
140142

141143
#define NAME_ERROR_MSG \
@@ -1507,8 +1509,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
15071509
TARGET(BINARY_ADD)
15081510
w = POP();
15091511
v = TOP();
1510-
x = PyNumber_Add(v, w);
1512+
if (PyUnicode_CheckExact(v) &&
1513+
PyUnicode_CheckExact(w)) {
1514+
x = unicode_concatenate(v, w, f, next_instr);
1515+
/* unicode_concatenate consumed the ref to v */
1516+
goto skip_decref_vx;
1517+
}
1518+
else {
1519+
x = PyNumber_Add(v, w);
1520+
}
15111521
Py_DECREF(v);
1522+
skip_decref_vx:
15121523
Py_DECREF(w);
15131524
SET_TOP(x);
15141525
if (x != NULL) DISPATCH();
@@ -1659,8 +1670,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
16591670
TARGET(INPLACE_ADD)
16601671
w = POP();
16611672
v = TOP();
1662-
x = PyNumber_InPlaceAdd(v, w);
1673+
if (PyUnicode_CheckExact(v) &&
1674+
PyUnicode_CheckExact(w)) {
1675+
x = unicode_concatenate(v, w, f, next_instr);
1676+
/* unicode_concatenate consumed the ref to v */
1677+
goto skip_decref_v;
1678+
}
1679+
else {
1680+
x = PyNumber_InPlaceAdd(v, w);
1681+
}
16631682
Py_DECREF(v);
1683+
skip_decref_v:
16641684
Py_DECREF(w);
16651685
SET_TOP(x);
16661686
if (x != NULL) DISPATCH();
@@ -3399,7 +3419,7 @@ save_exc_state(PyThreadState *tstate, PyFrameObject *f)
33993419
f->f_exc_traceback = tstate->exc_traceback;
34003420
Py_XDECREF(type);
34013421
Py_XDECREF(value);
3402-
Py_XDECREF(traceback);
3422+
Py_XDECREF(traceback);
34033423
}
34043424

34053425
static void
@@ -4495,6 +4515,56 @@ format_exc_unbound(PyCodeObject *co, int oparg)
44954515
}
44964516
}
44974517

4518+
static PyObject *
4519+
unicode_concatenate(PyObject *v, PyObject *w,
4520+
PyFrameObject *f, unsigned char *next_instr)
4521+
{
4522+
PyObject *res;
4523+
if (Py_REFCNT(v) == 2) {
4524+
/* In the common case, there are 2 references to the value
4525+
* stored in 'variable' when the += is performed: one on the
4526+
* value stack (in 'v') and one still stored in the
4527+
* 'variable'. We try to delete the variable now to reduce
4528+
* the refcnt to 1.
4529+
*/
4530+
switch (*next_instr) {
4531+
case STORE_FAST:
4532+
{
4533+
int oparg = PEEKARG();
4534+
PyObject **fastlocals = f->f_localsplus;
4535+
if (GETLOCAL(oparg) == v)
4536+
SETLOCAL(oparg, NULL);
4537+
break;
4538+
}
4539+
case STORE_DEREF:
4540+
{
4541+
PyObject **freevars = (f->f_localsplus +
4542+
f->f_code->co_nlocals);
4543+
PyObject *c = freevars[PEEKARG()];
4544+
if (PyCell_GET(c) == v)
4545+
PyCell_Set(c, NULL);
4546+
break;
4547+
}
4548+
case STORE_NAME:
4549+
{
4550+
PyObject *names = f->f_code->co_names;
4551+
PyObject *name = GETITEM(names, PEEKARG());
4552+
PyObject *locals = f->f_locals;
4553+
if (PyDict_CheckExact(locals) &&
4554+
PyDict_GetItem(locals, name) == v) {
4555+
if (PyDict_DelItem(locals, name) != 0) {
4556+
PyErr_Clear();
4557+
}
4558+
}
4559+
break;
4560+
}
4561+
}
4562+
}
4563+
res = v;
4564+
PyUnicode_Append(&res, w);
4565+
return res;
4566+
}
4567+
44984568
#ifdef DYNAMIC_EXECUTION_PROFILE
44994569

45004570
static PyObject *

0 commit comments

Comments
 (0)