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. ...@@ -777,6 +777,14 @@ All of the following opcodes use their arguments.
.. versionadded:: 3.6 .. 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) .. opcode:: LOAD_ATTR (namei)
Replaces TOS with ``getattr(TOS, co_names[namei])``. Replaces TOS with ``getattr(TOS, co_names[namei])``.
......
...@@ -123,6 +123,7 @@ extern "C" { ...@@ -123,6 +123,7 @@ extern "C" {
#define SETUP_ASYNC_WITH 154 #define SETUP_ASYNC_WITH 154
#define FORMAT_VALUE 155 #define FORMAT_VALUE 155
#define BUILD_CONST_KEY_MAP 156 #define BUILD_CONST_KEY_MAP 156
#define BUILD_STRING 157
/* EXCEPT_HANDLER is a special, implicit block type which is created when /* 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 entering an except handler. It is not an opcode but we define it here
......
...@@ -1955,6 +1955,14 @@ PyAPI_FUNC(PyObject*) PyUnicode_Join( ...@@ -1955,6 +1955,14 @@ PyAPI_FUNC(PyObject*) PyUnicode_Join(
PyObject *seq /* Sequence object */ 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 /* Return 1 if substr matches str[start:end] at the given tail end, 0
otherwise. */ otherwise. */
......
...@@ -232,7 +232,8 @@ _code_type = type(_write_atomic.__code__) ...@@ -232,7 +232,8 @@ _code_type = type(_write_atomic.__code__)
# Python 3.6a1 3370 (16 bit wordcode) # Python 3.6a1 3370 (16 bit wordcode)
# Python 3.6a1 3371 (add BUILD_CONST_KEY_MAP opcode #27140) # Python 3.6a1 3371 (add BUILD_CONST_KEY_MAP opcode #27140)
# Python 3.6a1 3372 (MAKE_FUNCTION simplification, remove MAKE_CLOSURE # 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 # MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually # longer be understood by older implementations of the eval loop (usually
...@@ -241,7 +242,7 @@ _code_type = type(_write_atomic.__code__) ...@@ -241,7 +242,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # 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 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'
......
...@@ -213,5 +213,6 @@ def_op('BUILD_SET_UNPACK', 153) ...@@ -213,5 +213,6 @@ def_op('BUILD_SET_UNPACK', 153)
def_op('FORMAT_VALUE', 155) def_op('FORMAT_VALUE', 155)
def_op('BUILD_CONST_KEY_MAP', 156) def_op('BUILD_CONST_KEY_MAP', 156)
def_op('BUILD_STRING', 157)
del def_op, name_op, jrel_op, jabs_op del def_op, name_op, jrel_op, jabs_op
...@@ -10,6 +10,8 @@ What's New in Python 3.6.0 beta 1 ...@@ -10,6 +10,8 @@ What's New in Python 3.6.0 beta 1
Core and Builtins 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 #17884: Python now requires systems with inttypes.h and stdint.h
- Issue #27961: Require platforms to support ``long long``. Python hasn't - Issue #27961: Require platforms to support ``long long``. Python hasn't
......
...@@ -675,13 +675,31 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) ...@@ -675,13 +675,31 @@ PyObject_Format(PyObject *obj, PyObject *format_spec)
PyObject *result = NULL; PyObject *result = NULL;
_Py_IDENTIFIER(__format__); _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 no format_spec is provided, use an empty string */
if (format_spec == NULL) { if (format_spec == NULL) {
empty = PyUnicode_New(0, 0); empty = PyUnicode_New(0, 0);
format_spec = empty; format_spec = empty;
} }
/* Find the (unbound!) __format__ method (a borrowed reference) */ /* Find the (unbound!) __format__ method */
meth = _PyObject_LookupSpecial(obj, &PyId___format__); meth = _PyObject_LookupSpecial(obj, &PyId___format__);
if (meth == NULL) { if (meth == NULL) {
if (!PyErr_Occurred()) if (!PyErr_Occurred())
......
...@@ -9892,20 +9892,10 @@ case_operation(PyObject *self, ...@@ -9892,20 +9892,10 @@ case_operation(PyObject *self,
PyObject * PyObject *
PyUnicode_Join(PyObject *separator, PyObject *seq) PyUnicode_Join(PyObject *separator, PyObject *seq)
{ {
PyObject *sep = NULL; PyObject *res;
Py_ssize_t seplen; PyObject *fseq;
PyObject *res = NULL; /* the result */ Py_ssize_t seqlen;
PyObject *fseq; /* PySequence_Fast(seq) */
Py_ssize_t seqlen; /* len(fseq) -- number of items in sequence */
PyObject **items; 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"); fseq = PySequence_Fast(seq, "can only join an iterable");
if (fseq == NULL) { if (fseq == NULL) {
...@@ -9916,21 +9906,39 @@ PyUnicode_Join(PyObject *separator, PyObject *seq) ...@@ -9916,21 +9906,39 @@ PyUnicode_Join(PyObject *separator, PyObject *seq)
* so we are sure that fseq won't be mutated. * so we are sure that fseq won't be mutated.
*/ */
items = PySequence_Fast_ITEMS(fseq);
seqlen = PySequence_Fast_GET_SIZE(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 empty sequence, return u"". */
if (seqlen == 0) { if (seqlen == 0) {
Py_DECREF(fseq);
_Py_RETURN_UNICODE_EMPTY(); _Py_RETURN_UNICODE_EMPTY();
} }
/* If singleton sequence with an exact Unicode, return that. */ /* If singleton sequence with an exact Unicode, return that. */
last_obj = NULL; last_obj = NULL;
items = PySequence_Fast_ITEMS(fseq);
if (seqlen == 1) { if (seqlen == 1) {
if (PyUnicode_CheckExact(items[0])) { if (PyUnicode_CheckExact(items[0])) {
res = items[0]; res = items[0];
Py_INCREF(res); Py_INCREF(res);
Py_DECREF(fseq);
return res; return res;
} }
seplen = 0; seplen = 0;
...@@ -10065,13 +10073,11 @@ PyUnicode_Join(PyObject *separator, PyObject *seq) ...@@ -10065,13 +10073,11 @@ PyUnicode_Join(PyObject *separator, PyObject *seq)
assert(res_offset == PyUnicode_GET_LENGTH(res)); assert(res_offset == PyUnicode_GET_LENGTH(res));
} }
Py_DECREF(fseq);
Py_XDECREF(sep); Py_XDECREF(sep);
assert(_PyUnicode_CheckConsistency(res, 1)); assert(_PyUnicode_CheckConsistency(res, 1));
return res; return res;
onError: onError:
Py_DECREF(fseq);
Py_XDECREF(sep); Py_XDECREF(sep);
Py_XDECREF(res); Py_XDECREF(res);
return NULL; return NULL;
......
...@@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = { ...@@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = {
{ 3190, 3230, L"3.3" }, { 3190, 3230, L"3.3" },
{ 3250, 3310, L"3.4" }, { 3250, 3310, L"3.4" },
{ 3320, 3351, L"3.5" }, { 3320, 3351, L"3.5" },
{ 3360, 3371, L"3.6" }, { 3360, 3373, L"3.6" },
{ 0 } { 0 }
}; };
......
...@@ -2538,6 +2538,24 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) ...@@ -2538,6 +2538,24 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
DISPATCH(); 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) { TARGET(BUILD_TUPLE) {
PyObject *tup = PyTuple_New(oparg); PyObject *tup = PyTuple_New(oparg);
if (tup == NULL) if (tup == NULL)
......
...@@ -970,6 +970,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) ...@@ -970,6 +970,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
case BUILD_TUPLE: case BUILD_TUPLE:
case BUILD_LIST: case BUILD_LIST:
case BUILD_SET: case BUILD_SET:
case BUILD_STRING:
return 1-oparg; return 1-oparg;
case BUILD_LIST_UNPACK: case BUILD_LIST_UNPACK:
case BUILD_TUPLE_UNPACK: case BUILD_TUPLE_UNPACK:
...@@ -3315,31 +3316,8 @@ compiler_call(struct compiler *c, expr_ty e) ...@@ -3315,31 +3316,8 @@ compiler_call(struct compiler *c, expr_ty e)
static int static int
compiler_joined_str(struct compiler *c, expr_ty e) 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); VISIT_SEQ(c, expr, e->v.JoinedStr.values);
ADDOP_I(c, BUILD_LIST, asdl_seq_LEN(e->v.JoinedStr.values)); ADDOP_I(c, BUILD_STRING, asdl_seq_LEN(e->v.JoinedStr.values));
ADDOP_I(c, CALL_FUNCTION, 1);
return 1; return 1;
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -156,7 +156,7 @@ static void *opcode_targets[256] = { ...@@ -156,7 +156,7 @@ static void *opcode_targets[256] = {
&&TARGET_SETUP_ASYNC_WITH, &&TARGET_SETUP_ASYNC_WITH,
&&TARGET_FORMAT_VALUE, &&TARGET_FORMAT_VALUE,
&&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_CONST_KEY_MAP,
&&_unknown_opcode, &&TARGET_BUILD_STRING,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_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