Commit ea525a2d authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #27078: Added BUILD_STRING opcode. Optimized f-strings evaluation.

parent 620bb277
......@@ -777,6 +777,14 @@ All of the following opcodes use their arguments.
.. versionadded:: 3.6
.. opcode:: BUILD_STRING (count)
Concatenates *count* strings from the stack and pushes the resulting string
onto the stack.
.. versionadded:: 3.6
.. opcode:: LOAD_ATTR (namei)
Replaces TOS with ``getattr(TOS, co_names[namei])``.
......
......@@ -123,6 +123,7 @@ extern "C" {
#define SETUP_ASYNC_WITH 154
#define FORMAT_VALUE 155
#define BUILD_CONST_KEY_MAP 156
#define BUILD_STRING 157
/* EXCEPT_HANDLER is a special, implicit block type which is created when
entering an except handler. It is not an opcode but we define it here
......
......@@ -1955,6 +1955,14 @@ PyAPI_FUNC(PyObject*) PyUnicode_Join(
PyObject *seq /* Sequence object */
);
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyUnicode_JoinArray(
PyObject *separator,
PyObject **items,
Py_ssize_t seqlen
);
#endif /* Py_LIMITED_API */
/* Return 1 if substr matches str[start:end] at the given tail end, 0
otherwise. */
......
......@@ -232,7 +232,8 @@ _code_type = type(_write_atomic.__code__)
# Python 3.6a1 3370 (16 bit wordcode)
# Python 3.6a1 3371 (add BUILD_CONST_KEY_MAP opcode #27140)
# Python 3.6a1 3372 (MAKE_FUNCTION simplification, remove MAKE_CLOSURE
#27095)
# #27095)
# Python 3.6b1 3373 (add BUILD_STRING opcode #27078)
#
# MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually
......@@ -241,7 +242,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3372).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3373).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__'
......
......@@ -213,5 +213,6 @@ def_op('BUILD_SET_UNPACK', 153)
def_op('FORMAT_VALUE', 155)
def_op('BUILD_CONST_KEY_MAP', 156)
def_op('BUILD_STRING', 157)
del def_op, name_op, jrel_op, jabs_op
......@@ -10,6 +10,8 @@ What's New in Python 3.6.0 beta 1
Core and Builtins
-----------------
- Issue #27078: Added BUILD_STRING opcode. Optimized f-strings evaluation.
- Issue #17884: Python now requires systems with inttypes.h and stdint.h
- Issue #27961: Require platforms to support ``long long``. Python hasn't
......
......@@ -675,13 +675,31 @@ PyObject_Format(PyObject *obj, PyObject *format_spec)
PyObject *result = NULL;
_Py_IDENTIFIER(__format__);
if (format_spec != NULL && !PyUnicode_Check(format_spec)) {
PyErr_Format(PyExc_SystemError,
"Format specifier must be a string, not %.200s",
Py_TYPE(format_spec)->tp_name);
return NULL;
}
/* Fast path for common types. */
if (format_spec == NULL || PyUnicode_GET_LENGTH(format_spec) == 0) {
if (PyUnicode_CheckExact(obj)) {
Py_INCREF(obj);
return obj;
}
if (PyLong_CheckExact(obj)) {
return PyObject_Str(obj);
}
}
/* If no format_spec is provided, use an empty string */
if (format_spec == NULL) {
empty = PyUnicode_New(0, 0);
format_spec = empty;
}
/* Find the (unbound!) __format__ method (a borrowed reference) */
/* Find the (unbound!) __format__ method */
meth = _PyObject_LookupSpecial(obj, &PyId___format__);
if (meth == NULL) {
if (!PyErr_Occurred())
......
......@@ -9892,20 +9892,10 @@ case_operation(PyObject *self,
PyObject *
PyUnicode_Join(PyObject *separator, PyObject *seq)
{
PyObject *sep = NULL;
Py_ssize_t seplen;
PyObject *res = NULL; /* the result */
PyObject *fseq; /* PySequence_Fast(seq) */
Py_ssize_t seqlen; /* len(fseq) -- number of items in sequence */
PyObject *res;
PyObject *fseq;
Py_ssize_t seqlen;
PyObject **items;
PyObject *item;
Py_ssize_t sz, i, res_offset;
Py_UCS4 maxchar;
Py_UCS4 item_maxchar;
int use_memcpy;
unsigned char *res_data = NULL, *sep_data = NULL;
PyObject *last_obj;
unsigned int kind = 0;
fseq = PySequence_Fast(seq, "can only join an iterable");
if (fseq == NULL) {
......@@ -9916,21 +9906,39 @@ PyUnicode_Join(PyObject *separator, PyObject *seq)
* so we are sure that fseq won't be mutated.
*/
items = PySequence_Fast_ITEMS(fseq);
seqlen = PySequence_Fast_GET_SIZE(fseq);
res = _PyUnicode_JoinArray(separator, items, seqlen);
Py_DECREF(fseq);
return res;
}
PyObject *
_PyUnicode_JoinArray(PyObject *separator, PyObject **items, Py_ssize_t seqlen)
{
PyObject *res = NULL; /* the result */
PyObject *sep = NULL;
Py_ssize_t seplen;
PyObject *item;
Py_ssize_t sz, i, res_offset;
Py_UCS4 maxchar;
Py_UCS4 item_maxchar;
int use_memcpy;
unsigned char *res_data = NULL, *sep_data = NULL;
PyObject *last_obj;
unsigned int kind = 0;
/* If empty sequence, return u"". */
if (seqlen == 0) {
Py_DECREF(fseq);
_Py_RETURN_UNICODE_EMPTY();
}
/* If singleton sequence with an exact Unicode, return that. */
last_obj = NULL;
items = PySequence_Fast_ITEMS(fseq);
if (seqlen == 1) {
if (PyUnicode_CheckExact(items[0])) {
res = items[0];
Py_INCREF(res);
Py_DECREF(fseq);
return res;
}
seplen = 0;
......@@ -10065,13 +10073,11 @@ PyUnicode_Join(PyObject *separator, PyObject *seq)
assert(res_offset == PyUnicode_GET_LENGTH(res));
}
Py_DECREF(fseq);
Py_XDECREF(sep);
assert(_PyUnicode_CheckConsistency(res, 1));
return res;
onError:
Py_DECREF(fseq);
Py_XDECREF(sep);
Py_XDECREF(res);
return NULL;
......
......@@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = {
{ 3190, 3230, L"3.3" },
{ 3250, 3310, L"3.4" },
{ 3320, 3351, L"3.5" },
{ 3360, 3371, L"3.6" },
{ 3360, 3373, L"3.6" },
{ 0 }
};
......
......@@ -2538,6 +2538,24 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET(BUILD_STRING) {
PyObject *str;
PyObject *empty = PyUnicode_New(0, 0);
if (empty == NULL) {
goto error;
}
str = _PyUnicode_JoinArray(empty, stack_pointer - oparg, oparg);
Py_DECREF(empty);
if (str == NULL)
goto error;
while (--oparg >= 0) {
PyObject *item = POP();
Py_DECREF(item);
}
PUSH(str);
DISPATCH();
}
TARGET(BUILD_TUPLE) {
PyObject *tup = PyTuple_New(oparg);
if (tup == NULL)
......
......@@ -970,6 +970,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
case BUILD_TUPLE:
case BUILD_LIST:
case BUILD_SET:
case BUILD_STRING:
return 1-oparg;
case BUILD_LIST_UNPACK:
case BUILD_TUPLE_UNPACK:
......@@ -3315,31 +3316,8 @@ compiler_call(struct compiler *c, expr_ty e)
static int
compiler_joined_str(struct compiler *c, expr_ty e)
{
/* Concatenate parts of a string using ''.join(parts). There are
probably better ways of doing this.
This is used for constructs like "'x=' f'{42}'", which have to
be evaluated at compile time. */
static PyObject *empty_string;
static PyObject *join_string;
if (!empty_string) {
empty_string = PyUnicode_FromString("");
if (!empty_string)
return 0;
}
if (!join_string) {
join_string = PyUnicode_FromString("join");
if (!join_string)
return 0;
}
ADDOP_O(c, LOAD_CONST, empty_string, consts);
ADDOP_NAME(c, LOAD_ATTR, join_string, names);
VISIT_SEQ(c, expr, e->v.JoinedStr.values);
ADDOP_I(c, BUILD_LIST, asdl_seq_LEN(e->v.JoinedStr.values));
ADDOP_I(c, CALL_FUNCTION, 1);
ADDOP_I(c, BUILD_STRING, asdl_seq_LEN(e->v.JoinedStr.values));
return 1;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -156,7 +156,7 @@ static void *opcode_targets[256] = {
&&TARGET_SETUP_ASYNC_WITH,
&&TARGET_FORMAT_VALUE,
&&TARGET_BUILD_CONST_KEY_MAP,
&&_unknown_opcode,
&&TARGET_BUILD_STRING,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment