Created
October 31, 2013 16:24
-
-
Save kjelly/7252623 to your computer and use it in GitHub Desktop.
python vm 對 += 的最佳化方法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static PyObject * | |
string_concatenate(PyObject *v, PyObject *w, | |
PyFrameObject *f, unsigned char *next_instr) | |
{ | |
/* This function implements 'variable += expr' when both arguments | |
are strings. */ | |
Py_ssize_t v_len = PyString_GET_SIZE(v); | |
Py_ssize_t w_len = PyString_GET_SIZE(w); | |
Py_ssize_t new_len = v_len + w_len; | |
if (new_len < 0) { | |
PyErr_SetString(PyExc_OverflowError, | |
"strings are too large to concat"); | |
return NULL; | |
} | |
if (v->ob_refcnt == 2) { | |
/* In the common case, there are 2 references to the value | |
* stored in 'variable' when the += is performed: one on the | |
* value stack (in 'v') and one still stored in the | |
* 'variable'. We try to delete the variable now to reduce | |
* the refcnt to 1. | |
*/ | |
switch (*next_instr) { | |
case STORE_FAST: | |
{ | |
int oparg = PEEKARG(); | |
PyObject **fastlocals = f->f_localsplus; | |
if (GETLOCAL(oparg) == v) | |
SETLOCAL(oparg, NULL); | |
break; | |
} | |
case STORE_DEREF: | |
{ | |
PyObject **freevars = (f->f_localsplus + | |
f->f_code->co_nlocals); | |
PyObject *c = freevars[PEEKARG()]; | |
if (PyCell_GET(c) == v) | |
PyCell_Set(c, NULL); | |
break; | |
} | |
case STORE_NAME: | |
{ | |
PyObject *names = f->f_code->co_names; | |
PyObject *name = GETITEM(names, PEEKARG()); | |
PyObject *locals = f->f_locals; | |
if (PyDict_CheckExact(locals) && | |
PyDict_GetItem(locals, name) == v) { | |
if (PyDict_DelItem(locals, name) != 0) { | |
PyErr_Clear(); | |
} | |
} | |
break; | |
} | |
} | |
} | |
if (v->ob_refcnt == 1 && !PyString_CHECK_INTERNED(v)) { | |
/* Now we own the last reference to 'v', so we can resize it | |
* in-place. | |
*/ | |
if (_PyString_Resize(&v, new_len) != 0) { | |
/* XXX if _PyString_Resize() fails, 'v' has been | |
* deallocated so it cannot be put back into | |
* 'variable'. The MemoryError is raised when there | |
* is no value in 'variable', which might (very | |
* remotely) be a cause of incompatibilities. | |
*/ | |
return NULL; | |
} | |
/* copy 'w' into the newly allocated area of 'v' */ | |
memcpy(PyString_AS_STRING(v) + v_len, | |
PyString_AS_STRING(w), w_len); | |
return v; | |
} | |
else { | |
/* When in-place resizing is not an option. */ | |
PyString_Concat(&v, w); | |
return v; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment