diff options
author | Ronald Oussoren <ronaldoussoren@mac.com> | 2011-03-16 09:43:06 -0400 |
---|---|---|
committer | Ronald Oussoren <ronaldoussoren@mac.com> | 2011-03-16 09:43:06 -0400 |
commit | 9d594ca842ed3426393a24236e8452fc0532f527 (patch) | |
tree | be6b249858fb277f0cc512d49b7f54ee439a3dae /Python | |
parent | c04ce0236c49d9f712ab8e4f11758d0b7d35154d (diff) | |
parent | 5c23d8fb736f0c55edec98df2030117bea152326 (diff) | |
download | cpython-9d594ca842ed3426393a24236e8452fc0532f527.tar.gz |
Merge with 3.1
Diffstat (limited to 'Python')
47 files changed, 4746 insertions, 3671 deletions
diff --git a/Python/Python-ast.c b/Python/Python-ast.c index efc69dcfec..2c09f96f0e 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -2,7 +2,7 @@ /* - __version__ 67616. + __version__ 82163. This module must be committed separately after each AST grammar change; The __version__ number is set to the revision number of the commit @@ -527,7 +527,7 @@ static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int } PyTuple_SET_ITEM(fnames, i, field); } - result = PyObject_CallFunction((PyObject*)&PyType_Type, "U(O){sOss}", + result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}", type, base, "_fields", fnames, "__module__", "_ast"); Py_DECREF(fnames); return (PyTypeObject*)result; @@ -537,8 +537,9 @@ static int add_attributes(PyTypeObject* type, char**attrs, int num_fields) { int i, result; PyObject *s, *l = PyTuple_New(num_fields); - if (!l) return 0; - for(i = 0; i < num_fields; i++) { + if (!l) + return 0; + for (i = 0; i < num_fields; i++) { s = PyUnicode_FromString(attrs[i]); if (!s) { Py_DECREF(l); @@ -1332,11 +1333,6 @@ ImportFrom(identifier module, asdl_seq * names, int level, int lineno, int col_offset, PyArena *arena) { stmt_ty p; - if (!module) { - PyErr_SetString(PyExc_ValueError, - "field module is required for ImportFrom"); - return NULL; - } p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; @@ -3520,6 +3516,7 @@ obj2ast_mod(PyObject* obj, mod_ty* out, PyArena* arena) PyErr_Format(PyExc_TypeError, "expected some sort of mod, but got %R", obj); failed: + Py_XDECREF(tmp); return 1; } @@ -4544,8 +4541,7 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena) Py_XDECREF(tmp); tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"module\" missing from ImportFrom"); - return 1; + module = NULL; } if (PyObject_HasAttrString(obj, "names")) { int res; @@ -4716,6 +4712,7 @@ obj2ast_stmt(PyObject* obj, stmt_ty* out, PyArena* arena) PyErr_Format(PyExc_TypeError, "expected some sort of stmt, but got %R", obj); failed: + Py_XDECREF(tmp); return 1; } @@ -5831,6 +5828,7 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena) PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %R", obj); failed: + Py_XDECREF(tmp); return 1; } @@ -6011,6 +6009,7 @@ obj2ast_slice(PyObject* obj, slice_ty* out, PyArena* arena) PyErr_Format(PyExc_TypeError, "expected some sort of slice, but got %R", obj); failed: + Py_XDECREF(tmp); return 1; } @@ -6443,6 +6442,7 @@ obj2ast_excepthandler(PyObject* obj, excepthandler_ty* out, PyArena* arena) PyErr_Format(PyExc_TypeError, "expected some sort of excepthandler, but got %R", obj); failed: + Py_XDECREF(tmp); return 1; } @@ -6739,7 +6739,7 @@ PyInit__ast(void) NULL; if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0) return NULL; - if (PyModule_AddStringConstant(m, "__version__", "67616") < 0) + if (PyModule_AddStringConstant(m, "__version__", "82163") < 0) return NULL; if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return NULL; diff --git a/Python/_warnings.c b/Python/_warnings.c index 543e0bb4ca..a797887b9c 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -251,7 +251,7 @@ show_warning(PyObject *filename, int lineno, PyObject *text, PyObject name = PyObject_GetAttrString(category, "__name__"); if (name == NULL) /* XXX Can an object lack a '__name__' attribute? */ - return; + return; f_stderr = PySys_GetObject("stderr"); if (f_stderr == NULL) { @@ -461,7 +461,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno, } else { globals = f->f_globals; - *lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); + *lineno = PyFrame_GetLineNumber(f); } *module = NULL; @@ -498,23 +498,21 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno, *filename = PyDict_GetItemString(globals, "__file__"); if (*filename != NULL) { Py_ssize_t len = PyUnicode_GetSize(*filename); - const char *file_str = _PyUnicode_AsString(*filename); - if (file_str == NULL || (len < 0 && PyErr_Occurred())) - goto handle_error; + Py_UNICODE *unicode = PyUnicode_AS_UNICODE(*filename); /* if filename.lower().endswith((".pyc", ".pyo")): */ if (len >= 4 && - file_str[len-4] == '.' && - tolower(file_str[len-3]) == 'p' && - tolower(file_str[len-2]) == 'y' && - (tolower(file_str[len-1]) == 'c' || - tolower(file_str[len-1]) == 'o')) + unicode[len-4] == '.' && + Py_UNICODE_TOLOWER(unicode[len-3]) == 'p' && + Py_UNICODE_TOLOWER(unicode[len-2]) == 'y' && + (Py_UNICODE_TOLOWER(unicode[len-1]) == 'c' || + Py_UNICODE_TOLOWER(unicode[len-1]) == 'o')) { - *filename = PyUnicode_FromStringAndSize(file_str, len-1); - if (*filename == NULL) - goto handle_error; - } - else + *filename = PyUnicode_FromUnicode(unicode, len-1); + if (*filename == NULL) + goto handle_error; + } + else Py_INCREF(*filename); } else { @@ -712,19 +710,17 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds) /* Function to issue a warning message; may raise an exception. */ -int -PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level) + +static int +warn_unicode(PyObject *category, PyObject *message, + Py_ssize_t stack_level) { PyObject *res; - PyObject *message = PyUnicode_FromString(text); - if (message == NULL) - return -1; if (category == NULL) category = PyExc_RuntimeWarning; res = do_warn(message, category, stack_level); - Py_DECREF(message); if (res == NULL) return -1; Py_DECREF(res); @@ -732,6 +728,42 @@ PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level) return 0; } +int +PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level, + const char *format, ...) +{ + int ret; + PyObject *message; + va_list vargs; + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + message = PyUnicode_FromFormatV(format, vargs); + if (message != NULL) { + ret = warn_unicode(category, message, stack_level); + Py_DECREF(message); + } + else + ret = -1; + va_end(vargs); + return ret; +} + +int +PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level) +{ + int ret; + PyObject *message = PyUnicode_FromString(text); + if (message == NULL) + return -1; + ret = warn_unicode(category, message, stack_level); + Py_DECREF(message); + return ret; +} + /* PyErr_Warn is only for backwards compatibility and will be removed. Use PyErr_WarnEx instead. */ @@ -751,7 +783,7 @@ PyErr_WarnExplicit(PyObject *category, const char *text, { PyObject *res; PyObject *message = PyUnicode_FromString(text); - PyObject *filename = PyUnicode_FromString(filename_str); + PyObject *filename = PyUnicode_DecodeFSDefault(filename_str); PyObject *module = NULL; int ret = -1; @@ -803,6 +835,7 @@ create_filter(PyObject *category, const char *action) static PyObject *ignore_str = NULL; static PyObject *error_str = NULL; static PyObject *default_str = NULL; + static PyObject *always_str = NULL; PyObject *action_obj = NULL; PyObject *lineno, *result; @@ -830,6 +863,14 @@ create_filter(PyObject *category, const char *action) } action_obj = default_str; } + else if (!strcmp(action, "always")) { + if (always_str == NULL) { + always_str = PyUnicode_InternFromString("always"); + if (always_str == NULL) + return NULL; + } + action_obj = always_str; + } else { Py_FatalError("unknown action"); } @@ -846,28 +887,42 @@ create_filter(PyObject *category, const char *action) static PyObject * init_filters(void) { - PyObject *filters = PyList_New(3); - const char *bytes_action; + /* Don't silence DeprecationWarning if -3 was used. */ + PyObject *filters = PyList_New(5); + unsigned int pos = 0; /* Post-incremented in each use. */ + unsigned int x; + const char *bytes_action, *resource_action; + if (filters == NULL) return NULL; - PyList_SET_ITEM(filters, 0, + PyList_SET_ITEM(filters, pos++, + create_filter(PyExc_DeprecationWarning, "ignore")); + PyList_SET_ITEM(filters, pos++, create_filter(PyExc_PendingDeprecationWarning, "ignore")); - PyList_SET_ITEM(filters, 1, create_filter(PyExc_ImportWarning, "ignore")); + PyList_SET_ITEM(filters, pos++, + create_filter(PyExc_ImportWarning, "ignore")); if (Py_BytesWarningFlag > 1) bytes_action = "error"; else if (Py_BytesWarningFlag) bytes_action = "default"; else bytes_action = "ignore"; - PyList_SET_ITEM(filters, 2, create_filter(PyExc_BytesWarning, + PyList_SET_ITEM(filters, pos++, create_filter(PyExc_BytesWarning, bytes_action)); - - if (PyList_GET_ITEM(filters, 0) == NULL || - PyList_GET_ITEM(filters, 1) == NULL || - PyList_GET_ITEM(filters, 2) == NULL) { - Py_DECREF(filters); - return NULL; + /* resource usage warnings are enabled by default in pydebug mode */ +#ifdef Py_DEBUG + resource_action = "always"; +#else + resource_action = "ignore"; +#endif + PyList_SET_ITEM(filters, pos++, create_filter(PyExc_ResourceWarning, + resource_action)); + for (x = 0; x < pos; x += 1) { + if (PyList_GET_ITEM(filters, x) == NULL) { + Py_DECREF(filters); + return NULL; + } } return filters; @@ -906,13 +961,13 @@ _PyWarnings_Init(void) if (_once_registry == NULL) return NULL; Py_INCREF(_once_registry); - if (PyModule_AddObject(m, "once_registry", _once_registry) < 0) + if (PyModule_AddObject(m, "_onceregistry", _once_registry) < 0) return NULL; _default_action = PyUnicode_FromString("default"); if (_default_action == NULL) return NULL; - if (PyModule_AddObject(m, "default_action", _default_action) < 0) + if (PyModule_AddObject(m, "_defaultaction", _default_action) < 0) return NULL; return m; } diff --git a/Python/ast.c b/Python/ast.c index 590bc90dab..4edf335c33 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -7,7 +7,6 @@ #include "Python-ast.h" #include "grammar.h" #include "node.h" -#include "pyarena.h" #include "ast.h" #include "token.h" #include "parsetok.h" @@ -90,7 +89,7 @@ new_identifier(const char* n, PyArena *arena) static int ast_error(const node *n, const char *errstr) { - PyObject *u = Py_BuildValue("zi", errstr, LINENO(n)); + PyObject *u = Py_BuildValue("zii", errstr, LINENO(n), n->n_col_offset); if (!u) return 0; PyErr_SetObject(PyExc_SyntaxError, u); @@ -101,7 +100,7 @@ ast_error(const node *n, const char *errstr) static void ast_error_finish(const char *filename) { - PyObject *type, *value, *tback, *errstr, *loc, *tmp; + PyObject *type, *value, *tback, *errstr, *offset, *loc, *tmp; PyObject *filename_obj; long lineno; @@ -119,6 +118,11 @@ ast_error_finish(const char *filename) Py_DECREF(errstr); return; } + offset = PyTuple_GetItem(value, 2); + if (!offset) { + Py_DECREF(errstr); + return; + } Py_DECREF(value); loc = PyErr_ProgramText(filename, lineno); @@ -133,7 +137,7 @@ ast_error_finish(const char *filename) filename_obj = Py_None; } if (filename_obj != NULL) - tmp = Py_BuildValue("(NlOO)", filename_obj, lineno, Py_None, loc); + tmp = Py_BuildValue("(NlOO)", filename_obj, lineno, offset, loc); else tmp = NULL; Py_DECREF(loc); @@ -367,19 +371,24 @@ static const char* FORBIDDEN[] = { "None", "True", "False", - "__debug__", NULL, }; static int -forbidden_name(expr_ty e, const node *n) +forbidden_name(identifier name, const node *n, int full_checks) { - const char **p; - assert(PyUnicode_Check(e->v.Name.id)); - for (p = FORBIDDEN; *p; p++) { - if (PyUnicode_CompareWithASCIIString(e->v.Name.id, *p) == 0) { - ast_error(n, "assignment to keyword"); - return 1; + assert(PyUnicode_Check(name)); + if (PyUnicode_CompareWithASCIIString(name, "__debug__") == 0) { + ast_error(n, "assignment to keyword"); + return 1; + } + if (full_checks) { + const char **p; + for (p = FORBIDDEN; *p; p++) { + if (PyUnicode_CompareWithASCIIString(name, *p) == 0) { + ast_error(n, "assignment to keyword"); + return 1; + } } } return 0; @@ -413,6 +422,8 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n) switch (e->kind) { case Attribute_kind: e->v.Attribute.ctx = ctx; + if (ctx == Store && forbidden_name(e->v.Attribute.attr, n, 1)) + return 0; break; case Subscript_kind: e->v.Subscript.ctx = ctx; @@ -424,7 +435,7 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n) break; case Name_kind: if (ctx == Store) { - if (forbidden_name(e, n)) + if (forbidden_name(e->v.Name.id, n, 1)) return 0; /* forbidden_name() calls ast_error() */ } e->v.Name.ctx = ctx; @@ -434,10 +445,13 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n) s = e->v.List.elts; break; case Tuple_kind: - if (asdl_seq_LEN(e->v.Tuple.elts) == 0) - return ast_error(n, "can't assign to ()"); - e->v.Tuple.ctx = ctx; - s = e->v.Tuple.elts; + if (asdl_seq_LEN(e->v.Tuple.elts)) { + e->v.Tuple.ctx = ctx; + s = e->v.Tuple.elts; + } + else { + expr_name = "()"; + } break; case Lambda_kind: expr_name = "lambda"; @@ -603,20 +617,23 @@ ast_for_comp_op(struct compiling *c, const node *n) static asdl_seq * seq_for_testlist(struct compiling *c, const node *n) { - /* testlist: test (',' test)* [','] */ + /* testlist: test (',' test)* [','] + testlist_star_expr: test|star_expr (',' test|star_expr)* [','] + */ asdl_seq *seq; expr_ty expression; int i; - assert(TYPE(n) == testlist || TYPE(n) == testlist_comp); + assert(TYPE(n) == testlist || TYPE(n) == testlist_star_expr || TYPE(n) == testlist_comp); seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); if (!seq) return NULL; for (i = 0; i < NCH(n); i += 2) { - assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == test_nocond); + const node *ch = CHILD(n, i); + assert(TYPE(ch) == test || TYPE(ch) == test_nocond || TYPE(ch) == star_expr); - expression = ast_for_expr(c, CHILD(n, i)); + expression = ast_for_expr(c, ch); if (!expression) return NULL; @@ -638,6 +655,8 @@ compiler_arg(struct compiling *c, const node *n) name = NEW_IDENTIFIER(ch); if (!name) return NULL; + if (forbidden_name(name, ch, 0)) + return NULL; if (NCH(n) == 3 && TYPE(CHILD(n, 1)) == COLON) { annotation = ast_for_expr(c, CHILD(n, 2)); @@ -704,6 +723,8 @@ handle_keywordonly_args(struct compiling *c, const node *n, int start, argname = NEW_IDENTIFIER(ch); if (!argname) goto error; + if (forbidden_name(argname, ch, 0)) + goto error; arg = arg(argname, annotation, c->c_arena); if (!arg) goto error; @@ -862,6 +883,8 @@ ast_for_arguments(struct compiling *c, const node *n) vararg = NEW_IDENTIFIER(CHILD(ch, 0)); if (!vararg) return NULL; + if (forbidden_name(vararg, CHILD(ch, 0), 0)) + return NULL; if (NCH(ch) > 1) { /* there is an annotation on the vararg */ varargannotation = ast_for_expr(c, CHILD(ch, 2)); @@ -891,6 +914,8 @@ ast_for_arguments(struct compiling *c, const node *n) if (!kwargannotation) return NULL; } + if (forbidden_name(kwarg, CHILD(ch, 0), 0)) + return NULL; i += 3; break; default: @@ -1008,6 +1033,8 @@ ast_for_funcdef(struct compiling *c, const node *n, asdl_seq *decorator_seq) name = NEW_IDENTIFIER(CHILD(n, name_i)); if (!name) return NULL; + if (forbidden_name(name, CHILD(n, name_i), 0)) + return NULL; args = ast_for_arguments(c, CHILD(n, name_i + 1)); if (!args) return NULL; @@ -1182,7 +1209,7 @@ ast_for_comprehension(struct compiling *c, const node *n) for (i = 0; i < n_fors; i++) { comprehension_ty comp; asdl_seq *t; - expr_ty expression; + expr_ty expression, first; node *for_ch; REQ(n, comp_for); @@ -1197,14 +1224,13 @@ ast_for_comprehension(struct compiling *c, const node *n) /* Check the # of children rather than the length of t, since (x for x, in ...) has 1 element in t, but still requires a Tuple. */ + first = (expr_ty)asdl_seq_GET(t, 0); if (NCH(for_ch) == 1) - comp = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, - NULL, c->c_arena); + comp = comprehension(first, expression, NULL, c->c_arena); else - comp = comprehension(Tuple(t, Store, LINENO(n), n->n_col_offset, - c->c_arena), - expression, NULL, c->c_arena); - + comp = comprehension(Tuple(t, Store, first->lineno, first->col_offset, + c->c_arena), + expression, NULL, c->c_arena); if (!comp) return NULL; @@ -1284,7 +1310,6 @@ ast_for_dictcomp(struct compiling *c, const node *n) key = ast_for_expr(c, CHILD(n, 0)); if (!key) return NULL; - value = ast_for_expr(c, CHILD(n, 2)); if (!value) return NULL; @@ -1523,14 +1548,7 @@ ast_for_slice(struct compiling *c, const node *n) ch = CHILD(n, NCH(n) - 1); if (TYPE(ch) == sliceop) { - if (NCH(ch) == 1) { - /* No expression, so step is None */ - ch = CHILD(ch, 0); - step = Name(new_identifier("None", c->c_arena), Load, - LINENO(ch), ch->n_col_offset, c->c_arena); - if (!step) - return NULL; - } else { + if (NCH(ch) != 1) { ch = CHILD(ch, 1); if (TYPE(ch) == test) { step = ast_for_expr(c, ch); @@ -1674,34 +1692,8 @@ ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr) static expr_ty ast_for_factor(struct compiling *c, const node *n) { - node *pfactor, *ppower, *patom, *pnum; expr_ty expression; - /* If the unary - operator is applied to a constant, don't generate - a UNARY_NEGATIVE opcode. Just store the approriate value as a - constant. The peephole optimizer already does something like - this but it doesn't handle the case where the constant is - (sys.maxint - 1). In that case, we want a PyIntObject, not a - PyLongObject. - */ - if (TYPE(CHILD(n, 0)) == MINUS - && NCH(n) == 2 - && TYPE((pfactor = CHILD(n, 1))) == factor - && NCH(pfactor) == 1 - && TYPE((ppower = CHILD(pfactor, 0))) == power - && NCH(ppower) == 1 - && TYPE((patom = CHILD(ppower, 0))) == atom - && TYPE((pnum = CHILD(patom, 0))) == NUMBER) { - char *s = PyObject_MALLOC(strlen(STR(pnum)) + 2); - if (s == NULL) - return NULL; - s[0] = '-'; - strcpy(s + 1, STR(pnum)); - PyObject_FREE(STR(pnum)); - STR(pnum) = s; - return ast_for_atom(c, patom); - } - expression = ast_for_expr(c, CHILD(n, 1)); if (!expression) return NULL; @@ -1885,10 +1877,7 @@ ast_for_expr(struct compiling *c, const node *n) break; case star_expr: - if (TYPE(CHILD(n, 0)) == STAR) { - return ast_for_starred(c, n); - } - /* Fallthrough */ + return ast_for_starred(c, n); /* The next five cases all handle BinOps. The main body of code is the same in each case, but the switch turned inside out to reuse the code for each type of operator. @@ -2024,7 +2013,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func) } else if (e->kind != Name_kind) { ast_error(CHILD(ch, 0), "keyword can't be an expression"); return NULL; - } else if (forbidden_name(e, ch)) { + } else if (forbidden_name(e->v.Name.id, ch, 1)) { return NULL; } key = e->v.Name.id; @@ -2066,7 +2055,6 @@ ast_for_testlist(struct compiling *c, const node* n) { /* testlist_comp: test (comp_for | (',' test)* [',']) */ /* testlist: test (',' test)* [','] */ - /* testlist1: test (',' test)* */ assert(NCH(n) > 0); if (TYPE(n) == testlist_comp) { if (NCH(n) > 1) @@ -2074,7 +2062,7 @@ ast_for_testlist(struct compiling *c, const node* n) } else { assert(TYPE(n) == testlist || - TYPE(n) == testlist1); + TYPE(n) == testlist_star_expr); } if (NCH(n) == 1) return ast_for_expr(c, CHILD(n, 0)); @@ -2090,9 +2078,9 @@ static stmt_ty ast_for_expr_stmt(struct compiling *c, const node *n) { REQ(n, expr_stmt); - /* expr_stmt: testlist (augassign (yield_expr|testlist) + /* expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist))*) - testlist: test (',' test)* [','] + testlist_star_expr: (test|star_expr) (',' test|star_expr)* [','] augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' test: ... here starts the operator precendence dance @@ -2172,7 +2160,7 @@ ast_for_expr_stmt(struct compiling *c, const node *n) asdl_seq_SET(targets, i / 2, e); } value = CHILD(n, NCH(n) - 1); - if (TYPE(value) == testlist) + if (TYPE(value) == testlist_star_expr) expression = ast_for_testlist(c, value); else expression = ast_for_expr(c, value); @@ -2182,6 +2170,7 @@ ast_for_expr_stmt(struct compiling *c, const node *n) } } + static asdl_seq * ast_for_exprlist(struct compiling *c, const node *n, expr_context_ty context) { @@ -2282,49 +2271,64 @@ ast_for_flow_stmt(struct compiling *c, const node *n) } static alias_ty -alias_for_import_name(struct compiling *c, const node *n) +alias_for_import_name(struct compiling *c, const node *n, int store) { /* import_as_name: NAME ['as' NAME] dotted_as_name: dotted_name ['as' NAME] dotted_name: NAME ('.' NAME)* */ - PyObject *str, *name; + identifier str, name; loop: switch (TYPE(n)) { - case import_as_name: + case import_as_name: { + node *name_node = CHILD(n, 0); str = NULL; + name = NEW_IDENTIFIER(name_node); + if (!name) + return NULL; if (NCH(n) == 3) { - str = NEW_IDENTIFIER(CHILD(n, 2)); + node *str_node = CHILD(n, 2); + str = NEW_IDENTIFIER(str_node); if (!str) return NULL; + if (store && forbidden_name(str, str_node, 0)) + return NULL; + } + else { + if (forbidden_name(name, name_node, 0)) + return NULL; } - name = NEW_IDENTIFIER(CHILD(n, 0)); - if (!name) - return NULL; return alias(name, str, c->c_arena); + } case dotted_as_name: if (NCH(n) == 1) { n = CHILD(n, 0); goto loop; } else { - alias_ty a = alias_for_import_name(c, CHILD(n, 0)); + node *asname_node = CHILD(n, 2); + alias_ty a = alias_for_import_name(c, CHILD(n, 0), 0); if (!a) return NULL; assert(!a->asname); - a->asname = NEW_IDENTIFIER(CHILD(n, 2)); + a->asname = NEW_IDENTIFIER(asname_node); if (!a->asname) return NULL; + if (forbidden_name(a->asname, asname_node, 0)) + return NULL; return a; } break; case dotted_name: if (NCH(n) == 1) { - name = NEW_IDENTIFIER(CHILD(n, 0)); + node *name_node = CHILD(n, 0); + name = NEW_IDENTIFIER(name_node); if (!name) return NULL; + if (store && forbidden_name(name, name_node, 0)) + return NULL; return alias(name, NULL, c->c_arena); } else { @@ -2404,7 +2408,7 @@ ast_for_import_stmt(struct compiling *c, const node *n) if (!aliases) return NULL; for (i = 0; i < NCH(n); i += 2) { - alias_ty import_alias = alias_for_import_name(c, CHILD(n, i)); + alias_ty import_alias = alias_for_import_name(c, CHILD(n, i), 1); if (!import_alias) return NULL; asdl_seq_SET(aliases, i / 2, import_alias); @@ -2415,13 +2419,15 @@ ast_for_import_stmt(struct compiling *c, const node *n) int n_children; int idx, ndots = 0; alias_ty mod = NULL; - identifier modname; + identifier modname = NULL; /* Count the number of dots (for relative imports) and check for the optional module name */ for (idx = 1; idx < NCH(n); idx++) { if (TYPE(CHILD(n, idx)) == dotted_name) { - mod = alias_for_import_name(c, CHILD(n, idx)); + mod = alias_for_import_name(c, CHILD(n, idx), 0); + if (!mod) + return NULL; idx++; break; } else if (TYPE(CHILD(n, idx)) == ELLIPSIS) { @@ -2466,14 +2472,14 @@ ast_for_import_stmt(struct compiling *c, const node *n) /* handle "from ... import *" special b/c there's no children */ if (TYPE(n) == STAR) { - alias_ty import_alias = alias_for_import_name(c, n); + alias_ty import_alias = alias_for_import_name(c, n, 1); if (!import_alias) return NULL; asdl_seq_SET(aliases, 0, import_alias); } else { for (i = 0; i < NCH(n); i += 2) { - alias_ty import_alias = alias_for_import_name(c, CHILD(n, i)); + alias_ty import_alias = alias_for_import_name(c, CHILD(n, i), 1); if (!import_alias) return NULL; asdl_seq_SET(aliases, i / 2, import_alias); @@ -2481,8 +2487,6 @@ ast_for_import_stmt(struct compiling *c, const node *n) } if (mod != NULL) modname = mod->name; - else - modname = new_identifier("", c->c_arena); return ImportFrom(modname, aliases, ndots, lineno, col_offset, c->c_arena); } @@ -2795,7 +2799,7 @@ ast_for_for_stmt(struct compiling *c, const node *n) { asdl_seq *_target, *seq = NULL, *suite_seq; expr_ty expression; - expr_ty target; + expr_ty target, first; const node *node_target; /* for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] */ REQ(n, for_stmt); @@ -2812,10 +2816,11 @@ ast_for_for_stmt(struct compiling *c, const node *n) return NULL; /* Check the # of children rather than the length of _target, since for x, in ... has 1 element in _target, but still requires a Tuple. */ + first = (expr_ty)asdl_seq_GET(_target, 0); if (NCH(node_target) == 1) - target = (expr_ty)asdl_seq_GET(_target, 0); + target = first; else - target = Tuple(_target, Store, LINENO(n), n->n_col_offset, c->c_arena); + target = Tuple(_target, Store, first->lineno, first->col_offset, c->c_arena); expression = ast_for_testlist(c, CHILD(n, 3)); if (!expression) @@ -2863,6 +2868,8 @@ ast_for_except_clause(struct compiling *c, const node *exc, node *body) identifier e = NEW_IDENTIFIER(CHILD(exc, 3)); if (!e) return NULL; + if (forbidden_name(e, CHILD(exc, 3), 0)) + return NULL; expression = ast_for_expr(c, CHILD(exc, 1)); if (!expression) return NULL; @@ -3035,6 +3042,8 @@ ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq) classname = NEW_IDENTIFIER(CHILD(n, 1)); if (!classname) return NULL; + if (forbidden_name(classname, CHILD(n, 3), 0)) + return NULL; return ClassDef(classname, NULL, NULL, NULL, NULL, s, decorator_seq, LINENO(n), n->n_col_offset, c->c_arena); } @@ -3046,6 +3055,8 @@ ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq) classname = NEW_IDENTIFIER(CHILD(n, 1)); if (!classname) return NULL; + if (forbidden_name(classname, CHILD(n, 3), 0)) + return NULL; return ClassDef(classname, NULL, NULL, NULL, NULL, s, decorator_seq, LINENO(n), n->n_col_offset, c->c_arena); } @@ -3069,6 +3080,8 @@ ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq) classname = NEW_IDENTIFIER(CHILD(n, 1)); if (!classname) return NULL; + if (forbidden_name(classname, CHILD(n, 1), 0)) + return NULL; return ClassDef(classname, call->v.Call.args, call->v.Call.keywords, call->v.Call.starargs, call->v.Call.kwargs, s, @@ -3153,17 +3166,13 @@ parsenumber(struct compiling *c, const char *s) const char *end; long x; double dx; -#ifndef WITHOUT_COMPLEX Py_complex compl; int imflag; -#endif assert(s != NULL); errno = 0; end = s + strlen(s) - 1; -#ifndef WITHOUT_COMPLEX imflag = *end == 'j' || *end == 'J'; -#endif if (s[0] == '0') { x = (long) PyOS_strtoul((char *)s, (char **)&end, 0); if (x < 0 && errno == 0) { @@ -3180,7 +3189,6 @@ parsenumber(struct compiling *c, const char *s) return PyLong_FromLong(x); } /* XXX Huge floats may silently fail */ -#ifndef WITHOUT_COMPLEX if (imflag) { compl.real = 0.; compl.imag = PyOS_string_to_double(s, (char **)&end, NULL); @@ -3189,7 +3197,6 @@ parsenumber(struct compiling *c, const char *s) return PyComplex_FromCComplex(compl); } else -#endif { dx = PyOS_string_to_double(s, NULL, NULL); if (dx == -1.0 && PyErr_Occurred()) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 3e44aa0566..2aea9f745f 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -5,10 +5,13 @@ #include "node.h" #include "code.h" -#include "eval.h" #include <ctype.h> +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> /* CODESET */ +#endif + /* The default encoding used by the platform file system APIs Can remain NULL for all platforms that don't have such a concept @@ -21,34 +24,14 @@ int Py_HasFileSystemDefaultEncoding = 1; #elif defined(__APPLE__) const char *Py_FileSystemDefaultEncoding = "utf-8"; int Py_HasFileSystemDefaultEncoding = 1; -#else -const char *Py_FileSystemDefaultEncoding = NULL; /* use default */ +#elif defined(HAVE_LANGINFO_H) && defined(CODESET) +const char *Py_FileSystemDefaultEncoding = NULL; /* set by initfsencoding() */ int Py_HasFileSystemDefaultEncoding = 0; +#else +const char *Py_FileSystemDefaultEncoding = "utf-8"; +int Py_HasFileSystemDefaultEncoding = 1; #endif -int -_Py_SetFileSystemEncoding(PyObject *s) -{ - PyObject *defenc, *codec; - if (!PyUnicode_Check(s)) { - PyErr_BadInternalCall(); - return -1; - } - defenc = _PyUnicode_AsDefaultEncodedString(s, NULL); - if (!defenc) - return -1; - codec = _PyCodec_Lookup(PyBytes_AsString(defenc)); - if (codec == NULL) - return -1; - Py_DECREF(codec); - if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) - /* A file system encoding was set at run-time */ - free((char*)Py_FileSystemDefaultEncoding); - Py_FileSystemDefaultEncoding = strdup(PyBytes_AsString(defenc)); - Py_HasFileSystemDefaultEncoding = 0; - return 0; -} - static PyObject * builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds) { @@ -189,8 +172,12 @@ builtin___import__(PyObject *self, PyObject *args, PyObject *kwds) PyDoc_STRVAR(import_doc, "__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module\n\ \n\ -Import a module. The globals are only used to determine the context;\n\ -they are not modified. The locals are currently unused. The fromlist\n\ +Import a module. Because this function is meant for use by the Python\n\ +interpreter and not for general use it is better to use\n\ +importlib.import_module() to programmatically import a module.\n\ +\n\ +The globals argument is only used to determine the context;\n\ +they are not modified. The locals argument is unused. The fromlist\n\ should be a list of names to emulate ``from name import ...'', or an\n\ empty list to emulate ``import name''.\n\ When importing a module from a package, note that __import__('A.B', ...)\n\ @@ -323,6 +310,20 @@ PyDoc_STRVAR(bin_doc, Return the binary representation of an integer or long integer."); +static PyObject * +builtin_callable(PyObject *self, PyObject *v) +{ + return PyBool_FromLong((long)PyCallable_Check(v)); +} + +PyDoc_STRVAR(callable_doc, +"callable(object) -> bool\n\ +\n\ +Return whether the object is callable (i.e., some kind of function).\n\ +Note that classes are callable, as are instances of classes with a\n\ +__call__() method."); + + typedef struct { PyObject_HEAD PyObject *func; @@ -542,19 +543,20 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) int mode = -1; int dont_inherit = 0; int supplied_flags = 0; + int optimize = -1; int is_ast; PyCompilerFlags cf; PyObject *cmd; static char *kwlist[] = {"source", "filename", "mode", "flags", - "dont_inherit", NULL}; + "dont_inherit", "optimize", NULL}; int start[] = {Py_file_input, Py_eval_input, Py_single_input}; PyObject *result; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&s|ii:compile", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&s|iii:compile", kwlist, &cmd, PyUnicode_FSConverter, &filename_obj, &startstr, &supplied_flags, - &dont_inherit)) + &dont_inherit, &optimize)) return NULL; filename = PyBytes_AS_STRING(filename_obj); @@ -569,6 +571,12 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) } /* XXX Warn if (supplied_flags & PyCF_MASK_OBSOLETE) != 0? */ + if (optimize < -1 || optimize > 2) { + PyErr_SetString(PyExc_ValueError, + "compile(): invalid optimize value"); + goto error; + } + if (!dont_inherit) { PyEval_MergeCompilerFlags(&cf); } @@ -603,8 +611,8 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) PyArena_Free(arena); goto error; } - result = (PyObject*)PyAST_Compile(mod, filename, - &cf, arena); + result = (PyObject*)PyAST_CompileEx(mod, filename, + &cf, optimize, arena); PyArena_Free(arena); } goto finally; @@ -614,7 +622,7 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) if (str == NULL) goto error; - result = Py_CompileStringFlags(str, filename, start[mode], &cf); + result = Py_CompileStringExFlags(str, filename, start[mode], &cf, optimize); goto finally; error: @@ -726,7 +734,7 @@ builtin_eval(PyObject *self, PyObject *args) "code object passed to eval() may not contain free variables"); return NULL; } - return PyEval_EvalCode((PyCodeObject *) cmd, globals, locals); + return PyEval_EvalCode(cmd, globals, locals); } cf.cf_flags = PyCF_SOURCE_IS_UTF8; @@ -802,7 +810,7 @@ builtin_exec(PyObject *self, PyObject *args) "contain free variables"); return NULL; } - v = PyEval_EvalCode((PyCodeObject *) prog, globals, locals); + v = PyEval_EvalCode(prog, globals, locals); } else { char *str; @@ -897,24 +905,21 @@ builtin_hasattr(PyObject *self, PyObject *args) } v = PyObject_GetAttr(v, name); if (v == NULL) { - if (!PyErr_ExceptionMatches(PyExc_Exception)) - return NULL; - else { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); - Py_INCREF(Py_False); - return Py_False; + Py_RETURN_FALSE; } + return NULL; } Py_DECREF(v); - Py_INCREF(Py_True); - return Py_True; + Py_RETURN_TRUE; } PyDoc_STRVAR(hasattr_doc, "hasattr(object, name) -> bool\n\ \n\ Return whether the object has an attribute with the given name.\n\ -(This is done by calling getattr(object, name) and catching exceptions.)"); +(This is done by calling getattr(object, name) and catching AttributeError.)"); static PyObject * @@ -1163,12 +1168,12 @@ Delete a named attribute on an object; delattr(x, 'y') is equivalent to\n\ static PyObject * builtin_hash(PyObject *self, PyObject *v) { - long x; + Py_hash_t x; x = PyObject_Hash(v); if (x == -1) return NULL; - return PyLong_FromLong(x); + return PyLong_FromSsize_t(x); } PyDoc_STRVAR(hash_doc, @@ -1486,13 +1491,19 @@ builtin_print(PyObject *self, PyObject *args, PyObject *kwds) Py_RETURN_NONE; } - if (sep && sep != Py_None && !PyUnicode_Check(sep)) { + if (sep == Py_None) { + sep = NULL; + } + else if (sep && !PyUnicode_Check(sep)) { PyErr_Format(PyExc_TypeError, "sep must be None or a string, not %.200s", sep->ob_type->tp_name); return NULL; } - if (end && end != Py_None && !PyUnicode_Check(end)) { + if (end == Py_None) { + end = NULL; + } + else if (end && !PyUnicode_Check(end)) { PyErr_Format(PyExc_TypeError, "end must be None or a string, not %.200s", end->ob_type->tp_name); @@ -1501,7 +1512,7 @@ builtin_print(PyObject *self, PyObject *args, PyObject *kwds) for (i = 0; i < PyTuple_Size(args); i++) { if (i > 0) { - if (sep == NULL || sep == Py_None) + if (sep == NULL) err = PyFile_WriteString(" ", file); else err = PyFile_WriteObject(sep, file, @@ -1515,7 +1526,7 @@ builtin_print(PyObject *self, PyObject *args, PyObject *kwds) return NULL; } - if (end == NULL || end == Py_None) + if (end == NULL) err = PyFile_WriteString("\n", file); else err = PyFile_WriteObject(end, file, Py_PRINT_RAW); @@ -1608,13 +1619,20 @@ builtin_input(PyObject *self, PyObject *args) char *prompt; char *s; PyObject *stdin_encoding; + char *stdin_encoding_str; PyObject *result; + size_t len; stdin_encoding = PyObject_GetAttrString(fin, "encoding"); if (!stdin_encoding) /* stdin is a text stream, so it must have an encoding. */ return NULL; + stdin_encoding_str = _PyUnicode_AsString(stdin_encoding); + if (stdin_encoding_str == NULL) { + Py_DECREF(stdin_encoding); + return NULL; + } tmp = PyObject_CallMethod(fout, "flush", ""); if (tmp == NULL) PyErr_Clear(); @@ -1623,12 +1641,18 @@ builtin_input(PyObject *self, PyObject *args) if (promptarg != NULL) { PyObject *stringpo; PyObject *stdout_encoding; - stdout_encoding = PyObject_GetAttrString(fout, - "encoding"); + char *stdout_encoding_str; + stdout_encoding = PyObject_GetAttrString(fout, "encoding"); if (stdout_encoding == NULL) { Py_DECREF(stdin_encoding); return NULL; } + stdout_encoding_str = _PyUnicode_AsString(stdout_encoding); + if (stdout_encoding_str == NULL) { + Py_DECREF(stdin_encoding); + Py_DECREF(stdout_encoding); + return NULL; + } stringpo = PyObject_Str(promptarg); if (stringpo == NULL) { Py_DECREF(stdin_encoding); @@ -1636,7 +1660,7 @@ builtin_input(PyObject *self, PyObject *args) return NULL; } po = PyUnicode_AsEncodedString(stringpo, - _PyUnicode_AsString(stdout_encoding), NULL); + stdout_encoding_str, NULL); Py_DECREF(stdout_encoding); Py_DECREF(stringpo); if (po == NULL) { @@ -1662,22 +1686,23 @@ builtin_input(PyObject *self, PyObject *args) Py_DECREF(stdin_encoding); return NULL; } - if (*s == '\0') { + + len = strlen(s); + if (len == 0) { PyErr_SetNone(PyExc_EOFError); result = NULL; } - else { /* strip trailing '\n' */ - size_t len = strlen(s); + else { if (len > PY_SSIZE_T_MAX) { PyErr_SetString(PyExc_OverflowError, "input: input too long"); result = NULL; } else { - result = PyUnicode_Decode - (s, len-1, - _PyUnicode_AsString(stdin_encoding), - NULL); + len--; /* strip trailing '\n' */ + if (len != 0 && s[len-1] == '\r') + len--; /* strip trailing '\r' */ + result = PyUnicode_Decode(s, len, stdin_encoding_str, NULL); } } Py_DECREF(stdin_encoding); @@ -1979,6 +2004,15 @@ builtin_sum(PyObject *self, PyObject *args) } break; } + /* It's tempting to use PyNumber_InPlaceAdd instead of + PyNumber_Add here, to avoid quadratic running time + when doing 'sum(list_of_lists, [])'. However, this + would produce a change in behaviour: a snippet like + + empty = [] + sum([[x] for x in range(10)], empty) + + would change the value of empty. */ temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); @@ -2233,6 +2267,7 @@ static PyMethodDef builtin_methods[] = { {"any", builtin_any, METH_O, any_doc}, {"ascii", builtin_ascii, METH_O, ascii_doc}, {"bin", builtin_bin, METH_O, bin_doc}, + {"callable", builtin_callable, METH_O, callable_doc}, {"chr", builtin_chr, METH_VARARGS, chr_doc}, {"compile", (PyCFunction)builtin_compile, METH_VARARGS | METH_KEYWORDS, compile_doc}, {"delattr", builtin_delattr, METH_VARARGS, delattr_doc}, @@ -2323,9 +2358,7 @@ _PyBuiltin_Init(void) SETBUILTIN("bytearray", &PyByteArray_Type); SETBUILTIN("bytes", &PyBytes_Type); SETBUILTIN("classmethod", &PyClassMethod_Type); -#ifndef WITHOUT_COMPLEX SETBUILTIN("complex", &PyComplex_Type); -#endif SETBUILTIN("dict", &PyDict_Type); SETBUILTIN("enumerate", &PyEnum_Type); SETBUILTIN("filter", &PyFilter_Type); diff --git a/Python/ceval.c b/Python/ceval.c index d3ed871770..43a5c904d1 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -13,7 +13,6 @@ #include "code.h" #include "frameobject.h" -#include "eval.h" #include "opcode.h" #include "structmember.h" @@ -136,8 +135,10 @@ static PyObject * cmp_outcome(int, PyObject *, PyObject *); static PyObject * import_from(PyObject *, PyObject *); static int import_all_from(PyObject *, PyObject *); static void format_exc_check_arg(PyObject *, const char *, PyObject *); +static void format_exc_unbound(PyCodeObject *co, int oparg); static PyObject * unicode_concatenate(PyObject *, PyObject *, PyFrameObject *, unsigned char *); +static PyObject * special_lookup(PyObject *, char *, PyObject **); #define NAME_ERROR_MSG \ "name '%.200s' is not defined" @@ -217,42 +218,127 @@ PyEval_GetCallStats(PyObject *self) #ifdef WITH_THREAD +#define GIL_REQUEST _Py_atomic_load_relaxed(&gil_drop_request) +#else +#define GIL_REQUEST 0 +#endif + +/* This can set eval_breaker to 0 even though gil_drop_request became + 1. We believe this is all right because the eval loop will release + the GIL eventually anyway. */ +#define COMPUTE_EVAL_BREAKER() \ + _Py_atomic_store_relaxed( \ + &eval_breaker, \ + GIL_REQUEST | \ + _Py_atomic_load_relaxed(&pendingcalls_to_do) | \ + pending_async_exc) + +#ifdef WITH_THREAD + +#define SET_GIL_DROP_REQUEST() \ + do { \ + _Py_atomic_store_relaxed(&gil_drop_request, 1); \ + _Py_atomic_store_relaxed(&eval_breaker, 1); \ + } while (0) + +#define RESET_GIL_DROP_REQUEST() \ + do { \ + _Py_atomic_store_relaxed(&gil_drop_request, 0); \ + COMPUTE_EVAL_BREAKER(); \ + } while (0) + +#endif + +/* Pending calls are only modified under pending_lock */ +#define SIGNAL_PENDING_CALLS() \ + do { \ + _Py_atomic_store_relaxed(&pendingcalls_to_do, 1); \ + _Py_atomic_store_relaxed(&eval_breaker, 1); \ + } while (0) + +#define UNSIGNAL_PENDING_CALLS() \ + do { \ + _Py_atomic_store_relaxed(&pendingcalls_to_do, 0); \ + COMPUTE_EVAL_BREAKER(); \ + } while (0) + +#define SIGNAL_ASYNC_EXC() \ + do { \ + pending_async_exc = 1; \ + _Py_atomic_store_relaxed(&eval_breaker, 1); \ + } while (0) + +#define UNSIGNAL_ASYNC_EXC() \ + do { pending_async_exc = 0; COMPUTE_EVAL_BREAKER(); } while (0) + + +#ifdef WITH_THREAD #ifdef HAVE_ERRNO_H #include <errno.h> #endif #include "pythread.h" -static PyThread_type_lock interpreter_lock = 0; /* This is the GIL */ static PyThread_type_lock pending_lock = 0; /* for pending calls */ static long main_thread = 0; +/* This single variable consolidates all requests to break out of the fast path + in the eval loop. */ +static _Py_atomic_int eval_breaker = {0}; +/* Request for dropping the GIL */ +static _Py_atomic_int gil_drop_request = {0}; +/* Request for running pending calls. */ +static _Py_atomic_int pendingcalls_to_do = {0}; +/* Request for looking at the `async_exc` field of the current thread state. + Guarded by the GIL. */ +static int pending_async_exc = 0; + +#include "ceval_gil.h" int PyEval_ThreadsInitialized(void) { - return interpreter_lock != 0; + return gil_created(); } void PyEval_InitThreads(void) { - if (interpreter_lock) + if (gil_created()) return; - interpreter_lock = PyThread_allocate_lock(); - PyThread_acquire_lock(interpreter_lock, 1); + create_gil(); + take_gil(PyThreadState_GET()); main_thread = PyThread_get_thread_ident(); + if (!pending_lock) + pending_lock = PyThread_allocate_lock(); +} + +void +_PyEval_FiniThreads(void) +{ + if (!gil_created()) + return; + destroy_gil(); + assert(!gil_created()); } void PyEval_AcquireLock(void) { - PyThread_acquire_lock(interpreter_lock, 1); + PyThreadState *tstate = PyThreadState_GET(); + if (tstate == NULL) + Py_FatalError("PyEval_AcquireLock: current thread state is NULL"); + take_gil(tstate); } void PyEval_ReleaseLock(void) { - PyThread_release_lock(interpreter_lock); + /* This function must succeed when the current thread state is NULL. + We therefore avoid PyThreadState_GET() which dumps a fatal error + in debug mode. + */ + drop_gil((PyThreadState*)_Py_atomic_load_relaxed( + &_PyThreadState_Current)); } void @@ -261,8 +347,8 @@ PyEval_AcquireThread(PyThreadState *tstate) if (tstate == NULL) Py_FatalError("PyEval_AcquireThread: NULL new thread state"); /* Check someone has called PyEval_InitThreads() to create the lock */ - assert(interpreter_lock); - PyThread_acquire_lock(interpreter_lock, 1); + assert(gil_created()); + take_gil(tstate); if (PyThreadState_Swap(tstate) != NULL) Py_FatalError( "PyEval_AcquireThread: non-NULL old thread state"); @@ -275,7 +361,7 @@ PyEval_ReleaseThread(PyThreadState *tstate) Py_FatalError("PyEval_ReleaseThread: NULL thread state"); if (PyThreadState_Swap(NULL) != tstate) Py_FatalError("PyEval_ReleaseThread: wrong thread state"); - PyThread_release_lock(interpreter_lock); + drop_gil(tstate); } /* This function is called from PyOS_AfterFork to ensure that newly @@ -287,17 +373,13 @@ void PyEval_ReInitThreads(void) { PyObject *threading, *result; - PyThreadState *tstate; + PyThreadState *tstate = PyThreadState_GET(); - if (!interpreter_lock) + if (!gil_created()) return; - /*XXX Can't use PyThread_free_lock here because it does too - much error-checking. Doing this cleanly would require - adding a new function to each thread_*.h. Instead, just - create a new lock and waste a little bit of memory */ - interpreter_lock = PyThread_allocate_lock(); + recreate_gil(); pending_lock = PyThread_allocate_lock(); - PyThread_acquire_lock(interpreter_lock, 1); + take_gil(tstate); main_thread = PyThread_get_thread_ident(); /* Update the threading module with the new state. @@ -317,7 +399,20 @@ PyEval_ReInitThreads(void) Py_DECREF(result); Py_DECREF(threading); } -#endif + +#else +static _Py_atomic_int eval_breaker = {0}; +static int pending_async_exc = 0; +#endif /* WITH_THREAD */ + +/* This function is used to signal that async exceptions are waiting to be + raised, therefore it is also useful in non-threaded builds. */ + +void +_PyEval_SignalAsyncExc(void) +{ + SIGNAL_ASYNC_EXC(); +} /* Functions save_thread and restore_thread are always defined so dynamically loaded modules needn't be compiled separately for use @@ -330,8 +425,8 @@ PyEval_SaveThread(void) if (tstate == NULL) Py_FatalError("PyEval_SaveThread: NULL tstate"); #ifdef WITH_THREAD - if (interpreter_lock) - PyThread_release_lock(interpreter_lock); + if (gil_created()) + drop_gil(tstate); #endif return tstate; } @@ -342,9 +437,9 @@ PyEval_RestoreThread(PyThreadState *tstate) if (tstate == NULL) Py_FatalError("PyEval_RestoreThread: NULL tstate"); #ifdef WITH_THREAD - if (interpreter_lock) { + if (gil_created()) { int err = errno; - PyThread_acquire_lock(interpreter_lock, 1); + take_gil(tstate); errno = err; } #endif @@ -390,7 +485,6 @@ static struct { } pendingcalls[NPENDINGCALLS]; static int pendingfirst = 0; static int pendinglast = 0; -static volatile int pendingcalls_to_do = 1; /* trigger initialization of lock */ static char pendingbusy = 0; int @@ -429,8 +523,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg) pendinglast = j; } /* signal main loop */ - _Py_Ticker = 0; - pendingcalls_to_do = 1; + SIGNAL_PENDING_CALLS(); if (lock != NULL) PyThread_release_lock(lock); return result; @@ -472,7 +565,10 @@ Py_MakePendingCalls(void) arg = pendingcalls[j].arg; pendingfirst = (j + 1) % NPENDINGCALLS; } - pendingcalls_to_do = pendingfirst != pendinglast; + if (pendingfirst != pendinglast) + SIGNAL_PENDING_CALLS(); + else + UNSIGNAL_PENDING_CALLS(); PyThread_release_lock(pending_lock); /* having released the lock, perform the callback */ if (func == NULL) @@ -517,7 +613,7 @@ static struct { } pendingcalls[NPENDINGCALLS]; static volatile int pendingfirst = 0; static volatile int pendinglast = 0; -static volatile int pendingcalls_to_do = 0; +static _Py_atomic_int pendingcalls_to_do = {0}; int Py_AddPendingCall(int (*func)(void *), void *arg) @@ -538,8 +634,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg) pendingcalls[i].arg = arg; pendinglast = j; - _Py_Ticker = 0; - pendingcalls_to_do = 1; /* Signal main loop */ + SIGNAL_PENDING_CALLS(); busy = 0; /* XXX End critical section */ return 0; @@ -552,7 +647,7 @@ Py_MakePendingCalls(void) if (busy) return 0; busy = 1; - pendingcalls_to_do = 0; + UNSIGNAL_PENDING_CALLS(); for (;;) { int i; int (*func)(void *); @@ -565,7 +660,7 @@ Py_MakePendingCalls(void) pendingfirst = (i + 1) % NPENDINGCALLS; if (func(arg) < 0) { busy = 0; - pendingcalls_to_do = 1; /* We're not done yet */ + SIGNAL_PENDING_CALLS(); /* We're not done yet */ return -1; } } @@ -658,13 +753,10 @@ static int unpack_iterable(PyObject *, int, int, PyObject **); fast_next_opcode*/ static int _Py_TracingPossible = 0; -/* for manipulating the thread switch and periodic "stuff" - used to be - per thread, now just a pair o' globals */ -int _Py_CheckInterval = 100; -volatile int _Py_Ticker = 0; /* so that we hit a "tick" first thing */ + PyObject * -PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals) +PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals) { return PyEval_EvalCodeEx(co, globals, locals, @@ -763,11 +855,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) -fno-crossjumping). */ -#if defined(USE_COMPUTED_GOTOS) && defined(DYNAMIC_EXECUTION_PROFILE) +#ifdef DYNAMIC_EXECUTION_PROFILE #undef USE_COMPUTED_GOTOS +#define USE_COMPUTED_GOTOS 0 #endif -#ifdef USE_COMPUTED_GOTOS +#ifdef HAVE_COMPUTED_GOTOS + #ifndef USE_COMPUTED_GOTOS + #define USE_COMPUTED_GOTOS 1 + #endif +#else + #if defined(USE_COMPUTED_GOTOS) && USE_COMPUTED_GOTOS + #error "Computed gotos are not supported on this compiler." + #endif + #undef USE_COMPUTED_GOTOS + #define USE_COMPUTED_GOTOS 0 +#endif + +#if USE_COMPUTED_GOTOS /* Import the static jump table */ #include "opcode_targets.h" @@ -791,11 +896,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) #define DISPATCH() \ { \ - /* Avoid multiple loads from _Py_Ticker despite `volatile` */ \ - int _tick = _Py_Ticker - 1; \ - _Py_Ticker = _tick; \ - if (_tick >= 0) { \ - FAST_DISPATCH(); \ + if (!_Py_atomic_load_relaxed(&eval_breaker)) { \ + FAST_DISPATCH(); \ } \ continue; \ } @@ -916,7 +1018,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) */ -#if defined(DYNAMIC_EXECUTION_PROFILE) || defined(USE_COMPUTED_GOTOS) +#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS #define PREDICT(op) if (0) goto PRED_##op #define PREDICTED(op) PRED_##op: #define PREDICTED_WITH_ARG(op) PRED_##op: @@ -937,10 +1039,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) #define SECOND() (stack_pointer[-2]) #define THIRD() (stack_pointer[-3]) #define FOURTH() (stack_pointer[-4]) +#define PEEK(n) (stack_pointer[-(n)]) #define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v)) #define SET_THIRD(v) (stack_pointer[-3] = (v)) #define SET_FOURTH(v) (stack_pointer[-4] = (v)) +#define SET_VALUE(n, v) (stack_pointer[-(n)] = (v)) #define BASIC_STACKADJ(n) (stack_pointer += n) #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) @@ -1124,7 +1228,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL; #endif #if defined(Py_DEBUG) || defined(LLTRACE) - filename = _PyUnicode_AsString(co->co_filename); + { + PyObject *error_type, *error_value, *error_traceback; + PyErr_Fetch(&error_type, &error_value, &error_traceback); + filename = _PyUnicode_AsString(co->co_filename); + if (filename == NULL && tstate->overflowed) { + /* maximum recursion depth exceeded */ + goto exit_eval_frame; + } + PyErr_Restore(error_type, error_value, error_traceback); + } #endif why = WHY_NOT; @@ -1166,55 +1279,46 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) async I/O handler); see Py_AddPendingCall() and Py_MakePendingCalls() above. */ - if (--_Py_Ticker < 0) { + if (_Py_atomic_load_relaxed(&eval_breaker)) { if (*next_instr == SETUP_FINALLY) { /* Make the last opcode before a try: finally: block uninterruptible. */ goto fast_next_opcode; } - _Py_Ticker = _Py_CheckInterval; tstate->tick_counter++; #ifdef WITH_TSC ticked = 1; #endif - if (pendingcalls_to_do) { + if (_Py_atomic_load_relaxed(&pendingcalls_to_do)) { if (Py_MakePendingCalls() < 0) { why = WHY_EXCEPTION; goto on_error; } - if (pendingcalls_to_do) - /* MakePendingCalls() didn't succeed. - Force early re-execution of this - "periodic" code, possibly after - a thread switch */ - _Py_Ticker = 0; } #ifdef WITH_THREAD - if (interpreter_lock) { + if (_Py_atomic_load_relaxed(&gil_drop_request)) { /* Give another thread a chance */ - if (PyThreadState_Swap(NULL) != tstate) Py_FatalError("ceval: tstate mix-up"); - PyThread_release_lock(interpreter_lock); + drop_gil(tstate); /* Other threads may run now */ - PyThread_acquire_lock(interpreter_lock, 1); + take_gil(tstate); if (PyThreadState_Swap(tstate) != NULL) Py_FatalError("ceval: orphan tstate"); - - /* Check for thread interrupts */ - - if (tstate->async_exc != NULL) { - x = tstate->async_exc; - tstate->async_exc = NULL; - PyErr_SetNone(x); - Py_DECREF(x); - why = WHY_EXCEPTION; - goto on_error; - } } #endif + /* Check for asynchronous exceptions. */ + if (tstate->async_exc != NULL) { + x = tstate->async_exc; + tstate->async_exc = NULL; + UNSIGNAL_ASYNC_EXC(); + PyErr_SetNone(x); + Py_DECREF(x); + why = WHY_EXCEPTION; + goto on_error; + } } fast_next_opcode: @@ -1335,50 +1439,21 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) SET_THIRD(v); FAST_DISPATCH(); - TARGET(ROT_FOUR) - u = TOP(); - v = SECOND(); - w = THIRD(); - x = FOURTH(); - SET_TOP(v); - SET_SECOND(w); - SET_THIRD(x); - SET_FOURTH(u); - FAST_DISPATCH(); - TARGET(DUP_TOP) v = TOP(); Py_INCREF(v); PUSH(v); FAST_DISPATCH(); - TARGET(DUP_TOPX) - if (oparg == 2) { - x = TOP(); - Py_INCREF(x); - w = SECOND(); - Py_INCREF(w); - STACKADJ(2); - SET_TOP(x); - SET_SECOND(w); - FAST_DISPATCH(); - } else if (oparg == 3) { - x = TOP(); - Py_INCREF(x); - w = SECOND(); - Py_INCREF(w); - v = THIRD(); - Py_INCREF(v); - STACKADJ(3); - SET_TOP(x); - SET_SECOND(w); - SET_THIRD(v); - FAST_DISPATCH(); - } - Py_FatalError("invalid argument to DUP_TOPX" - " (bytecode corruption?)"); - /* Never returns, so don't bother to set why. */ - break; + TARGET(DUP_TOP_TWO) + x = TOP(); + Py_INCREF(x); + w = SECOND(); + Py_INCREF(w); + STACKADJ(2); + SET_TOP(x); + SET_SECOND(w); + FAST_DISPATCH(); TARGET(UNARY_POSITIVE) v = TOP(); @@ -1566,7 +1641,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) TARGET(LIST_APPEND) w = POP(); - v = stack_pointer[-oparg]; + v = PEEK(oparg); err = PyList_Append(v, w); Py_DECREF(w); if (err == 0) { @@ -1841,15 +1916,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) created when the exception was caught, otherwise the stack will be in an inconsistent state. */ PyTryBlock *b = PyFrame_BlockPop(f); - if (b->b_type != EXCEPT_HANDLER) { - PyErr_SetString(PyExc_SystemError, - "popped block is not an except handler"); - why = WHY_EXCEPTION; - } - else { - UNWIND_EXCEPT_HANDLER(b); - why = WHY_NOT; - } + assert(b->b_type == EXCEPT_HANDLER); + UNWIND_EXCEPT_HANDLER(b); + why = WHY_NOT; } } else if (PyExceptionClass_Check(v)) { @@ -1933,7 +2002,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } } else if (unpack_iterable(v, oparg, -1, stack_pointer + oparg)) { - stack_pointer += oparg; + STACKADJ(oparg); } else { /* unpack_iterable() raised an exception */ why = WHY_EXCEPTION; @@ -2033,7 +2102,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) /* Inline the PyDict_GetItem() calls. WARNING: this is an extreme speed hack. Do not try this at home. */ - long hash = ((PyUnicodeObject *)w)->hash; + Py_hash_t hash = ((PyUnicodeObject *)w)->hash; if (hash != -1) { PyDictObject *d; PyDictEntry *e; @@ -2093,6 +2162,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ); break; + TARGET(DELETE_DEREF) + x = freevars[oparg]; + if (PyCell_GET(x) != NULL) { + PyCell_Set(x, NULL); + DISPATCH(); + } + err = -1; + format_exc_unbound(co, oparg); + break; + TARGET(LOAD_CLOSURE) x = freevars[oparg]; Py_INCREF(x); @@ -2108,22 +2187,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) DISPATCH(); } err = -1; - /* Don't stomp existing exception */ - if (PyErr_Occurred()) - break; - if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) { - v = PyTuple_GET_ITEM(co->co_cellvars, - oparg); - format_exc_check_arg( - PyExc_UnboundLocalError, - UNBOUNDLOCAL_ERROR_MSG, - v); - } else { - v = PyTuple_GET_ITEM(co->co_freevars, oparg - - PyTuple_GET_SIZE(co->co_cellvars)); - format_exc_check_arg(PyExc_NameError, - UNBOUNDFREE_ERROR_MSG, v); - } + format_exc_unbound(co, oparg); break; TARGET(STORE_DEREF) @@ -2474,6 +2538,33 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) STACK_LEVEL()); DISPATCH(); + TARGET(SETUP_WITH) + { + static PyObject *exit, *enter; + w = TOP(); + x = special_lookup(w, "__exit__", &exit); + if (!x) + break; + SET_TOP(x); + u = special_lookup(w, "__enter__", &enter); + Py_DECREF(w); + if (!u) { + x = NULL; + break; + } + x = PyObject_CallFunctionObjArgs(u, NULL); + Py_DECREF(u); + if (!x) + break; + /* Setup the finally block before pushing the result + of __enter__ on the stack. */ + PyFrame_BlockSetup(f, SETUP_FINALLY, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + + PUSH(x); + DISPATCH(); + } + TARGET(WITH_CLEANUP) { /* At the top of the stack are 1-3 values indicating @@ -2482,33 +2573,70 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) - (TOP, SECOND) = (WHY_{RETURN,CONTINUE}), retval - TOP = WHY_*; no retval below it - (TOP, SECOND, THIRD) = exc_info() + (FOURTH, FITH, SIXTH) = previous exception for EXCEPT_HANDLER Below them is EXIT, the context.__exit__ bound method. In the last case, we must call EXIT(TOP, SECOND, THIRD) otherwise we must call EXIT(None, None, None) - In all cases, we remove EXIT from the stack, leaving - the rest in the same order. + In the first two cases, we remove EXIT from the + stack, leaving the rest in the same order. In the + third case, we shift the bottom 3 values of the + stack down, and replace the empty spot with NULL. In addition, if the stack represents an exception, *and* the function call returns a 'true' value, we - "zap" this information, to prevent END_FINALLY from - re-raising the exception. (But non-local gotos - should still be resumed.) + push WHY_SILENCED onto the stack. END_FINALLY will + then not re-raise the exception. (But non-local + gotos should still be resumed.) */ - PyObject *exit_func = POP(); + PyObject *exit_func; u = TOP(); if (u == Py_None) { + (void)POP(); + exit_func = TOP(); + SET_TOP(u); v = w = Py_None; } else if (PyLong_Check(u)) { + (void)POP(); + switch(PyLong_AsLong(u)) { + case WHY_RETURN: + case WHY_CONTINUE: + /* Retval in TOP. */ + exit_func = SECOND(); + SET_SECOND(TOP()); + SET_TOP(u); + break; + default: + exit_func = TOP(); + SET_TOP(u); + break; + } u = v = w = Py_None; } else { + PyObject *tp, *exc, *tb; + PyTryBlock *block; v = SECOND(); w = THIRD(); + tp = FOURTH(); + exc = PEEK(5); + tb = PEEK(6); + exit_func = PEEK(7); + SET_VALUE(7, tb); + SET_VALUE(6, exc); + SET_VALUE(5, tp); + /* UNWIND_EXCEPT_HANDLER will pop this off. */ + SET_FOURTH(NULL); + /* We just shifted the stack down, so we have + to tell the except handler block that the + values are lower than it expects. */ + block = &f->f_blockstack[f->f_iblock - 1]; + assert(block->b_type == EXCEPT_HANDLER); + block->b_level--; } /* XXX Not the fastest way to call it... */ x = PyObject_CallFunctionObjArgs(exit_func, u, v, w, @@ -2528,11 +2656,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) else if (err > 0) { err = 0; /* There was an exception and a True return */ - STACKADJ(-2); - SET_TOP(PyLong_FromLong((long) WHY_SILENCED)); - Py_DECREF(u); - Py_DECREF(v); - Py_DECREF(w); + PUSH(PyLong_FromLong((long) WHY_SILENCED)); } PREDICT(END_FINALLY); break; @@ -2717,13 +2841,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) oparg = oparg<<16 | NEXTARG(); goto dispatch_opcode; -#ifdef USE_COMPUTED_GOTOS +#if USE_COMPUTED_GOTOS _unknown_opcode: #endif default: fprintf(stderr, "XXX lineno: %d, opcode: %d\n", - PyCode_Addr2Line(f->f_code, f->f_lasti), + PyFrame_GetLineNumber(f), opcode); PyErr_SetString(PyExc_SystemError, "unknown opcode"); why = WHY_EXCEPTION; @@ -2801,19 +2925,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) fast_block_end: while (why != WHY_NOT && f->f_iblock > 0) { - PyTryBlock *b = PyFrame_BlockPop(f); + /* Peek at the current block. */ + PyTryBlock *b = &f->f_blockstack[f->f_iblock - 1]; assert(why != WHY_YIELD); if (b->b_type == SETUP_LOOP && why == WHY_CONTINUE) { - /* For a continue inside a try block, - don't pop the block for the loop. */ - PyFrame_BlockSetup(f, b->b_type, b->b_handler, - b->b_level); why = WHY_NOT; JUMPTO(PyLong_AS_LONG(retval)); Py_DECREF(retval); break; } + /* Now we have to pop the block. */ + f->f_iblock--; if (b->b_type == EXCEPT_HANDLER) { UNWIND_EXCEPT_HANDLER(b); @@ -2937,15 +3060,17 @@ exit_eval_frame: the test in the if statements in Misc/gdbinit (pystack and pystackv). */ PyObject * -PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, +PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals, PyObject **args, int argcount, PyObject **kws, int kwcount, PyObject **defs, int defcount, PyObject *kwdefs, PyObject *closure) { + PyCodeObject* co = (PyCodeObject*)_co; register PyFrameObject *f; register PyObject *retval = NULL; register PyObject **fastlocals, **freevars; PyThreadState *tstate = PyThreadState_GET(); PyObject *x, *u; + int total_args = co->co_argcount + co->co_kwonlyargcount; if (globals == NULL) { PyErr_SetString(PyExc_SystemError, @@ -2962,9 +3087,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, fastlocals = f->f_localsplus; freevars = f->f_localsplus + co->co_nlocals; - if (co->co_argcount > 0 || - co->co_kwonlyargcount > 0 || - co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { + if (total_args || co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { int i; int n = argcount; PyObject *kwdict = NULL; @@ -2972,7 +3095,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, kwdict = PyDict_New(); if (kwdict == NULL) goto fail; - i = co->co_argcount + co->co_kwonlyargcount; + i = total_args; if (co->co_flags & CO_VARARGS) i++; SETLOCAL(i, kwdict); @@ -2981,13 +3104,12 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, if (!(co->co_flags & CO_VARARGS)) { PyErr_Format(PyExc_TypeError, "%U() takes %s %d " - "%spositional argument%s (%d given)", + "positional argument%s (%d given)", co->co_name, defcount ? "at most" : "exactly", co->co_argcount, - kwcount ? "non-keyword " : "", co->co_argcount == 1 ? "" : "s", - argcount); + argcount + kwcount); goto fail; } n = co->co_argcount; @@ -3001,7 +3123,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, u = PyTuple_New(argcount - n); if (u == NULL) goto fail; - SETLOCAL(co->co_argcount + co->co_kwonlyargcount, u); + SETLOCAL(total_args, u); for (i = n; i < argcount; i++) { x = args[i]; Py_INCREF(x); @@ -3021,18 +3143,14 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, } /* Speed hack: do raw pointer compares. As names are normally interned this should almost always hit. */ - co_varnames = PySequence_Fast_ITEMS(co->co_varnames); - for (j = 0; - j < co->co_argcount + co->co_kwonlyargcount; - j++) { + co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item; + for (j = 0; j < total_args; j++) { PyObject *nm = co_varnames[j]; if (nm == keyword) goto kw_found; } /* Slow fallback, just in case */ - for (j = 0; - j < co->co_argcount + co->co_kwonlyargcount; - j++) { + for (j = 0; j < total_args; j++) { PyObject *nm = co_varnames[j]; int cmp = PyObject_RichCompareBool( keyword, nm, Py_EQ); @@ -3041,22 +3159,17 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, else if (cmp < 0) goto fail; } - /* Check errors from Compare */ - if (PyErr_Occurred()) + if (j >= total_args && kwdict == NULL) { + PyErr_Format(PyExc_TypeError, + "%U() got an unexpected " + "keyword argument '%S'", + co->co_name, + keyword); goto fail; - if (j >= co->co_argcount + co->co_kwonlyargcount) { - if (kwdict == NULL) { - PyErr_Format(PyExc_TypeError, - "%U() got an unexpected " - "keyword argument '%S'", - co->co_name, - keyword); - goto fail; - } - PyDict_SetItem(kwdict, keyword, value); - continue; } -kw_found: + PyDict_SetItem(kwdict, keyword, value); + continue; + kw_found: if (GETLOCAL(j) != NULL) { PyErr_Format(PyExc_TypeError, "%U() got multiple " @@ -3070,20 +3183,18 @@ kw_found: SETLOCAL(j, value); } if (co->co_kwonlyargcount > 0) { - for (i = co->co_argcount; - i < co->co_argcount + co->co_kwonlyargcount; - i++) { - PyObject *name, *def; + for (i = co->co_argcount; i < total_args; i++) { + PyObject *name; if (GETLOCAL(i) != NULL) continue; name = PyTuple_GET_ITEM(co->co_varnames, i); - def = NULL; - if (kwdefs != NULL) - def = PyDict_GetItem(kwdefs, name); - if (def != NULL) { - Py_INCREF(def); - SETLOCAL(i, def); - continue; + if (kwdefs != NULL) { + PyObject *def = PyDict_GetItem(kwdefs, name); + if (def) { + Py_INCREF(def); + SETLOCAL(i, def); + continue; + } } PyErr_Format(PyExc_TypeError, "%U() needs keyword-only argument %S", @@ -3095,16 +3206,19 @@ kw_found: int m = co->co_argcount - defcount; for (i = argcount; i < m; i++) { if (GETLOCAL(i) == NULL) { + int j, given = 0; + for (j = 0; j < co->co_argcount; j++) + if (GETLOCAL(j)) + given++; PyErr_Format(PyExc_TypeError, "%U() takes %s %d " - "%spositional argument%s " + "argument%s " "(%d given)", co->co_name, ((co->co_flags & CO_VARARGS) || defcount) ? "at least" : "exactly", - m, kwcount ? "non-keyword " : "", - m == 1 ? "" : "s", i); + m, m == 1 ? "" : "s", given); goto fail; } } @@ -3121,14 +3235,12 @@ kw_found: } } } - else { - if (argcount > 0 || kwcount > 0) { - PyErr_Format(PyExc_TypeError, - "%U() takes no arguments (%d given)", - co->co_name, - argcount + kwcount); - goto fail; - } + else if (argcount > 0 || kwcount > 0) { + PyErr_Format(PyExc_TypeError, + "%U() takes no arguments (%d given)", + co->co_name, + argcount + kwcount); + goto fail; } /* Allocate and initialize storage for cell vars, and copy free vars into frame. This isn't too efficient right now. */ @@ -3137,7 +3249,7 @@ kw_found: Py_UNICODE *cellname, *argname; PyObject *c; - nargs = co->co_argcount + co->co_kwonlyargcount; + nargs = total_args; if (co->co_flags & CO_VARARGS) nargs++; if (co->co_flags & CO_VARKEYWORDS) @@ -3213,6 +3325,19 @@ fail: /* Jump here from prelude on failure */ } +static PyObject * +special_lookup(PyObject *o, char *meth, PyObject **cache) +{ + PyObject *res; + res = _PyObject_LookupSpecial(o, meth, cache); + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetObject(PyExc_AttributeError, *cache); + return NULL; + } + return res; +} + + /* Logic for the raise statement (too complicated for inlining). This *consumes* a reference count to each of its arguments. */ static enum why_code @@ -3343,7 +3468,8 @@ unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp) return 1; } Py_DECREF(w); - PyErr_SetString(PyExc_ValueError, "too many values to unpack"); + PyErr_Format(PyExc_ValueError, "too many values to unpack " + "(expected %d)", argcnt); goto Error; } @@ -3471,33 +3597,30 @@ _PyEval_CallTracing(PyObject *func, PyObject *args) return result; } +/* See Objects/lnotab_notes.txt for a description of how tracing works. */ static int maybe_call_line_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame, int *instr_lb, int *instr_ub, int *instr_prev) { int result = 0; + int line = frame->f_lineno; /* If the last instruction executed isn't in the current - instruction window, reset the window. If the last - instruction happens to fall at the start of a line or if it - represents a jump backwards, call the trace function. + instruction window, reset the window. */ - if ((frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub)) { - int line; + if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) { PyAddrPair bounds; - - line = PyCode_CheckLineNumber(frame->f_code, frame->f_lasti, - &bounds); - if (line >= 0) { - frame->f_lineno = line; - result = call_trace(func, obj, frame, - PyTrace_LINE, Py_None); - } + line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti, + &bounds); *instr_lb = bounds.ap_lower; *instr_ub = bounds.ap_upper; } - else if (frame->f_lasti <= *instr_prev) { + /* If the last instruction falls at the start of a line or if + it represents a jump backwards, update the frame's line + number and call the trace function. */ + if (frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev) { + frame->f_lineno = line; result = call_trace(func, obj, frame, PyTrace_LINE, Py_None); } *instr_prev = frame->f_lasti; @@ -3602,18 +3725,7 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf) /* External interface to call any callable object. - The arg must be a tuple or NULL. */ - -#undef PyEval_CallObject -/* for backward compatibility: export this interface */ - -PyObject * -PyEval_CallObject(PyObject *func, PyObject *arg) -{ - return PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL); -} -#define PyEval_CallObject(func,arg) \ - PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) + The arg must be a tuple or NULL. The kw must be a dict or NULL. */ PyObject * PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw) @@ -3858,7 +3970,7 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) d = &PyTuple_GET_ITEM(argdefs, 0); nd = Py_SIZE(argdefs); } - return PyEval_EvalCodeEx(co, globals, + return PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, (*pp_stack)-n, na, (*pp_stack)-2*nk, nk, d, nd, kwdefs, PyFunction_GET_CLOSURE(func)); @@ -4255,6 +4367,28 @@ format_exc_check_arg(PyObject *exc, const char *format_str, PyObject *obj) PyErr_Format(exc, format_str, obj_str); } +static void +format_exc_unbound(PyCodeObject *co, int oparg) +{ + PyObject *name; + /* Don't stomp existing exception */ + if (PyErr_Occurred()) + return; + if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) { + name = PyTuple_GET_ITEM(co->co_cellvars, + oparg); + format_exc_check_arg( + PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + name); + } else { + name = PyTuple_GET_ITEM(co->co_freevars, oparg - + PyTuple_GET_SIZE(co->co_cellvars)); + format_exc_check_arg(PyExc_NameError, + UNBOUNDFREE_ERROR_MSG, name); + } +} + static PyObject * unicode_concatenate(PyObject *v, PyObject *w, PyFrameObject *f, unsigned char *next_instr) @@ -4270,7 +4404,7 @@ unicode_concatenate(PyObject *v, PyObject *w, return NULL; } - if (v->ob_refcnt == 2) { + if (Py_REFCNT(v) == 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 @@ -4311,7 +4445,7 @@ unicode_concatenate(PyObject *v, PyObject *w, } } - if (v->ob_refcnt == 1 && !PyUnicode_CHECK_INTERNED(v)) { + if (Py_REFCNT(v) == 1 && !PyUnicode_CHECK_INTERNED(v)) { /* Now we own the last reference to 'v', so we can resize it * in-place. */ diff --git a/Python/ceval_gil.h b/Python/ceval_gil.h new file mode 100644 index 0000000000..bf7a350791 --- /dev/null +++ b/Python/ceval_gil.h @@ -0,0 +1,433 @@ +/* + * Implementation of the Global Interpreter Lock (GIL). + */ + +#include <stdlib.h> +#include <errno.h> + + +/* First some general settings */ + +/* microseconds (the Python API uses seconds, though) */ +#define DEFAULT_INTERVAL 5000 +static unsigned long gil_interval = DEFAULT_INTERVAL; +#define INTERVAL (gil_interval >= 1 ? gil_interval : 1) + +/* Enable if you want to force the switching of threads at least every `gil_interval` */ +#undef FORCE_SWITCHING +#define FORCE_SWITCHING + + +/* + Notes about the implementation: + + - The GIL is just a boolean variable (gil_locked) whose access is protected + by a mutex (gil_mutex), and whose changes are signalled by a condition + variable (gil_cond). gil_mutex is taken for short periods of time, + and therefore mostly uncontended. + + - In the GIL-holding thread, the main loop (PyEval_EvalFrameEx) must be + able to release the GIL on demand by another thread. A volatile boolean + variable (gil_drop_request) is used for that purpose, which is checked + at every turn of the eval loop. That variable is set after a wait of + `interval` microseconds on `gil_cond` has timed out. + + [Actually, another volatile boolean variable (eval_breaker) is used + which ORs several conditions into one. Volatile booleans are + sufficient as inter-thread signalling means since Python is run + on cache-coherent architectures only.] + + - A thread wanting to take the GIL will first let pass a given amount of + time (`interval` microseconds) before setting gil_drop_request. This + encourages a defined switching period, but doesn't enforce it since + opcodes can take an arbitrary time to execute. + + The `interval` value is available for the user to read and modify + using the Python API `sys.{get,set}switchinterval()`. + + - When a thread releases the GIL and gil_drop_request is set, that thread + ensures that another GIL-awaiting thread gets scheduled. + It does so by waiting on a condition variable (switch_cond) until + the value of gil_last_holder is changed to something else than its + own thread state pointer, indicating that another thread was able to + take the GIL. + + This is meant to prohibit the latency-adverse behaviour on multi-core + machines where one thread would speculatively release the GIL, but still + run and end up being the first to re-acquire it, making the "timeslices" + much longer than expected. + (Note: this mechanism is enabled with FORCE_SWITCHING above) +*/ + +#ifndef _POSIX_THREADS +/* This means pthreads are not implemented in libc headers, hence the macro + not present in unistd.h. But they still can be implemented as an external + library (e.g. gnu pth in pthread emulation) */ +# ifdef HAVE_PTHREAD_H +# include <pthread.h> /* _POSIX_THREADS */ +# endif +#endif + + +#ifdef _POSIX_THREADS + +/* + * POSIX support + */ + +#include <pthread.h> + +#define ADD_MICROSECONDS(tv, interval) \ +do { \ + tv.tv_usec += (long) interval; \ + tv.tv_sec += tv.tv_usec / 1000000; \ + tv.tv_usec %= 1000000; \ +} while (0) + +/* We assume all modern POSIX systems have gettimeofday() */ +#ifdef GETTIMEOFDAY_NO_TZ +#define GETTIMEOFDAY(ptv) gettimeofday(ptv) +#else +#define GETTIMEOFDAY(ptv) gettimeofday(ptv, (struct timezone *)NULL) +#endif + +#define MUTEX_T pthread_mutex_t +#define MUTEX_INIT(mut) \ + if (pthread_mutex_init(&mut, NULL)) { \ + Py_FatalError("pthread_mutex_init(" #mut ") failed"); }; +#define MUTEX_FINI(mut) \ + if (pthread_mutex_destroy(&mut)) { \ + Py_FatalError("pthread_mutex_destroy(" #mut ") failed"); }; +#define MUTEX_LOCK(mut) \ + if (pthread_mutex_lock(&mut)) { \ + Py_FatalError("pthread_mutex_lock(" #mut ") failed"); }; +#define MUTEX_UNLOCK(mut) \ + if (pthread_mutex_unlock(&mut)) { \ + Py_FatalError("pthread_mutex_unlock(" #mut ") failed"); }; + +#define COND_T pthread_cond_t +#define COND_INIT(cond) \ + if (pthread_cond_init(&cond, NULL)) { \ + Py_FatalError("pthread_cond_init(" #cond ") failed"); }; +#define COND_FINI(cond) \ + if (pthread_cond_destroy(&cond)) { \ + Py_FatalError("pthread_cond_destroy(" #cond ") failed"); }; +#define COND_SIGNAL(cond) \ + if (pthread_cond_signal(&cond)) { \ + Py_FatalError("pthread_cond_signal(" #cond ") failed"); }; +#define COND_WAIT(cond, mut) \ + if (pthread_cond_wait(&cond, &mut)) { \ + Py_FatalError("pthread_cond_wait(" #cond ") failed"); }; +#define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \ + { \ + int r; \ + struct timespec ts; \ + struct timeval deadline; \ + \ + GETTIMEOFDAY(&deadline); \ + ADD_MICROSECONDS(deadline, microseconds); \ + ts.tv_sec = deadline.tv_sec; \ + ts.tv_nsec = deadline.tv_usec * 1000; \ + \ + r = pthread_cond_timedwait(&cond, &mut, &ts); \ + if (r == ETIMEDOUT) \ + timeout_result = 1; \ + else if (r) \ + Py_FatalError("pthread_cond_timedwait(" #cond ") failed"); \ + else \ + timeout_result = 0; \ + } \ + +#elif defined(NT_THREADS) + +/* + * Windows (2000 and later, as well as (hopefully) CE) support + */ + +#include <windows.h> + +#define MUTEX_T CRITICAL_SECTION +#define MUTEX_INIT(mut) do { \ + if (!(InitializeCriticalSectionAndSpinCount(&(mut), 4000))) \ + Py_FatalError("CreateMutex(" #mut ") failed"); \ +} while (0) +#define MUTEX_FINI(mut) \ + DeleteCriticalSection(&(mut)) +#define MUTEX_LOCK(mut) \ + EnterCriticalSection(&(mut)) +#define MUTEX_UNLOCK(mut) \ + LeaveCriticalSection(&(mut)) + +/* We emulate condition variables with a semaphore. + We use a Semaphore rather than an auto-reset event, because although + an auto-resent event might appear to solve the lost-wakeup bug (race + condition between releasing the outer lock and waiting) because it + maintains state even though a wait hasn't happened, there is still + a lost wakeup problem if more than one thread are interrupted in the + critical place. A semaphore solves that. + Because it is ok to signal a condition variable with no one + waiting, we need to keep track of the number of + waiting threads. Otherwise, the semaphore's state could rise + without bound. + + Generic emulations of the pthread_cond_* API using + Win32 functions can be found on the Web. + The following read can be edificating (or not): + http://www.cse.wustl.edu/~schmidt/win32-cv-1.html +*/ +typedef struct COND_T +{ + HANDLE sem; /* the semaphore */ + int n_waiting; /* how many are unreleased */ +} COND_T; + +__inline static void _cond_init(COND_T *cond) +{ + /* A semaphore with a large max value, The positive value + * is only needed to catch those "lost wakeup" events and + * race conditions when a timed wait elapses. + */ + if (!(cond->sem = CreateSemaphore(NULL, 0, 1000, NULL))) + Py_FatalError("CreateSemaphore() failed"); + cond->n_waiting = 0; +} + +__inline static void _cond_fini(COND_T *cond) +{ + BOOL ok = CloseHandle(cond->sem); + if (!ok) + Py_FatalError("CloseHandle() failed"); +} + +__inline static void _cond_wait(COND_T *cond, MUTEX_T *mut) +{ + ++cond->n_waiting; + MUTEX_UNLOCK(*mut); + /* "lost wakeup bug" would occur if the caller were interrupted here, + * but we are safe because we are using a semaphore wich has an internal + * count. + */ + if (WaitForSingleObject(cond->sem, INFINITE) == WAIT_FAILED) + Py_FatalError("WaitForSingleObject() failed"); + MUTEX_LOCK(*mut); +} + +__inline static int _cond_timed_wait(COND_T *cond, MUTEX_T *mut, + int us) +{ + DWORD r; + ++cond->n_waiting; + MUTEX_UNLOCK(*mut); + r = WaitForSingleObject(cond->sem, us / 1000); + if (r == WAIT_FAILED) + Py_FatalError("WaitForSingleObject() failed"); + MUTEX_LOCK(*mut); + if (r == WAIT_TIMEOUT) + --cond->n_waiting; + /* Here we have a benign race condition with _cond_signal. If the + * wait operation has timed out, but before we can acquire the + * mutex again to decrement n_waiting, a thread holding the mutex + * still sees a positive n_waiting value and may call + * ReleaseSemaphore and decrement n_waiting. + * This will cause n_waiting to be decremented twice. + * This is benign, though, because ReleaseSemaphore will also have + * been called, leaving the semaphore state positive. We may + * thus end up with semaphore in state 1, and n_waiting == -1, and + * the next time someone calls _cond_wait(), that thread will + * pass right through, decrementing the semaphore state and + * incrementing n_waiting, thus correcting the extra _cond_signal. + */ + return r == WAIT_TIMEOUT; +} + +__inline static void _cond_signal(COND_T *cond) { + /* NOTE: This must be called with the mutex held */ + if (cond->n_waiting > 0) { + if (!ReleaseSemaphore(cond->sem, 1, NULL)) + Py_FatalError("ReleaseSemaphore() failed"); + --cond->n_waiting; + } +} + +#define COND_INIT(cond) \ + _cond_init(&(cond)) +#define COND_FINI(cond) \ + _cond_fini(&(cond)) +#define COND_SIGNAL(cond) \ + _cond_signal(&(cond)) +#define COND_WAIT(cond, mut) \ + _cond_wait(&(cond), &(mut)) +#define COND_TIMED_WAIT(cond, mut, us, timeout_result) do { \ + (timeout_result) = _cond_timed_wait(&(cond), &(mut), us); \ +} while (0) + +#else + +#error You need either a POSIX-compatible or a Windows system! + +#endif /* _POSIX_THREADS, NT_THREADS */ + + +/* Whether the GIL is already taken (-1 if uninitialized). This is atomic + because it can be read without any lock taken in ceval.c. */ +static _Py_atomic_int gil_locked = {-1}; +/* Number of GIL switches since the beginning. */ +static unsigned long gil_switch_number = 0; +/* Last PyThreadState holding / having held the GIL. This helps us know + whether anyone else was scheduled after we dropped the GIL. */ +static _Py_atomic_address gil_last_holder = {NULL}; + +/* This condition variable allows one or several threads to wait until + the GIL is released. In addition, the mutex also protects the above + variables. */ +static COND_T gil_cond; +static MUTEX_T gil_mutex; + +#ifdef FORCE_SWITCHING +/* This condition variable helps the GIL-releasing thread wait for + a GIL-awaiting thread to be scheduled and take the GIL. */ +static COND_T switch_cond; +static MUTEX_T switch_mutex; +#endif + + +static int gil_created(void) +{ + return _Py_atomic_load_explicit(&gil_locked, _Py_memory_order_acquire) >= 0; +} + +static void create_gil(void) +{ + MUTEX_INIT(gil_mutex); +#ifdef FORCE_SWITCHING + MUTEX_INIT(switch_mutex); +#endif + COND_INIT(gil_cond); +#ifdef FORCE_SWITCHING + COND_INIT(switch_cond); +#endif + _Py_atomic_store_relaxed(&gil_last_holder, NULL); + _Py_ANNOTATE_RWLOCK_CREATE(&gil_locked); + _Py_atomic_store_explicit(&gil_locked, 0, _Py_memory_order_release); +} + +static void destroy_gil(void) +{ + MUTEX_FINI(gil_mutex); +#ifdef FORCE_SWITCHING + MUTEX_FINI(switch_mutex); +#endif + COND_FINI(gil_cond); +#ifdef FORCE_SWITCHING + COND_FINI(switch_cond); +#endif + _Py_atomic_store_explicit(&gil_locked, -1, _Py_memory_order_release); + _Py_ANNOTATE_RWLOCK_DESTROY(&gil_locked); +} + +static void recreate_gil(void) +{ + _Py_ANNOTATE_RWLOCK_DESTROY(&gil_locked); + /* XXX should we destroy the old OS resources here? */ + create_gil(); +} + +static void drop_gil(PyThreadState *tstate) +{ + if (!_Py_atomic_load_relaxed(&gil_locked)) + Py_FatalError("drop_gil: GIL is not locked"); + /* tstate is allowed to be NULL (early interpreter init) */ + if (tstate != NULL) { + /* Sub-interpreter support: threads might have been switched + under our feet using PyThreadState_Swap(). Fix the GIL last + holder variable so that our heuristics work. */ + _Py_atomic_store_relaxed(&gil_last_holder, tstate); + } + + MUTEX_LOCK(gil_mutex); + _Py_ANNOTATE_RWLOCK_RELEASED(&gil_locked, /*is_write=*/1); + _Py_atomic_store_relaxed(&gil_locked, 0); + COND_SIGNAL(gil_cond); + MUTEX_UNLOCK(gil_mutex); + +#ifdef FORCE_SWITCHING + if (_Py_atomic_load_relaxed(&gil_drop_request) && tstate != NULL) { + MUTEX_LOCK(switch_mutex); + /* Not switched yet => wait */ + if (_Py_atomic_load_relaxed(&gil_last_holder) == tstate) { + RESET_GIL_DROP_REQUEST(); + /* NOTE: if COND_WAIT does not atomically start waiting when + releasing the mutex, another thread can run through, take + the GIL and drop it again, and reset the condition + before we even had a chance to wait for it. */ + COND_WAIT(switch_cond, switch_mutex); + } + MUTEX_UNLOCK(switch_mutex); + } +#endif +} + +static void take_gil(PyThreadState *tstate) +{ + int err; + if (tstate == NULL) + Py_FatalError("take_gil: NULL tstate"); + + err = errno; + MUTEX_LOCK(gil_mutex); + + if (!_Py_atomic_load_relaxed(&gil_locked)) + goto _ready; + + while (_Py_atomic_load_relaxed(&gil_locked)) { + int timed_out = 0; + unsigned long saved_switchnum; + + saved_switchnum = gil_switch_number; + COND_TIMED_WAIT(gil_cond, gil_mutex, INTERVAL, timed_out); + /* If we timed out and no switch occurred in the meantime, it is time + to ask the GIL-holding thread to drop it. */ + if (timed_out && + _Py_atomic_load_relaxed(&gil_locked) && + gil_switch_number == saved_switchnum) { + SET_GIL_DROP_REQUEST(); + } + } +_ready: +#ifdef FORCE_SWITCHING + /* This mutex must be taken before modifying gil_last_holder (see drop_gil()). */ + MUTEX_LOCK(switch_mutex); +#endif + /* We now hold the GIL */ + _Py_atomic_store_relaxed(&gil_locked, 1); + _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil_locked, /*is_write=*/1); + + if (tstate != _Py_atomic_load_relaxed(&gil_last_holder)) { + _Py_atomic_store_relaxed(&gil_last_holder, tstate); + ++gil_switch_number; + } + +#ifdef FORCE_SWITCHING + COND_SIGNAL(switch_cond); + MUTEX_UNLOCK(switch_mutex); +#endif + if (_Py_atomic_load_relaxed(&gil_drop_request)) { + RESET_GIL_DROP_REQUEST(); + } + if (tstate->async_exc != NULL) { + _PyEval_SignalAsyncExc(); + } + + MUTEX_UNLOCK(gil_mutex); + errno = err; +} + +void _PyEval_SetSwitchInterval(unsigned long microseconds) +{ + gil_interval = microseconds; +} + +unsigned long _PyEval_GetSwitchInterval() +{ + return gil_interval; +} diff --git a/Python/compile.c b/Python/compile.c index 19b2addc10..1d6e38c22e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -25,10 +25,8 @@ #include "Python-ast.h" #include "node.h" -#include "pyarena.h" #include "ast.h" #include "code.h" -#include "compile.h" #include "symtable.h" #include "opcode.h" @@ -117,13 +115,13 @@ struct compiler_unit { members, you can reach all early allocated blocks. */ basicblock *u_blocks; basicblock *u_curblock; /* pointer to current block */ - int u_tmpname; /* temporary variables for list comps */ int u_nfblocks; struct fblockinfo u_fblock[CO_MAXBLOCKS]; int u_firstlineno; /* the first lineno of the block */ int u_lineno; /* the lineno for the current stmt */ + int u_col_offset; /* the offset of the current stmt */ int u_lineno_set; /* boolean to indicate whether instr has been generated with current lineno */ }; @@ -141,12 +139,12 @@ struct compiler { PyFutureFeatures *c_future; /* pointer to module's __future__ */ PyCompilerFlags *c_flags; + int c_optimize; /* optimization level */ int c_interactive; /* true if in interactive mode */ int c_nestlevel; struct compiler_unit *u; /* compiler state for current block */ PyObject *c_stack; /* Python list holding compiler_unit ptrs */ - char *c_encoding; /* source encoding (a borrowed reference) */ PyArena *c_arena; /* pointer to memory allocation arena */ }; @@ -178,7 +176,7 @@ static void compiler_pop_fblock(struct compiler *, enum fblocktype, static int compiler_in_loop(struct compiler *); static int inplace_binop(struct compiler *, operator_ty); -static int expr_constant(expr_ty e); +static int expr_constant(struct compiler *, expr_ty); static int compiler_with(struct compiler *, stmt_ty); static int compiler_call_helper(struct compiler *c, int n, @@ -257,8 +255,8 @@ compiler_init(struct compiler *c) } PyCodeObject * -PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags, - PyArena *arena) +PyAST_CompileEx(mod_ty mod, const char *filename, PyCompilerFlags *flags, + int optimize, PyArena *arena) { struct compiler c; PyCodeObject *co = NULL; @@ -286,6 +284,7 @@ PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags, c.c_future->ff_features = merged; flags->cf_flags = merged; c.c_flags = flags; + c.c_optimize = (optimize == -1) ? Py_OptimizeFlag : optimize; c.c_nestlevel = 0; c.c_st = PySymtable_Build(mod, filename, c.c_future); @@ -295,9 +294,6 @@ PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags, goto finally; } - /* XXX initialize to NULL for now, need to handle */ - c.c_encoding = NULL; - co = compiler_mod(&c, mod); finally: @@ -488,10 +484,10 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key, } u->u_blocks = NULL; - u->u_tmpname = 0; u->u_nfblocks = 0; u->u_firstlineno = lineno; u->u_lineno = 0; + u->u_col_offset = 0; u->u_lineno_set = 0; u->u_consts = PyDict_New(); if (!u->u_consts) { @@ -551,16 +547,6 @@ compiler_exit_scope(struct compiler *c) } -/* Allocate a new "anonymous" local variable. Used by with statements. */ - -static PyObject * -compiler_new_tmpname(struct compiler *c) -{ - char tmpname[256]; - PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->u->u_tmpname); - return PyUnicode_FromString(tmpname); -} - /* Allocate a new block and return a pointer to it. Returns NULL on error. */ @@ -696,8 +682,8 @@ opcode_stack_effect(int opcode, int oparg) return 0; case DUP_TOP: return 1; - case ROT_FOUR: - return 0; + case DUP_TOP_TWO: + return 2; case UNARY_POSITIVE: case UNARY_NEGATIVE: @@ -759,6 +745,8 @@ opcode_stack_effect(int opcode, int oparg) return -1; case BREAK_LOOP: return 0; + case SETUP_WITH: + return 7; case WITH_CLEANUP: return -1; /* XXX Sometimes more */ case STORE_LOCALS: @@ -786,7 +774,7 @@ opcode_stack_effect(int opcode, int oparg) case UNPACK_EX: return (oparg&0xFF) + (oparg>>8); case FOR_ITER: - return 1; + return 1; /* or -1, at end of iterator */ case STORE_ATTR: return -2; @@ -796,8 +784,6 @@ opcode_stack_effect(int opcode, int oparg) return -1; case DELETE_GLOBAL: return 0; - case DUP_TOPX: - return oparg; case LOAD_CONST: return 1; case LOAD_NAME: @@ -813,7 +799,7 @@ opcode_stack_effect(int opcode, int oparg) case COMPARE_OP: return -1; case IMPORT_NAME: - return 0; + return -1; case IMPORT_FROM: return 1; @@ -873,6 +859,8 @@ opcode_stack_effect(int opcode, int oparg) return 1; case STORE_DEREF: return -1; + case DELETE_DEREF: + return 0; default: fprintf(stderr, "opcode = %d\n", opcode); Py_FatalError("opcode_stack_effect()"); @@ -923,7 +911,6 @@ compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o) else t = PyTuple_Pack(2, o, o->ob_type); } -#ifndef WITHOUT_COMPLEX else if (PyComplex_Check(o)) { Py_complex z; int real_negzero, imag_negzero; @@ -948,7 +935,6 @@ compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o) t = PyTuple_Pack(2, o, o->ob_type); } } -#endif /* WITHOUT_COMPLEX */ else { t = PyTuple_Pack(2, o, o->ob_type); } @@ -1165,7 +1151,7 @@ compiler_body(struct compiler *c, asdl_seq *stmts) if (!asdl_seq_LEN(stmts)) return 1; st = (stmt_ty)asdl_seq_GET(stmts, 0); - if (compiler_isdocstring(st) && Py_OptimizeFlag < 2) { + if (compiler_isdocstring(st) && c->c_optimize < 2) { /* don't generate docstrings if -OO */ i = 1; VISIT(c, expr, st->v.Expr.value); @@ -1479,7 +1465,7 @@ compiler_function(struct compiler *c, stmt_ty s) st = (stmt_ty)asdl_seq_GET(s->v.FunctionDef.body, 0); docstring = compiler_isdocstring(st); - if (docstring && Py_OptimizeFlag < 2) + if (docstring && c->c_optimize < 2) first_const = st->v.Expr.value->v.Str.s; if (compiler_add_o(c, c->u->u_consts, first_const) < 0) { compiler_exit_scope(c); @@ -1676,6 +1662,11 @@ compiler_lambda(struct compiler *c, expr_ty e) if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) return 0; + /* Make None the first constant, so the lambda can't have a + docstring. */ + if (compiler_add_o(c, c->u->u_consts, Py_None) < 0) + return 0; + c->u->u_argcount = asdl_seq_LEN(args->args); c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); VISIT_IN_SCOPE(c, expr, e->v.Lambda.body); @@ -1708,7 +1699,7 @@ compiler_if(struct compiler *c, stmt_ty s) if (end == NULL) return 0; - constant = expr_constant(s->v.If.test); + constant = expr_constant(c, s->v.If.test); /* constant = 0: "if 0" * constant = 1: "if 1", "if 2", ... * constant = -1: rest */ @@ -1754,9 +1745,6 @@ compiler_for(struct compiler *c, stmt_ty s) VISIT(c, expr, s->v.For.iter); ADDOP(c, GET_ITER); compiler_use_next_block(c, start); - /* for expressions must be traced on each iteration, - so we need to set an extra line number. */ - c->u->u_lineno_set = 0; ADDOP_JREL(c, FOR_ITER, cleanup); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); @@ -1773,7 +1761,7 @@ static int compiler_while(struct compiler *c, stmt_ty s) { basicblock *loop, *orelse, *end, *anchor = NULL; - int constant = expr_constant(s->v.While.test); + int constant = expr_constant(c, s->v.While.test); if (constant == 0) { if (s->v.While.orelse) @@ -1802,9 +1790,6 @@ compiler_while(struct compiler *c, stmt_ty s) if (!compiler_push_fblock(c, LOOP, loop)) return 0; if (constant == -1) { - /* while expressions must be traced on each iteration, - so we need to set an extra line number. */ - c->u->u_lineno_set = 0; VISIT(c, expr, s->v.While.test); ADDOP_JABS(c, POP_JUMP_IF_FALSE, anchor); } @@ -1982,6 +1967,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) return compiler_error(c, "default 'except:' must be last"); c->u->u_lineno_set = 0; c->u->u_lineno = handler->lineno; + c->u->u_col_offset = handler->col_offset; except = compiler_new_block(c); if (except == NULL) return 0; @@ -2154,6 +2140,13 @@ compiler_from_import(struct compiler *c, stmt_ty s) PyObject *names = PyTuple_New(n); PyObject *level; + static PyObject *empty_string; + + if (!empty_string) { + empty_string = PyUnicode_FromString(""); + if (!empty_string) + return 0; + } if (!names) return 0; @@ -2171,23 +2164,24 @@ compiler_from_import(struct compiler *c, stmt_ty s) PyTuple_SET_ITEM(names, i, alias->name); } - if (s->lineno > c->c_future->ff_lineno) { - if (!PyUnicode_CompareWithASCIIString(s->v.ImportFrom.module, - "__future__")) { - Py_DECREF(level); - Py_DECREF(names); - return compiler_error(c, - "from __future__ imports must occur " - "at the beginning of the file"); - - } + if (s->lineno > c->c_future->ff_lineno && s->v.ImportFrom.module && + !PyUnicode_CompareWithASCIIString(s->v.ImportFrom.module, "__future__")) { + Py_DECREF(level); + Py_DECREF(names); + return compiler_error(c, "from __future__ imports must occur " + "at the beginning of the file"); } ADDOP_O(c, LOAD_CONST, level, consts); Py_DECREF(level); ADDOP_O(c, LOAD_CONST, names, consts); Py_DECREF(names); - ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names); + if (s->v.ImportFrom.module) { + ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names); + } + else { + ADDOP_NAME(c, IMPORT_NAME, empty_string, names); + } for (i = 0; i < n; i++) { alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i); identifier store_name; @@ -2219,7 +2213,7 @@ compiler_assert(struct compiler *c, stmt_ty s) static PyObject *assertion_error = NULL; basicblock *end; - if (Py_OptimizeFlag) + if (c->c_optimize) return 1; if (assertion_error == NULL) { assertion_error = PyUnicode_InternFromString("AssertionError"); @@ -2256,6 +2250,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) /* Always assign a lineno to the next instruction for a stmt. */ c->u->u_lineno = s->lineno; + c->u->u_col_offset = s->col_offset; c->u->u_lineno_set = 0; switch (s->kind) { @@ -2517,13 +2512,7 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) case AugLoad: case AugStore: break; - case Del: - PyErr_Format(PyExc_SyntaxError, - "can not delete variable '%S' referenced " - "in nested scope", - name); - Py_DECREF(mangled); - return 0; + case Del: op = DELETE_DEREF; break; case Param: default: PyErr_SetString(PyExc_SystemError, @@ -3024,7 +3013,7 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k) */ static int -expr_constant(expr_ty e) +expr_constant(struct compiler *c, expr_ty e) { char *id; switch (e->kind) { @@ -3042,7 +3031,7 @@ expr_constant(expr_ty e) if (strcmp(id, "False") == 0) return 0; if (strcmp(id, "None") == 0) return 0; if (strcmp(id, "__debug__") == 0) - return ! Py_OptimizeFlag; + return ! c->c_optimize; /* fall through */ default: return -1; @@ -3075,86 +3064,32 @@ expr_constant(expr_ty e) static int compiler_with(struct compiler *c, stmt_ty s) { - static identifier enter_attr, exit_attr; basicblock *block, *finally; - identifier tmpvalue = NULL, tmpexit = NULL; assert(s->kind == With_kind); - if (!enter_attr) { - enter_attr = PyUnicode_InternFromString("__enter__"); - if (!enter_attr) - return 0; - } - if (!exit_attr) { - exit_attr = PyUnicode_InternFromString("__exit__"); - if (!exit_attr) - return 0; - } - block = compiler_new_block(c); finally = compiler_new_block(c); if (!block || !finally) return 0; - if (s->v.With.optional_vars) { - /* Create a temporary variable to hold context.__enter__(). - We need to do this rather than preserving it on the stack - because SETUP_FINALLY remembers the stack level. - We need to do the assignment *inside* the try/finally - so that context.__exit__() is called when the assignment - fails. But we need to call context.__enter__() *before* - the try/finally so that if it fails we won't call - context.__exit__(). - */ - tmpvalue = compiler_new_tmpname(c); - if (tmpvalue == NULL) - return 0; - PyArena_AddPyObject(c->c_arena, tmpvalue); - } - tmpexit = compiler_new_tmpname(c); - if (tmpexit == NULL) - return 0; - PyArena_AddPyObject(c->c_arena, tmpexit); - /* Evaluate EXPR */ VISIT(c, expr, s->v.With.context_expr); + ADDOP_JREL(c, SETUP_WITH, finally); - /* Squirrel away context.__exit__ by stuffing it under context */ - ADDOP(c, DUP_TOP); - ADDOP_O(c, LOAD_ATTR, exit_attr, names); - if (!compiler_nameop(c, tmpexit, Store)) - return 0; - - /* Call context.__enter__() */ - ADDOP_O(c, LOAD_ATTR, enter_attr, names); - ADDOP_I(c, CALL_FUNCTION, 0); - - if (s->v.With.optional_vars) { - /* Store it in tmpvalue */ - if (!compiler_nameop(c, tmpvalue, Store)) - return 0; - } - else { - /* Discard result from context.__enter__() */ - ADDOP(c, POP_TOP); - } - - /* Start the try block */ - ADDOP_JREL(c, SETUP_FINALLY, finally); - + /* SETUP_WITH pushes a finally block. */ compiler_use_next_block(c, block); if (!compiler_push_fblock(c, FINALLY_TRY, block)) { return 0; } if (s->v.With.optional_vars) { - /* Bind saved result of context.__enter__() to VAR */ - if (!compiler_nameop(c, tmpvalue, Load) || - !compiler_nameop(c, tmpvalue, Del)) - return 0; VISIT(c, expr, s->v.With.optional_vars); } + else { + /* Discard result from context.__enter__() */ + ADDOP(c, POP_TOP); + } /* BLOCK code */ VISIT_SEQ(c, stmt, s->v.With.body); @@ -3171,9 +3106,6 @@ compiler_with(struct compiler *c, stmt_ty s) /* Finally block starts; context.__exit__ is on the stack under the exception or return information. Just issue our magic opcode. */ - if (!compiler_nameop(c, tmpexit, Load) || - !compiler_nameop(c, tmpexit, Del)) - return 0; ADDOP(c, WITH_CLEANUP); /* Finally block ends. */ @@ -3194,6 +3126,8 @@ compiler_visit_expr(struct compiler *c, expr_ty e) c->u->u_lineno = e->lineno; c->u->u_lineno_set = 0; } + /* Updating the column offset is always harmless. */ + c->u->u_col_offset = e->col_offset; switch (e->kind) { case BoolOp_kind: return compiler_boolop(c, e); @@ -3427,7 +3361,7 @@ compiler_in_loop(struct compiler *c) { static int compiler_error(struct compiler *c, const char *errstr) { - PyObject *loc; + PyObject *loc, *filename; PyObject *u = NULL, *v = NULL; loc = PyErr_ProgramText(c->c_filename, c->u->u_lineno); @@ -3435,8 +3369,17 @@ compiler_error(struct compiler *c, const char *errstr) Py_INCREF(Py_None); loc = Py_None; } - u = Py_BuildValue("(ziOO)", c->c_filename, c->u->u_lineno, - Py_None, loc); + if (c->c_filename != NULL) { + filename = PyUnicode_DecodeFSDefault(c->c_filename); + if (!filename) + goto exit; + } + else { + Py_INCREF(Py_None); + filename = Py_None; + } + u = Py_BuildValue("(NiiO)", filename, c->u->u_lineno, + c->u->u_col_offset, loc); if (!u) goto exit; v = Py_BuildValue("(zO)", errstr, u); @@ -3470,7 +3413,7 @@ compiler_handle_subscr(struct compiler *c, const char *kind, return 0; } if (ctx == AugLoad) { - ADDOP_I(c, DUP_TOPX, 2); + ADDOP(c, DUP_TOP_TWO); } else if (ctx == AugStore) { ADDOP(c, ROT_THREE); @@ -3607,7 +3550,7 @@ dfs(struct compiler *c, basicblock *b, struct assembler *a) static int stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth) { - int i; + int i, target_depth; struct instr *instr; if (b->b_seen || b->b_startdepth >= depth) return maxdepth; @@ -3620,8 +3563,17 @@ stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth) maxdepth = depth; assert(depth >= 0); /* invalid code or bug in stackdepth() */ if (instr->i_jrel || instr->i_jabs) { + target_depth = depth; + if (instr->i_opcode == FOR_ITER) { + target_depth = depth-2; + } else if (instr->i_opcode == SETUP_FINALLY || + instr->i_opcode == SETUP_EXCEPT) { + target_depth = depth+3; + if (target_depth > maxdepth) + maxdepth = target_depth; + } maxdepth = stackdepth_walk(c, instr->i_target, - depth, maxdepth); + target_depth, maxdepth); if (instr->i_opcode == JUMP_ABSOLUTE || instr->i_opcode == JUMP_FORWARD) { goto out; /* remaining code is dead */ @@ -3709,51 +3661,9 @@ blocksize(basicblock *b) return size; } -/* All about a_lnotab. - -c_lnotab is an array of unsigned bytes disguised as a Python string. -It is used to map bytecode offsets to source code line #s (when needed -for tracebacks). - -The array is conceptually a list of - (bytecode offset increment, line number increment) -pairs. The details are important and delicate, best illustrated by example: - - byte code offset source code line number - 0 1 - 6 2 - 50 7 - 350 307 - 361 308 - -The first trick is that these numbers aren't stored, only the increments -from one row to the next (this doesn't really work, but it's a start): - - 0, 1, 6, 1, 44, 5, 300, 300, 11, 1 - -The second trick is that an unsigned byte can't hold negative values, or -values larger than 255, so (a) there's a deep assumption that byte code -offsets and their corresponding line #s both increase monotonically, and (b) -if at least one column jumps by more than 255 from one row to the next, more -than one pair is written to the table. In case #b, there's no way to know -from looking at the table later how many were written. That's the delicate -part. A user of c_lnotab desiring to find the source line number -corresponding to a bytecode address A should do something like this - - lineno = addr = 0 - for addr_incr, line_incr in c_lnotab: - addr += addr_incr - if addr > A: - return lineno - lineno += line_incr - -In order for this to work, when the addr field increments by more than 255, -the line # increment in each pair generated must be 0 until the remaining addr -increment is < 256. So, in the example above, assemble_lnotab (it used -to be called com_set_lineno) should not (as was actually done until 2.2) -expand 300, 300 to 255, 255, 45, 45, - but to 255, 0, 45, 255, 0, 45. -*/ +/* Appends a pair to the end of the line number table, a_lnotab, representing + the instruction's bytecode offset and line number. See + Objects/lnotab_notes.txt for the description of the line number table. */ static int assemble_lnotab(struct assembler *a, struct instr *i) @@ -3895,49 +3805,47 @@ static void assemble_jump_offsets(struct assembler *a, struct compiler *c) { basicblock *b; - int bsize, totsize, extended_arg_count, last_extended_arg_count = 0; + int bsize, totsize, extended_arg_count = 0, last_extended_arg_count; int i; /* Compute the size of each block and fixup jump args. Replace block pointer with position in bytecode. */ -start: - totsize = 0; - for (i = a->a_nblocks - 1; i >= 0; i--) { - b = a->a_postorder[i]; - bsize = blocksize(b); - b->b_offset = totsize; - totsize += bsize; - } - extended_arg_count = 0; - for (b = c->u->u_blocks; b != NULL; b = b->b_list) { - bsize = b->b_offset; - for (i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; - /* Relative jumps are computed relative to - the instruction pointer after fetching - the jump instruction. - */ - bsize += instrsize(instr); - if (instr->i_jabs) - instr->i_oparg = instr->i_target->b_offset; - else if (instr->i_jrel) { - int delta = instr->i_target->b_offset - bsize; - instr->i_oparg = delta; + do { + totsize = 0; + for (i = a->a_nblocks - 1; i >= 0; i--) { + b = a->a_postorder[i]; + bsize = blocksize(b); + b->b_offset = totsize; + totsize += bsize; + } + last_extended_arg_count = extended_arg_count; + extended_arg_count = 0; + for (b = c->u->u_blocks; b != NULL; b = b->b_list) { + bsize = b->b_offset; + for (i = 0; i < b->b_iused; i++) { + struct instr *instr = &b->b_instr[i]; + /* Relative jumps are computed relative to + the instruction pointer after fetching + the jump instruction. + */ + bsize += instrsize(instr); + if (instr->i_jabs) + instr->i_oparg = instr->i_target->b_offset; + else if (instr->i_jrel) { + int delta = instr->i_target->b_offset - bsize; + instr->i_oparg = delta; + } + else + continue; + if (instr->i_oparg > 0xffff) + extended_arg_count++; } - else - continue; - if (instr->i_oparg > 0xffff) - extended_arg_count++; } - } /* XXX: This is an awful hack that could hurt performance, but on the bright side it should work until we come up with a better solution. - In the meantime, should the goto be dropped in favor - of a loop? - The issue is that in the first loop blocksize() is called which calls instrsize() which requires i_oparg be set appropriately. There is a bootstrap problem because @@ -3948,10 +3856,7 @@ start: ones in jump instructions. So this should converge fairly quickly. */ - if (last_extended_arg_count != extended_arg_count) { - last_extended_arg_count = extended_arg_count; - goto start; - } + } while (last_extended_arg_count != extended_arg_count); } static PyObject * @@ -4177,3 +4082,13 @@ assemble(struct compiler *c, int addNone) assemble_free(&a); return co; } + +#undef PyAST_Compile +PyAPI_FUNC(PyCodeObject *) +PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags, + PyArena *arena) +{ + return PyAST_CompileEx(mod, filename, flags, -1, arena); +} + + diff --git a/Python/dtoa.c b/Python/dtoa.c index 4b2c6c36e3..44dc01f1d5 100644 --- a/Python/dtoa.c +++ b/Python/dtoa.c @@ -1382,7 +1382,6 @@ bigcomp(U *rv, const char *s0, BCinfo *bc) Bigint *b, *d; int b2, d2, dd, i, nd, nd0, odd, p2, p5; - dd = 0; /* silence compiler warning about possibly unused variable */ nd = bc->nd; nd0 = bc->nd0; p5 = nd + bc->e0; @@ -2362,7 +2361,7 @@ _Py_dg_dtoa(double dd, int mode, int ndigits, /* set pointers to NULL, to silence gcc compiler warnings and make cleanup easier on error */ - mlo = mhi = b = S = 0; + mlo = mhi = S = 0; s0 = 0; u.d = dd; @@ -2713,8 +2712,6 @@ _Py_dg_dtoa(double dd, int mode, int ndigits, * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ - if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)) - i = 32 - i; #define iInc 28 i = dshift(S, s2); b2 += i; diff --git a/Python/dynamic_annotations.c b/Python/dynamic_annotations.c new file mode 100644 index 0000000000..10511da466 --- /dev/null +++ b/Python/dynamic_annotations.c @@ -0,0 +1,154 @@ +/* Copyright (c) 2008-2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * --- + * Author: Kostya Serebryany + */ + +#ifdef _MSC_VER +# include <windows.h> +#endif + +#ifdef __cplusplus +# error "This file should be built as pure C to avoid name mangling" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "dynamic_annotations.h" + +/* Each function is empty and called (via a macro) only in debug mode. + The arguments are captured by dynamic tools at runtime. */ + +#if DYNAMIC_ANNOTATIONS_ENABLED == 1 + +void AnnotateRWLockCreate(const char *file, int line, + const volatile void *lock){} +void AnnotateRWLockDestroy(const char *file, int line, + const volatile void *lock){} +void AnnotateRWLockAcquired(const char *file, int line, + const volatile void *lock, long is_w){} +void AnnotateRWLockReleased(const char *file, int line, + const volatile void *lock, long is_w){} +void AnnotateBarrierInit(const char *file, int line, + const volatile void *barrier, long count, + long reinitialization_allowed) {} +void AnnotateBarrierWaitBefore(const char *file, int line, + const volatile void *barrier) {} +void AnnotateBarrierWaitAfter(const char *file, int line, + const volatile void *barrier) {} +void AnnotateBarrierDestroy(const char *file, int line, + const volatile void *barrier) {} + +void AnnotateCondVarWait(const char *file, int line, + const volatile void *cv, + const volatile void *lock){} +void AnnotateCondVarSignal(const char *file, int line, + const volatile void *cv){} +void AnnotateCondVarSignalAll(const char *file, int line, + const volatile void *cv){} +void AnnotatePublishMemoryRange(const char *file, int line, + const volatile void *address, + long size){} +void AnnotateUnpublishMemoryRange(const char *file, int line, + const volatile void *address, + long size){} +void AnnotatePCQCreate(const char *file, int line, + const volatile void *pcq){} +void AnnotatePCQDestroy(const char *file, int line, + const volatile void *pcq){} +void AnnotatePCQPut(const char *file, int line, + const volatile void *pcq){} +void AnnotatePCQGet(const char *file, int line, + const volatile void *pcq){} +void AnnotateNewMemory(const char *file, int line, + const volatile void *mem, + long size){} +void AnnotateExpectRace(const char *file, int line, + const volatile void *mem, + const char *description){} +void AnnotateBenignRace(const char *file, int line, + const volatile void *mem, + const char *description){} +void AnnotateBenignRaceSized(const char *file, int line, + const volatile void *mem, + long size, + const char *description) {} +void AnnotateMutexIsUsedAsCondVar(const char *file, int line, + const volatile void *mu){} +void AnnotateTraceMemory(const char *file, int line, + const volatile void *arg){} +void AnnotateThreadName(const char *file, int line, + const char *name){} +void AnnotateIgnoreReadsBegin(const char *file, int line){} +void AnnotateIgnoreReadsEnd(const char *file, int line){} +void AnnotateIgnoreWritesBegin(const char *file, int line){} +void AnnotateIgnoreWritesEnd(const char *file, int line){} +void AnnotateIgnoreSyncBegin(const char *file, int line){} +void AnnotateIgnoreSyncEnd(const char *file, int line){} +void AnnotateEnableRaceDetection(const char *file, int line, int enable){} +void AnnotateNoOp(const char *file, int line, + const volatile void *arg){} +void AnnotateFlushState(const char *file, int line){} + +static int GetRunningOnValgrind(void) { +#ifdef RUNNING_ON_VALGRIND + if (RUNNING_ON_VALGRIND) return 1; +#endif + +#ifndef _MSC_VER + char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); + if (running_on_valgrind_str) { + return strcmp(running_on_valgrind_str, "0") != 0; + } +#else + /* Visual Studio issues warnings if we use getenv, + * so we use GetEnvironmentVariableA instead. + */ + char value[100] = "1"; + int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND", + value, sizeof(value)); + /* value will remain "1" if res == 0 or res >= sizeof(value). The latter + * can happen only if the given value is long, in this case it can't be "0". + */ + if (res > 0 && !strcmp(value, "0")) + return 1; +#endif + return 0; +} + +/* See the comments in dynamic_annotations.h */ +int RunningOnValgrind(void) { + static volatile int running_on_valgrind = -1; + /* C doesn't have thread-safe initialization of statics, and we + don't want to depend on pthread_once here, so hack it. */ + int local_running_on_valgrind = running_on_valgrind; + if (local_running_on_valgrind == -1) + running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind(); + return local_running_on_valgrind; +} + +#endif /* DYNAMIC_ANNOTATIONS_ENABLED == 1 */ diff --git a/Python/dynload_atheos.c b/Python/dynload_atheos.c deleted file mode 100644 index 396a35bb9e..0000000000 --- a/Python/dynload_atheos.c +++ /dev/null @@ -1,47 +0,0 @@ - -/* Support for dynamic loading of extension modules */ - -#include <atheos/image.h> -#include <errno.h> - -#include "Python.h" -#include "importdl.h" - - -const struct filedescr _PyImport_DynLoadFiletab[] = { - {".so", "rb", C_EXTENSION}, - {"module.so", "rb", C_EXTENSION}, - {0, 0} -}; - -dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, - const char *pathname, FILE *fp) -{ - void *p; - int lib; - char funcname[258]; - - if (Py_VerboseFlag) - printf("load_library %s\n", pathname); - - lib = load_library(pathname, 0); - if (lib < 0) { - char buf[512]; - if (Py_VerboseFlag) - perror(pathname); - PyOS_snprintf(buf, sizeof(buf), "Failed to load %.200s: %.200s", - pathname, strerror(errno)); - PyErr_SetString(PyExc_ImportError, buf); - return NULL; - } - PyOS_snprintf(funcname, sizeof(funcname), "PyInit_%.200s", shortname); - if (Py_VerboseFlag) - printf("get_symbol_address %s\n", funcname); - if (get_symbol_address(lib, funcname, -1, &p) < 0) { - p = NULL; - if (Py_VerboseFlag) - perror(funcname); - } - - return (dl_funcptr) p; -} diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c index 87dae27ed4..7ea510e862 100644 --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -30,27 +30,36 @@ #define LEAD_UNDERSCORE "" #endif +/* The .so extension module ABI tag, supplied by the Makefile via + Makefile.pre.in and configure. This is used to discriminate between + incompatible .so files so that extensions for different Python builds can + live in the same directory. E.g. foomodule.cpython-32.so +*/ const struct filedescr _PyImport_DynLoadFiletab[] = { #ifdef __CYGWIN__ {".dll", "rb", C_EXTENSION}, {"module.dll", "rb", C_EXTENSION}, -#else +#else /* !__CYGWIN__ */ #if defined(PYOS_OS2) && defined(PYCC_GCC) {".pyd", "rb", C_EXTENSION}, {".dll", "rb", C_EXTENSION}, -#else +#else /* !(defined(PYOS_OS2) && defined(PYCC_GCC)) */ #ifdef __VMS {".exe", "rb", C_EXTENSION}, {".EXE", "rb", C_EXTENSION}, {"module.exe", "rb", C_EXTENSION}, {"MODULE.EXE", "rb", C_EXTENSION}, -#else +#else /* !__VMS */ + {"." SOABI ".so", "rb", C_EXTENSION}, + {"module." SOABI ".so", "rb", C_EXTENSION}, + {".abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION}, + {"module.abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION}, {".so", "rb", C_EXTENSION}, {"module.so", "rb", C_EXTENSION}, -#endif -#endif -#endif +#endif /* __VMS */ +#endif /* defined(PYOS_OS2) && defined(PYCC_GCC) */ +#endif /* __CYGWIN__ */ {0, 0} }; diff --git a/Python/dynload_win.c b/Python/dynload_win.c index e7d61ce8e0..73a1dcf897 100644 --- a/Python/dynload_win.c +++ b/Python/dynload_win.c @@ -134,6 +134,15 @@ static char *GetPythonImport (HINSTANCE hModule) !strncmp(import_name,"python",6)) { char *pch; +#ifndef _DEBUG + /* In a release version, don't claim that python3.dll is + a Python DLL. */ + if (strcmp(import_name, "python3.dll") == 0) { + import_data += 20; + continue; + } +#endif + /* Ensure python prefix is followed only by numbers to the end of the basename */ pch = import_name + 6; @@ -162,13 +171,16 @@ static char *GetPythonImport (HINSTANCE hModule) return NULL; } - dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, const char *pathname, FILE *fp) { dl_funcptr p; char funcname[258], *import_python; +#ifndef _DEBUG + _Py_CheckPython3(); +#endif + PyOS_snprintf(funcname, sizeof(funcname), "PyInit_%.200s", shortname); { diff --git a/Python/errors.c b/Python/errors.c index db0baf1c24..5a9a624279 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -130,9 +130,14 @@ PyErr_SetString(PyObject *exception, const char *string) PyObject * PyErr_Occurred(void) { - PyThreadState *tstate = PyThreadState_GET(); - - return tstate->curexc_type; + /* If there is no thread state, PyThreadState_GET calls + Py_FatalError, which calls PyErr_Occurred. To avoid the + resulting infinite loop, we inline PyThreadState_GET here and + treat no thread as no error. */ + PyThreadState *tstate = + ((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)); + + return tstate == NULL ? NULL : tstate->curexc_type; } @@ -338,25 +343,17 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject) PyObject *message; PyObject *v; int i = errno; -#ifdef PLAN9 - char errbuf[ERRMAX]; -#else #ifndef MS_WINDOWS char *s; #else WCHAR *s_buf = NULL; #endif /* Unix/Windows */ -#endif /* PLAN 9*/ #ifdef EINTR if (i == EINTR && PyErr_CheckSignals()) return NULL; #endif -#ifdef PLAN9 - rerrstr(errbuf, sizeof errbuf); - message = PyUnicode_DecodeUTF8(errbuf, strlen(errbuf), "ignore"); -#else #ifndef MS_WINDOWS if (i == 0) s = "Error"; /* Sometimes errno didn't get set */ @@ -403,7 +400,6 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject) } } #endif /* Unix/Windows */ -#endif /* PLAN 9*/ if (message == NULL) { @@ -433,7 +429,7 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject) PyObject * PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename) { - PyObject *name = filename ? PyUnicode_FromString(filename) : NULL; + PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name); Py_XDECREF(name); return result; @@ -519,7 +515,7 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilename( int ierr, const char *filename) { - PyObject *name = filename ? PyUnicode_FromString(filename) : NULL; + PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc, ierr, name); @@ -556,7 +552,7 @@ PyObject *PyErr_SetFromWindowsErrWithFilename( int ierr, const char *filename) { - PyObject *name = filename ? PyUnicode_FromString(filename) : NULL; + PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject( PyExc_WindowsError, ierr, name); @@ -661,7 +657,7 @@ PyErr_NewException(const char *name, PyObject *base, PyObject *dict) goto failure; } /* Create a real new-style class. */ - result = PyObject_CallFunction((PyObject *)&PyType_Type, "UOO", + result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO", dot+1, bases, dict); failure: Py_XDECREF(bases); @@ -671,6 +667,41 @@ PyErr_NewException(const char *name, PyObject *base, PyObject *dict) return result; } + +/* Create an exception with docstring */ +PyObject * +PyErr_NewExceptionWithDoc(const char *name, const char *doc, + PyObject *base, PyObject *dict) +{ + int result; + PyObject *ret = NULL; + PyObject *mydict = NULL; /* points to the dict only if we create it */ + PyObject *docobj; + + if (dict == NULL) { + dict = mydict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + } + + if (doc != NULL) { + docobj = PyUnicode_FromString(doc); + if (docobj == NULL) + goto failure; + result = PyDict_SetItemString(dict, "__doc__", docobj); + Py_DECREF(docobj); + if (result < 0) + goto failure; + } + + ret = PyErr_NewException(name, base, dict); + failure: + Py_XDECREF(mydict); + return ret; +} + + /* Call when an exception has occurred but there is no way for Python to handle it. Examples: exception in __del__ or during GC. */ void @@ -714,8 +745,10 @@ PyErr_WriteUnraisable(PyObject *obj) } Py_XDECREF(moduleName); } - PyFile_WriteString(" in ", f); - PyFile_WriteObject(obj, f, 0); + if (obj) { + PyFile_WriteString(" in ", f); + PyFile_WriteObject(obj, f, 0); + } PyFile_WriteString(" ignored\n", f); PyErr_Clear(); /* Just in case */ } @@ -727,12 +760,18 @@ PyErr_WriteUnraisable(PyObject *obj) extern PyObject *PyModule_GetWarningsModule(void); +void +PyErr_SyntaxLocation(const char *filename, int lineno) { + PyErr_SyntaxLocationEx(filename, lineno, -1); +} + + /* Set file and line information for the current exception. If the exception is not a SyntaxError, also sets additional attributes to make printing of exceptions believe it is a syntax error. */ void -PyErr_SyntaxLocation(const char *filename, int lineno) +PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset) { PyObject *exc, *v, *tb, *tmp; @@ -749,8 +788,18 @@ PyErr_SyntaxLocation(const char *filename, int lineno) PyErr_Clear(); Py_DECREF(tmp); } + if (col_offset >= 0) { + tmp = PyLong_FromLong(col_offset); + if (tmp == NULL) + PyErr_Clear(); + else { + if (PyObject_SetAttrString(v, "offset", tmp)) + PyErr_Clear(); + Py_DECREF(tmp); + } + } if (filename != NULL) { - tmp = PyUnicode_FromString(filename); + tmp = PyUnicode_DecodeFSDefault(filename); if (tmp == NULL) PyErr_Clear(); else { diff --git a/Python/fileutils.c b/Python/fileutils.c new file mode 100644 index 0000000000..c563eaa5fb --- /dev/null +++ b/Python/fileutils.c @@ -0,0 +1,431 @@ +#include "Python.h" +#ifdef MS_WINDOWS +# include <windows.h> +#endif + +#ifdef HAVE_STAT + +/* Decode a byte string from the locale encoding with the + surrogateescape error handler (undecodable bytes are decoded as characters + in range U+DC80..U+DCFF). If a byte sequence can be decoded as a surrogate + character, escape the bytes using the surrogateescape error handler instead + of decoding them. + + Use _Py_wchar2char() to encode the character string back to a byte string. + + Return a pointer to a newly allocated wide character string (use + PyMem_Free() to free the memory) and write the number of written wide + characters excluding the null character into *size if size is not NULL, or + NULL on error (conversion or memory allocation error). + + Conversion errors should never happen, unless there is a bug in the C + library. */ +wchar_t* +_Py_char2wchar(const char* arg, size_t *size) +{ + wchar_t *res; +#ifdef HAVE_BROKEN_MBSTOWCS + /* Some platforms have a broken implementation of + * mbstowcs which does not count the characters that + * would result from conversion. Use an upper bound. + */ + size_t argsize = strlen(arg); +#else + size_t argsize = mbstowcs(NULL, arg, 0); +#endif + size_t count; + unsigned char *in; + wchar_t *out; +#ifdef HAVE_MBRTOWC + mbstate_t mbs; +#endif + if (argsize != (size_t)-1) { + res = (wchar_t *)PyMem_Malloc((argsize+1)*sizeof(wchar_t)); + if (!res) + goto oom; + count = mbstowcs(res, arg, argsize+1); + if (count != (size_t)-1) { + wchar_t *tmp; + /* Only use the result if it contains no + surrogate characters. */ + for (tmp = res; *tmp != 0 && + (*tmp < 0xd800 || *tmp > 0xdfff); tmp++) + ; + if (*tmp == 0) { + if (size != NULL) + *size = count; + return res; + } + } + PyMem_Free(res); + } + /* Conversion failed. Fall back to escaping with surrogateescape. */ +#ifdef HAVE_MBRTOWC + /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */ + + /* Overallocate; as multi-byte characters are in the argument, the + actual output could use less memory. */ + argsize = strlen(arg) + 1; + res = (wchar_t*)PyMem_Malloc(argsize*sizeof(wchar_t)); + if (!res) + goto oom; + in = (unsigned char*)arg; + out = res; + memset(&mbs, 0, sizeof mbs); + while (argsize) { + size_t converted = mbrtowc(out, (char*)in, argsize, &mbs); + if (converted == 0) + /* Reached end of string; null char stored. */ + break; + if (converted == (size_t)-2) { + /* Incomplete character. This should never happen, + since we provide everything that we have - + unless there is a bug in the C library, or I + misunderstood how mbrtowc works. */ + fprintf(stderr, "unexpected mbrtowc result -2\n"); + PyMem_Free(res); + return NULL; + } + if (converted == (size_t)-1) { + /* Conversion error. Escape as UTF-8b, and start over + in the initial shift state. */ + *out++ = 0xdc00 + *in++; + argsize--; + memset(&mbs, 0, sizeof mbs); + continue; + } + if (*out >= 0xd800 && *out <= 0xdfff) { + /* Surrogate character. Escape the original + byte sequence with surrogateescape. */ + argsize -= converted; + while (converted--) + *out++ = 0xdc00 + *in++; + continue; + } + /* successfully converted some bytes */ + in += converted; + argsize -= converted; + out++; + } +#else + /* Cannot use C locale for escaping; manually escape as if charset + is ASCII (i.e. escape all bytes > 128. This will still roundtrip + correctly in the locale's charset, which must be an ASCII superset. */ + res = PyMem_Malloc((strlen(arg)+1)*sizeof(wchar_t)); + if (!res) goto oom; + in = (unsigned char*)arg; + out = res; + while(*in) + if(*in < 128) + *out++ = *in++; + else + *out++ = 0xdc00 + *in++; + *out = 0; +#endif + if (size != NULL) + *size = out - res; + return res; +oom: + fprintf(stderr, "out of memory\n"); + return NULL; +} + +/* Encode a (wide) character string to the locale encoding with the + surrogateescape error handler (characters in range U+DC80..U+DCFF are + converted to bytes 0x80..0xFF). + + This function is the reverse of _Py_char2wchar(). + + Return a pointer to a newly allocated byte string (use PyMem_Free() to free + the memory), or NULL on conversion or memory allocation error. + + If error_pos is not NULL: *error_pos is the index of the invalid character + on conversion error, or (size_t)-1 otherwise. */ +char* +_Py_wchar2char(const wchar_t *text, size_t *error_pos) +{ + const size_t len = wcslen(text); + char *result = NULL, *bytes = NULL; + size_t i, size, converted; + wchar_t c, buf[2]; + + if (error_pos != NULL) + *error_pos = (size_t)-1; + + /* The function works in two steps: + 1. compute the length of the output buffer in bytes (size) + 2. outputs the bytes */ + size = 0; + buf[1] = 0; + while (1) { + for (i=0; i < len; i++) { + c = text[i]; + if (c >= 0xdc80 && c <= 0xdcff) { + /* UTF-8b surrogate */ + if (bytes != NULL) { + *bytes++ = c - 0xdc00; + size--; + } + else + size++; + continue; + } + else { + buf[0] = c; + if (bytes != NULL) + converted = wcstombs(bytes, buf, size); + else + converted = wcstombs(NULL, buf, 0); + if (converted == (size_t)-1) { + if (result != NULL) + PyMem_Free(result); + if (error_pos != NULL) + *error_pos = i; + return NULL; + } + if (bytes != NULL) { + bytes += converted; + size -= converted; + } + else + size += converted; + } + } + if (result != NULL) { + *bytes = 0; + break; + } + + size += 1; /* nul byte at the end */ + result = PyMem_Malloc(size); + if (result == NULL) + return NULL; + bytes = result; + } + return result; +} + +/* In principle, this should use HAVE__WSTAT, and _wstat + should be detected by autoconf. However, no current + POSIX system provides that function, so testing for + it is pointless. + Not sure whether the MS_WINDOWS guards are necessary: + perhaps for cygwin/mingw builds? +*/ +#if defined(HAVE_STAT) && !defined(MS_WINDOWS) + +/* Get file status. Encode the path to the locale encoding. */ + +int +_Py_wstat(const wchar_t* path, struct stat *buf) +{ + int err; + char *fname; + fname = _Py_wchar2char(path, NULL); + if (fname == NULL) { + errno = EINVAL; + return -1; + } + err = stat(fname, buf); + PyMem_Free(fname); + return err; +} +#endif + +/* Call _wstat() on Windows, or encode the path to the filesystem encoding and + call stat() otherwise. Only fill st_mode attribute on Windows. + + Return 0 on success, -1 on _wstat() / stat() error or (if PyErr_Occurred()) + unicode error. */ + +int +_Py_stat(PyObject *path, struct stat *statbuf) +{ +#ifdef MS_WINDOWS + int err; + struct _stat wstatbuf; + + err = _wstat(PyUnicode_AS_UNICODE(path), &wstatbuf); + if (!err) + statbuf->st_mode = wstatbuf.st_mode; + return err; +#else + int ret; + PyObject *bytes = PyUnicode_EncodeFSDefault(path); + if (bytes == NULL) + return -1; + ret = stat(PyBytes_AS_STRING(bytes), statbuf); + Py_DECREF(bytes); + return ret; +#endif +} + +/* Open a file. Use _wfopen() on Windows, encode the path to the locale + encoding and use fopen() otherwise. */ + +FILE * +_Py_wfopen(const wchar_t *path, const wchar_t *mode) +{ +#ifndef MS_WINDOWS + FILE *f; + char *cpath; + char cmode[10]; + size_t r; + r = wcstombs(cmode, mode, 10); + if (r == (size_t)-1 || r >= 10) { + errno = EINVAL; + return NULL; + } + cpath = _Py_wchar2char(path, NULL); + if (cpath == NULL) + return NULL; + f = fopen(cpath, cmode); + PyMem_Free(cpath); + return f; +#else + return _wfopen(path, mode); +#endif +} + +/* Call _wfopen() on Windows, or encode the path to the filesystem encoding and + call fopen() otherwise. + + Return the new file object on success, or NULL if the file cannot be open or + (if PyErr_Occurred()) on unicode error */ + +FILE* +_Py_fopen(PyObject *path, const char *mode) +{ +#ifdef MS_WINDOWS + wchar_t wmode[10]; + int usize; + + usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, wmode, sizeof(wmode)); + if (usize == 0) + return NULL; + + return _wfopen(PyUnicode_AS_UNICODE(path), wmode); +#else + FILE *f; + PyObject *bytes = PyUnicode_EncodeFSDefault(path); + if (bytes == NULL) + return NULL; + f = fopen(PyBytes_AS_STRING(bytes), mode); + Py_DECREF(bytes); + return f; +#endif +} + +#ifdef HAVE_READLINK + +/* Read value of symbolic link. Encode the path to the locale encoding, decode + the result from the locale encoding. */ + +int +_Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t bufsiz) +{ + char *cpath; + char cbuf[PATH_MAX]; + wchar_t *wbuf; + int res; + size_t r1; + + cpath = _Py_wchar2char(path, NULL); + if (cpath == NULL) { + errno = EINVAL; + return -1; + } + res = (int)readlink(cpath, cbuf, PATH_MAX); + PyMem_Free(cpath); + if (res == -1) + return -1; + if (res == PATH_MAX) { + errno = EINVAL; + return -1; + } + cbuf[res] = '\0'; /* buf will be null terminated */ + wbuf = _Py_char2wchar(cbuf, &r1); + if (wbuf == NULL) { + errno = EINVAL; + return -1; + } + if (bufsiz <= r1) { + PyMem_Free(wbuf); + errno = EINVAL; + return -1; + } + wcsncpy(buf, wbuf, bufsiz); + PyMem_Free(wbuf); + return (int)r1; +} +#endif + +#ifdef HAVE_REALPATH + +/* Return the canonicalized absolute pathname. Encode path to the locale + encoding, decode the result from the locale encoding. */ + +wchar_t* +_Py_wrealpath(const wchar_t *path, + wchar_t *resolved_path, size_t resolved_path_size) +{ + char *cpath; + char cresolved_path[PATH_MAX]; + wchar_t *wresolved_path; + char *res; + size_t r; + cpath = _Py_wchar2char(path, NULL); + if (cpath == NULL) { + errno = EINVAL; + return NULL; + } + res = realpath(cpath, cresolved_path); + PyMem_Free(cpath); + if (res == NULL) + return NULL; + + wresolved_path = _Py_char2wchar(cresolved_path, &r); + if (wresolved_path == NULL) { + errno = EINVAL; + return NULL; + } + if (resolved_path_size <= r) { + PyMem_Free(wresolved_path); + errno = EINVAL; + return NULL; + } + wcsncpy(resolved_path, wresolved_path, resolved_path_size); + PyMem_Free(wresolved_path); + return resolved_path; +} +#endif + +/* Get the current directory. size is the buffer size in wide characters + including the null character. Decode the path from the locale encoding. */ + +wchar_t* +_Py_wgetcwd(wchar_t *buf, size_t size) +{ +#ifdef MS_WINDOWS + return _wgetcwd(buf, size); +#else + char fname[PATH_MAX]; + wchar_t *wname; + size_t len; + + if (getcwd(fname, PATH_MAX) == NULL) + return NULL; + wname = _Py_char2wchar(fname, &len); + if (wname == NULL) + return NULL; + if (size <= len) { + PyMem_Free(wname); + return NULL; + } + wcsncpy(buf, wname, size); + PyMem_Free(wname); + return buf; +#endif +} + +#endif diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c index 79cb5f9192..c350907da1 100644 --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -9,8 +9,6 @@ #define FORMAT_STRING _PyUnicode_FormatAdvanced #define FORMAT_LONG _PyLong_FormatAdvanced #define FORMAT_FLOAT _PyFloat_FormatAdvanced -#ifndef WITHOUT_COMPLEX #define FORMAT_COMPLEX _PyComplex_FormatAdvanced -#endif #include "../Objects/stringlib/formatter.h" diff --git a/Python/future.c b/Python/future.c index 515dcd9dc6..d6b653f315 100644 --- a/Python/future.c +++ b/Python/future.c @@ -4,7 +4,6 @@ #include "token.h" #include "graminit.h" #include "code.h" -#include "compile.h" #include "symtable.h" #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" @@ -44,12 +43,12 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename) } else if (strcmp(feature, "braces") == 0) { PyErr_SetString(PyExc_SyntaxError, "not a chance"); - PyErr_SyntaxLocation(filename, s->lineno); + PyErr_SyntaxLocationEx(filename, s->lineno, s->col_offset); return 0; } else { PyErr_Format(PyExc_SyntaxError, UNDEFINED_FUTURE_FEATURE, feature); - PyErr_SyntaxLocation(filename, s->lineno); + PyErr_SyntaxLocationEx(filename, s->lineno, s->col_offset); return 0; } } @@ -98,8 +97,7 @@ future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename) if (done) { PyErr_SetString(PyExc_SyntaxError, ERR_LATE_FUTURE); - PyErr_SyntaxLocation(filename, - s->lineno); + PyErr_SyntaxLocationEx(filename, s->lineno, s->col_offset); return 0; } if (!future_check_features(ff, s, filename)) diff --git a/Python/getargs.c b/Python/getargs.c index 686eac532f..600941d9c7 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -105,15 +105,7 @@ PyArg_VaParse(PyObject *args, const char *format, va_list va) { va_list lva; -#ifdef VA_LIST_IS_ARRAY - memcpy(lva, va, sizeof(va_list)); -#else -#ifdef __va_copy - __va_copy(lva, va); -#else - lva = va; -#endif -#endif + Py_VA_COPY(lva, va); return vgetargs1(args, format, &lva, 0); } @@ -123,15 +115,7 @@ _PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va) { va_list lva; -#ifdef VA_LIST_IS_ARRAY - memcpy(lva, va, sizeof(va_list)); -#else -#ifdef __va_copy - __va_copy(lva, va); -#else - lva = va; -#endif -#endif + Py_VA_COPY(lva, va); return vgetargs1(args, format, &lva, FLAG_SIZE_T); } @@ -162,10 +146,19 @@ cleanup_buffer(PyObject *self) } static int -addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr) +addcleanup(void *ptr, PyObject **freelist, int is_buffer) { PyObject *cobj; const char *name; + PyCapsule_Destructor destr; + + if (is_buffer) { + destr = cleanup_buffer; + name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER; + } else { + destr = cleanup_ptr; + name = GETARGS_CAPSULE_NAME_CLEANUP_PTR; + } if (!*freelist) { *freelist = PyList_New(0); @@ -175,13 +168,6 @@ addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr) } } - if (destr == cleanup_ptr) { - name = GETARGS_CAPSULE_NAME_CLEANUP_PTR; - } else if (destr == cleanup_buffer) { - name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER; - } else { - return -1; - } cobj = PyCapsule_New(ptr, name, destr); if (!cobj) { destr(ptr); @@ -613,8 +599,19 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, #define FETCH_SIZE int *q=NULL;Py_ssize_t *q2=NULL;\ if (flags & FLAG_SIZE_T) q2=va_arg(*p_va, Py_ssize_t*); \ else q=va_arg(*p_va, int*); -#define STORE_SIZE(s) if (flags & FLAG_SIZE_T) *q2=s; else *q=s; +#define STORE_SIZE(s) \ + if (flags & FLAG_SIZE_T) \ + *q2=s; \ + else { \ + if (INT_MAX < s) { \ + PyErr_SetString(PyExc_OverflowError, \ + "size does not fit in an int"); \ + return converterr("", arg, msgbuf, bufsize); \ + } \ + *q=s; \ + } #define BUFFER_LEN ((flags & FLAG_SIZE_T) ? *q2:*q) +#define RETURN_ERR_OCCURRED return msgbuf const char *format = *p_format; char c = *format++; @@ -626,19 +623,19 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, char *p = va_arg(*p_va, char *); long ival; if (float_argument_error(arg)) - return converterr("integer<b>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer<b>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, - "unsigned byte integer is less than minimum"); - return converterr("integer<b>", arg, msgbuf, bufsize); + "unsigned byte integer is less than minimum"); + RETURN_ERR_OCCURRED; } else if (ival > UCHAR_MAX) { PyErr_SetString(PyExc_OverflowError, - "unsigned byte integer is greater than maximum"); - return converterr("integer<b>", arg, msgbuf, bufsize); + "unsigned byte integer is greater than maximum"); + RETURN_ERR_OCCURRED; } else *p = (unsigned char) ival; @@ -650,10 +647,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, char *p = va_arg(*p_va, char *); long ival; if (float_argument_error(arg)) - return converterr("integer<B>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsUnsignedLongMask(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer<B>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = (unsigned char) ival; break; @@ -663,19 +660,19 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, short *p = va_arg(*p_va, short *); long ival; if (float_argument_error(arg)) - return converterr("integer<h>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer<h>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else if (ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - return converterr("integer<h>", arg, msgbuf, bufsize); + "signed short integer is less than minimum"); + RETURN_ERR_OCCURRED; } else if (ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - return converterr("integer<h>", arg, msgbuf, bufsize); + "signed short integer is greater than maximum"); + RETURN_ERR_OCCURRED; } else *p = (short) ival; @@ -687,10 +684,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, unsigned short *p = va_arg(*p_va, unsigned short *); long ival; if (float_argument_error(arg)) - return converterr("integer<H>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsUnsignedLongMask(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer<H>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = (unsigned short) ival; break; @@ -700,19 +697,19 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, int *p = va_arg(*p_va, int *); long ival; if (float_argument_error(arg)) - return converterr("integer<i>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer<i>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else if (ival > INT_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed integer is greater than maximum"); - return converterr("integer<i>", arg, msgbuf, bufsize); + "signed integer is greater than maximum"); + RETURN_ERR_OCCURRED; } else if (ival < INT_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed integer is less than minimum"); - return converterr("integer<i>", arg, msgbuf, bufsize); + "signed integer is less than minimum"); + RETURN_ERR_OCCURRED; } else *p = ival; @@ -724,10 +721,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, unsigned int *p = va_arg(*p_va, unsigned int *); unsigned int ival; if (float_argument_error(arg)) - return converterr("integer<I>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = (unsigned int)PyLong_AsUnsignedLongMask(arg); if (ival == (unsigned int)-1 && PyErr_Occurred()) - return converterr("integer<I>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = ival; break; @@ -739,14 +736,14 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *); Py_ssize_t ival = -1; if (float_argument_error(arg)) - return converterr("integer<n>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; iobj = PyNumber_Index(arg); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); } if (ival == -1 && PyErr_Occurred()) - return converterr("integer<n>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; *p = ival; break; } @@ -754,10 +751,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, long *p = va_arg(*p_va, long *); long ival; if (float_argument_error(arg)) - return converterr("integer<l>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer<l>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = ival; break; @@ -777,12 +774,14 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, #ifdef HAVE_LONG_LONG case 'L': {/* PY_LONG_LONG */ PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * ); - PY_LONG_LONG ival = PyLong_AsLongLong( arg ); - if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred() ) { - return converterr("long<L>", arg, msgbuf, bufsize); - } else { + PY_LONG_LONG ival; + if (float_argument_error(arg)) + RETURN_ERR_OCCURRED; + ival = PyLong_AsLongLong(arg); + if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred()) + RETURN_ERR_OCCURRED; + else *p = ival; - } break; } @@ -802,7 +801,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, float *p = va_arg(*p_va, float *); double dval = PyFloat_AsDouble(arg); if (PyErr_Occurred()) - return converterr("float<f>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = (float) dval; break; @@ -812,24 +811,22 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, double *p = va_arg(*p_va, double *); double dval = PyFloat_AsDouble(arg); if (PyErr_Occurred()) - return converterr("float<d>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = dval; break; } -#ifndef WITHOUT_COMPLEX case 'D': {/* complex double */ Py_complex *p = va_arg(*p_va, Py_complex *); Py_complex cval; cval = PyComplex_AsCComplex(arg); if (PyErr_Occurred()) - return converterr("complex<D>", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = cval; break; } -#endif /* WITHOUT_COMPLEX */ case 'c': {/* char */ char *p = va_arg(*p_va, char *); @@ -850,73 +847,9 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, break; } - /* XXX WAAAAH! 's', 'y', 'z', 'u', 'Z', 'e', 'w', 't' codes all + /* XXX WAAAAH! 's', 'y', 'z', 'u', 'Z', 'e', 'w' codes all need to be cleaned up! */ - case 's': {/* text string */ - if (*format == '*') { - Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *); - - if (PyUnicode_Check(arg)) { - uarg = UNICODE_DEFAULT_ENCODING(arg); - if (uarg == NULL) - return converterr(CONV_UNICODE, - arg, msgbuf, bufsize); - PyBuffer_FillInfo(p, arg, - PyBytes_AS_STRING(uarg), PyBytes_GET_SIZE(uarg), - 1, 0); - } - else { /* any buffer-like object */ - char *buf; - if (getbuffer(arg, p, &buf) < 0) - return converterr(buf, arg, msgbuf, bufsize); - } - if (addcleanup(p, freelist, cleanup_buffer)) { - return converterr( - "(cleanup problem)", - arg, msgbuf, bufsize); - } - format++; - } else if (*format == '#') { - void **p = (void **)va_arg(*p_va, char **); - FETCH_SIZE; - - if (PyUnicode_Check(arg)) { - uarg = UNICODE_DEFAULT_ENCODING(arg); - if (uarg == NULL) - return converterr(CONV_UNICODE, - arg, msgbuf, bufsize); - *p = PyBytes_AS_STRING(uarg); - STORE_SIZE(PyBytes_GET_SIZE(uarg)); - } - else { /* any buffer-like object */ - /* XXX Really? */ - char *buf; - Py_ssize_t count = convertbuffer(arg, p, &buf); - if (count < 0) - return converterr(buf, arg, msgbuf, bufsize); - STORE_SIZE(count); - } - format++; - } else { - char **p = va_arg(*p_va, char **); - - if (PyUnicode_Check(arg)) { - uarg = UNICODE_DEFAULT_ENCODING(arg); - if (uarg == NULL) - return converterr(CONV_UNICODE, - arg, msgbuf, bufsize); - *p = PyBytes_AS_STRING(uarg); - } - else - return converterr("string", arg, msgbuf, bufsize); - if ((Py_ssize_t) strlen(*p) != PyBytes_GET_SIZE(uarg)) - return converterr("string without null bytes", - arg, msgbuf, bufsize); - } - break; - } - case 'y': {/* any buffer-like object, but not PyUnicode */ void **p = (void **)va_arg(*p_va, char **); char *buf; @@ -925,7 +858,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); format++; - if (addcleanup(p, freelist, cleanup_buffer)) { + if (addcleanup(p, freelist, 1)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -935,19 +868,27 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, count = convertbuffer(arg, p, &buf); if (count < 0) return converterr(buf, arg, msgbuf, bufsize); - else if (*format == '#') { + if (*format == '#') { FETCH_SIZE; STORE_SIZE(count); format++; + } else { + if (strlen(*p) != count) + return converterr( + "bytes without null bytes", + arg, msgbuf, bufsize); } break; } - case 'z': {/* like 's' or 's#', but None is okay, stored as NULL */ + case 's': /* text string */ + case 'z': /* text string or None */ + { if (*format == '*') { + /* "s*" or "z*" */ Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *); - if (arg == Py_None) + if (c == 'z' && arg == Py_None) PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0); else if (PyUnicode_Check(arg)) { uarg = UNICODE_DEFAULT_ENCODING(arg); @@ -963,18 +904,19 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, cleanup_buffer)) { + if (addcleanup(p, freelist, 1)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } format++; } else if (*format == '#') { /* any buffer-like object */ + /* "s#" or "z#" */ void **p = (void **)va_arg(*p_va, char **); FETCH_SIZE; - if (arg == Py_None) { - *p = 0; + if (c == 'z' && arg == Py_None) { + *p = NULL; STORE_SIZE(0); } else if (PyUnicode_Check(arg)) { @@ -995,16 +937,12 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } format++; } else { + /* "s" or "z" */ char **p = va_arg(*p_va, char **); uarg = NULL; - if (arg == Py_None) - *p = 0; - else if (PyBytes_Check(arg)) { - /* Enable null byte check below */ - uarg = arg; - *p = PyBytes_AS_STRING(arg); - } + if (c == 'z' && arg == Py_None) + *p = NULL; else if (PyUnicode_Check(arg)) { uarg = UNICODE_DEFAULT_ENCODING(arg); if (uarg == NULL) @@ -1013,35 +951,28 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, *p = PyBytes_AS_STRING(uarg); } else - return converterr("string or None", + return converterr(c == 'z' ? "str or None" : "str", arg, msgbuf, bufsize); - if (*format == '#') { - FETCH_SIZE; - assert(0); /* XXX redundant with if-case */ - if (arg == Py_None) { - STORE_SIZE(0); - } - else { - STORE_SIZE(PyBytes_Size(arg)); - } - format++; - } - else if (*p != NULL && uarg != NULL && + if (*p != NULL && uarg != NULL && (Py_ssize_t) strlen(*p) != PyBytes_GET_SIZE(uarg)) return converterr( - "string without null bytes or None", + c == 'z' ? "str without null bytes or None" + : "str without null bytes", arg, msgbuf, bufsize); } break; } - case 'Z': {/* unicode, may be NULL (None) */ + case 'u': /* raw unicode buffer (Py_UNICODE *) */ + case 'Z': /* raw unicode buffer or None */ + { if (*format == '#') { /* any buffer-like object */ + /* "s#" or "Z#" */ Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **); FETCH_SIZE; - if (arg == Py_None) { - *p = 0; + if (c == 'Z' && arg == Py_None) { + *p = NULL; STORE_SIZE(0); } else if (PyUnicode_Check(arg)) { @@ -1052,14 +983,20 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, return converterr("str or None", arg, msgbuf, bufsize); format++; } else { + /* "s" or "Z" */ Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **); - if (arg == Py_None) - *p = 0; - else if (PyUnicode_Check(arg)) + if (c == 'Z' && arg == Py_None) + *p = NULL; + else if (PyUnicode_Check(arg)) { *p = PyUnicode_AS_UNICODE(arg); - else - return converterr("str or None", arg, msgbuf, bufsize); + if (Py_UNICODE_strlen(*p) != PyUnicode_GET_SIZE(arg)) + return converterr( + "str without null character or None", + arg, msgbuf, bufsize); + } else + return converterr(c == 'Z' ? "str or None" : "str", + arg, msgbuf, bufsize); } break; } @@ -1170,11 +1107,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); - return converterr( - "(memory error)", - arg, msgbuf, bufsize); + PyErr_NoMemory(); + RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, cleanup_ptr)) { + if (addcleanup(*buffer, freelist, 0)) { Py_DECREF(s); return converterr( "(cleanup problem)", @@ -1213,10 +1149,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); - return converterr("(memory error)", - arg, msgbuf, bufsize); + PyErr_NoMemory(); + RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, cleanup_ptr)) { + if (addcleanup(*buffer, freelist, 0)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize); @@ -1227,19 +1163,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, break; } - case 'u': {/* raw unicode buffer (Py_UNICODE *) */ - Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **); - if (!PyUnicode_Check(arg)) - return converterr("str", arg, msgbuf, bufsize); - *p = PyUnicode_AS_UNICODE(arg); - if (*format == '#') { /* store pointer and size */ - FETCH_SIZE; - STORE_SIZE(PyUnicode_GET_SIZE(arg)); - format++; - } - break; - } - case 'S': { /* PyBytes object */ PyObject **p = va_arg(*p_va, PyObject **); if (PyBytes_Check(arg)) @@ -1280,17 +1203,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, return converterr(type->tp_name, arg, msgbuf, bufsize); } - else if (*format == '?') { - inquiry pred = va_arg(*p_va, inquiry); - p = va_arg(*p_va, PyObject **); - format++; - if ((*pred)(arg)) - *p = arg; - else - return converterr("(unspecified)", - arg, msgbuf, bufsize); - - } else if (*format == '&') { typedef int (*converter)(PyObject *, void *); converter convert = va_arg(*p_va, converter); @@ -1313,96 +1225,29 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } - case 'w': { /* memory buffer, read-write access */ + case 'w': { /* "w*": memory buffer, read-write access */ void **p = va_arg(*p_va, void **); - PyBufferProcs *pb = arg->ob_type->tp_as_buffer; - Py_ssize_t count; - int temp=-1; - Py_buffer view; - - if (pb && pb->bf_releasebuffer && *format != '*') - /* Buffer must be released, yet caller does not use - the Py_buffer protocol. */ - return converterr("pinned buffer", arg, msgbuf, bufsize); + if (*format != '*') + return converterr( + "invalid use of 'w' format character", + arg, msgbuf, bufsize); + format++; - if (pb && pb->bf_getbuffer && *format == '*') { - /* Caller is interested in Py_buffer, and the object - supports it directly. */ - format++; - if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { - PyErr_Clear(); - return converterr("read-write buffer", arg, msgbuf, bufsize); - } - if (addcleanup(p, freelist, cleanup_buffer)) { - return converterr( - "(cleanup problem)", - arg, msgbuf, bufsize); - } - if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C')) - return converterr("contiguous buffer", arg, msgbuf, bufsize); - break; - } - - /* Here we have processed w*, only w and w# remain. */ - if (pb == NULL || - pb->bf_getbuffer == NULL || - ((temp = PyObject_GetBuffer(arg, &view, - PyBUF_SIMPLE)) != 0) || - view.readonly == 1) { - if (temp==0) { - PyBuffer_Release(&view); - } - return converterr("single-segment read-write buffer", - arg, msgbuf, bufsize); + /* Caller is interested in Py_buffer, and the object + supports it directly. */ + if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { + PyErr_Clear(); + return converterr("read-write buffer", arg, msgbuf, bufsize); } - - if ((count = view.len) < 0) - return converterr("(unspecified)", arg, msgbuf, bufsize); - *p = view.buf; - if (*format == '#') { - FETCH_SIZE; - STORE_SIZE(count); - format++; + if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C')) { + PyBuffer_Release((Py_buffer*)p); + return converterr("contiguous buffer", arg, msgbuf, bufsize); } - break; - } - - /*TEO: This can be eliminated --- here only for backward - compatibility */ - case 't': { /* 8-bit character buffer, read-only access */ - char **p = va_arg(*p_va, char **); - PyBufferProcs *pb = arg->ob_type->tp_as_buffer; - Py_ssize_t count; - Py_buffer view; - - if (*format++ != '#') - return converterr( - "invalid use of 't' format character", - arg, msgbuf, bufsize); - if (pb == NULL || pb->bf_getbuffer == NULL) + if (addcleanup(p, freelist, 1)) { return converterr( - "bytes or read-only character buffer", + "(cleanup problem)", arg, msgbuf, bufsize); - if (pb->bf_releasebuffer) - return converterr( - "string or pinned buffer", - arg, msgbuf, bufsize); - - if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) != 0) - return converterr("string or single-segment read-only buffer", - arg, msgbuf, bufsize); - - count = view.len; - *p = view.buf; - - PyBuffer_Release(&view); - - if (count < 0) - return converterr("(unspecified)", arg, msgbuf, bufsize); - { - FETCH_SIZE; - STORE_SIZE(count); } break; } @@ -1414,65 +1259,47 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, *p_format = format; return NULL; + +#undef FETCH_SIZE +#undef STORE_SIZE +#undef BUFFER_LEN +#undef RETURN_ERR_OCCURRED } static Py_ssize_t convertbuffer(PyObject *arg, void **p, char **errmsg) { - PyBufferProcs *pb = arg->ob_type->tp_as_buffer; + PyBufferProcs *pb = Py_TYPE(arg)->tp_as_buffer; Py_ssize_t count; Py_buffer view; *errmsg = NULL; *p = NULL; - if (pb == NULL || - pb->bf_getbuffer == NULL || - pb->bf_releasebuffer != NULL) { - *errmsg = "bytes or read-only buffer"; + if (pb != NULL && pb->bf_releasebuffer != NULL) { + *errmsg = "read-only pinned buffer"; return -1; } - if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) != 0) { - *errmsg = "bytes or single-segment read-only buffer"; + if (getbuffer(arg, &view, errmsg) < 0) return -1; - } count = view.len; *p = view.buf; PyBuffer_Release(&view); return count; } -/* XXX for 3.x, getbuffer and convertbuffer can probably - be merged again. */ static int getbuffer(PyObject *arg, Py_buffer *view, char **errmsg) { - void *buf; - Py_ssize_t count; - PyBufferProcs *pb = arg->ob_type->tp_as_buffer; - if (pb == NULL) { + if (PyObject_GetBuffer(arg, view, PyBUF_SIMPLE) != 0) { *errmsg = "bytes or buffer"; return -1; } - if (pb->bf_getbuffer) { - if (PyObject_GetBuffer(arg, view, 0) < 0) { - *errmsg = "convertible to a buffer"; - return -1; - } - if (!PyBuffer_IsContiguous(view, 'C')) { - PyBuffer_Release(view); - *errmsg = "contiguous buffer"; - return -1; - } - return 0; - } - - count = convertbuffer(arg, &buf, errmsg); - if (count < 0) { - *errmsg = "convertible to a buffer"; - return count; + if (!PyBuffer_IsContiguous(view, 'C')) { + PyBuffer_Release(view); + *errmsg = "contiguous buffer"; + return -1; } - PyBuffer_FillInfo(view, NULL, buf, count, 1, 0); return 0; } @@ -1548,15 +1375,7 @@ PyArg_VaParseTupleAndKeywords(PyObject *args, return 0; } -#ifdef VA_LIST_IS_ARRAY - memcpy(lva, va, sizeof(va_list)); -#else -#ifdef __va_copy - __va_copy(lva, va); -#else - lva = va; -#endif -#endif + Py_VA_COPY(lva, va); retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0); return retval; @@ -1580,21 +1399,28 @@ _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args, return 0; } -#ifdef VA_LIST_IS_ARRAY - memcpy(lva, va, sizeof(va_list)); -#else -#ifdef __va_copy - __va_copy(lva, va); -#else - lva = va; -#endif -#endif + Py_VA_COPY(lva, va); retval = vgetargskeywords(args, keywords, format, kwlist, &lva, FLAG_SIZE_T); return retval; } +int +PyArg_ValidateKeywordArguments(PyObject *kwargs) +{ + if (!PyDict_Check(kwargs)) { + PyErr_BadInternalCall(); + return 0; + } + if (!_PyDict_HasOnlyStringKeys(kwargs)) { + PyErr_SetString(PyExc_TypeError, + "keyword arguments must be strings"); + return 0; + } + return 1; +} + #define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':') static int @@ -1728,18 +1554,21 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, "keywords must be strings"); return cleanreturn(0, freelist); } + /* check that _PyUnicode_AsString() result is not NULL */ ks = _PyUnicode_AsString(key); - for (i = 0; i < len; i++) { - if (!strcmp(ks, kwlist[i])) { - match = 1; - break; + if (ks != NULL) { + for (i = 0; i < len; i++) { + if (!strcmp(ks, kwlist[i])) { + match = 1; + break; + } } } if (!match) { PyErr_Format(PyExc_TypeError, - "'%s' is an invalid keyword " + "'%U' is an invalid keyword " "argument for this function", - ks); + key); return cleanreturn(0, freelist); } } @@ -1774,9 +1603,7 @@ skipitem(const char **p_format, va_list *p_va, int flags) #endif case 'f': /* float */ case 'd': /* double */ -#ifndef WITHOUT_COMPLEX case 'D': /* complex double */ -#endif case 'c': /* char */ case 'C': /* unicode char */ { @@ -1806,7 +1633,6 @@ skipitem(const char **p_format, va_list *p_va, int flags) case 'z': /* string or None */ case 'y': /* bytes */ case 'u': /* unicode string */ - case 't': /* buffer, read-only */ case 'w': /* buffer, read-write */ { (void) va_arg(*p_va, char **); @@ -1839,16 +1665,6 @@ skipitem(const char **p_format, va_list *p_va, int flags) (void) va_arg(*p_va, PyTypeObject*); (void) va_arg(*p_va, PyObject **); } -#if 0 -/* I don't know what this is for */ - else if (*format == '?') { - inquiry pred = va_arg(*p_va, inquiry); - format++; - if ((*pred)(arg)) { - (void) va_arg(*p_va, PyObject **); - } - } -#endif else if (*format == '&') { typedef int (*converter)(PyObject *, void *); (void) va_arg(*p_va, converter); diff --git a/Python/getcopyright.c b/Python/getcopyright.c index 824c7b1c82..1388f2c98c 100644 --- a/Python/getcopyright.c +++ b/Python/getcopyright.c @@ -2,7 +2,7 @@ #include "Python.h" -static char cprt[] = +static char cprt[] = "\ Copyright (c) 2001-2011 Python Software Foundation.\n\ All Rights Reserved.\n\ diff --git a/Python/getopt.c b/Python/getopt.c index 5147320af2..064a1874ea 100644 --- a/Python/getopt.c +++ b/Python/getopt.c @@ -89,12 +89,6 @@ int _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring) return '_'; } - if (option == 'X') { - fprintf(stderr, - "-X is reserved for implementation-specific arguments\n"); - return '_'; - } - if ((ptr = wcschr(optstring, option)) == NULL) { if (_PyOS_opterr) fprintf(stderr, "Unknown option: -%c\n", (char)option); diff --git a/Python/graminit.c b/Python/graminit.c index 91dae03aac..a8af5833a9 100644 --- a/Python/graminit.c +++ b/Python/graminit.c @@ -180,8 +180,8 @@ static arc arcs_8_4[1] = { {24, 9}, }; static arc arcs_8_5[4] = { - {28, 1}, - {31, 2}, + {28, 10}, + {31, 11}, {32, 3}, {0, 5}, }; @@ -190,7 +190,7 @@ static arc arcs_8_6[2] = { {0, 6}, }; static arc arcs_8_7[2] = { - {28, 10}, + {28, 12}, {32, 3}, }; static arc arcs_8_8[1] = { @@ -201,14 +201,40 @@ static arc arcs_8_9[2] = { {0, 9}, }; static arc arcs_8_10[3] = { - {30, 7}, - {29, 11}, + {30, 5}, + {29, 4}, {0, 10}, }; -static arc arcs_8_11[1] = { +static arc arcs_8_11[3] = { + {28, 13}, + {30, 14}, + {0, 11}, +}; +static arc arcs_8_12[3] = { + {30, 7}, + {29, 15}, + {0, 12}, +}; +static arc arcs_8_13[2] = { + {30, 14}, + {0, 13}, +}; +static arc arcs_8_14[2] = { + {28, 16}, + {32, 3}, +}; +static arc arcs_8_15[1] = { {24, 6}, }; -static state states_8[12] = { +static arc arcs_8_16[3] = { + {30, 14}, + {29, 17}, + {0, 16}, +}; +static arc arcs_8_17[1] = { + {24, 13}, +}; +static state states_8[18] = { {3, arcs_8_0}, {3, arcs_8_1}, {3, arcs_8_2}, @@ -220,7 +246,13 @@ static state states_8[12] = { {1, arcs_8_8}, {2, arcs_8_9}, {3, arcs_8_10}, - {1, arcs_8_11}, + {3, arcs_8_11}, + {3, arcs_8_12}, + {2, arcs_8_13}, + {2, arcs_8_14}, + {1, arcs_8_15}, + {3, arcs_8_16}, + {1, arcs_8_17}, }; static arc arcs_9_0[1] = { {21, 1}, @@ -263,8 +295,8 @@ static arc arcs_10_4[1] = { {24, 9}, }; static arc arcs_10_5[4] = { - {34, 1}, - {31, 2}, + {34, 10}, + {31, 11}, {32, 3}, {0, 5}, }; @@ -273,7 +305,7 @@ static arc arcs_10_6[2] = { {0, 6}, }; static arc arcs_10_7[2] = { - {34, 10}, + {34, 12}, {32, 3}, }; static arc arcs_10_8[1] = { @@ -284,14 +316,40 @@ static arc arcs_10_9[2] = { {0, 9}, }; static arc arcs_10_10[3] = { - {30, 7}, - {29, 11}, + {30, 5}, + {29, 4}, {0, 10}, }; -static arc arcs_10_11[1] = { +static arc arcs_10_11[3] = { + {34, 13}, + {30, 14}, + {0, 11}, +}; +static arc arcs_10_12[3] = { + {30, 7}, + {29, 15}, + {0, 12}, +}; +static arc arcs_10_13[2] = { + {30, 14}, + {0, 13}, +}; +static arc arcs_10_14[2] = { + {34, 16}, + {32, 3}, +}; +static arc arcs_10_15[1] = { {24, 6}, }; -static state states_10[12] = { +static arc arcs_10_16[3] = { + {30, 14}, + {29, 17}, + {0, 16}, +}; +static arc arcs_10_17[1] = { + {24, 13}, +}; +static state states_10[18] = { {3, arcs_10_0}, {3, arcs_10_1}, {3, arcs_10_2}, @@ -303,7 +361,13 @@ static state states_10[12] = { {1, arcs_10_8}, {2, arcs_10_9}, {3, arcs_10_10}, - {1, arcs_10_11}, + {3, arcs_10_11}, + {3, arcs_10_12}, + {2, arcs_10_13}, + {2, arcs_10_14}, + {1, arcs_10_15}, + {3, arcs_10_16}, + {1, arcs_10_17}, }; static arc arcs_11_0[1] = { {21, 1}, @@ -364,20 +428,20 @@ static state states_14[2] = { {1, arcs_14_1}, }; static arc arcs_15_0[1] = { - {9, 1}, + {45, 1}, }; static arc arcs_15_1[3] = { - {45, 2}, + {46, 2}, {29, 3}, {0, 1}, }; static arc arcs_15_2[2] = { - {46, 4}, + {47, 4}, {9, 4}, }; static arc arcs_15_3[2] = { - {46, 5}, - {9, 5}, + {47, 5}, + {45, 5}, }; static arc arcs_15_4[1] = { {0, 4}, @@ -394,9 +458,25 @@ static state states_15[6] = { {1, arcs_15_4}, {2, arcs_15_5}, }; -static arc arcs_16_0[12] = { - {47, 1}, +static arc arcs_16_0[2] = { + {24, 1}, {48, 1}, +}; +static arc arcs_16_1[2] = { + {30, 2}, + {0, 1}, +}; +static arc arcs_16_2[3] = { + {24, 1}, + {48, 1}, + {0, 2}, +}; +static state states_16[3] = { + {2, arcs_16_0}, + {2, arcs_16_1}, + {3, arcs_16_2}, +}; +static arc arcs_17_0[12] = { {49, 1}, {50, 1}, {51, 1}, @@ -407,64 +487,56 @@ static arc arcs_16_0[12] = { {56, 1}, {57, 1}, {58, 1}, -}; -static arc arcs_16_1[1] = { - {0, 1}, -}; -static state states_16[2] = { - {12, arcs_16_0}, - {1, arcs_16_1}, -}; -static arc arcs_17_0[1] = { {59, 1}, + {60, 1}, }; static arc arcs_17_1[1] = { - {60, 2}, -}; -static arc arcs_17_2[1] = { - {0, 2}, + {0, 1}, }; -static state states_17[3] = { - {1, arcs_17_0}, +static state states_17[2] = { + {12, arcs_17_0}, {1, arcs_17_1}, - {1, arcs_17_2}, }; static arc arcs_18_0[1] = { {61, 1}, }; static arc arcs_18_1[1] = { - {0, 1}, + {62, 2}, +}; +static arc arcs_18_2[1] = { + {0, 2}, }; -static state states_18[2] = { +static state states_18[3] = { {1, arcs_18_0}, {1, arcs_18_1}, + {1, arcs_18_2}, }; -static arc arcs_19_0[5] = { - {62, 1}, +static arc arcs_19_0[1] = { {63, 1}, - {64, 1}, - {65, 1}, - {66, 1}, }; static arc arcs_19_1[1] = { {0, 1}, }; static state states_19[2] = { - {5, arcs_19_0}, + {1, arcs_19_0}, {1, arcs_19_1}, }; -static arc arcs_20_0[1] = { +static arc arcs_20_0[5] = { + {64, 1}, + {65, 1}, + {66, 1}, {67, 1}, + {68, 1}, }; static arc arcs_20_1[1] = { {0, 1}, }; static state states_20[2] = { - {1, arcs_20_0}, + {5, arcs_20_0}, {1, arcs_20_1}, }; static arc arcs_21_0[1] = { - {68, 1}, + {69, 1}, }; static arc arcs_21_1[1] = { {0, 1}, @@ -474,144 +546,135 @@ static state states_21[2] = { {1, arcs_21_1}, }; static arc arcs_22_0[1] = { - {69, 1}, + {70, 1}, }; -static arc arcs_22_1[2] = { - {9, 2}, +static arc arcs_22_1[1] = { {0, 1}, }; -static arc arcs_22_2[1] = { - {0, 2}, -}; -static state states_22[3] = { +static state states_22[2] = { {1, arcs_22_0}, - {2, arcs_22_1}, - {1, arcs_22_2}, + {1, arcs_22_1}, }; static arc arcs_23_0[1] = { - {46, 1}, + {71, 1}, }; -static arc arcs_23_1[1] = { +static arc arcs_23_1[2] = { + {9, 2}, {0, 1}, }; -static state states_23[2] = { +static arc arcs_23_2[1] = { + {0, 2}, +}; +static state states_23[3] = { {1, arcs_23_0}, - {1, arcs_23_1}, + {2, arcs_23_1}, + {1, arcs_23_2}, }; static arc arcs_24_0[1] = { - {70, 1}, + {47, 1}, +}; +static arc arcs_24_1[1] = { + {0, 1}, }; -static arc arcs_24_1[2] = { +static state states_24[2] = { + {1, arcs_24_0}, + {1, arcs_24_1}, +}; +static arc arcs_25_0[1] = { + {72, 1}, +}; +static arc arcs_25_1[2] = { {24, 2}, {0, 1}, }; -static arc arcs_24_2[2] = { - {71, 3}, +static arc arcs_25_2[2] = { + {73, 3}, {0, 2}, }; -static arc arcs_24_3[1] = { +static arc arcs_25_3[1] = { {24, 4}, }; -static arc arcs_24_4[1] = { +static arc arcs_25_4[1] = { {0, 4}, }; -static state states_24[5] = { - {1, arcs_24_0}, - {2, arcs_24_1}, - {2, arcs_24_2}, - {1, arcs_24_3}, - {1, arcs_24_4}, +static state states_25[5] = { + {1, arcs_25_0}, + {2, arcs_25_1}, + {2, arcs_25_2}, + {1, arcs_25_3}, + {1, arcs_25_4}, }; -static arc arcs_25_0[2] = { - {72, 1}, - {73, 1}, +static arc arcs_26_0[2] = { + {74, 1}, + {75, 1}, }; -static arc arcs_25_1[1] = { +static arc arcs_26_1[1] = { {0, 1}, }; -static state states_25[2] = { - {2, arcs_25_0}, - {1, arcs_25_1}, +static state states_26[2] = { + {2, arcs_26_0}, + {1, arcs_26_1}, }; -static arc arcs_26_0[1] = { - {74, 1}, +static arc arcs_27_0[1] = { + {76, 1}, }; -static arc arcs_26_1[1] = { - {75, 2}, +static arc arcs_27_1[1] = { + {77, 2}, }; -static arc arcs_26_2[1] = { +static arc arcs_27_2[1] = { {0, 2}, }; -static state states_26[3] = { - {1, arcs_26_0}, - {1, arcs_26_1}, - {1, arcs_26_2}, +static state states_27[3] = { + {1, arcs_27_0}, + {1, arcs_27_1}, + {1, arcs_27_2}, }; -static arc arcs_27_0[1] = { - {71, 1}, +static arc arcs_28_0[1] = { + {73, 1}, }; -static arc arcs_27_1[3] = { - {76, 2}, - {77, 2}, +static arc arcs_28_1[3] = { + {78, 2}, + {79, 2}, {12, 3}, }; -static arc arcs_27_2[4] = { - {76, 2}, - {77, 2}, +static arc arcs_28_2[4] = { + {78, 2}, + {79, 2}, {12, 3}, - {74, 4}, + {76, 4}, }; -static arc arcs_27_3[1] = { - {74, 4}, +static arc arcs_28_3[1] = { + {76, 4}, }; -static arc arcs_27_4[3] = { +static arc arcs_28_4[3] = { {31, 5}, {13, 6}, - {78, 5}, + {80, 5}, }; -static arc arcs_27_5[1] = { +static arc arcs_28_5[1] = { {0, 5}, }; -static arc arcs_27_6[1] = { - {78, 7}, +static arc arcs_28_6[1] = { + {80, 7}, }; -static arc arcs_27_7[1] = { +static arc arcs_28_7[1] = { {15, 5}, }; -static state states_27[8] = { - {1, arcs_27_0}, - {3, arcs_27_1}, - {4, arcs_27_2}, - {1, arcs_27_3}, - {3, arcs_27_4}, - {1, arcs_27_5}, - {1, arcs_27_6}, - {1, arcs_27_7}, -}; -static arc arcs_28_0[1] = { - {21, 1}, -}; -static arc arcs_28_1[2] = { - {80, 2}, - {0, 1}, -}; -static arc arcs_28_2[1] = { - {21, 3}, -}; -static arc arcs_28_3[1] = { - {0, 3}, -}; -static state states_28[4] = { +static state states_28[8] = { {1, arcs_28_0}, - {2, arcs_28_1}, - {1, arcs_28_2}, + {3, arcs_28_1}, + {4, arcs_28_2}, {1, arcs_28_3}, + {3, arcs_28_4}, + {1, arcs_28_5}, + {1, arcs_28_6}, + {1, arcs_28_7}, }; static arc arcs_29_0[1] = { - {12, 1}, + {21, 1}, }; static arc arcs_29_1[2] = { - {80, 2}, + {82, 2}, {0, 1}, }; static arc arcs_29_2[1] = { @@ -627,37 +690,45 @@ static state states_29[4] = { {1, arcs_29_3}, }; static arc arcs_30_0[1] = { - {79, 1}, + {12, 1}, }; static arc arcs_30_1[2] = { - {30, 2}, + {82, 2}, {0, 1}, }; -static arc arcs_30_2[2] = { - {79, 1}, - {0, 2}, +static arc arcs_30_2[1] = { + {21, 3}, +}; +static arc arcs_30_3[1] = { + {0, 3}, }; -static state states_30[3] = { +static state states_30[4] = { {1, arcs_30_0}, {2, arcs_30_1}, - {2, arcs_30_2}, + {1, arcs_30_2}, + {1, arcs_30_3}, }; static arc arcs_31_0[1] = { {81, 1}, }; static arc arcs_31_1[2] = { - {30, 0}, + {30, 2}, {0, 1}, }; -static state states_31[2] = { +static arc arcs_31_2[2] = { + {81, 1}, + {0, 2}, +}; +static state states_31[3] = { {1, arcs_31_0}, {2, arcs_31_1}, + {2, arcs_31_2}, }; static arc arcs_32_0[1] = { - {21, 1}, + {83, 1}, }; static arc arcs_32_1[2] = { - {76, 0}, + {30, 0}, {0, 1}, }; static state states_32[2] = { @@ -665,22 +736,18 @@ static state states_32[2] = { {2, arcs_32_1}, }; static arc arcs_33_0[1] = { - {82, 1}, -}; -static arc arcs_33_1[1] = { - {21, 2}, + {21, 1}, }; -static arc arcs_33_2[2] = { - {30, 1}, - {0, 2}, +static arc arcs_33_1[2] = { + {78, 0}, + {0, 1}, }; -static state states_33[3] = { +static state states_33[2] = { {1, arcs_33_0}, - {1, arcs_33_1}, - {2, arcs_33_2}, + {2, arcs_33_1}, }; static arc arcs_34_0[1] = { - {83, 1}, + {84, 1}, }; static arc arcs_34_1[1] = { {21, 2}, @@ -695,83 +762,62 @@ static state states_34[3] = { {2, arcs_34_2}, }; static arc arcs_35_0[1] = { - {84, 1}, + {85, 1}, }; static arc arcs_35_1[1] = { - {24, 2}, + {21, 2}, }; static arc arcs_35_2[2] = { - {30, 3}, + {30, 1}, {0, 2}, }; -static arc arcs_35_3[1] = { - {24, 4}, -}; -static arc arcs_35_4[1] = { - {0, 4}, -}; -static state states_35[5] = { +static state states_35[3] = { {1, arcs_35_0}, {1, arcs_35_1}, {2, arcs_35_2}, - {1, arcs_35_3}, - {1, arcs_35_4}, }; -static arc arcs_36_0[8] = { - {85, 1}, +static arc arcs_36_0[1] = { {86, 1}, - {87, 1}, - {88, 1}, - {89, 1}, - {19, 1}, - {18, 1}, - {17, 1}, }; static arc arcs_36_1[1] = { - {0, 1}, -}; -static state states_36[2] = { - {8, arcs_36_0}, - {1, arcs_36_1}, -}; -static arc arcs_37_0[1] = { - {90, 1}, -}; -static arc arcs_37_1[1] = { {24, 2}, }; -static arc arcs_37_2[1] = { - {25, 3}, +static arc arcs_36_2[2] = { + {30, 3}, + {0, 2}, }; -static arc arcs_37_3[1] = { - {26, 4}, +static arc arcs_36_3[1] = { + {24, 4}, }; -static arc arcs_37_4[3] = { - {91, 1}, - {92, 5}, +static arc arcs_36_4[1] = { {0, 4}, }; -static arc arcs_37_5[1] = { - {25, 6}, +static state states_36[5] = { + {1, arcs_36_0}, + {1, arcs_36_1}, + {2, arcs_36_2}, + {1, arcs_36_3}, + {1, arcs_36_4}, }; -static arc arcs_37_6[1] = { - {26, 7}, +static arc arcs_37_0[8] = { + {87, 1}, + {88, 1}, + {89, 1}, + {90, 1}, + {91, 1}, + {19, 1}, + {18, 1}, + {17, 1}, }; -static arc arcs_37_7[1] = { - {0, 7}, +static arc arcs_37_1[1] = { + {0, 1}, }; -static state states_37[8] = { - {1, arcs_37_0}, +static state states_37[2] = { + {8, arcs_37_0}, {1, arcs_37_1}, - {1, arcs_37_2}, - {1, arcs_37_3}, - {3, arcs_37_4}, - {1, arcs_37_5}, - {1, arcs_37_6}, - {1, arcs_37_7}, }; static arc arcs_38_0[1] = { - {93, 1}, + {92, 1}, }; static arc arcs_38_1[1] = { {24, 2}, @@ -782,8 +828,9 @@ static arc arcs_38_2[1] = { static arc arcs_38_3[1] = { {26, 4}, }; -static arc arcs_38_4[2] = { - {92, 5}, +static arc arcs_38_4[3] = { + {93, 1}, + {94, 5}, {0, 4}, }; static arc arcs_38_5[1] = { @@ -800,267 +847,279 @@ static state states_38[8] = { {1, arcs_38_1}, {1, arcs_38_2}, {1, arcs_38_3}, - {2, arcs_38_4}, + {3, arcs_38_4}, {1, arcs_38_5}, {1, arcs_38_6}, {1, arcs_38_7}, }; static arc arcs_39_0[1] = { - {94, 1}, + {95, 1}, }; static arc arcs_39_1[1] = { - {60, 2}, + {24, 2}, }; static arc arcs_39_2[1] = { - {95, 3}, + {25, 3}, }; static arc arcs_39_3[1] = { - {9, 4}, + {26, 4}, }; -static arc arcs_39_4[1] = { - {25, 5}, +static arc arcs_39_4[2] = { + {94, 5}, + {0, 4}, }; static arc arcs_39_5[1] = { - {26, 6}, + {25, 6}, }; -static arc arcs_39_6[2] = { - {92, 7}, - {0, 6}, +static arc arcs_39_6[1] = { + {26, 7}, }; static arc arcs_39_7[1] = { - {25, 8}, -}; -static arc arcs_39_8[1] = { - {26, 9}, -}; -static arc arcs_39_9[1] = { - {0, 9}, + {0, 7}, }; -static state states_39[10] = { +static state states_39[8] = { {1, arcs_39_0}, {1, arcs_39_1}, {1, arcs_39_2}, {1, arcs_39_3}, - {1, arcs_39_4}, + {2, arcs_39_4}, {1, arcs_39_5}, - {2, arcs_39_6}, + {1, arcs_39_6}, {1, arcs_39_7}, - {1, arcs_39_8}, - {1, arcs_39_9}, }; static arc arcs_40_0[1] = { {96, 1}, }; static arc arcs_40_1[1] = { - {25, 2}, + {62, 2}, }; static arc arcs_40_2[1] = { - {26, 3}, + {97, 3}, }; -static arc arcs_40_3[2] = { - {97, 4}, - {98, 5}, +static arc arcs_40_3[1] = { + {9, 4}, }; static arc arcs_40_4[1] = { - {25, 6}, + {25, 5}, }; static arc arcs_40_5[1] = { - {25, 7}, + {26, 6}, }; -static arc arcs_40_6[1] = { - {26, 8}, +static arc arcs_40_6[2] = { + {94, 7}, + {0, 6}, }; static arc arcs_40_7[1] = { - {26, 9}, + {25, 8}, }; -static arc arcs_40_8[4] = { - {97, 4}, - {92, 10}, - {98, 5}, - {0, 8}, +static arc arcs_40_8[1] = { + {26, 9}, }; static arc arcs_40_9[1] = { {0, 9}, }; -static arc arcs_40_10[1] = { - {25, 11}, -}; -static arc arcs_40_11[1] = { - {26, 12}, -}; -static arc arcs_40_12[2] = { - {98, 5}, - {0, 12}, -}; -static state states_40[13] = { +static state states_40[10] = { {1, arcs_40_0}, {1, arcs_40_1}, {1, arcs_40_2}, - {2, arcs_40_3}, + {1, arcs_40_3}, {1, arcs_40_4}, {1, arcs_40_5}, - {1, arcs_40_6}, + {2, arcs_40_6}, {1, arcs_40_7}, - {4, arcs_40_8}, + {1, arcs_40_8}, {1, arcs_40_9}, - {1, arcs_40_10}, - {1, arcs_40_11}, - {2, arcs_40_12}, }; static arc arcs_41_0[1] = { - {99, 1}, + {98, 1}, }; static arc arcs_41_1[1] = { - {100, 2}, + {25, 2}, }; -static arc arcs_41_2[2] = { - {30, 1}, - {25, 3}, +static arc arcs_41_2[1] = { + {26, 3}, }; -static arc arcs_41_3[1] = { - {26, 4}, +static arc arcs_41_3[2] = { + {99, 4}, + {100, 5}, }; static arc arcs_41_4[1] = { - {0, 4}, + {25, 6}, +}; +static arc arcs_41_5[1] = { + {25, 7}, +}; +static arc arcs_41_6[1] = { + {26, 8}, +}; +static arc arcs_41_7[1] = { + {26, 9}, +}; +static arc arcs_41_8[4] = { + {99, 4}, + {94, 10}, + {100, 5}, + {0, 8}, +}; +static arc arcs_41_9[1] = { + {0, 9}, +}; +static arc arcs_41_10[1] = { + {25, 11}, +}; +static arc arcs_41_11[1] = { + {26, 12}, }; -static state states_41[5] = { +static arc arcs_41_12[2] = { + {100, 5}, + {0, 12}, +}; +static state states_41[13] = { {1, arcs_41_0}, {1, arcs_41_1}, - {2, arcs_41_2}, - {1, arcs_41_3}, + {1, arcs_41_2}, + {2, arcs_41_3}, {1, arcs_41_4}, + {1, arcs_41_5}, + {1, arcs_41_6}, + {1, arcs_41_7}, + {4, arcs_41_8}, + {1, arcs_41_9}, + {1, arcs_41_10}, + {1, arcs_41_11}, + {2, arcs_41_12}, }; static arc arcs_42_0[1] = { - {24, 1}, + {101, 1}, }; -static arc arcs_42_1[2] = { - {80, 2}, - {0, 1}, +static arc arcs_42_1[1] = { + {102, 2}, }; -static arc arcs_42_2[1] = { - {101, 3}, +static arc arcs_42_2[2] = { + {30, 1}, + {25, 3}, }; static arc arcs_42_3[1] = { - {0, 3}, + {26, 4}, }; -static state states_42[4] = { +static arc arcs_42_4[1] = { + {0, 4}, +}; +static state states_42[5] = { {1, arcs_42_0}, - {2, arcs_42_1}, - {1, arcs_42_2}, + {1, arcs_42_1}, + {2, arcs_42_2}, {1, arcs_42_3}, + {1, arcs_42_4}, }; static arc arcs_43_0[1] = { - {102, 1}, + {24, 1}, }; static arc arcs_43_1[2] = { - {24, 2}, + {82, 2}, {0, 1}, }; -static arc arcs_43_2[2] = { - {80, 3}, - {0, 2}, +static arc arcs_43_2[1] = { + {103, 3}, }; static arc arcs_43_3[1] = { - {21, 4}, -}; -static arc arcs_43_4[1] = { - {0, 4}, + {0, 3}, }; -static state states_43[5] = { +static state states_43[4] = { {1, arcs_43_0}, {2, arcs_43_1}, - {2, arcs_43_2}, + {1, arcs_43_2}, {1, arcs_43_3}, - {1, arcs_43_4}, }; -static arc arcs_44_0[2] = { - {3, 1}, - {2, 2}, +static arc arcs_44_0[1] = { + {104, 1}, }; -static arc arcs_44_1[1] = { +static arc arcs_44_1[2] = { + {24, 2}, {0, 1}, }; -static arc arcs_44_2[1] = { - {103, 3}, +static arc arcs_44_2[2] = { + {82, 3}, + {0, 2}, }; static arc arcs_44_3[1] = { - {6, 4}, + {21, 4}, }; -static arc arcs_44_4[2] = { - {6, 4}, - {104, 1}, +static arc arcs_44_4[1] = { + {0, 4}, }; static state states_44[5] = { - {2, arcs_44_0}, - {1, arcs_44_1}, - {1, arcs_44_2}, + {1, arcs_44_0}, + {2, arcs_44_1}, + {2, arcs_44_2}, {1, arcs_44_3}, - {2, arcs_44_4}, + {1, arcs_44_4}, }; static arc arcs_45_0[2] = { - {105, 1}, - {106, 2}, + {3, 1}, + {2, 2}, }; -static arc arcs_45_1[2] = { - {90, 3}, +static arc arcs_45_1[1] = { {0, 1}, }; static arc arcs_45_2[1] = { - {0, 2}, + {105, 3}, }; static arc arcs_45_3[1] = { - {105, 4}, -}; -static arc arcs_45_4[1] = { - {92, 5}, + {6, 4}, }; -static arc arcs_45_5[1] = { - {24, 2}, +static arc arcs_45_4[2] = { + {6, 4}, + {106, 1}, }; -static state states_45[6] = { +static state states_45[5] = { {2, arcs_45_0}, - {2, arcs_45_1}, + {1, arcs_45_1}, {1, arcs_45_2}, {1, arcs_45_3}, - {1, arcs_45_4}, - {1, arcs_45_5}, + {2, arcs_45_4}, }; static arc arcs_46_0[2] = { - {105, 1}, - {108, 1}, + {107, 1}, + {108, 2}, }; -static arc arcs_46_1[1] = { +static arc arcs_46_1[2] = { + {92, 3}, {0, 1}, }; -static state states_46[2] = { - {2, arcs_46_0}, - {1, arcs_46_1}, +static arc arcs_46_2[1] = { + {0, 2}, }; -static arc arcs_47_0[1] = { - {109, 1}, +static arc arcs_46_3[1] = { + {107, 4}, }; -static arc arcs_47_1[2] = { - {33, 2}, - {25, 3}, +static arc arcs_46_4[1] = { + {94, 5}, }; -static arc arcs_47_2[1] = { - {25, 3}, +static arc arcs_46_5[1] = { + {24, 2}, }; -static arc arcs_47_3[1] = { - {24, 4}, +static state states_46[6] = { + {2, arcs_46_0}, + {2, arcs_46_1}, + {1, arcs_46_2}, + {1, arcs_46_3}, + {1, arcs_46_4}, + {1, arcs_46_5}, +}; +static arc arcs_47_0[2] = { + {107, 1}, + {110, 1}, }; -static arc arcs_47_4[1] = { - {0, 4}, +static arc arcs_47_1[1] = { + {0, 1}, }; -static state states_47[5] = { - {1, arcs_47_0}, - {2, arcs_47_1}, - {1, arcs_47_2}, - {1, arcs_47_3}, - {1, arcs_47_4}, +static state states_47[2] = { + {2, arcs_47_0}, + {1, arcs_47_1}, }; static arc arcs_48_0[1] = { - {109, 1}, + {111, 1}, }; static arc arcs_48_1[2] = { {33, 2}, @@ -1070,7 +1129,7 @@ static arc arcs_48_2[1] = { {25, 3}, }; static arc arcs_48_3[1] = { - {107, 4}, + {24, 4}, }; static arc arcs_48_4[1] = { {0, 4}, @@ -1083,15 +1142,27 @@ static state states_48[5] = { {1, arcs_48_4}, }; static arc arcs_49_0[1] = { - {110, 1}, + {111, 1}, }; static arc arcs_49_1[2] = { - {111, 0}, - {0, 1}, + {33, 2}, + {25, 3}, +}; +static arc arcs_49_2[1] = { + {25, 3}, +}; +static arc arcs_49_3[1] = { + {109, 4}, +}; +static arc arcs_49_4[1] = { + {0, 4}, }; -static state states_49[2] = { +static state states_49[5] = { {1, arcs_49_0}, {2, arcs_49_1}, + {1, arcs_49_2}, + {1, arcs_49_3}, + {1, arcs_49_4}, }; static arc arcs_50_0[1] = { {112, 1}, @@ -1104,91 +1175,90 @@ static state states_50[2] = { {1, arcs_50_0}, {2, arcs_50_1}, }; -static arc arcs_51_0[2] = { +static arc arcs_51_0[1] = { {114, 1}, - {115, 2}, }; -static arc arcs_51_1[1] = { - {112, 2}, +static arc arcs_51_1[2] = { + {115, 0}, + {0, 1}, +}; +static state states_51[2] = { + {1, arcs_51_0}, + {2, arcs_51_1}, +}; +static arc arcs_52_0[2] = { + {116, 1}, + {117, 2}, }; -static arc arcs_51_2[1] = { +static arc arcs_52_1[1] = { + {114, 2}, +}; +static arc arcs_52_2[1] = { {0, 2}, }; -static state states_51[3] = { - {2, arcs_51_0}, - {1, arcs_51_1}, - {1, arcs_51_2}, +static state states_52[3] = { + {2, arcs_52_0}, + {1, arcs_52_1}, + {1, arcs_52_2}, }; -static arc arcs_52_0[1] = { - {116, 1}, +static arc arcs_53_0[1] = { + {103, 1}, }; -static arc arcs_52_1[2] = { - {117, 0}, +static arc arcs_53_1[2] = { + {118, 0}, {0, 1}, }; -static state states_52[2] = { - {1, arcs_52_0}, - {2, arcs_52_1}, +static state states_53[2] = { + {1, arcs_53_0}, + {2, arcs_53_1}, }; -static arc arcs_53_0[10] = { - {118, 1}, +static arc arcs_54_0[10] = { {119, 1}, {120, 1}, {121, 1}, {122, 1}, {123, 1}, {124, 1}, - {95, 1}, - {114, 2}, - {125, 3}, + {125, 1}, + {97, 1}, + {116, 2}, + {126, 3}, }; -static arc arcs_53_1[1] = { +static arc arcs_54_1[1] = { {0, 1}, }; -static arc arcs_53_2[1] = { - {95, 1}, +static arc arcs_54_2[1] = { + {97, 1}, }; -static arc arcs_53_3[2] = { - {114, 1}, +static arc arcs_54_3[2] = { + {116, 1}, {0, 3}, }; -static state states_53[4] = { - {10, arcs_53_0}, - {1, arcs_53_1}, - {1, arcs_53_2}, - {2, arcs_53_3}, -}; -static arc arcs_54_0[2] = { - {31, 1}, - {101, 2}, -}; -static arc arcs_54_1[1] = { - {101, 2}, -}; -static arc arcs_54_2[1] = { - {0, 2}, -}; -static state states_54[3] = { - {2, arcs_54_0}, +static state states_54[4] = { + {10, arcs_54_0}, {1, arcs_54_1}, {1, arcs_54_2}, + {2, arcs_54_3}, }; static arc arcs_55_0[1] = { - {126, 1}, + {31, 1}, }; -static arc arcs_55_1[2] = { - {127, 0}, - {0, 1}, +static arc arcs_55_1[1] = { + {103, 2}, +}; +static arc arcs_55_2[1] = { + {0, 2}, }; -static state states_55[2] = { +static state states_55[3] = { {1, arcs_55_0}, - {2, arcs_55_1}, + {1, arcs_55_1}, + {1, arcs_55_2}, }; static arc arcs_56_0[1] = { - {128, 1}, + {127, 1}, }; static arc arcs_56_1[2] = { - {129, 0}, + {128, 0}, {0, 1}, }; static state states_56[2] = { @@ -1196,10 +1266,10 @@ static state states_56[2] = { {2, arcs_56_1}, }; static arc arcs_57_0[1] = { - {130, 1}, + {129, 1}, }; static arc arcs_57_1[2] = { - {131, 0}, + {130, 0}, {0, 1}, }; static state states_57[2] = { @@ -1207,23 +1277,22 @@ static state states_57[2] = { {2, arcs_57_1}, }; static arc arcs_58_0[1] = { - {132, 1}, + {131, 1}, }; -static arc arcs_58_1[3] = { - {133, 0}, - {134, 0}, +static arc arcs_58_1[2] = { + {132, 0}, {0, 1}, }; static state states_58[2] = { {1, arcs_58_0}, - {3, arcs_58_1}, + {2, arcs_58_1}, }; static arc arcs_59_0[1] = { - {135, 1}, + {133, 1}, }; static arc arcs_59_1[3] = { - {136, 0}, - {137, 0}, + {134, 0}, + {135, 0}, {0, 1}, }; static state states_59[2] = { @@ -1231,477 +1300,482 @@ static state states_59[2] = { {3, arcs_59_1}, }; static arc arcs_60_0[1] = { - {138, 1}, + {136, 1}, +}; +static arc arcs_60_1[3] = { + {137, 0}, + {138, 0}, + {0, 1}, }; -static arc arcs_60_1[5] = { +static state states_60[2] = { + {1, arcs_60_0}, + {3, arcs_60_1}, +}; +static arc arcs_61_0[1] = { + {139, 1}, +}; +static arc arcs_61_1[5] = { {31, 0}, - {139, 0}, {140, 0}, {141, 0}, + {142, 0}, {0, 1}, }; -static state states_60[2] = { - {1, arcs_60_0}, - {5, arcs_60_1}, +static state states_61[2] = { + {1, arcs_61_0}, + {5, arcs_61_1}, }; -static arc arcs_61_0[4] = { - {136, 1}, +static arc arcs_62_0[4] = { {137, 1}, - {142, 1}, - {143, 2}, + {138, 1}, + {143, 1}, + {144, 2}, }; -static arc arcs_61_1[1] = { - {138, 2}, +static arc arcs_62_1[1] = { + {139, 2}, }; -static arc arcs_61_2[1] = { +static arc arcs_62_2[1] = { {0, 2}, }; -static state states_61[3] = { - {4, arcs_61_0}, - {1, arcs_61_1}, - {1, arcs_61_2}, -}; -static arc arcs_62_0[1] = { - {144, 1}, +static state states_62[3] = { + {4, arcs_62_0}, + {1, arcs_62_1}, + {1, arcs_62_2}, }; -static arc arcs_62_1[3] = { +static arc arcs_63_0[1] = { {145, 1}, +}; +static arc arcs_63_1[3] = { + {146, 1}, {32, 2}, {0, 1}, }; -static arc arcs_62_2[1] = { - {138, 3}, +static arc arcs_63_2[1] = { + {139, 3}, }; -static arc arcs_62_3[1] = { +static arc arcs_63_3[1] = { {0, 3}, }; -static state states_62[4] = { - {1, arcs_62_0}, - {3, arcs_62_1}, - {1, arcs_62_2}, - {1, arcs_62_3}, +static state states_63[4] = { + {1, arcs_63_0}, + {3, arcs_63_1}, + {1, arcs_63_2}, + {1, arcs_63_3}, }; -static arc arcs_63_0[10] = { +static arc arcs_64_0[10] = { {13, 1}, - {147, 2}, - {149, 3}, + {148, 2}, + {150, 3}, {21, 4}, - {152, 4}, - {153, 5}, - {77, 4}, - {154, 4}, + {153, 4}, + {154, 5}, + {79, 4}, {155, 4}, {156, 4}, + {157, 4}, }; -static arc arcs_63_1[3] = { - {46, 6}, - {146, 6}, +static arc arcs_64_1[3] = { + {47, 6}, + {147, 6}, {15, 4}, }; -static arc arcs_63_2[2] = { - {146, 7}, - {148, 4}, +static arc arcs_64_2[2] = { + {147, 7}, + {149, 4}, }; -static arc arcs_63_3[2] = { - {150, 8}, - {151, 4}, +static arc arcs_64_3[2] = { + {151, 8}, + {152, 4}, }; -static arc arcs_63_4[1] = { +static arc arcs_64_4[1] = { {0, 4}, }; -static arc arcs_63_5[2] = { - {153, 5}, +static arc arcs_64_5[2] = { + {154, 5}, {0, 5}, }; -static arc arcs_63_6[1] = { +static arc arcs_64_6[1] = { {15, 4}, }; -static arc arcs_63_7[1] = { - {148, 4}, +static arc arcs_64_7[1] = { + {149, 4}, }; -static arc arcs_63_8[1] = { - {151, 4}, +static arc arcs_64_8[1] = { + {152, 4}, }; -static state states_63[9] = { - {10, arcs_63_0}, - {3, arcs_63_1}, - {2, arcs_63_2}, - {2, arcs_63_3}, - {1, arcs_63_4}, - {2, arcs_63_5}, - {1, arcs_63_6}, - {1, arcs_63_7}, - {1, arcs_63_8}, -}; -static arc arcs_64_0[1] = { +static state states_64[9] = { + {10, arcs_64_0}, + {3, arcs_64_1}, + {2, arcs_64_2}, + {2, arcs_64_3}, + {1, arcs_64_4}, + {2, arcs_64_5}, + {1, arcs_64_6}, + {1, arcs_64_7}, + {1, arcs_64_8}, +}; +static arc arcs_65_0[2] = { {24, 1}, + {48, 1}, }; -static arc arcs_64_1[3] = { - {157, 2}, +static arc arcs_65_1[3] = { + {158, 2}, {30, 3}, {0, 1}, }; -static arc arcs_64_2[1] = { +static arc arcs_65_2[1] = { {0, 2}, }; -static arc arcs_64_3[2] = { +static arc arcs_65_3[3] = { {24, 4}, + {48, 4}, {0, 3}, }; -static arc arcs_64_4[2] = { +static arc arcs_65_4[2] = { {30, 3}, {0, 4}, }; -static state states_64[5] = { - {1, arcs_64_0}, - {3, arcs_64_1}, - {1, arcs_64_2}, - {2, arcs_64_3}, - {2, arcs_64_4}, +static state states_65[5] = { + {2, arcs_65_0}, + {3, arcs_65_1}, + {1, arcs_65_2}, + {3, arcs_65_3}, + {2, arcs_65_4}, }; -static arc arcs_65_0[3] = { +static arc arcs_66_0[3] = { {13, 1}, - {147, 2}, - {76, 3}, + {148, 2}, + {78, 3}, }; -static arc arcs_65_1[2] = { +static arc arcs_66_1[2] = { {14, 4}, {15, 5}, }; -static arc arcs_65_2[1] = { - {158, 6}, +static arc arcs_66_2[1] = { + {159, 6}, }; -static arc arcs_65_3[1] = { +static arc arcs_66_3[1] = { {21, 5}, }; -static arc arcs_65_4[1] = { +static arc arcs_66_4[1] = { {15, 5}, }; -static arc arcs_65_5[1] = { +static arc arcs_66_5[1] = { {0, 5}, }; -static arc arcs_65_6[1] = { - {148, 5}, +static arc arcs_66_6[1] = { + {149, 5}, }; -static state states_65[7] = { - {3, arcs_65_0}, - {2, arcs_65_1}, - {1, arcs_65_2}, - {1, arcs_65_3}, - {1, arcs_65_4}, - {1, arcs_65_5}, - {1, arcs_65_6}, +static state states_66[7] = { + {3, arcs_66_0}, + {2, arcs_66_1}, + {1, arcs_66_2}, + {1, arcs_66_3}, + {1, arcs_66_4}, + {1, arcs_66_5}, + {1, arcs_66_6}, }; -static arc arcs_66_0[1] = { - {159, 1}, +static arc arcs_67_0[1] = { + {160, 1}, }; -static arc arcs_66_1[2] = { +static arc arcs_67_1[2] = { {30, 2}, {0, 1}, }; -static arc arcs_66_2[2] = { - {159, 1}, +static arc arcs_67_2[2] = { + {160, 1}, {0, 2}, }; -static state states_66[3] = { - {1, arcs_66_0}, - {2, arcs_66_1}, - {2, arcs_66_2}, +static state states_67[3] = { + {1, arcs_67_0}, + {2, arcs_67_1}, + {2, arcs_67_2}, }; -static arc arcs_67_0[2] = { +static arc arcs_68_0[2] = { {24, 1}, {25, 2}, }; -static arc arcs_67_1[2] = { +static arc arcs_68_1[2] = { {25, 2}, {0, 1}, }; -static arc arcs_67_2[3] = { +static arc arcs_68_2[3] = { {24, 3}, - {160, 4}, + {161, 4}, {0, 2}, }; -static arc arcs_67_3[2] = { - {160, 4}, +static arc arcs_68_3[2] = { + {161, 4}, {0, 3}, }; -static arc arcs_67_4[1] = { +static arc arcs_68_4[1] = { {0, 4}, }; -static state states_67[5] = { - {2, arcs_67_0}, - {2, arcs_67_1}, - {3, arcs_67_2}, - {2, arcs_67_3}, - {1, arcs_67_4}, +static state states_68[5] = { + {2, arcs_68_0}, + {2, arcs_68_1}, + {3, arcs_68_2}, + {2, arcs_68_3}, + {1, arcs_68_4}, }; -static arc arcs_68_0[1] = { +static arc arcs_69_0[1] = { {25, 1}, }; -static arc arcs_68_1[2] = { +static arc arcs_69_1[2] = { {24, 2}, {0, 1}, }; -static arc arcs_68_2[1] = { +static arc arcs_69_2[1] = { {0, 2}, }; -static state states_68[3] = { - {1, arcs_68_0}, - {2, arcs_68_1}, - {1, arcs_68_2}, +static state states_69[3] = { + {1, arcs_69_0}, + {2, arcs_69_1}, + {1, arcs_69_2}, }; -static arc arcs_69_0[1] = { - {116, 1}, +static arc arcs_70_0[2] = { + {103, 1}, + {48, 1}, }; -static arc arcs_69_1[2] = { +static arc arcs_70_1[2] = { {30, 2}, {0, 1}, }; -static arc arcs_69_2[2] = { - {116, 1}, +static arc arcs_70_2[3] = { + {103, 1}, + {48, 1}, {0, 2}, }; -static state states_69[3] = { - {1, arcs_69_0}, - {2, arcs_69_1}, - {2, arcs_69_2}, +static state states_70[3] = { + {2, arcs_70_0}, + {2, arcs_70_1}, + {3, arcs_70_2}, }; -static arc arcs_70_0[1] = { +static arc arcs_71_0[1] = { {24, 1}, }; -static arc arcs_70_1[2] = { +static arc arcs_71_1[2] = { {30, 2}, {0, 1}, }; -static arc arcs_70_2[2] = { +static arc arcs_71_2[2] = { {24, 1}, {0, 2}, }; -static state states_70[3] = { - {1, arcs_70_0}, - {2, arcs_70_1}, - {2, arcs_70_2}, +static state states_71[3] = { + {1, arcs_71_0}, + {2, arcs_71_1}, + {2, arcs_71_2}, }; -static arc arcs_71_0[1] = { +static arc arcs_72_0[1] = { {24, 1}, }; -static arc arcs_71_1[4] = { +static arc arcs_72_1[4] = { {25, 2}, - {157, 3}, + {158, 3}, {30, 4}, {0, 1}, }; -static arc arcs_71_2[1] = { +static arc arcs_72_2[1] = { {24, 5}, }; -static arc arcs_71_3[1] = { +static arc arcs_72_3[1] = { {0, 3}, }; -static arc arcs_71_4[2] = { +static arc arcs_72_4[2] = { {24, 6}, {0, 4}, }; -static arc arcs_71_5[3] = { - {157, 3}, +static arc arcs_72_5[3] = { + {158, 3}, {30, 7}, {0, 5}, }; -static arc arcs_71_6[2] = { +static arc arcs_72_6[2] = { {30, 4}, {0, 6}, }; -static arc arcs_71_7[2] = { +static arc arcs_72_7[2] = { {24, 8}, {0, 7}, }; -static arc arcs_71_8[1] = { +static arc arcs_72_8[1] = { {25, 9}, }; -static arc arcs_71_9[1] = { +static arc arcs_72_9[1] = { {24, 10}, }; -static arc arcs_71_10[2] = { +static arc arcs_72_10[2] = { {30, 7}, {0, 10}, }; -static state states_71[11] = { - {1, arcs_71_0}, - {4, arcs_71_1}, - {1, arcs_71_2}, - {1, arcs_71_3}, - {2, arcs_71_4}, - {3, arcs_71_5}, - {2, arcs_71_6}, - {2, arcs_71_7}, - {1, arcs_71_8}, - {1, arcs_71_9}, - {2, arcs_71_10}, -}; -static arc arcs_72_0[1] = { - {161, 1}, +static state states_72[11] = { + {1, arcs_72_0}, + {4, arcs_72_1}, + {1, arcs_72_2}, + {1, arcs_72_3}, + {2, arcs_72_4}, + {3, arcs_72_5}, + {2, arcs_72_6}, + {2, arcs_72_7}, + {1, arcs_72_8}, + {1, arcs_72_9}, + {2, arcs_72_10}, +}; +static arc arcs_73_0[1] = { + {162, 1}, }; -static arc arcs_72_1[1] = { +static arc arcs_73_1[1] = { {21, 2}, }; -static arc arcs_72_2[2] = { +static arc arcs_73_2[2] = { {13, 3}, {25, 4}, }; -static arc arcs_72_3[2] = { +static arc arcs_73_3[2] = { {14, 5}, {15, 6}, }; -static arc arcs_72_4[1] = { +static arc arcs_73_4[1] = { {26, 7}, }; -static arc arcs_72_5[1] = { +static arc arcs_73_5[1] = { {15, 6}, }; -static arc arcs_72_6[1] = { +static arc arcs_73_6[1] = { {25, 4}, }; -static arc arcs_72_7[1] = { +static arc arcs_73_7[1] = { {0, 7}, }; -static state states_72[8] = { - {1, arcs_72_0}, - {1, arcs_72_1}, - {2, arcs_72_2}, - {2, arcs_72_3}, - {1, arcs_72_4}, - {1, arcs_72_5}, - {1, arcs_72_6}, - {1, arcs_72_7}, -}; -static arc arcs_73_0[3] = { - {162, 1}, +static state states_73[8] = { + {1, arcs_73_0}, + {1, arcs_73_1}, + {2, arcs_73_2}, + {2, arcs_73_3}, + {1, arcs_73_4}, + {1, arcs_73_5}, + {1, arcs_73_6}, + {1, arcs_73_7}, +}; +static arc arcs_74_0[3] = { + {163, 1}, {31, 2}, {32, 3}, }; -static arc arcs_73_1[2] = { +static arc arcs_74_1[2] = { {30, 4}, {0, 1}, }; -static arc arcs_73_2[1] = { +static arc arcs_74_2[1] = { {24, 5}, }; -static arc arcs_73_3[1] = { +static arc arcs_74_3[1] = { {24, 6}, }; -static arc arcs_73_4[4] = { - {162, 1}, +static arc arcs_74_4[4] = { + {163, 1}, {31, 2}, {32, 3}, {0, 4}, }; -static arc arcs_73_5[2] = { +static arc arcs_74_5[2] = { {30, 7}, {0, 5}, }; -static arc arcs_73_6[1] = { +static arc arcs_74_6[1] = { {0, 6}, }; -static arc arcs_73_7[2] = { - {162, 5}, +static arc arcs_74_7[2] = { + {163, 5}, {32, 3}, }; -static state states_73[8] = { - {3, arcs_73_0}, - {2, arcs_73_1}, - {1, arcs_73_2}, - {1, arcs_73_3}, - {4, arcs_73_4}, - {2, arcs_73_5}, - {1, arcs_73_6}, - {2, arcs_73_7}, +static state states_74[8] = { + {3, arcs_74_0}, + {2, arcs_74_1}, + {1, arcs_74_2}, + {1, arcs_74_3}, + {4, arcs_74_4}, + {2, arcs_74_5}, + {1, arcs_74_6}, + {2, arcs_74_7}, }; -static arc arcs_74_0[1] = { +static arc arcs_75_0[1] = { {24, 1}, }; -static arc arcs_74_1[3] = { - {157, 2}, +static arc arcs_75_1[3] = { + {158, 2}, {29, 3}, {0, 1}, }; -static arc arcs_74_2[1] = { +static arc arcs_75_2[1] = { {0, 2}, }; -static arc arcs_74_3[1] = { +static arc arcs_75_3[1] = { {24, 2}, }; -static state states_74[4] = { - {1, arcs_74_0}, - {3, arcs_74_1}, - {1, arcs_74_2}, - {1, arcs_74_3}, +static state states_75[4] = { + {1, arcs_75_0}, + {3, arcs_75_1}, + {1, arcs_75_2}, + {1, arcs_75_3}, }; -static arc arcs_75_0[2] = { - {157, 1}, - {164, 1}, -}; -static arc arcs_75_1[1] = { - {0, 1}, -}; -static state states_75[2] = { - {2, arcs_75_0}, - {1, arcs_75_1}, -}; -static arc arcs_76_0[1] = { - {94, 1}, +static arc arcs_76_0[2] = { + {158, 1}, + {165, 1}, }; static arc arcs_76_1[1] = { - {60, 2}, -}; -static arc arcs_76_2[1] = { - {95, 3}, -}; -static arc arcs_76_3[1] = { - {105, 4}, -}; -static arc arcs_76_4[2] = { - {163, 5}, - {0, 4}, -}; -static arc arcs_76_5[1] = { - {0, 5}, + {0, 1}, }; -static state states_76[6] = { - {1, arcs_76_0}, +static state states_76[2] = { + {2, arcs_76_0}, {1, arcs_76_1}, - {1, arcs_76_2}, - {1, arcs_76_3}, - {2, arcs_76_4}, - {1, arcs_76_5}, }; static arc arcs_77_0[1] = { - {90, 1}, + {96, 1}, }; static arc arcs_77_1[1] = { - {107, 2}, + {62, 2}, }; -static arc arcs_77_2[2] = { - {163, 3}, - {0, 2}, +static arc arcs_77_2[1] = { + {97, 3}, }; static arc arcs_77_3[1] = { - {0, 3}, + {107, 4}, +}; +static arc arcs_77_4[2] = { + {164, 5}, + {0, 4}, }; -static state states_77[4] = { +static arc arcs_77_5[1] = { + {0, 5}, +}; +static state states_77[6] = { {1, arcs_77_0}, {1, arcs_77_1}, - {2, arcs_77_2}, + {1, arcs_77_2}, {1, arcs_77_3}, + {2, arcs_77_4}, + {1, arcs_77_5}, }; static arc arcs_78_0[1] = { - {24, 1}, + {92, 1}, }; -static arc arcs_78_1[2] = { - {30, 0}, - {0, 1}, +static arc arcs_78_1[1] = { + {109, 2}, +}; +static arc arcs_78_2[2] = { + {164, 3}, + {0, 2}, +}; +static arc arcs_78_3[1] = { + {0, 3}, }; -static state states_78[2] = { +static state states_78[4] = { {1, arcs_78_0}, - {2, arcs_78_1}, + {1, arcs_78_1}, + {2, arcs_78_2}, + {1, arcs_78_3}, }; static arc arcs_79_0[1] = { {21, 1}, @@ -1730,11 +1804,11 @@ static state states_80[3] = { }; static dfa dfas[81] = { {256, "single_input", 0, 3, states_0, - "\004\050\060\200\000\000\000\050\370\044\034\144\011\040\004\000\000\103\050\037\202"}, + "\004\050\060\200\000\000\000\240\340\223\160\220\045\200\020\000\000\206\120\076\204"}, {257, "file_input", 0, 2, states_1, - "\204\050\060\200\000\000\000\050\370\044\034\144\011\040\004\000\000\103\050\037\202"}, + "\204\050\060\200\000\000\000\240\340\223\160\220\045\200\020\000\000\206\120\076\204"}, {258, "eval_input", 0, 3, states_2, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, {259, "decorator", 0, 7, states_3, "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {260, "decorators", 0, 2, states_4, @@ -1745,148 +1819,148 @@ static dfa dfas[81] = { "\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {263, "parameters", 0, 4, states_7, "\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {264, "typedargslist", 0, 12, states_8, + {264, "typedargslist", 0, 18, states_8, "\000\000\040\200\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {265, "tfpdef", 0, 4, states_9, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {266, "varargslist", 0, 12, states_10, + {266, "varargslist", 0, 18, states_10, "\000\000\040\200\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {267, "vfpdef", 0, 2, states_11, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {268, "stmt", 0, 2, states_12, - "\000\050\060\200\000\000\000\050\370\044\034\144\011\040\004\000\000\103\050\037\202"}, + "\000\050\060\200\000\000\000\240\340\223\160\220\045\200\020\000\000\206\120\076\204"}, {269, "simple_stmt", 0, 4, states_13, - "\000\040\040\200\000\000\000\050\370\044\034\000\000\040\004\000\000\103\050\037\200"}, + "\000\040\040\200\000\000\000\240\340\223\160\000\000\200\020\000\000\206\120\076\200"}, {270, "small_stmt", 0, 2, states_14, - "\000\040\040\200\000\000\000\050\370\044\034\000\000\040\004\000\000\103\050\037\200"}, + "\000\040\040\200\000\000\000\240\340\223\160\000\000\200\020\000\000\206\120\076\200"}, {271, "expr_stmt", 0, 6, states_15, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {272, "augassign", 0, 2, states_16, - "\000\000\000\000\000\200\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {273, "del_stmt", 0, 3, states_17, - "\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {274, "pass_stmt", 0, 2, states_18, + "\000\040\040\200\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {272, "testlist_star_expr", 0, 3, states_16, + "\000\040\040\200\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {273, "augassign", 0, 2, states_17, + "\000\000\000\000\000\000\376\037\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {274, "del_stmt", 0, 3, states_18, "\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {275, "flow_stmt", 0, 2, states_19, - "\000\000\000\000\000\000\000\000\170\000\000\000\000\000\000\000\000\000\000\000\200"}, - {276, "break_stmt", 0, 2, states_20, - "\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000"}, - {277, "continue_stmt", 0, 2, states_21, - "\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000"}, - {278, "return_stmt", 0, 3, states_22, + {275, "pass_stmt", 0, 2, states_19, + "\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {276, "flow_stmt", 0, 2, states_20, + "\000\000\000\000\000\000\000\000\340\001\000\000\000\000\000\000\000\000\000\000\200"}, + {277, "break_stmt", 0, 2, states_21, "\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000"}, - {279, "yield_stmt", 0, 2, states_23, - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200"}, - {280, "raise_stmt", 0, 5, states_24, + {278, "continue_stmt", 0, 2, states_22, "\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000\000\000\000"}, - {281, "import_stmt", 0, 2, states_25, - "\000\000\000\000\000\000\000\000\200\004\000\000\000\000\000\000\000\000\000\000\000"}, - {282, "import_name", 0, 3, states_26, - "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"}, - {283, "import_from", 0, 8, states_27, + {279, "return_stmt", 0, 3, states_23, "\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000"}, - {284, "import_as_name", 0, 4, states_28, + {280, "yield_stmt", 0, 2, states_24, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200"}, + {281, "raise_stmt", 0, 5, states_25, + "\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000"}, + {282, "import_stmt", 0, 2, states_26, + "\000\000\000\000\000\000\000\000\000\022\000\000\000\000\000\000\000\000\000\000\000"}, + {283, "import_name", 0, 3, states_27, + "\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000"}, + {284, "import_from", 0, 8, states_28, + "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000"}, + {285, "import_as_name", 0, 4, states_29, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {285, "dotted_as_name", 0, 4, states_29, + {286, "dotted_as_name", 0, 4, states_30, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {286, "import_as_names", 0, 3, states_30, + {287, "import_as_names", 0, 3, states_31, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {287, "dotted_as_names", 0, 2, states_31, + {288, "dotted_as_names", 0, 2, states_32, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {288, "dotted_name", 0, 2, states_32, + {289, "dotted_name", 0, 2, states_33, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {289, "global_stmt", 0, 3, states_33, - "\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000"}, - {290, "nonlocal_stmt", 0, 3, states_34, - "\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000"}, - {291, "assert_stmt", 0, 5, states_35, + {290, "global_stmt", 0, 3, states_34, "\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000"}, - {292, "compound_stmt", 0, 2, states_36, - "\000\010\020\000\000\000\000\000\000\000\000\144\011\000\000\000\000\000\000\000\002"}, - {293, "if_stmt", 0, 8, states_37, - "\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000"}, - {294, "while_stmt", 0, 8, states_38, - "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000"}, - {295, "for_stmt", 0, 10, states_39, - "\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000"}, - {296, "try_stmt", 0, 13, states_40, + {291, "nonlocal_stmt", 0, 3, states_35, + "\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000"}, + {292, "assert_stmt", 0, 5, states_36, + "\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000\000"}, + {293, "compound_stmt", 0, 2, states_37, + "\000\010\020\000\000\000\000\000\000\000\000\220\045\000\000\000\000\000\000\000\004"}, + {294, "if_stmt", 0, 8, states_38, + "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000"}, + {295, "while_stmt", 0, 8, states_39, + "\000\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000"}, + {296, "for_stmt", 0, 10, states_40, "\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000"}, - {297, "with_stmt", 0, 5, states_41, - "\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000"}, - {298, "with_item", 0, 4, states_42, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {299, "except_clause", 0, 5, states_43, - "\000\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000"}, - {300, "suite", 0, 5, states_44, - "\004\040\040\200\000\000\000\050\370\044\034\000\000\040\004\000\000\103\050\037\200"}, - {301, "test", 0, 6, states_45, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {302, "test_nocond", 0, 2, states_46, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {303, "lambdef", 0, 5, states_47, - "\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000"}, - {304, "lambdef_nocond", 0, 5, states_48, - "\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000"}, - {305, "or_test", 0, 2, states_49, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\000\004\000\000\103\050\037\000"}, - {306, "and_test", 0, 2, states_50, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\000\004\000\000\103\050\037\000"}, - {307, "not_test", 0, 3, states_51, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\000\004\000\000\103\050\037\000"}, - {308, "comparison", 0, 2, states_52, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {309, "comp_op", 0, 4, states_53, - "\000\000\000\000\000\000\000\000\000\000\000\200\000\000\304\077\000\000\000\000\000"}, - {310, "star_expr", 0, 3, states_54, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {311, "expr", 0, 2, states_55, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {312, "xor_expr", 0, 2, states_56, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {313, "and_expr", 0, 2, states_57, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {314, "shift_expr", 0, 2, states_58, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {315, "arith_expr", 0, 2, states_59, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {316, "term", 0, 2, states_60, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {317, "factor", 0, 3, states_61, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {318, "power", 0, 4, states_62, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\050\037\000"}, - {319, "atom", 0, 9, states_63, - "\000\040\040\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\050\037\000"}, - {320, "testlist_comp", 0, 5, states_64, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {321, "trailer", 0, 7, states_65, - "\000\040\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\010\000\000"}, - {322, "subscriptlist", 0, 3, states_66, - "\000\040\040\202\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {323, "subscript", 0, 5, states_67, - "\000\040\040\202\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {324, "sliceop", 0, 3, states_68, + {297, "try_stmt", 0, 13, states_41, + "\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000"}, + {298, "with_stmt", 0, 5, states_42, + "\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"}, + {299, "with_item", 0, 4, states_43, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {300, "except_clause", 0, 5, states_44, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000"}, + {301, "suite", 0, 5, states_45, + "\004\040\040\200\000\000\000\240\340\223\160\000\000\200\020\000\000\206\120\076\200"}, + {302, "test", 0, 6, states_46, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {303, "test_nocond", 0, 2, states_47, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {304, "lambdef", 0, 5, states_48, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000"}, + {305, "lambdef_nocond", 0, 5, states_49, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000"}, + {306, "or_test", 0, 2, states_50, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\020\000\000\206\120\076\000"}, + {307, "and_test", 0, 2, states_51, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\020\000\000\206\120\076\000"}, + {308, "not_test", 0, 3, states_52, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\020\000\000\206\120\076\000"}, + {309, "comparison", 0, 2, states_53, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {310, "comp_op", 0, 4, states_54, + "\000\000\000\000\000\000\000\000\000\000\000\000\002\000\220\177\000\000\000\000\000"}, + {311, "star_expr", 0, 3, states_55, + "\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {312, "expr", 0, 2, states_56, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {313, "xor_expr", 0, 2, states_57, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {314, "and_expr", 0, 2, states_58, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {315, "shift_expr", 0, 2, states_59, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {316, "arith_expr", 0, 2, states_60, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {317, "term", 0, 2, states_61, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {318, "factor", 0, 3, states_62, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {319, "power", 0, 4, states_63, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\120\076\000"}, + {320, "atom", 0, 9, states_64, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\120\076\000"}, + {321, "testlist_comp", 0, 5, states_65, + "\000\040\040\200\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {322, "trailer", 0, 7, states_66, + "\000\040\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\020\000\000"}, + {323, "subscriptlist", 0, 3, states_67, + "\000\040\040\002\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {324, "subscript", 0, 5, states_68, + "\000\040\040\002\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {325, "sliceop", 0, 3, states_69, "\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {325, "exprlist", 0, 3, states_69, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\000\000\000\000\103\050\037\000"}, - {326, "testlist", 0, 3, states_70, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {327, "dictorsetmaker", 0, 11, states_71, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {328, "classdef", 0, 8, states_72, - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002"}, - {329, "arglist", 0, 8, states_73, - "\000\040\040\200\001\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {330, "argument", 0, 4, states_74, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, - {331, "comp_iter", 0, 2, states_75, - "\000\000\000\000\000\000\000\000\000\000\000\104\000\000\000\000\000\000\000\000\000"}, - {332, "comp_for", 0, 6, states_76, - "\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000"}, - {333, "comp_if", 0, 4, states_77, - "\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000"}, - {334, "testlist1", 0, 2, states_78, - "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\000\103\050\037\000"}, + {326, "exprlist", 0, 3, states_70, + "\000\040\040\200\000\000\000\000\000\200\000\000\000\000\000\000\000\206\120\076\000"}, + {327, "testlist", 0, 3, states_71, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {328, "dictorsetmaker", 0, 11, states_72, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {329, "classdef", 0, 8, states_73, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004"}, + {330, "arglist", 0, 8, states_74, + "\000\040\040\200\001\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {331, "argument", 0, 4, states_75, + "\000\040\040\000\000\000\000\000\000\200\000\000\000\200\020\000\000\206\120\076\000"}, + {332, "comp_iter", 0, 2, states_76, + "\000\000\000\000\000\000\000\000\000\000\000\020\001\000\000\000\000\000\000\000\000"}, + {333, "comp_for", 0, 6, states_77, + "\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000"}, + {334, "comp_if", 0, 4, states_78, + "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000"}, {335, "encoding_decl", 0, 2, states_79, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {336, "yield_expr", 0, 3, states_80, @@ -1897,29 +1971,29 @@ static label labels[168] = { {256, 0}, {4, 0}, {269, 0}, - {292, 0}, + {293, 0}, {257, 0}, {268, 0}, {0, 0}, {258, 0}, - {326, 0}, + {327, 0}, {259, 0}, {50, 0}, - {288, 0}, + {289, 0}, {7, 0}, - {329, 0}, + {330, 0}, {8, 0}, {260, 0}, {261, 0}, - {328, 0}, + {329, 0}, {262, 0}, {1, "def"}, {1, 0}, {263, 0}, {51, 0}, - {301, 0}, + {302, 0}, {11, 0}, - {300, 0}, + {301, 0}, {264, 0}, {265, 0}, {22, 0}, @@ -1931,15 +2005,17 @@ static label labels[168] = { {270, 0}, {13, 0}, {271, 0}, - {273, 0}, {274, 0}, {275, 0}, - {281, 0}, - {289, 0}, + {276, 0}, + {282, 0}, {290, 0}, {291, 0}, + {292, 0}, {272, 0}, + {273, 0}, {336, 0}, + {311, 0}, {37, 0}, {38, 0}, {39, 0}, @@ -1953,36 +2029,36 @@ static label labels[168] = { {47, 0}, {49, 0}, {1, "del"}, - {325, 0}, + {326, 0}, {1, "pass"}, - {276, 0}, {277, 0}, {278, 0}, - {280, 0}, {279, 0}, + {281, 0}, + {280, 0}, {1, "break"}, {1, "continue"}, {1, "return"}, {1, "raise"}, {1, "from"}, - {282, 0}, {283, 0}, + {284, 0}, {1, "import"}, - {287, 0}, + {288, 0}, {23, 0}, {52, 0}, - {286, 0}, - {284, 0}, - {1, "as"}, + {287, 0}, {285, 0}, + {1, "as"}, + {286, 0}, {1, "global"}, {1, "nonlocal"}, {1, "assert"}, - {293, 0}, {294, 0}, {295, 0}, {296, 0}, {297, 0}, + {298, 0}, {1, "if"}, {1, "elif"}, {1, "else"}, @@ -1990,27 +2066,26 @@ static label labels[168] = { {1, "for"}, {1, "in"}, {1, "try"}, - {299, 0}, + {300, 0}, {1, "finally"}, {1, "with"}, - {298, 0}, - {311, 0}, + {299, 0}, + {312, 0}, {1, "except"}, {5, 0}, {6, 0}, - {305, 0}, - {303, 0}, - {302, 0}, + {306, 0}, {304, 0}, + {303, 0}, + {305, 0}, {1, "lambda"}, - {306, 0}, - {1, "or"}, {307, 0}, + {1, "or"}, + {308, 0}, {1, "and"}, {1, "not"}, - {308, 0}, - {310, 0}, {309, 0}, + {310, 0}, {20, 0}, {21, 0}, {28, 0}, @@ -2019,45 +2094,44 @@ static label labels[168] = { {29, 0}, {29, 0}, {1, "is"}, - {312, 0}, - {18, 0}, {313, 0}, - {33, 0}, + {18, 0}, {314, 0}, - {19, 0}, + {33, 0}, {315, 0}, + {19, 0}, + {316, 0}, {34, 0}, {35, 0}, - {316, 0}, + {317, 0}, {14, 0}, {15, 0}, - {317, 0}, + {318, 0}, {17, 0}, {24, 0}, {48, 0}, {32, 0}, - {318, 0}, {319, 0}, - {321, 0}, {320, 0}, + {322, 0}, + {321, 0}, {9, 0}, {10, 0}, {26, 0}, - {327, 0}, + {328, 0}, {27, 0}, {2, 0}, {3, 0}, {1, "None"}, {1, "True"}, {1, "False"}, - {332, 0}, - {322, 0}, + {333, 0}, {323, 0}, {324, 0}, + {325, 0}, {1, "class"}, - {330, 0}, {331, 0}, - {333, 0}, + {332, 0}, {334, 0}, {335, 0}, {1, "yield"}, diff --git a/Python/import.c b/Python/import.c index 5d80983408..23752eeb72 100644 --- a/Python/import.c +++ b/Python/import.c @@ -5,13 +5,9 @@ #include "Python-ast.h" #undef Yield /* undefine macro conflicting with winbase.h */ -#include "pyarena.h" -#include "pythonrun.h" #include "errcode.h" #include "marshal.h" #include "code.h" -#include "compile.h" -#include "eval.h" #include "osdefs.h" #include "importdl.h" @@ -25,6 +21,8 @@ extern "C" { #ifdef MS_WINDOWS /* for stat.st_mode */ typedef unsigned short mode_t; +/* for _mkdir */ +#include <direct.h> #endif @@ -43,6 +41,15 @@ typedef unsigned short mode_t; The current working scheme is to increment the previous value by 10. + Starting with the adoption of PEP 3147 in Python 3.2, every bump in magic + number also includes a new "magic tag", i.e. a human readable string used + to represent the magic number in __pycache__ directories. When you change + the magic number, you must also set a new unique magic tag. Generally this + can be named after the Python major version of the magic number bump, but + it can really be anything, as long as it's different than anything else + that's come before. The tags are included in the following table, starting + with Python 3.2a0. + Known values: Python 1.5: 20121 Python 1.5.1: 20121 @@ -78,26 +85,39 @@ typedef unsigned short mode_t; 3040 (added signature annotations) 3050 (print becomes a function) 3060 (PEP 3115 metaclass syntax) - 3070 (PEP 3109 raise changes) - 3080 (PEP 3137 make __file__ and __name__ unicode) - 3090 (kill str8 interning) - 3100 (merge from 2.6a0, see 62151) - 3102 (__file__ points to source file) - Python 3.0a4: 3110 (WITH_CLEANUP optimization). - Python 3.0a5: 3130 (lexical exception stacking, including POP_EXCEPT) - Python 3.1a0: 3140 (optimize list, set and dict comprehensions: + 3061 (string literals become unicode) + 3071 (PEP 3109 raise changes) + 3081 (PEP 3137 make __file__ and __name__ unicode) + 3091 (kill str8 interning) + 3101 (merge from 2.6a0, see 62151) + 3103 (__file__ points to source file) + Python 3.0a4: 3111 (WITH_CLEANUP optimization). + Python 3.0a5: 3131 (lexical exception stacking, including POP_EXCEPT) + Python 3.1a0: 3141 (optimize list, set and dict comprehensions: change LIST_APPEND and SET_ADD, add MAP_ADD) - Python 3.1a0: 3150 (optimize conditional branches: + Python 3.1a0: 3151 (optimize conditional branches: introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE) + Python 3.2a0: 3160 (add SETUP_WITH) + tag: cpython-32 + Python 3.2a1: 3170 (add DUP_TOP_TWO, remove DUP_TOPX and ROT_FOUR) + tag: cpython-32 + Python 3.2a2 3180 (add DELETE_DEREF) */ -#define MAGIC (3150 | ((long)'\r'<<16) | ((long)'\n'<<24)) -/* Magic word as global; note that _PyImport_Init() can change the - value of this global to accommodate for alterations of how the - compiler works which are enabled by command line switches. */ +/* MAGIC must change whenever the bytecode emitted by the compiler may no + longer be understood by older implementations of the eval loop (usually + due to the addition of new opcodes) + TAG must change for each major Python release. The magic number will take + care of any bytecode changes that occur during development. +*/ +#define MAGIC (3180 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define TAG "cpython-32" +#define CACHEDIR "__pycache__" +/* Current magic word and string tag as globals. */ static long pyc_magic = MAGIC; +static const char *pyc_tag = TAG; -/* See _PyImport_FixupExtension() below */ +/* See _PyImport_FixupExtensionUnicode() below */ static PyObject *extensions = NULL; /* This table is defined in config.c: */ @@ -160,13 +180,6 @@ _PyImport_Init(void) filetab->suffix = ".pyo"; } } - - { - /* Fix the pyc_magic so that byte compiled code created - using the all-Unicode method doesn't interfere with - code created in normal operation mode. */ - pyc_magic = MAGIC + 1; - } } void @@ -302,14 +315,27 @@ _PyImport_ReleaseLock(void) return 1; } -/* This function used to be called from PyOS_AfterFork to ensure that newly - created child processes do not share locks with the parent, but for some - reason only on AIX systems. Instead of re-initializing the lock, we now - acquire the import lock around fork() calls. */ +/* This function is called from PyOS_AfterFork to ensure that newly + created child processes do not share locks with the parent. + We now acquire the import lock around fork() calls but on some platforms + (Solaris 9 and earlier? see isue7242) that still left us with problems. */ void _PyImport_ReInitLock(void) { + if (import_lock != NULL) + import_lock = PyThread_allocate_lock(); + if (import_lock_level > 1) { + /* Forked as a side effect of import */ + long me = PyThread_get_thread_ident(); + PyThread_acquire_lock(import_lock, 0); + /* XXX: can the previous line fail? */ + import_lock_thread = me; + import_lock_level--; + } else { + import_lock_thread = -1; + import_lock_level = 0; + } } #endif @@ -520,7 +546,7 @@ PyImport_Cleanup(void) } -/* Helper for pythonrun.c -- return magic number */ +/* Helper for pythonrun.c -- return magic number and tag. */ long PyImport_GetMagicNumber(void) @@ -529,24 +555,30 @@ PyImport_GetMagicNumber(void) } +const char * +PyImport_GetMagicTag(void) +{ + return pyc_tag; +} + /* Magic for extension modules (built-in as well as dynamically loaded). To prevent initializing an extension module more than once, we keep a static dictionary 'extensions' keyed by module name (for built-in modules) or by filename (for dynamically loaded modules), containing these modules. A copy of the module's - dictionary is stored by calling _PyImport_FixupExtension() + dictionary is stored by calling _PyImport_FixupExtensionUnicode() immediately after the module initialization function succeeds. A copy can be retrieved from there by calling - _PyImport_FindExtension(). + _PyImport_FindExtensionUnicode(). - Modules which do support multiple multiple initialization set - their m_size field to a non-negative number (indicating the size - of the module-specific state). They are still recorded in the - extensions dictionary, to avoid loading shared libraries twice. + Modules which do support multiple initialization set their m_size + field to a non-negative number (indicating the size of the + module-specific state). They are still recorded in the extensions + dictionary, to avoid loading shared libraries twice. */ int -_PyImport_FixupExtension(PyObject *mod, char *name, char *filename) +_PyImport_FixupExtensionUnicode(PyObject *mod, char *name, PyObject *filename) { PyObject *modules, *dict; struct PyModuleDef *def; @@ -586,18 +618,31 @@ _PyImport_FixupExtension(PyObject *mod, char *name, char *filename) if (def->m_base.m_copy == NULL) return -1; } - PyDict_SetItemString(extensions, filename, (PyObject*)def); + PyDict_SetItem(extensions, filename, (PyObject*)def); return 0; } +int +_PyImport_FixupBuiltin(PyObject *mod, char *name) +{ + int res; + PyObject *filename; + filename = PyUnicode_FromString(name); + if (filename == NULL) + return -1; + res = _PyImport_FixupExtensionUnicode(mod, name, filename); + Py_DECREF(filename); + return res; +} + PyObject * -_PyImport_FindExtension(char *name, char *filename) +_PyImport_FindExtensionUnicode(char *name, PyObject *filename) { PyObject *mod, *mdict; PyModuleDef* def; if (extensions == NULL) return NULL; - def = (PyModuleDef*)PyDict_GetItemString(extensions, filename); + def = (PyModuleDef*)PyDict_GetItem(extensions, filename); if (def == NULL) return NULL; if (def->m_size == -1) { @@ -628,12 +673,23 @@ _PyImport_FindExtension(char *name, char *filename) return NULL; } if (Py_VerboseFlag) - PySys_WriteStderr("import %s # previously loaded (%s)\n", + PySys_FormatStderr("import %s # previously loaded (%U)\n", name, filename); return mod; } +PyObject * +_PyImport_FindBuiltin(char *name) +{ + PyObject *res, *filename; + filename = PyUnicode_FromString(name); + if (filename == NULL) + return NULL; + res = _PyImport_FindExtensionUnicode(name, filename); + Py_DECREF(filename); + return res; +} /* Get the module object corresponding to a module name. First check the modules dictionary if there's one there, @@ -664,7 +720,7 @@ PyImport_AddModule(const char *name) /* Remove name from sys.modules, if it's there. */ static void -_RemoveModule(const char *name) +remove_module(const char *name) { PyObject *modules = PyImport_GetModuleDict(); if (PyDict_GetItemString(modules, name) == NULL) @@ -674,7 +730,10 @@ _RemoveModule(const char *name) "sys.modules failed"); } -static PyObject * get_sourcefile(const char *file); +static PyObject * get_sourcefile(char *file); +static char *make_source_pathname(char *pathname, char *buf); +static char *make_compiled_pathname(char *pathname, char *buf, size_t buflen, + int debug); /* Execute a code object in a module and return the module object * WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is @@ -682,16 +741,28 @@ static PyObject * get_sourcefile(const char *file); * in sys.modules. The caller may wish to restore the original * module object (if any) in this case; PyImport_ReloadModule is an * example. + * + * Note that PyImport_ExecCodeModuleWithPathnames() is the preferred, richer + * interface. The other two exist primarily for backward compatibility. */ PyObject * PyImport_ExecCodeModule(char *name, PyObject *co) { - return PyImport_ExecCodeModuleEx(name, co, (char *)NULL); + return PyImport_ExecCodeModuleWithPathnames( + name, co, (char *)NULL, (char *)NULL); } PyObject * PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname) { + return PyImport_ExecCodeModuleWithPathnames( + name, co, pathname, (char *)NULL); +} + +PyObject * +PyImport_ExecCodeModuleWithPathnames(char *name, PyObject *co, char *pathname, + char *cpathname) +{ PyObject *modules = PyImport_GetModuleDict(); PyObject *m, *d, *v; @@ -721,7 +792,21 @@ PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname) PyErr_Clear(); /* Not important enough to report */ Py_DECREF(v); - v = PyEval_EvalCode((PyCodeObject *)co, d, d); + /* Remember the pyc path name as the __cached__ attribute. */ + if (cpathname == NULL) { + v = Py_None; + Py_INCREF(v); + } + else if ((v = PyUnicode_FromString(cpathname)) == NULL) { + PyErr_Clear(); /* Not important enough to report */ + v = Py_None; + Py_INCREF(v); + } + if (PyDict_SetItemString(d, "__cached__", v) != 0) + PyErr_Clear(); /* Not important enough to report */ + Py_DECREF(v); + + v = PyEval_EvalCode(co, d, d); if (v == NULL) goto error; Py_DECREF(v); @@ -738,37 +823,194 @@ PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname) return m; error: - _RemoveModule(name); + remove_module(name); return NULL; } +/* Like strrchr(string, '/') but searches for the rightmost of either SEP + or ALTSEP, if the latter is defined. +*/ +static char * +rightmost_sep(char *s) +{ + char *found, c; + for (found = NULL; (c = *s); s++) { + if (c == SEP +#ifdef ALTSEP + || c == ALTSEP +#endif + ) + { + found = s; + } + } + return found; +} + + /* Given a pathname for a Python source file, fill a buffer with the pathname for the corresponding compiled file. Return the pathname for the compiled file, or NULL if there's no space in the buffer. Doesn't set an exception. */ static char * -make_compiled_pathname(char *pathname, char *buf, size_t buflen) +make_compiled_pathname(char *pathname, char *buf, size_t buflen, int debug) { + /* foo.py -> __pycache__/foo.<tag>.pyc */ size_t len = strlen(pathname); - if (len+2 > buflen) + size_t i, save; + char *pos; + int sep = SEP; + + /* Sanity check that the buffer has roughly enough space to hold what + will eventually be the full path to the compiled file. The 5 extra + bytes include the slash afer __pycache__, the two extra dots, the + extra trailing character ('c' or 'o') and null. This isn't exact + because the contents of the buffer can affect how many actual + characters of the string get into the buffer. We'll do a final + sanity check before writing the extension to ensure we do not + overflow the buffer. + */ + if (len + strlen(CACHEDIR) + strlen(pyc_tag) + 5 > buflen) return NULL; -#ifdef MS_WINDOWS - /* Treat .pyw as if it were .py. The case of ".pyw" must match - that used in _PyImport_StandardFiletab. */ - if (len >= 4 && strcmp(&pathname[len-4], ".pyw") == 0) - --len; /* pretend 'w' isn't there */ + /* Find the last path separator and copy everything from the start of + the source string up to and including the separator. + */ + if ((pos = rightmost_sep(pathname)) == NULL) { + i = 0; + } + else { + sep = *pos; + i = pos - pathname + 1; + strncpy(buf, pathname, i); + } + + save = i; + buf[i++] = '\0'; + /* Add __pycache__/ */ + strcat(buf, CACHEDIR); + i += strlen(CACHEDIR) - 1; + buf[i++] = sep; + buf[i++] = '\0'; + /* Add the base filename, but remove the .py or .pyw extension, since + the tag name must go before the extension. + */ + strcat(buf, pathname + save); + if ((pos = strrchr(buf, '.')) != NULL) + *++pos = '\0'; + strcat(buf, pyc_tag); + /* The length test above assumes that we're only adding one character + to the end of what would normally be the extension. What if there + is no extension, or the string ends in '.' or '.p', and otherwise + fills the buffer? By appending 4 more characters onto the string + here, we could overrun the buffer. + + As a simple example, let's say buflen=32 and the input string is + 'xxx.py'. strlen() would be 6 and the test above would yield: + + (6 + 11 + 10 + 5 == 32) > 32 + + which is false and so the name mangling would continue. This would + be fine because we'd end up with this string in buf: + + __pycache__/xxx.cpython-32.pyc\0 + + strlen(of that) == 30 + the nul fits inside a 32 character buffer. + We can even handle an input string of say 'xxxxx' above because + that's (5 + 11 + 10 + 5 == 31) > 32 which is also false. Name + mangling that yields: + + __pycache__/xxxxxcpython-32.pyc\0 + + which is 32 characters including the nul, and thus fits in the + buffer. However, an input string of 'xxxxxx' would yield a result + string of: + + __pycache__/xxxxxxcpython-32.pyc\0 + + which is 33 characters long (including the nul), thus overflowing + the buffer, even though the first test would fail, i.e.: the input + string is also 6 characters long, so 32 > 32 is false. + + The reason the first test fails but we still overflow the buffer is + that the test above only expects to add one extra character to be + added to the extension, and here we're adding three (pyc). We + don't add the first dot, so that reclaims one of expected + positions, leaving us overflowing by 1 byte (3 extra - 1 reclaimed + dot - 1 expected extra == 1 overflowed). + + The best we can do is ensure that we still have enough room in the + target buffer before we write the extension. Because it's always + only the extension that can cause the overflow, and never the other + path bytes we've written, it's sufficient to just do one more test + here. Still, the assertion that follows can't hurt. + */ +#if 0 + printf("strlen(buf): %d; buflen: %d\n", (int)strlen(buf), (int)buflen); #endif - memcpy(buf, pathname, len); - buf[len] = Py_OptimizeFlag ? 'o' : 'c'; - buf[len+1] = '\0'; - + if (strlen(buf) + 5 > buflen) + return NULL; + strcat(buf, debug ? ".pyc" : ".pyo"); + assert(strlen(buf) < buflen); return buf; } +/* Given a pathname to a Python byte compiled file, return the path to the + source file, if the path matches the PEP 3147 format. This does not check + for any file existence, however, if the pyc file name does not match PEP + 3147 style, NULL is returned. buf must be at least as big as pathname; + the resulting path will always be shorter. */ + +static char * +make_source_pathname(char *pathname, char *buf) +{ + /* __pycache__/foo.<tag>.pyc -> foo.py */ + size_t i, j; + char *left, *right, *dot0, *dot1, sep; + + /* Look back two slashes from the end. In between these two slashes + must be the string __pycache__ or this is not a PEP 3147 style + path. It's possible for there to be only one slash. + */ + if ((right = rightmost_sep(pathname)) == NULL) + return NULL; + sep = *right; + *right = '\0'; + left = rightmost_sep(pathname); + *right = sep; + if (left == NULL) + left = pathname; + else + left++; + if (right-left != strlen(CACHEDIR) || + strncmp(left, CACHEDIR, right-left) != 0) + return NULL; + + /* Now verify that the path component to the right of the last slash + has two dots in it. + */ + if ((dot0 = strchr(right + 1, '.')) == NULL) + return NULL; + if ((dot1 = strchr(dot0 + 1, '.')) == NULL) + return NULL; + /* Too many dots? */ + if (strchr(dot1 + 1, '.') != NULL) + return NULL; + + /* This is a PEP 3147 path. Start by copying everything from the + start of pathname up to and including the leftmost slash. Then + copy the file's basename, removing the magic tag and adding a .py + suffix. + */ + strncpy(buf, pathname, (i=left-pathname)); + strncpy(buf+i, right+1, (j=dot0-right)); + strcpy(buf+i+j, "py"); + return buf; +} + /* Given a pathname for a Python source file, its time of last modification, and a pathname for a compiled file, check whether the compiled file represents the same version of the source. If so, @@ -849,7 +1091,8 @@ load_compiled_module(char *name, char *cpathname, FILE *fp) if (Py_VerboseFlag) PySys_WriteStderr("import %s # precompiled from %s\n", name, cpathname); - m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, cpathname); + m = PyImport_ExecCodeModuleWithPathnames( + name, (PyObject *)co, cpathname, cpathname); Py_DECREF(co); return m; @@ -922,12 +1165,42 @@ static void write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat) { FILE *fp; + char *dirpath; time_t mtime = srcstat->st_mtime; #ifdef MS_WINDOWS /* since Windows uses different permissions */ mode_t mode = srcstat->st_mode & ~S_IEXEC; #else mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH; + mode_t dirmode = (srcstat->st_mode | + S_IXUSR | S_IXGRP | S_IXOTH | + S_IWUSR | S_IWGRP | S_IWOTH); +#endif + int saved; + + /* Ensure that the __pycache__ directory exists. */ + dirpath = rightmost_sep(cpathname); + if (dirpath == NULL) { + if (Py_VerboseFlag) + PySys_WriteStderr( + "# no %s path found %s\n", + CACHEDIR, cpathname); + return; + } + saved = *dirpath; + *dirpath = '\0'; + +#ifdef MS_WINDOWS + if (_mkdir(cpathname) < 0 && errno != EEXIST) { +#else + if (mkdir(cpathname, dirmode) < 0 && errno != EEXIST) { #endif + *dirpath = saved; + if (Py_VerboseFlag) + PySys_WriteStderr( + "# cannot create cache dir %s\n", cpathname); + return; + } + *dirpath = saved; fp = open_exclusive(cpathname, mode); if (fp == NULL) { @@ -1035,8 +1308,8 @@ load_source_module(char *name, char *pathname, FILE *fp) return NULL; } #endif - cpathname = make_compiled_pathname(pathname, buf, - (size_t)MAXPATHLEN + 1); + cpathname = make_compiled_pathname( + pathname, buf, (size_t)MAXPATHLEN + 1, !Py_OptimizeFlag); if (cpathname != NULL && (fpc = check_compiled_module(pathname, st.st_mtime, cpathname))) { co = read_compiled_module(cpathname, fpc); @@ -1063,7 +1336,8 @@ load_source_module(char *name, char *pathname, FILE *fp) write_compiled_module(co, cpathname, &st); } } - m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname); + m = PyImport_ExecCodeModuleWithPathnames( + name, (PyObject *)co, pathname, cpathname); Py_DECREF(co); return m; @@ -1073,7 +1347,7 @@ load_source_module(char *name, char *pathname, FILE *fp) * Returns the path to the py file if available, else the given path */ static PyObject * -get_sourcefile(const char *file) +get_sourcefile(char *file) { char py[MAXPATHLEN + 1]; Py_ssize_t len; @@ -1090,8 +1364,15 @@ get_sourcefile(const char *file) return PyUnicode_DecodeFSDefault(file); } - strncpy(py, file, len-1); - py[len-1] = '\0'; + /* Start by trying to turn PEP 3147 path into source path. If that + * fails, just chop off the trailing character, i.e. legacy pyc path + * to py. + */ + if (make_source_pathname(file, py) == NULL) { + strncpy(py, file, len-1); + py[len-1] = '\0'; + } + if (stat(py, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) { u = PyUnicode_DecodeFSDefault(py); @@ -1390,8 +1671,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (!v) return NULL; if (PyUnicode_Check(v)) { - v = PyUnicode_AsEncodedString(v, - Py_FileSystemDefaultEncoding, NULL); + v = PyUnicode_EncodeFSDefault(v); if (v == NULL) return NULL; } @@ -1461,14 +1741,16 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, return &fd_package; } else { - char warnstr[MAXPATHLEN+80]; - sprintf(warnstr, "Not importing directory " - "'%.*s': missing __init__.py", - MAXPATHLEN, buf); - if (PyErr_WarnEx(PyExc_ImportWarning, - warnstr, 1)) { + int err; + PyObject *unicode = PyUnicode_DecodeFSDefault(buf); + if (unicode == NULL) + return NULL; + err = PyErr_WarnFormat(PyExc_ImportWarning, 1, + "Not importing directory '%U': missing __init__.py", + unicode); + Py_DECREF(unicode); + if (err) return NULL; - } } } #endif @@ -1548,22 +1830,6 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, return fdp; } -/* Helpers for main.c - * Find the source file corresponding to a named module - */ -struct filedescr * -_PyImport_FindModule(const char *name, PyObject *path, char *buf, - size_t buflen, FILE **p_fp, PyObject **p_loader) -{ - return find_module((char *) name, (char *) name, path, - buf, buflen, p_fp, p_loader); -} - -PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr * fd) -{ - return fd->type == PY_SOURCE || fd->type == PY_COMPILED; -} - /* case_ok(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name) * The arguments here are tricky, best shown by example: * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0 @@ -1718,8 +1984,8 @@ case_ok(char *buf, Py_ssize_t len, Py_ssize_t namelen, char *name) #endif } - #ifdef HAVE_STAT + /* Helper to look for __init__.py or __init__.py[co] in potential package */ static int find_init_module(char *buf) @@ -1771,15 +2037,52 @@ find_init_module(char *buf) static int init_builtin(char *); /* Forward */ +static PyObject* +load_builtin(char *name, char *pathname, int type) +{ + PyObject *m, *modules; + int err; + + if (pathname != NULL && pathname[0] != '\0') + name = pathname; + + if (type == C_BUILTIN) + err = init_builtin(name); + else + err = PyImport_ImportFrozenModule(name); + if (err < 0) + return NULL; + if (err == 0) { + PyErr_Format(PyExc_ImportError, + "Purported %s module %.200s not found", + type == C_BUILTIN ? + "builtin" : "frozen", + name); + return NULL; + } + + modules = PyImport_GetModuleDict(); + m = PyDict_GetItemString(modules, name); + if (m == NULL) { + PyErr_Format( + PyExc_ImportError, + "%s module %.200s not properly initialized", + type == C_BUILTIN ? + "builtin" : "frozen", + name); + return NULL; + } + Py_INCREF(m); + return m; +} + /* Load an external module using the default search path and return its module object WITH INCREMENTED REFERENCE COUNT */ static PyObject * load_module(char *name, FILE *fp, char *pathname, int type, PyObject *loader) { - PyObject *modules; PyObject *m; - int err; /* First check that there's an open file (if we need one) */ switch (type) { @@ -1815,34 +2118,7 @@ load_module(char *name, FILE *fp, char *pathname, int type, PyObject *loader) case C_BUILTIN: case PY_FROZEN: - if (pathname != NULL && pathname[0] != '\0') - name = pathname; - if (type == C_BUILTIN) - err = init_builtin(name); - else - err = PyImport_ImportFrozenModule(name); - if (err < 0) - return NULL; - if (err == 0) { - PyErr_Format(PyExc_ImportError, - "Purported %s module %.200s not found", - type == C_BUILTIN ? - "builtin" : "frozen", - name); - return NULL; - } - modules = PyImport_GetModuleDict(); - m = PyDict_GetItemString(modules, name); - if (m == NULL) { - PyErr_Format( - PyExc_ImportError, - "%s module %.200s not properly initialized", - type == C_BUILTIN ? - "builtin" : "frozen", - name); - return NULL; - } - Py_INCREF(m); + m = load_builtin(name, pathname, type); break; case IMP_HOOK: { @@ -1876,7 +2152,7 @@ init_builtin(char *name) { struct _inittab *p; - if (_PyImport_FindExtension(name, name) != NULL) + if (_PyImport_FindBuiltin(name) != NULL) return 1; for (p = PyImport_Inittab; p->name != NULL; p++) { @@ -1893,7 +2169,7 @@ init_builtin(char *name) mod = (*p->initfunc)(); if (mod == 0) return -1; - if (_PyImport_FixupExtension(mod, name, name) < 0) + if (_PyImport_FixupBuiltin(mod, name) < 0) return -1; /* FixupExtension has put the module into sys.modules, so we can release our own reference. */ @@ -2510,14 +2786,7 @@ ensure_fromlist(PyObject *mod, PyObject *fromlist, char *buf, Py_ssize_t buflen, char *subname; PyObject *submod; char *p; - if (!Py_FileSystemDefaultEncoding) { - item8 = PyUnicode_EncodeASCII(PyUnicode_AsUnicode(item), - PyUnicode_GetSize(item), - NULL); - } else { - item8 = PyUnicode_AsEncodedString(item, - Py_FileSystemDefaultEncoding, NULL); - } + item8 = PyUnicode_EncodeFSDefault(item); if (!item8) { PyErr_SetString(PyExc_ValueError, "Cannot encode path item"); return 0; @@ -2739,7 +3008,7 @@ PyImport_ReloadModule(PyObject *m) more accurately -- it invokes the __import__() function from the builtins of the current globals. This means that the import is done using whatever import hooks are installed in the current - environment, e.g. by "rexec". + environment. A dummy list ["__doc__"] is passed as the 4th argument so that e.g. PyImport_Import(PyUnicode_FromString("win32com.client.gencache")) will return <module "gencache"> instead of <module "win32com">. */ @@ -2753,6 +3022,7 @@ PyImport_Import(PyObject *module_name) PyObject *globals = NULL; PyObject *import = NULL; PyObject *builtins = NULL; + PyObject *modules = NULL; PyObject *r = NULL; /* Initialize constant string objects */ @@ -2763,7 +3033,7 @@ PyImport_Import(PyObject *module_name) builtins_str = PyUnicode_InternFromString("__builtins__"); if (builtins_str == NULL) return NULL; - silly_list = Py_BuildValue("[s]", "__doc__"); + silly_list = PyList_New(0); if (silly_list == NULL) return NULL; } @@ -2799,9 +3069,18 @@ PyImport_Import(PyObject *module_name) goto err; /* Call the __import__ function with the proper argument list - * Always use absolute import here. */ + Always use absolute import here. + Calling for side-effect of import. */ r = PyObject_CallFunction(import, "OOOOi", module_name, globals, globals, silly_list, 0, NULL); + if (r == NULL) + goto err; + Py_DECREF(r); + + modules = PyImport_GetModuleDict(); + r = PyDict_GetItem(modules, module_name); + if (r != NULL) + Py_INCREF(r); err: Py_XDECREF(globals); @@ -2817,19 +3096,31 @@ PyImport_Import(PyObject *module_name) */ static PyObject * -imp_get_magic(PyObject *self, PyObject *noargs) +imp_make_magic(long magic) { char buf[4]; - buf[0] = (char) ((pyc_magic >> 0) & 0xff); - buf[1] = (char) ((pyc_magic >> 8) & 0xff); - buf[2] = (char) ((pyc_magic >> 16) & 0xff); - buf[3] = (char) ((pyc_magic >> 24) & 0xff); + buf[0] = (char) ((magic >> 0) & 0xff); + buf[1] = (char) ((magic >> 8) & 0xff); + buf[2] = (char) ((magic >> 16) & 0xff); + buf[3] = (char) ((magic >> 24) & 0xff); return PyBytes_FromStringAndSize(buf, 4); } static PyObject * +imp_get_magic(PyObject *self, PyObject *noargs) +{ + return imp_make_magic(pyc_magic); +} + +static PyObject * +imp_get_tag(PyObject *self, PyObject *noargs) +{ + return PyUnicode_FromString(pyc_tag); +} + +static PyObject * imp_get_suffixes(PyObject *self, PyObject *noargs) { PyObject *list; @@ -2915,14 +3206,14 @@ call_find_module(char *name, PyObject *path) static PyObject * imp_find_module(PyObject *self, PyObject *args) { - char *name; + PyObject *name; PyObject *ret, *path = NULL; - if (!PyArg_ParseTuple(args, "es|O:find_module", - Py_FileSystemDefaultEncoding, &name, + if (!PyArg_ParseTuple(args, "O&|O:find_module", + PyUnicode_FSConverter, &name, &path)) return NULL; - ret = call_find_module(name, path); - PyMem_Free(name); + ret = call_find_module(PyBytes_AS_STRING(name), path); + Py_DECREF(name); return ret; } @@ -3040,23 +3331,23 @@ static PyObject * imp_load_compiled(PyObject *self, PyObject *args) { char *name; - char *pathname; + PyObject *pathname; PyObject *fob = NULL; PyObject *m; FILE *fp; - if (!PyArg_ParseTuple(args, "ses|O:load_compiled", + if (!PyArg_ParseTuple(args, "sO&|O:load_compiled", &name, - Py_FileSystemDefaultEncoding, &pathname, + PyUnicode_FSConverter, &pathname, &fob)) return NULL; - fp = get_file(pathname, fob, "rb"); + fp = get_file(PyBytes_AS_STRING(pathname), fob, "rb"); if (fp == NULL) { - PyMem_Free(pathname); + Py_DECREF(pathname); return NULL; } - m = load_compiled_module(name, pathname, fp); + m = load_compiled_module(name, PyBytes_AS_STRING(pathname), fp); fclose(fp); - PyMem_Free(pathname); + Py_DECREF(pathname); return m; } @@ -3066,24 +3357,24 @@ static PyObject * imp_load_dynamic(PyObject *self, PyObject *args) { char *name; + PyObject *pathbytes; char *pathname; PyObject *fob = NULL; PyObject *m; FILE *fp = NULL; - if (!PyArg_ParseTuple(args, "ses|O:load_dynamic", - &name, - Py_FileSystemDefaultEncoding, &pathname, - &fob)) + if (!PyArg_ParseTuple(args, "sO&|O:load_dynamic", + &name, PyUnicode_FSConverter, &pathbytes, &fob)) return NULL; + pathname = PyBytes_AS_STRING(pathbytes); if (fob) { fp = get_file(pathname, fob, "r"); if (fp == NULL) { - PyMem_Free(pathname); + Py_DECREF(pathbytes); return NULL; } } m = _PyImport_LoadDynamicModule(name, pathname, fp); - PyMem_Free(pathname); + Py_DECREF(pathbytes); if (fp) fclose(fp); return m; @@ -3095,22 +3386,22 @@ static PyObject * imp_load_source(PyObject *self, PyObject *args) { char *name; - char *pathname; + PyObject *pathname; PyObject *fob = NULL; PyObject *m; FILE *fp; - if (!PyArg_ParseTuple(args, "ses|O:load_source", + if (!PyArg_ParseTuple(args, "sO&|O:load_source", &name, - Py_FileSystemDefaultEncoding, &pathname, + PyUnicode_FSConverter, &pathname, &fob)) return NULL; - fp = get_file(pathname, fob, "r"); + fp = get_file(PyBytes_AS_STRING(pathname), fob, "r"); if (fp == NULL) { - PyMem_Free(pathname); + Py_DECREF(pathname); return NULL; } - m = load_source_module(name, pathname, fp); - PyMem_Free(pathname); + m = load_source_module(name, PyBytes_AS_STRING(pathname), fp); + Py_DECREF(pathname); fclose(fp); return m; } @@ -3120,16 +3411,16 @@ imp_load_module(PyObject *self, PyObject *args) { char *name; PyObject *fob; - char *pathname; + PyObject *pathname; PyObject * ret; char *suffix; /* Unused */ char *mode; int type; FILE *fp; - if (!PyArg_ParseTuple(args, "sOes(ssi):load_module", + if (!PyArg_ParseTuple(args, "sOO&(ssi):load_module", &name, &fob, - Py_FileSystemDefaultEncoding, &pathname, + PyUnicode_FSConverter, &pathname, &suffix, &mode, &type)) return NULL; if (*mode) { @@ -3140,7 +3431,7 @@ imp_load_module(PyObject *self, PyObject *args) if (!(*mode == 'r' || *mode == 'U') || strchr(mode, '+')) { PyErr_Format(PyExc_ValueError, "invalid file open mode %.200s", mode); - PyMem_Free(pathname); + Py_DECREF(pathname); return NULL; } } @@ -3149,12 +3440,12 @@ imp_load_module(PyObject *self, PyObject *args) else { fp = get_file(NULL, fob, mode); if (fp == NULL) { - PyMem_Free(pathname); + Py_DECREF(pathname); return NULL; } } - ret = load_module(name, fp, pathname, type, NULL); - PyMem_Free(pathname); + ret = load_module(name, fp, PyBytes_AS_STRING(pathname), type, NULL); + Py_DECREF(pathname); if (fp) fclose(fp); return ret; @@ -3164,13 +3455,13 @@ static PyObject * imp_load_package(PyObject *self, PyObject *args) { char *name; - char *pathname; + PyObject *pathname; PyObject * ret; - if (!PyArg_ParseTuple(args, "ses:load_package", - &name, Py_FileSystemDefaultEncoding, &pathname)) + if (!PyArg_ParseTuple(args, "sO&:load_package", + &name, PyUnicode_FSConverter, &pathname)) return NULL; - ret = load_package(name, pathname); - PyMem_Free(pathname); + ret = load_package(name, PyBytes_AS_STRING(pathname)); + Py_DECREF(pathname); return ret; } @@ -3194,6 +3485,82 @@ PyDoc_STRVAR(doc_reload, \n\ Reload the module. The module must have been successfully imported before."); +static PyObject * +imp_cache_from_source(PyObject *self, PyObject *args, PyObject *kws) +{ + static char *kwlist[] = {"path", "debug_override", NULL}; + + char buf[MAXPATHLEN+1]; + PyObject *pathbytes; + char *cpathname; + PyObject *debug_override = NULL; + int debug = !Py_OptimizeFlag; + + if (!PyArg_ParseTupleAndKeywords( + args, kws, "O&|O", kwlist, + PyUnicode_FSConverter, &pathbytes, &debug_override)) + return NULL; + + if (debug_override != NULL && + (debug = PyObject_IsTrue(debug_override)) < 0) { + Py_DECREF(pathbytes); + return NULL; + } + + cpathname = make_compiled_pathname( + PyBytes_AS_STRING(pathbytes), + buf, MAXPATHLEN+1, debug); + Py_DECREF(pathbytes); + + if (cpathname == NULL) { + PyErr_Format(PyExc_SystemError, "path buffer too short"); + return NULL; + } + return PyUnicode_DecodeFSDefault(buf); +} + +PyDoc_STRVAR(doc_cache_from_source, +"Given the path to a .py file, return the path to its .pyc/.pyo file.\n\ +\n\ +The .py file does not need to exist; this simply returns the path to the\n\ +.pyc/.pyo file calculated as if the .py file were imported. The extension\n\ +will be .pyc unless __debug__ is not defined, then it will be .pyo.\n\ +\n\ +If debug_override is not None, then it must be a boolean and is taken as\n\ +the value of __debug__ instead."); + +static PyObject * +imp_source_from_cache(PyObject *self, PyObject *args, PyObject *kws) +{ + static char *kwlist[] = {"path", NULL}; + + PyObject *pathname_obj; + char *pathname; + char buf[MAXPATHLEN+1]; + + if (!PyArg_ParseTupleAndKeywords( + args, kws, "O&", kwlist, + PyUnicode_FSConverter, &pathname_obj)) + return NULL; + + pathname = PyBytes_AS_STRING(pathname_obj); + if (make_source_pathname(pathname, buf) == NULL) { + PyErr_Format(PyExc_ValueError, "Not a PEP 3147 pyc path: %s", + pathname); + Py_DECREF(pathname_obj); + return NULL; + } + Py_DECREF(pathname_obj); + return PyUnicode_FromString(buf); +} + +PyDoc_STRVAR(doc_source_from_cache, +"Given the path to a .pyc./.pyo file, return the path to its .py file.\n\ +\n\ +The .pyc/.pyo file does not need to exist; this simply returns the path to\n\ +the .py file calculated to correspond to the .pyc/.pyo file. If path\n\ +does not conform to PEP 3147 format, ValueError will be raised."); + /* Doc strings */ PyDoc_STRVAR(doc_imp, @@ -3216,6 +3583,10 @@ PyDoc_STRVAR(doc_get_magic, "get_magic() -> string\n\ Return the magic number for .pyc or .pyo files."); +PyDoc_STRVAR(doc_get_tag, +"get_tag() -> string\n\ +Return the magic tag for .pyc or .pyo files."); + PyDoc_STRVAR(doc_get_suffixes, "get_suffixes() -> [(suffix, mode, type), ...]\n\ Return a list of (suffix, mode, type) tuples describing the files\n\ @@ -3246,6 +3617,7 @@ On platforms without threads, this function does nothing."); static PyMethodDef imp_methods[] = { {"find_module", imp_find_module, METH_VARARGS, doc_find_module}, {"get_magic", imp_get_magic, METH_NOARGS, doc_get_magic}, + {"get_tag", imp_get_tag, METH_NOARGS, doc_get_tag}, {"get_suffixes", imp_get_suffixes, METH_NOARGS, doc_get_suffixes}, {"load_module", imp_load_module, METH_VARARGS, doc_load_module}, {"new_module", imp_new_module, METH_VARARGS, doc_new_module}, @@ -3253,6 +3625,10 @@ static PyMethodDef imp_methods[] = { {"acquire_lock", imp_acquire_lock, METH_NOARGS, doc_acquire_lock}, {"release_lock", imp_release_lock, METH_NOARGS, doc_release_lock}, {"reload", imp_reload, METH_O, doc_reload}, + {"cache_from_source", (PyCFunction)imp_cache_from_source, + METH_VARARGS | METH_KEYWORDS, doc_cache_from_source}, + {"source_from_cache", (PyCFunction)imp_source_from_cache, + METH_VARARGS | METH_KEYWORDS, doc_source_from_cache}, /* The rest are obsolete */ {"get_frozen_object", imp_get_frozen_object, METH_VARARGS}, {"is_frozen_package", imp_is_frozen_package, METH_VARARGS}, @@ -3288,56 +3664,69 @@ typedef struct { static int NullImporter_init(NullImporter *self, PyObject *args, PyObject *kwds) { - char *path; - Py_ssize_t pathlen; +#ifndef MS_WINDOWS + PyObject *path; + struct stat statbuf; + int rv; if (!_PyArg_NoKeywords("NullImporter()", kwds)) return -1; - if (!PyArg_ParseTuple(args, "es:NullImporter", - Py_FileSystemDefaultEncoding, &path)) + if (!PyArg_ParseTuple(args, "O&:NullImporter", + PyUnicode_FSConverter, &path)) return -1; - pathlen = strlen(path); - if (pathlen == 0) { - PyMem_Free(path); + if (PyBytes_GET_SIZE(path) == 0) { + Py_DECREF(path); PyErr_SetString(PyExc_ImportError, "empty pathname"); return -1; - } else { -#ifndef MS_WINDOWS - struct stat statbuf; - int rv; - - rv = stat(path, &statbuf); - PyMem_Free(path); - if (rv == 0) { - /* it exists */ - if (S_ISDIR(statbuf.st_mode)) { - /* it's a directory */ - PyErr_SetString(PyExc_ImportError, - "existing directory"); - return -1; - } + } + + rv = stat(PyBytes_AS_STRING(path), &statbuf); + Py_DECREF(path); + if (rv == 0) { + /* it exists */ + if (S_ISDIR(statbuf.st_mode)) { + /* it's a directory */ + PyErr_SetString(PyExc_ImportError, "existing directory"); + return -1; } + } #else /* MS_WINDOWS */ - DWORD rv; - /* see issue1293 and issue3677: - * stat() on Windows doesn't recognise paths like - * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs. - */ - rv = GetFileAttributesA(path); - PyMem_Free(path); - if (rv != INVALID_FILE_ATTRIBUTES) { - /* it exists */ - if (rv & FILE_ATTRIBUTE_DIRECTORY) { - /* it's a directory */ - PyErr_SetString(PyExc_ImportError, - "existing directory"); - return -1; - } + PyObject *pathobj; + DWORD rv; + wchar_t *path; + + if (!_PyArg_NoKeywords("NullImporter()", kwds)) + return -1; + + if (!PyArg_ParseTuple(args, "U:NullImporter", + &pathobj)) + return -1; + + if (PyUnicode_GET_SIZE(pathobj) == 0) { + PyErr_SetString(PyExc_ImportError, "empty pathname"); + return -1; + } + + path = PyUnicode_AsWideCharString(pathobj, NULL); + if (path == NULL) + return -1; + /* see issue1293 and issue3677: + * stat() on Windows doesn't recognise paths like + * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs. + */ + rv = GetFileAttributesW(path); + PyMem_Free(path); + if (rv != INVALID_FILE_ATTRIBUTES) { + /* it exists */ + if (rv & FILE_ATTRIBUTE_DIRECTORY) { + /* it's a directory */ + PyErr_SetString(PyExc_ImportError, "existing directory"); + return -1; } -#endif } +#endif return 0; } @@ -3440,7 +3829,6 @@ PyInit_imp(void) failure: Py_XDECREF(m); return NULL; - } diff --git a/Python/importdl.c b/Python/importdl.c index 507222b0c2..9caed453aa 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -27,10 +27,16 @@ _PyImport_LoadDynamicModule(char *name, char *pathname, FILE *fp) dl_funcptr p0; PyObject* (*p)(void); struct PyModuleDef *def; + PyObject *result; - if ((m = _PyImport_FindExtension(name, pathname)) != NULL) { + path = PyUnicode_DecodeFSDefault(pathname); + if (path == NULL) + return NULL; + + if ((m = _PyImport_FindExtensionUnicode(name, path)) != NULL) { Py_INCREF(m); - return m; + result = m; + goto finally; } lastdot = strrchr(name, '.'); if (lastdot == NULL) { @@ -45,26 +51,26 @@ _PyImport_LoadDynamicModule(char *name, char *pathname, FILE *fp) p0 = _PyImport_GetDynLoadFunc(name, shortname, pathname, fp); p = (PyObject*(*)(void))p0; if (PyErr_Occurred()) - return NULL; + goto error; if (p == NULL) { PyErr_Format(PyExc_ImportError, "dynamic module does not define init function (PyInit_%.200s)", shortname); - return NULL; + goto error; } oldcontext = _Py_PackageContext; _Py_PackageContext = packagecontext; m = (*p)(); _Py_PackageContext = oldcontext; if (m == NULL) - return NULL; + goto error; if (PyErr_Occurred()) { Py_DECREF(m); PyErr_Format(PyExc_SystemError, "initialization of %s raised unreported exception", shortname); - return NULL; + goto error; } /* Remember pointer to module init function. */ @@ -72,17 +78,25 @@ _PyImport_LoadDynamicModule(char *name, char *pathname, FILE *fp) def->m_base.m_init = p; /* Remember the filename as the __file__ attribute */ - path = PyUnicode_DecodeFSDefault(pathname); if (PyModule_AddObject(m, "__file__", path) < 0) PyErr_Clear(); /* Not important enough to report */ + else + Py_INCREF(path); - if (_PyImport_FixupExtension(m, name, pathname) < 0) - return NULL; + if (_PyImport_FixupExtensionUnicode(m, name, path) < 0) + goto error; if (Py_VerboseFlag) PySys_WriteStderr( "import %s # dynamically loaded from %s\n", name, pathname); - return m; + result = m; + goto finally; + +error: + result = NULL; +finally: + Py_DECREF(path); + return result; } #endif /* HAVE_DYNAMIC_LOADING */ diff --git a/Python/marshal.c b/Python/marshal.c index 21093eec45..73d4f374cd 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -254,7 +254,6 @@ w_object(PyObject *v, WFILE *p) PyMem_Free(buf); } } -#ifndef WITHOUT_COMPLEX else if (PyComplex_CheckExact(v)) { if (p->version > 1) { unsigned char buf[8]; @@ -297,7 +296,6 @@ w_object(PyObject *v, WFILE *p) PyMem_Free(buf); } } -#endif else if (PyBytes_CheckExact(v)) { w_byte(TYPE_STRING, p); n = PyBytes_GET_SIZE(v); @@ -714,7 +712,6 @@ r_object(RFILE *p) break; } -#ifndef WITHOUT_COMPLEX case TYPE_COMPLEX: { char buf[256]; @@ -773,7 +770,6 @@ r_object(RFILE *p) retval = PyComplex_FromCComplex(c); break; } -#endif case TYPE_STRING: n = r_long(p); @@ -1082,23 +1078,13 @@ getfilesize(FILE *fp) PyObject * PyMarshal_ReadLastObjectFromFile(FILE *fp) { -/* 75% of 2.1's .pyc files can exploit SMALL_FILE_LIMIT. - * REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. - */ -#define SMALL_FILE_LIMIT (1L << 14) +/* REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. */ #define REASONABLE_FILE_LIMIT (1L << 18) #ifdef HAVE_FSTAT off_t filesize; -#endif -#ifdef HAVE_FSTAT filesize = getfilesize(fp); - if (filesize > 0) { - char buf[SMALL_FILE_LIMIT]; - char* pBuf = NULL; - if (filesize <= SMALL_FILE_LIMIT) - pBuf = buf; - else if (filesize <= REASONABLE_FILE_LIMIT) - pBuf = (char *)PyMem_MALLOC(filesize); + if (filesize > 0 && filesize <= REASONABLE_FILE_LIMIT) { + char* pBuf = (char *)PyMem_MALLOC(filesize); if (pBuf != NULL) { PyObject* v; size_t n; @@ -1106,8 +1092,7 @@ PyMarshal_ReadLastObjectFromFile(FILE *fp) is smaller than REASONABLE_FILE_LIMIT */ n = fread(pBuf, 1, (int)filesize, fp); v = PyMarshal_ReadObjectFromString(pBuf, n); - if (pBuf != buf) - PyMem_FREE(pBuf); + PyMem_FREE(pBuf); return v; } @@ -1118,7 +1103,6 @@ PyMarshal_ReadLastObjectFromFile(FILE *fp) */ return PyMarshal_ReadObjectFromFile(fp); -#undef SMALL_FILE_LIMIT #undef REASONABLE_FILE_LIMIT } diff --git a/Python/modsupport.c b/Python/modsupport.c index f405bae9d2..85b0d66358 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -279,11 +279,9 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags) return PyFloat_FromDouble( (double)va_arg(*p_va, va_double)); -#ifndef WITHOUT_COMPLEX case 'D': return PyComplex_FromCComplex( *((Py_complex *)va_arg(*p_va, Py_complex *))); -#endif /* WITHOUT_COMPLEX */ case 'c': { @@ -304,39 +302,7 @@ do_mkvalue(const char **p_format, va_list *p_va, int flags) case 's': case 'z': - { - PyObject *v; - char *str = va_arg(*p_va, char *); - Py_ssize_t n; - if (**p_format == '#') { - ++*p_format; - if (flags & FLAG_SIZE_T) - n = va_arg(*p_va, Py_ssize_t); - else - n = va_arg(*p_va, int); - } - else - n = -1; - if (str == NULL) { - v = Py_None; - Py_INCREF(v); - } - else { - if (n < 0) { - size_t m = strlen(str); - if (m > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "string too long for Python string"); - return NULL; - } - n = (Py_ssize_t)m; - } - v = PyUnicode_FromStringAndSize(str, n); - } - return v; - } - - case 'U': + case 'U': /* XXX deprecated alias */ { PyObject *v; char *str = va_arg(*p_va, char *); @@ -490,15 +456,7 @@ va_build_value(const char *format, va_list va, int flags) int n = countformat(f, '\0'); va_list lva; -#ifdef VA_LIST_IS_ARRAY - memcpy(lva, va, sizeof(va_list)); -#else -#ifdef __va_copy - __va_copy(lva, va); -#else - lva = va; -#endif -#endif + Py_VA_COPY(lva, va); if (n < 0) return NULL; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index c47c7c836a..a91da79be6 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -4,7 +4,7 @@ static void *opcode_targets[256] = { &&TARGET_ROT_TWO, &&TARGET_ROT_THREE, &&TARGET_DUP_TOP, - &&TARGET_ROT_FOUR, + &&TARGET_DUP_TOP_TWO, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, @@ -98,7 +98,7 @@ static void *opcode_targets[256] = { &&TARGET_DELETE_ATTR, &&TARGET_STORE_GLOBAL, &&TARGET_DELETE_GLOBAL, - &&TARGET_DUP_TOPX, + &&_unknown_opcode, &&TARGET_LOAD_CONST, &&TARGET_LOAD_NAME, &&TARGET_BUILD_TUPLE, @@ -137,13 +137,13 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_CLOSURE, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, - &&_unknown_opcode, + &&TARGET_DELETE_DEREF, &&_unknown_opcode, &&TARGET_CALL_FUNCTION_VAR, &&TARGET_CALL_FUNCTION_KW, &&TARGET_CALL_FUNCTION_VAR_KW, + &&TARGET_SETUP_WITH, &&TARGET_EXTENDED_ARG, - &&_unknown_opcode, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, diff --git a/Python/peephole.c b/Python/peephole.c index 06e7fe6fd5..6985043917 100644 --- a/Python/peephole.c +++ b/Python/peephole.c @@ -4,10 +4,8 @@ #include "Python-ast.h" #include "node.h" -#include "pyarena.h" #include "ast.h" #include "code.h" -#include "compile.h" #include "symtable.h" #include "opcode.h" @@ -31,7 +29,8 @@ new constant (c1, c2, ... cn) can be appended. Called with codestr pointing to the first LOAD_CONST. Bails out with no change if one or more of the LOAD_CONSTs is missing. - Also works for BUILD_LIST when followed by an "in" or "not in" test. + Also works for BUILD_LIST and BUILT_SET when followed by an "in" or "not in" + test; for BUILD_SET it assembles a frozenset rather than a tuple. */ static int tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts) @@ -41,7 +40,7 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts) /* Pre-conditions */ assert(PyList_CheckExact(consts)); - assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST); + assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST || codestr[n*3] == BUILD_SET); assert(GETARG(codestr, (n*3)) == n); for (i=0 ; i<n ; i++) assert(codestr[i*3] == LOAD_CONST); @@ -59,6 +58,16 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n, PyObject *consts) PyTuple_SET_ITEM(newconst, i, constant); } + /* If it's a BUILD_SET, use the PyTuple we just built to create a + PyFrozenSet, and use that as the constant instead: */ + if (codestr[n*3] == BUILD_SET) { + PyObject *tuple = newconst; + newconst = PyFrozenSet_New(tuple); + Py_DECREF(tuple); + if (newconst == NULL) + return 0; + } + /* Append folded constant onto consts */ if (PyList_Append(consts, newconst)) { Py_DECREF(newconst); @@ -148,13 +157,16 @@ fold_binops_on_constants(unsigned char *codestr, PyObject *consts) return 0; } if (newconst == NULL) { - PyErr_Clear(); + if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) + PyErr_Clear(); return 0; } size = PyObject_Size(newconst); - if (size == -1) + if (size == -1) { + if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) + return 0; PyErr_Clear(); - else if (size > 20) { + } else if (size > 20) { Py_DECREF(newconst); return 0; } @@ -197,6 +209,9 @@ fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts) case UNARY_INVERT: newconst = PyNumber_Invert(v); break; + case UNARY_POSITIVE: + newconst = PyNumber_Positive(v); + break; default: /* Called with an unknown opcode */ PyErr_Format(PyExc_SystemError, @@ -205,7 +220,8 @@ fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts) return 0; } if (newconst == NULL) { - PyErr_Clear(); + if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) + PyErr_Clear(); return 0; } @@ -251,6 +267,7 @@ markblocks(unsigned char *code, Py_ssize_t len) case SETUP_LOOP: case SETUP_EXCEPT: case SETUP_FINALLY: + case SETUP_WITH: j = GETJUMPTGT(code, i); blocks[j] = 1; break; @@ -432,20 +449,21 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, cumlc = 0; break; - /* Try to fold tuples of constants (includes a case for lists + /* Try to fold tuples of constants (includes a case for lists and sets which are only used for "in" and "not in" tests). Skip over BUILD_SEQN 1 UNPACK_SEQN 1. Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2. Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */ case BUILD_TUPLE: case BUILD_LIST: + case BUILD_SET: j = GETARG(codestr, i); h = i - 3 * j; if (h >= 0 && j <= lastlc && ((opcode == BUILD_TUPLE && ISBASICBLOCK(blocks, h, 3*(j+1))) || - (opcode == BUILD_LIST && + ((opcode == BUILD_LIST || opcode == BUILD_SET) && codestr[i+3]==COMPARE_OP && ISBASICBLOCK(blocks, h, 3*(j+2)) && (GETARG(codestr,i+3)==6 || @@ -457,7 +475,8 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, } if (codestr[i+3] != UNPACK_SEQUENCE || !ISBASICBLOCK(blocks,i,6) || - j != GETARG(codestr, i+3)) + j != GETARG(codestr, i+3) || + opcode == BUILD_SET) continue; if (j == 1) { memset(codestr+i, NOP, 6); @@ -499,6 +518,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ case UNARY_NEGATIVE: case UNARY_INVERT: + case UNARY_POSITIVE: if (lastlc >= 1 && ISBASICBLOCK(blocks, i-3, 4) && fold_unaryops_on_constants(&codestr[i-3], consts)) { @@ -566,6 +586,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, case SETUP_LOOP: case SETUP_EXCEPT: case SETUP_FINALLY: + case SETUP_WITH: tgt = GETJUMPTGT(codestr, i); /* Replace JUMP_* to a RETURN into just a RETURN */ if (UNCONDITIONAL_JUMP(opcode) && @@ -648,6 +669,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, case SETUP_LOOP: case SETUP_EXCEPT: case SETUP_FINALLY: + case SETUP_WITH: j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3; SETARG(codestr, i, j); break; diff --git a/Python/pyarena.c b/Python/pyarena.c index 2d63638856..5a255ae497 100644 --- a/Python/pyarena.c +++ b/Python/pyarena.c @@ -1,5 +1,4 @@ #include "Python.h" -#include "pyarena.h" /* A simple arena block structure. diff --git a/Python/pymath.c b/Python/pymath.c index 9159b6ed51..827a773a6a 100644 --- a/Python/pymath.c +++ b/Python/pymath.c @@ -77,202 +77,3 @@ round(double x) return copysign(y, x); } #endif /* HAVE_ROUND */ - -#ifndef HAVE_LOG1P -#include <float.h> - -double -log1p(double x) -{ - /* For x small, we use the following approach. Let y be the nearest - float to 1+x, then - - 1+x = y * (1 - (y-1-x)/y) - - so log(1+x) = log(y) + log(1-(y-1-x)/y). Since (y-1-x)/y is tiny, - the second term is well approximated by (y-1-x)/y. If abs(x) >= - DBL_EPSILON/2 or the rounding-mode is some form of round-to-nearest - then y-1-x will be exactly representable, and is computed exactly - by (y-1)-x. - - If abs(x) < DBL_EPSILON/2 and the rounding mode is not known to be - round-to-nearest then this method is slightly dangerous: 1+x could - be rounded up to 1+DBL_EPSILON instead of down to 1, and in that - case y-1-x will not be exactly representable any more and the - result can be off by many ulps. But this is easily fixed: for a - floating-point number |x| < DBL_EPSILON/2., the closest - floating-point number to log(1+x) is exactly x. - */ - - double y; - if (fabs(x) < DBL_EPSILON/2.) { - return x; - } else if (-0.5 <= x && x <= 1.) { - /* WARNING: it's possible than an overeager compiler - will incorrectly optimize the following two lines - to the equivalent of "return log(1.+x)". If this - happens, then results from log1p will be inaccurate - for small x. */ - y = 1.+x; - return log(y)-((y-1.)-x)/y; - } else { - /* NaNs and infinities should end up here */ - return log(1.+x); - } -} -#endif /* HAVE_LOG1P */ - -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -static const double ln2 = 6.93147180559945286227E-01; -static const double two_pow_m28 = 3.7252902984619141E-09; /* 2**-28 */ -static const double two_pow_p28 = 268435456.0; /* 2**28 */ -static const double zero = 0.0; - -/* asinh(x) - * Method : - * Based on - * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ] - * we have - * asinh(x) := x if 1+x*x=1, - * := sign(x)*(log(x)+ln2)) for large |x|, else - * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else - * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2))) - */ - -#ifndef HAVE_ASINH -double -asinh(double x) -{ - double w; - double absx = fabs(x); - - if (Py_IS_NAN(x) || Py_IS_INFINITY(x)) { - return x+x; - } - if (absx < two_pow_m28) { /* |x| < 2**-28 */ - return x; /* return x inexact except 0 */ - } - if (absx > two_pow_p28) { /* |x| > 2**28 */ - w = log(absx)+ln2; - } - else if (absx > 2.0) { /* 2 < |x| < 2**28 */ - w = log(2.0*absx + 1.0 / (sqrt(x*x + 1.0) + absx)); - } - else { /* 2**-28 <= |x| < 2= */ - double t = x*x; - w = log1p(absx + t / (1.0 + sqrt(1.0 + t))); - } - return copysign(w, x); - -} -#endif /* HAVE_ASINH */ - -/* acosh(x) - * Method : - * Based on - * acosh(x) = log [ x + sqrt(x*x-1) ] - * we have - * acosh(x) := log(x)+ln2, if x is large; else - * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else - * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1. - * - * Special cases: - * acosh(x) is NaN with signal if x<1. - * acosh(NaN) is NaN without signal. - */ - -#ifndef HAVE_ACOSH -double -acosh(double x) -{ - if (Py_IS_NAN(x)) { - return x+x; - } - if (x < 1.) { /* x < 1; return a signaling NaN */ - errno = EDOM; -#ifdef Py_NAN - return Py_NAN; -#else - return (x-x)/(x-x); -#endif - } - else if (x >= two_pow_p28) { /* x > 2**28 */ - if (Py_IS_INFINITY(x)) { - return x+x; - } else { - return log(x)+ln2; /* acosh(huge)=log(2x) */ - } - } - else if (x == 1.) { - return 0.0; /* acosh(1) = 0 */ - } - else if (x > 2.) { /* 2 < x < 2**28 */ - double t = x*x; - return log(2.0*x - 1.0 / (x + sqrt(t - 1.0))); - } - else { /* 1 < x <= 2 */ - double t = x - 1.0; - return log1p(t + sqrt(2.0*t + t*t)); - } -} -#endif /* HAVE_ACOSH */ - -/* atanh(x) - * Method : - * 1.Reduced x to positive by atanh(-x) = -atanh(x) - * 2.For x>=0.5 - * 1 2x x - * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) - * 2 1 - x 1 - x - * - * For x<0.5 - * atanh(x) = 0.5*log1p(2x+2x*x/(1-x)) - * - * Special cases: - * atanh(x) is NaN if |x| >= 1 with signal; - * atanh(NaN) is that NaN with no signal; - * - */ - -#ifndef HAVE_ATANH -double -atanh(double x) -{ - double absx; - double t; - - if (Py_IS_NAN(x)) { - return x+x; - } - absx = fabs(x); - if (absx >= 1.) { /* |x| >= 1 */ - errno = EDOM; -#ifdef Py_NAN - return Py_NAN; -#else - return x/zero; -#endif - } - if (absx < two_pow_m28) { /* |x| < 2**-28 */ - return x; - } - if (absx < 0.5) { /* |x| < 0.5 */ - t = absx+absx; - t = 0.5 * log1p(t + t*absx / (1.0 - absx)); - } - else { /* 0.5 <= |x| <= 1.0 */ - t = 0.5 * log1p((absx + absx) / (1.0 - absx)); - } - return copysign(t, x); -} -#endif /* HAVE_ATANH */ diff --git a/Python/pystate.c b/Python/pystate.c index ea0d05d833..922e9a3780 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -47,7 +47,9 @@ static int autoTLSkey = 0; static PyInterpreterState *interp_head = NULL; -PyThreadState *_PyThreadState_Current = NULL; +/* Assuming the current thread holds the GIL, this is the + PyThreadState for the current thread. */ +_Py_atomic_address _PyThreadState_Current = {NULL}; PyThreadFrameGetter _PyThreadState_GetFrame = NULL; #ifdef WITH_THREAD @@ -334,7 +336,7 @@ tstate_delete_common(PyThreadState *tstate) void PyThreadState_Delete(PyThreadState *tstate) { - if (tstate == _PyThreadState_Current) + if (tstate == _Py_atomic_load_relaxed(&_PyThreadState_Current)) Py_FatalError("PyThreadState_Delete: tstate is still current"); tstate_delete_common(tstate); #ifdef WITH_THREAD @@ -348,11 +350,12 @@ PyThreadState_Delete(PyThreadState *tstate) void PyThreadState_DeleteCurrent() { - PyThreadState *tstate = _PyThreadState_Current; + PyThreadState *tstate = (PyThreadState*)_Py_atomic_load_relaxed( + &_PyThreadState_Current); if (tstate == NULL) Py_FatalError( "PyThreadState_DeleteCurrent: no current tstate"); - _PyThreadState_Current = NULL; + _Py_atomic_store_relaxed(&_PyThreadState_Current, NULL); tstate_delete_common(tstate); if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) PyThread_delete_key_value(autoTLSkey); @@ -364,19 +367,22 @@ PyThreadState_DeleteCurrent() PyThreadState * PyThreadState_Get(void) { - if (_PyThreadState_Current == NULL) + PyThreadState *tstate = (PyThreadState*)_Py_atomic_load_relaxed( + &_PyThreadState_Current); + if (tstate == NULL) Py_FatalError("PyThreadState_Get: no current thread"); - return _PyThreadState_Current; + return tstate; } PyThreadState * PyThreadState_Swap(PyThreadState *newts) { - PyThreadState *oldts = _PyThreadState_Current; + PyThreadState *oldts = (PyThreadState*)_Py_atomic_load_relaxed( + &_PyThreadState_Current); - _PyThreadState_Current = newts; + _Py_atomic_store_relaxed(&_PyThreadState_Current, newts); /* It should not be possible for more than one thread state to be used for a thread. Check this the best we can in debug builds. @@ -405,16 +411,18 @@ PyThreadState_Swap(PyThreadState *newts) PyObject * PyThreadState_GetDict(void) { - if (_PyThreadState_Current == NULL) + PyThreadState *tstate = (PyThreadState*)_Py_atomic_load_relaxed( + &_PyThreadState_Current); + if (tstate == NULL) return NULL; - if (_PyThreadState_Current->dict == NULL) { + if (tstate->dict == NULL) { PyObject *d; - _PyThreadState_Current->dict = d = PyDict_New(); + tstate->dict = d = PyDict_New(); if (d == NULL) PyErr_Clear(); } - return _PyThreadState_Current->dict; + return tstate->dict; } @@ -453,6 +461,7 @@ PyThreadState_SetAsyncExc(long id, PyObject *exc) { p->async_exc = exc; HEAD_UNLOCK(); Py_XDECREF(old_exc); + _PyEval_SignalAsyncExc(); return 1; } } @@ -549,10 +558,7 @@ PyThreadState_IsCurrent(PyThreadState *tstate) { /* Must be the tstate for this thread */ assert(PyGILState_GetThisThreadState()==tstate); - /* On Windows at least, simple reads and writes to 32 bit values - are atomic. - */ - return tstate == _PyThreadState_Current; + return tstate == _Py_atomic_load_relaxed(&_PyThreadState_Current); } /* Internal initialization/finalization functions called by @@ -563,6 +569,8 @@ _PyGILState_Init(PyInterpreterState *i, PyThreadState *t) { assert(i && t); /* must init with valid states */ autoTLSkey = PyThread_create_key(); + if (autoTLSkey == -1) + Py_FatalError("Could not allocate TLS entry"); autoInterpreterState = i; assert(PyThread_get_key_value(autoTLSkey) == NULL); assert(t->gilstate_counter == 0); diff --git a/Python/pystrtod.c b/Python/pystrtod.c index f7ddd13d99..75e3032fb7 100644 --- a/Python/pystrtod.c +++ b/Python/pystrtod.c @@ -3,11 +3,8 @@ #include <Python.h> #include <locale.h> -/* _Py_parse_inf_or_nan: Attempt to parse a string of the form "nan", "inf" or - "infinity", with an optional leading sign of "+" or "-". On success, - return the NaN or Infinity as a double and set *endptr to point just beyond - the successfully parsed portion of the string. On failure, return -1.0 and - set *endptr to point to the start of the string. */ +/* Case-insensitive string match used for nan and inf detection; t should be + lower-case. Returns 1 for a successful match, 0 otherwise. */ static int case_insensitive_match(const char *s, const char *t) @@ -19,6 +16,12 @@ case_insensitive_match(const char *s, const char *t) return *t ? 0 : 1; } +/* _Py_parse_inf_or_nan: Attempt to parse a string of the form "nan", "inf" or + "infinity", with an optional leading sign of "+" or "-". On success, + return the NaN or Infinity as a double and set *endptr to point just beyond + the successfully parsed portion of the string. On failure, return -1.0 and + set *endptr to point to the start of the string. */ + double _Py_parse_inf_or_nan(const char *p, char **endptr) { @@ -55,7 +58,7 @@ _Py_parse_inf_or_nan(const char *p, char **endptr) } /** - * PyOS_ascii_strtod: + * _PyOS_ascii_strtod: * @nptr: the string to convert to a numeric value. * @endptr: if non-%NULL, it returns the character after * the last character used in the conversion. @@ -85,7 +88,7 @@ _Py_parse_inf_or_nan(const char *p, char **endptr) #ifndef PY_NO_SHORT_FLOAT_REPR -double +static double _PyOS_ascii_strtod(const char *nptr, char **endptr) { double result; @@ -118,7 +121,7 @@ _PyOS_ascii_strtod(const char *nptr, char **endptr) correctly rounded results. */ -double +static double _PyOS_ascii_strtod(const char *nptr, char **endptr) { char *fail_pos; @@ -267,48 +270,10 @@ _PyOS_ascii_strtod(const char *nptr, char **endptr) #endif -/* PyOS_ascii_strtod is DEPRECATED in Python 3.1 */ - -double -PyOS_ascii_strtod(const char *nptr, char **endptr) -{ - char *fail_pos; - const char *p; - double x; - - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "PyOS_ascii_strtod and PyOS_ascii_atof are " - "deprecated. Use PyOS_string_to_double " - "instead.", 1) < 0) - return -1.0; - - /* _PyOS_ascii_strtod already does everything that we want, - except that it doesn't parse leading whitespace */ - p = nptr; - while (Py_ISSPACE(*p)) - p++; - x = _PyOS_ascii_strtod(p, &fail_pos); - if (fail_pos == p) - fail_pos = (char *)nptr; - if (endptr) - *endptr = (char *)fail_pos; - return x; -} - -/* PyOS_ascii_strtod is DEPRECATED in Python 3.1 */ - -double -PyOS_ascii_atof(const char *nptr) -{ - return PyOS_ascii_strtod(nptr, NULL); -} - -/* PyOS_string_to_double is the recommended replacement for the deprecated - PyOS_ascii_strtod and PyOS_ascii_atof functions. It converts a - null-terminated byte string s (interpreted as a string of ASCII characters) - to a float. The string should not have leading or trailing whitespace (in - contrast, PyOS_ascii_strtod allows leading whitespace but not trailing - whitespace). The conversion is independent of the current locale. +/* PyOS_string_to_double converts a null-terminated byte string s (interpreted + as a string of ASCII characters) to a float. The string should not have + leading or trailing whitespace. The conversion is independent of the + current locale. If endptr is NULL, try to convert the whole string. Raise ValueError and return -1.0 if the string is not a valid representation of a floating-point @@ -366,6 +331,8 @@ PyOS_string_to_double(const char *s, return result; } +#ifdef PY_NO_SHORT_FLOAT_REPR + /* Given a string that may have a decimal point in the current locale, change it back to a dot. Since the string cannot get longer, no need for a maximum buffer size parameter. */ @@ -615,12 +582,13 @@ ensure_decimal_point(char* buffer, size_t buf_size, int precision) #define FLOAT_FORMATBUFLEN 120 /** - * PyOS_ascii_formatd: + * _PyOS_ascii_formatd: * @buffer: A buffer to place the resulting string in * @buf_size: The length of the buffer. * @format: The printf()-style format to use for the * code to use for converting. * @d: The #gdouble to convert + * @precision: The precision to use when formatting. * * Converts a #gdouble to a string, using the '.' as * decimal point. To format the number you pass in @@ -633,7 +601,7 @@ ensure_decimal_point(char* buffer, size_t buf_size, int precision) * Return value: The pointer to the buffer with the converted string. * On failure returns NULL but does not set any Python exception. **/ -char * +static char * _PyOS_ascii_formatd(char *buffer, size_t buf_size, const char *format, @@ -713,22 +681,6 @@ _PyOS_ascii_formatd(char *buffer, return buffer; } -char * -PyOS_ascii_formatd(char *buffer, - size_t buf_size, - const char *format, - double d) -{ - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "PyOS_ascii_formatd is deprecated, " - "use PyOS_double_to_string instead", 1) < 0) - return NULL; - - return _PyOS_ascii_formatd(buffer, buf_size, format, d, -1); -} - -#ifdef PY_NO_SHORT_FLOAT_REPR - /* The fallback code to use if _Py_dg_dtoa is not available. */ PyAPI_FUNC(char *) PyOS_double_to_string(double val, diff --git a/Python/pythonrun.c b/Python/pythonrun.c index c6cf088232..8e97d7fc24 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -11,14 +11,10 @@ #include "parsetok.h" #include "errcode.h" #include "code.h" -#include "compile.h" #include "symtable.h" -#include "pyarena.h" #include "ast.h" -#include "eval.h" #include "marshal.h" #include "osdefs.h" -#include "abstract.h" #ifdef HAVE_SIGNAL_H #include <signal.h> @@ -57,6 +53,7 @@ extern grammar _PyParser_Grammar; /* From graminit.c */ /* Forward */ static void initmain(void); +static void initfsencoding(void); static void initsite(void); static int initstdio(void); static void flush_io(void); @@ -81,6 +78,7 @@ extern void _PyGILState_Fini(void); int Py_DebugFlag; /* Needed by parser.c */ int Py_VerboseFlag; /* Needed by import.c */ +int Py_QuietFlag; /* Needed by sysmodule.c */ int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ int Py_InspectFlag; /* Needed to determine whether to exit at SystemError */ int Py_NoSiteFlag; /* Suppress 'import site' */ @@ -133,18 +131,13 @@ add_flag(int flag, const char *envs) return flag; } -#if defined(HAVE_LANGINFO_H) && defined(CODESET) static char* -get_codeset(void) +get_codec_name(const char *encoding) { - char* codeset; - PyObject *codec, *name; - - codeset = nl_langinfo(CODESET); - if (!codeset || codeset[0] == '\0') - return NULL; + char *name_utf8, *name_str; + PyObject *codec, *name = NULL; - codec = _PyCodec_Lookup(codeset); + codec = _PyCodec_Lookup(encoding); if (!codec) goto error; @@ -153,15 +146,34 @@ get_codeset(void) if (!name) goto error; - codeset = strdup(_PyUnicode_AsString(name)); + name_utf8 = _PyUnicode_AsString(name); + if (name == NULL) + goto error; + name_str = strdup(name_utf8); Py_DECREF(name); - return codeset; + if (name_str == NULL) { + PyErr_NoMemory(); + return NULL; + } + return name_str; error: Py_XDECREF(codec); - PyErr_Clear(); + Py_XDECREF(name); return NULL; } + +#if defined(HAVE_LANGINFO_H) && defined(CODESET) +static char* +get_codeset(void) +{ + char* codeset = nl_langinfo(CODESET); + if (!codeset || codeset[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "CODESET is not set or empty"); + return NULL; + } + return get_codec_name(codeset); +} #endif void @@ -171,16 +183,13 @@ Py_InitializeEx(int install_sigs) PyThreadState *tstate; PyObject *bimod, *sysmod, *pstderr; char *p; -#if defined(HAVE_LANGINFO_H) && defined(CODESET) - char *codeset; -#endif extern void _Py_ReadyTypes(void); if (initialized) return; initialized = 1; -#ifdef HAVE_SETLOCALE +#if defined(HAVE_LANGINFO_H) && defined(HAVE_SETLOCALE) /* Set up the LC_CTYPE locale, so we can obtain the locale's charset without having to switch locales. */ @@ -205,6 +214,18 @@ Py_InitializeEx(int install_sigs) Py_FatalError("Py_Initialize: can't make first thread"); (void) PyThreadState_Swap(tstate); +#ifdef WITH_THREAD + /* We can't call _PyEval_FiniThreads() in Py_Finalize because + destroying the GIL might fail when it is being referenced from + another running thread (see issue #9901). + Instead we destroy the previously created GIL here, which ensures + that we can call Py_Initialize / Py_Finalize multiple times. */ + _PyEval_FiniThreads(); + + /* Auto-thread-state API */ + _PyGILState_Init(interp, tstate); +#endif /* WITH_THREAD */ + _Py_ReadyTypes(); if (!_PyFrame_Init()) @@ -231,7 +252,7 @@ Py_InitializeEx(int install_sigs) bimod = _PyBuiltin_Init(); if (bimod == NULL) Py_FatalError("Py_Initialize: can't initialize builtins modules"); - _PyImport_FixupExtension(bimod, "builtins", "builtins"); + _PyImport_FixupBuiltin(bimod, "builtins"); interp->builtins = PyModule_GetDict(bimod); if (interp->builtins == NULL) Py_FatalError("Py_Initialize: can't initialize builtins dict"); @@ -247,7 +268,7 @@ Py_InitializeEx(int install_sigs) if (interp->sysdict == NULL) Py_FatalError("Py_Initialize: can't initialize sys dict"); Py_INCREF(interp->sysdict); - _PyImport_FixupExtension(sysmod, "sys", "sys"); + _PyImport_FixupBuiltin(sysmod, "sys"); PySys_SetPath(Py_GetPath()); PyDict_SetItemString(interp->sysdict, "modules", interp->modules); @@ -268,42 +289,27 @@ Py_InitializeEx(int install_sigs) /* Initialize _warnings. */ _PyWarnings_Init(); -#if defined(HAVE_LANGINFO_H) && defined(CODESET) - /* On Unix, set the file system encoding according to the - user's preference, if the CODESET names a well-known - Python codec, and Py_FileSystemDefaultEncoding isn't - initialized by other means. Also set the encoding of - stdin and stdout if these are terminals. */ - - codeset = get_codeset(); - if (codeset) { - if (!Py_FileSystemDefaultEncoding) - Py_FileSystemDefaultEncoding = codeset; - else - free(codeset); - } -#endif + _PyTime_Init(); + + initfsencoding(); if (install_sigs) initsigs(); /* Signal handling stuff, including initintr() */ - /* Initialize warnings. */ - if (PySys_HasWarnOptions()) { - PyObject *warnings_module = PyImport_ImportModule("warnings"); - if (!warnings_module) - PyErr_Clear(); - Py_XDECREF(warnings_module); - } - initmain(); /* Module __main__ */ if (initstdio() < 0) Py_FatalError( "Py_Initialize: can't initialize sys standard streams"); - /* auto-thread-state API, if available */ -#ifdef WITH_THREAD - _PyGILState_Init(interp, tstate); -#endif /* WITH_THREAD */ + /* Initialize warnings. */ + if (PySys_HasWarnOptions()) { + PyObject *warnings_module = PyImport_ImportModule("warnings"); + if (warnings_module == NULL) { + fprintf(stderr, "'import warnings' failed; traceback:\n"); + PyErr_Print(); + } + Py_XDECREF(warnings_module); + } if (!Py_NoSiteFlag) initsite(); /* Module site */ @@ -416,6 +422,9 @@ Py_Finalize(void) while (PyGC_Collect() > 0) /* nothing */; #endif + /* We run this while most interpreter state is still alive, so that + debug information can be printed out */ + _PyGC_Fini(); /* Destroy all modules */ PyImport_Cleanup(); @@ -499,7 +508,7 @@ Py_Finalize(void) _PyUnicode_Fini(); /* reset file system default encoding */ - if (!Py_HasFileSystemDefaultEncoding) { + if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { free((char*)Py_FileSystemDefaultEncoding); Py_FileSystemDefaultEncoding = NULL; } @@ -568,7 +577,7 @@ Py_NewInterpreter(void) interp->modules = PyDict_New(); interp->modules_reloading = PyDict_New(); - bimod = _PyImport_FindExtension("builtins", "builtins"); + bimod = _PyImport_FindBuiltin("builtins"); if (bimod != NULL) { interp->builtins = PyModule_GetDict(bimod); if (interp->builtins == NULL) @@ -579,7 +588,7 @@ Py_NewInterpreter(void) /* initialize builtin exceptions */ _PyExc_Init(); - sysmod = _PyImport_FindExtension("sys", "sys"); + sysmod = _PyImport_FindBuiltin("sys"); if (bimod != NULL && sysmod != NULL) { PyObject *pstderr; interp->sysdict = PyModule_GetDict(sysmod); @@ -711,30 +720,51 @@ initmain(void) } } +static void +initfsencoding(void) +{ + PyObject *codec; +#if defined(HAVE_LANGINFO_H) && defined(CODESET) + char *codeset = NULL; + + if (Py_FileSystemDefaultEncoding == NULL) { + /* On Unix, set the file system encoding according to the + user's preference, if the CODESET names a well-known + Python codec, and Py_FileSystemDefaultEncoding isn't + initialized by other means. */ + codeset = get_codeset(); + if (codeset == NULL) + Py_FatalError("Py_Initialize: Unable to get the locale encoding"); + + Py_FileSystemDefaultEncoding = codeset; + Py_HasFileSystemDefaultEncoding = 0; + return; + } +#endif + + /* the encoding is mbcs, utf-8 or ascii */ + codec = _PyCodec_Lookup(Py_FileSystemDefaultEncoding); + if (!codec) { + /* Such error can only occurs in critical situations: no more + * memory, import a module of the standard library failed, + * etc. */ + Py_FatalError("Py_Initialize: unable to load the file system codec"); + } else { + Py_DECREF(codec); + } +} + /* Import the site module (not into __main__ though) */ static void initsite(void) { - PyObject *m, *f; + PyObject *m; m = PyImport_ImportModule("site"); if (m == NULL) { - f = PySys_GetObject("stderr"); - if (f == NULL || f == Py_None) - return; - if (Py_VerboseFlag) { - PyObject *type, *value, *traceback; - PyErr_Fetch(&type, &value, &traceback); - PyFile_WriteString( - "'import site' failed; traceback:\n", f); - PyErr_Restore(type, value, traceback); - PyErr_Print(); - } - else { - PyErr_Clear(); - PyFile_WriteString( - "'import site' failed; use -v for traceback\n", f); - } + PyErr_Print(); + Py_Finalize(); + exit(1); } else { Py_DECREF(m); @@ -748,6 +778,7 @@ create_stdio(PyObject* io, { PyObject *buf = NULL, *stream = NULL, *text = NULL, *raw = NULL, *res; const char* mode; + const char* newline; PyObject *line_buffering; int buffering, isatty; @@ -798,9 +829,17 @@ create_stdio(PyObject* io, Py_CLEAR(raw); Py_CLEAR(text); + newline = "\n"; +#ifdef MS_WINDOWS + if (!write_mode) { + /* translate \r\n to \n for sys.stdin on Windows */ + newline = NULL; + } +#endif + stream = PyObject_CallMethod(io, "TextIOWrapper", "OsssO", buf, encoding, errors, - "\n", line_buffering); + newline, line_buffering); Py_CLEAR(buf); if (stream == NULL) goto error; @@ -860,8 +899,10 @@ initstdio(void) /* Set builtins.open */ if (PyObject_SetAttrString(bimod, "open", wrapper) == -1) { + Py_DECREF(wrapper); goto error; } + Py_DECREF(wrapper); encoding = Py_GETENV("PYTHONIOENCODING"); errors = NULL; @@ -1056,22 +1097,34 @@ PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags if (!oenc) return -1; enc = _PyUnicode_AsString(oenc); + if (enc == NULL) + return -1; } v = PySys_GetObject("ps1"); if (v != NULL) { v = PyObject_Str(v); if (v == NULL) PyErr_Clear(); - else if (PyUnicode_Check(v)) + else if (PyUnicode_Check(v)) { ps1 = _PyUnicode_AsString(v); + if (ps1 == NULL) { + PyErr_Clear(); + ps1 = ""; + } + } } w = PySys_GetObject("ps2"); if (w != NULL) { w = PyObject_Str(w); if (w == NULL) PyErr_Clear(); - else if (PyUnicode_Check(w)) + else if (PyUnicode_Check(w)) { ps2 = _PyUnicode_AsString(w); + if (ps2 == NULL) { + PyErr_Clear(); + ps2 = ""; + } + } } arena = PyArena_New(); if (arena == NULL) { @@ -1158,7 +1211,8 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, { PyObject *m, *d, *v; const char *ext; - int set_file_name = 0, ret, len; + int set_file_name = 0, ret; + size_t len; m = PyImport_AddModule("__main__"); if (m == NULL) @@ -1173,6 +1227,8 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, Py_DECREF(f); return -1; } + if (PyDict_SetItemString(d, "__cached__", Py_None) < 0) + return -1; set_file_name = 1; Py_DECREF(f); } @@ -1359,10 +1415,12 @@ handle_system_exit(void) exitcode = (int)PyLong_AsLong(value); else { PyObject *sys_stderr = PySys_GetObject("stderr"); - if (sys_stderr != NULL) - PyObject_CallMethod(sys_stderr, "flush", NULL); - PyObject_Print(value, stderr, Py_PRINT_RAW); - fflush(stderr); + if (sys_stderr != NULL && sys_stderr != Py_None) { + PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW); + } else { + PyObject_Print(value, stderr, Py_PRINT_RAW); + fflush(stderr); + } PySys_WriteStderr("\n"); exitcode = 1; } @@ -1708,7 +1766,7 @@ run_mod(mod_ty mod, const char *filename, PyObject *globals, PyObject *locals, co = PyAST_Compile(mod, filename, flags, arena); if (co == NULL) return NULL; - v = PyEval_EvalCode(co, globals, locals); + v = PyEval_EvalCode((PyObject*)co, globals, locals); Py_DECREF(co); return v; } @@ -1738,7 +1796,7 @@ run_pyc_file(FILE *fp, const char *filename, PyObject *globals, return NULL; } co = (PyCodeObject *)v; - v = PyEval_EvalCode(co, globals, locals); + v = PyEval_EvalCode((PyObject*)co, globals, locals); if (v && flags) flags->cf_flags |= (co->co_flags & PyCF_MASK); Py_DECREF(co); @@ -1746,8 +1804,8 @@ run_pyc_file(FILE *fp, const char *filename, PyObject *globals, } PyObject * -Py_CompileStringFlags(const char *str, const char *filename, int start, - PyCompilerFlags *flags) +Py_CompileStringExFlags(const char *str, const char *filename, int start, + PyCompilerFlags *flags, int optimize) { PyCodeObject *co; mod_ty mod; @@ -1765,11 +1823,19 @@ Py_CompileStringFlags(const char *str, const char *filename, int start, PyArena_Free(arena); return result; } - co = PyAST_Compile(mod, filename, flags, arena); + co = PyAST_CompileEx(mod, filename, flags, optimize, arena); PyArena_Free(arena); return (PyObject *)co; } +/* For use in Py_LIMITED_API */ +#undef Py_CompileString +PyObject * +PyCompileString(const char *str, const char *filename, int start) +{ + return Py_CompileStringFlags(str, filename, start, NULL); +} + struct symtable * Py_SymtableString(const char *str, const char *filename, int start) { @@ -1913,7 +1979,7 @@ static void err_input(perrdetail *err) { PyObject *v, *w, *errtype, *errtext; - PyObject* u = NULL; + PyObject *msg_obj = NULL; PyObject *filename; char *msg = NULL; @@ -1971,14 +2037,9 @@ err_input(perrdetail *err) case E_DECODE: { PyObject *type, *value, *tb; PyErr_Fetch(&type, &value, &tb); - if (value != NULL) { - u = PyObject_Str(value); - if (u != NULL) { - msg = _PyUnicode_AsString(u); - } - } - if (msg == NULL) - msg = "unknown decode error"; + msg = "unknown decode error"; + if (value != NULL) + msg_obj = PyObject_Str(value); Py_XDECREF(type); Py_XDECREF(value); Py_XDECREF(tb); @@ -2016,14 +2077,18 @@ err_input(perrdetail *err) err->lineno, err->offset, errtext); else v = NULL; - w = NULL; - if (v != NULL) - w = Py_BuildValue("(sO)", msg, v); - Py_XDECREF(u); + if (v != NULL) { + if (msg_obj) + w = Py_BuildValue("(OO)", msg_obj, v); + else + w = Py_BuildValue("(sO)", msg, v); + } else + w = NULL; Py_XDECREF(v); PyErr_SetObject(errtype, w); Py_XDECREF(w); cleanup: + Py_XDECREF(msg_obj); if (err->text != NULL) { PyObject_FREE(err->text); err->text = NULL; @@ -2160,6 +2225,27 @@ initsigs(void) } +/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. + * + * All of the code in this function must only use async-signal-safe functions, + * listed at `man 7 signal` or + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. + */ +void +_Py_RestoreSignals(void) +{ +#ifdef SIGPIPE + PyOS_setsig(SIGPIPE, SIG_DFL); +#endif +#ifdef SIGXFZ + PyOS_setsig(SIGXFZ, SIG_DFL); +#endif +#ifdef SIGXFSZ + PyOS_setsig(SIGXFSZ, SIG_DFL); +#endif +} + + /* * The file descriptor fd is considered ``interactive'' if either * a) isatty(fd) is TRUE, or @@ -2253,6 +2339,11 @@ PyOS_getsig(int sig) #endif } +/* + * All of the code in this function must only use async-signal-safe functions, + * listed at `man 7 signal` or + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. + */ PyOS_sighandler_t PyOS_setsig(int sig, PyOS_sighandler_t handler) { @@ -2370,7 +2461,15 @@ PyRun_SimpleString(const char *s) PyAPI_FUNC(PyObject *) Py_CompileString(const char *str, const char *p, int s) { - return Py_CompileStringFlags(str, p, s, NULL); + return Py_CompileStringExFlags(str, p, s, NULL, -1); +} + +#undef Py_CompileStringFlags +PyAPI_FUNC(PyObject *) +Py_CompileStringFlags(const char *str, const char *p, int s, + PyCompilerFlags *flags) +{ + return Py_CompileStringExFlags(str, p, s, flags, -1); } #undef PyRun_InteractiveOne diff --git a/Python/pytime.c b/Python/pytime.c new file mode 100644 index 0000000000..6fb7695911 --- /dev/null +++ b/Python/pytime.c @@ -0,0 +1,60 @@ +#include "Python.h" + +#ifdef __APPLE__ +#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME) + /* + * _PyTime_gettimeofday falls back to ftime when getttimeofday fails because the latter + * might fail on some platforms. This fallback is unwanted on MacOSX because + * that makes it impossible to use a binary build on OSX 10.4 on earlier + * releases of the OS. Therefore claim we don't support ftime. + */ +# undef HAVE_FTIME +#endif +#endif + +#ifdef HAVE_FTIME +#include <sys/timeb.h> +#if !defined(MS_WINDOWS) && !defined(PYOS_OS2) +extern int ftime(struct timeb *); +#endif /* MS_WINDOWS */ +#endif /* HAVE_FTIME */ + +void +_PyTime_gettimeofday(_PyTime_timeval *tp) +{ + /* There are three ways to get the time: + (1) gettimeofday() -- resolution in microseconds + (2) ftime() -- resolution in milliseconds + (3) time() -- resolution in seconds + In all cases the return value in a timeval struct. + Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may + fail, so we fall back on ftime() or time(). + Note: clock resolution does not imply clock accuracy! */ +#ifdef HAVE_GETTIMEOFDAY +#ifdef GETTIMEOFDAY_NO_TZ + if (gettimeofday(tp) == 0) + return; +#else /* !GETTIMEOFDAY_NO_TZ */ + if (gettimeofday(tp, (struct timezone *)NULL) == 0) + return; +#endif /* !GETTIMEOFDAY_NO_TZ */ +#endif /* !HAVE_GETTIMEOFDAY */ +#if defined(HAVE_FTIME) + { + struct timeb t; + ftime(&t); + tp->tv_sec = t.time; + tp->tv_usec = t.millitm * 1000; + } +#else /* !HAVE_FTIME */ + tp->tv_sec = time(NULL); + tp->tv_usec = 0; +#endif /* !HAVE_FTIME */ + return; +} + +void +_PyTime_Init() +{ + /* Do nothing. Needed to force linking. */ +} diff --git a/Python/symtable.c b/Python/symtable.c index 376ad2c45a..15ba6b5e2f 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -25,7 +25,7 @@ static PySTEntryObject * ste_new(struct symtable *st, identifier name, _Py_block_ty block, - void *key, int lineno) + void *key, int lineno, int col_offset) { PySTEntryObject *ste = NULL; PyObject *k; @@ -38,7 +38,6 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block, goto fail; ste->ste_table = st; ste->ste_id = k; - ste->ste_tmpname = 0; ste->ste_name = name; Py_INCREF(name); @@ -66,9 +65,10 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block, ste->ste_varargs = 0; ste->ste_varkeywords = 0; ste->ste_opt_lineno = 0; - ste->ste_tmpname = 0; + ste->ste_opt_col_offset = 0; ste->ste_tmpname = 0; ste->ste_lineno = lineno; + ste->ste_col_offset = col_offset; if (st->st_cur != NULL && (st->st_cur->ste_nested || @@ -166,7 +166,8 @@ PyTypeObject PySTEntry_Type = { static int symtable_analyze(struct symtable *st); static int symtable_warn(struct symtable *st, char *msg, int lineno); static int symtable_enter_block(struct symtable *st, identifier name, - _Py_block_ty block, void *ast, int lineno); + _Py_block_ty block, void *ast, int lineno, + int col_offset); static int symtable_exit_block(struct symtable *st, void *ast); static int symtable_visit_stmt(struct symtable *st, stmt_ty s); static int symtable_visit_expr(struct symtable *st, expr_ty s); @@ -233,7 +234,7 @@ PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future) st->st_future = future; /* Make the initial symbol information gathering pass */ if (!GET_IDENTIFIER(top) || - !symtable_enter_block(st, top, ModuleBlock, (void *)mod, 0)) { + !symtable_enter_block(st, top, ModuleBlock, (void *)mod, 0, 0)) { PySymtable_Free(st); return NULL; } @@ -393,8 +394,8 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, PyErr_Format(PyExc_SyntaxError, "name '%U' is parameter and global", name); - PyErr_SyntaxLocation(ste->ste_table->st_filename, - ste->ste_lineno); + PyErr_SyntaxLocationEx(ste->ste_table->st_filename, + ste->ste_lineno, ste->ste_col_offset); return 0; } @@ -537,8 +538,8 @@ check_unoptimized(const PySTEntryObject* ste) { break; } - PyErr_SyntaxLocation(ste->ste_table->st_filename, - ste->ste_opt_lineno); + PyErr_SyntaxLocationEx(ste->ste_table->st_filename, ste->ste_opt_lineno, + ste->ste_opt_col_offset); return 0; } @@ -876,8 +877,8 @@ symtable_warn(struct symtable *st, char *msg, int lineno) lineno, NULL, NULL) < 0) { if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { PyErr_SetString(PyExc_SyntaxError, msg); - PyErr_SyntaxLocation(st->st_filename, - st->st_cur->ste_lineno); + PyErr_SyntaxLocationEx(st->st_filename, st->st_cur->ste_lineno, + st->st_cur->ste_col_offset); } return 0; } @@ -910,7 +911,7 @@ symtable_exit_block(struct symtable *st, void *ast) static int symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block, - void *ast, int lineno) + void *ast, int lineno, int col_offset) { PySTEntryObject *prev = NULL; @@ -921,7 +922,7 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block, } Py_DECREF(st->st_cur); } - st->st_cur = ste_new(st, name, block, ast, lineno); + st->st_cur = ste_new(st, name, block, ast, lineno, col_offset); if (st->st_cur == NULL) return 0; if (block == ModuleBlock) @@ -966,8 +967,9 @@ symtable_add_def(struct symtable *st, PyObject *name, int flag) if ((flag & DEF_PARAM) && (val & DEF_PARAM)) { /* Is it better to use 'mangled' or 'name' here? */ PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT, name); - PyErr_SyntaxLocation(st->st_filename, - st->st_cur->ste_lineno); + PyErr_SyntaxLocationEx(st->st_filename, + st->st_cur->ste_lineno, + st->st_cur->ste_col_offset); goto error; } val |= flag; @@ -1100,7 +1102,6 @@ symtable_new_tmpname(struct symtable *st) } - static int symtable_visit_stmt(struct symtable *st, stmt_ty s) { @@ -1118,7 +1119,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) if (s->v.FunctionDef.decorator_list) VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list); if (!symtable_enter_block(st, s->v.FunctionDef.name, - FunctionBlock, (void *)s, s->lineno)) + FunctionBlock, (void *)s, s->lineno, + s->col_offset)) return 0; VISIT_IN_BLOCK(st, arguments, s->v.FunctionDef.args, s); VISIT_SEQ_IN_BLOCK(st, stmt, s->v.FunctionDef.body, s); @@ -1138,7 +1140,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) if (s->v.ClassDef.decorator_list) VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list); if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, - (void *)s, s->lineno)) + (void *)s, s->lineno, s->col_offset)) return 0; if (!GET_IDENTIFIER(__class__) || !symtable_add_def(st, __class__, DEF_LOCAL) || @@ -1162,8 +1164,9 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) if (st->st_cur->ste_generator) { PyErr_SetString(PyExc_SyntaxError, RETURN_VAL_IN_GENERATOR); - PyErr_SyntaxLocation(st->st_filename, - s->lineno); + PyErr_SyntaxLocationEx(st->st_filename, + s->lineno, + s->col_offset); return 0; } } @@ -1225,15 +1228,19 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_SEQ(st, alias, s->v.Import.names); /* XXX Don't have the lineno available inside visit_alias */ - if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno) + if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno) { st->st_cur->ste_opt_lineno = s->lineno; + st->st_cur->ste_opt_col_offset = s->col_offset; + } break; case ImportFrom_kind: VISIT_SEQ(st, alias, s->v.ImportFrom.names); /* XXX Don't have the lineno available inside visit_alias */ - if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno) + if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno) { st->st_cur->ste_opt_lineno = s->lineno; + st->st_cur->ste_opt_col_offset = s->col_offset; + } break; case Global_kind: { int i; @@ -1298,12 +1305,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) /* nothing to do here */ break; case With_kind: - if (!symtable_new_tmpname(st)) - return 0; VISIT(st, expr, s->v.With.context_expr); if (s->v.With.optional_vars) { - if (!symtable_new_tmpname(st)) - return 0; VISIT(st, expr, s->v.With.optional_vars); } VISIT_SEQ(st, stmt, s->v.With.body); @@ -1327,13 +1330,13 @@ symtable_visit_expr(struct symtable *st, expr_ty e) VISIT(st, expr, e->v.UnaryOp.operand); break; case Lambda_kind: { - if (!GET_IDENTIFIER(lambda) || - !symtable_add_def(st, lambda, DEF_LOCAL)) + if (!GET_IDENTIFIER(lambda)) return 0; if (e->v.Lambda.args->defaults) VISIT_SEQ(st, expr, e->v.Lambda.args->defaults); if (!symtable_enter_block(st, lambda, - FunctionBlock, (void *)e, e->lineno)) + FunctionBlock, (void *)e, e->lineno, + e->col_offset)) return 0; VISIT_IN_BLOCK(st, arguments, e->v.Lambda.args, (void*)e); VISIT_IN_BLOCK(st, expr, e->v.Lambda.body, (void*)e); @@ -1376,8 +1379,8 @@ symtable_visit_expr(struct symtable *st, expr_ty e) if (st->st_cur->ste_returns_value) { PyErr_SetString(PyExc_SyntaxError, RETURN_VAL_IN_GENERATOR); - PyErr_SyntaxLocation(st->st_filename, - e->lineno); + PyErr_SyntaxLocationEx(st->st_filename, + e->lineno, e->col_offset); return 0; } break; @@ -1542,7 +1545,7 @@ static int symtable_visit_alias(struct symtable *st, alias_ty a) { /* Compute store_name, the name actually bound by the import - operation. It is diferent than a->name when a->name is a + operation. It is different than a->name when a->name is a dotted package name (e.g. spam.eggs) */ PyObject *store_name; @@ -1566,8 +1569,9 @@ symtable_visit_alias(struct symtable *st, alias_ty a) else { if (st->st_cur->ste_type != ModuleBlock) { int lineno = st->st_cur->ste_lineno; + int col_offset = st->st_cur->ste_col_offset; PyErr_SetString(PyExc_SyntaxError, IMPORT_STAR_WARNING); - PyErr_SyntaxLocation(st->st_filename, lineno); + PyErr_SyntaxLocationEx(st->st_filename, lineno, col_offset); Py_DECREF(store_name); return 0; } @@ -1631,7 +1635,8 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e, VISIT(st, expr, outermost->iter); /* Create comprehension scope for the rest */ if (!scope_name || - !symtable_enter_block(st, scope_name, FunctionBlock, (void *)e, e->lineno)) { + !symtable_enter_block(st, scope_name, FunctionBlock, (void *)e, + e->lineno, e->col_offset)) { return 0; } st->st_cur->ste_generator = is_generator; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index f85cc55ad1..8d44135be1 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -15,10 +15,8 @@ Data members: */ #include "Python.h" -#include "structseq.h" #include "code.h" #include "frameobject.h" -#include "eval.h" #include "osdefs.h" @@ -67,6 +65,68 @@ PySys_SetObject(const char *name, PyObject *v) return PyDict_SetItemString(sd, name, v); } +/* Write repr(o) to sys.stdout using sys.stdout.encoding and 'backslashreplace' + error handler. If sys.stdout has a buffer attribute, use + sys.stdout.buffer.write(encoded), otherwise redecode the string and use + sys.stdout.write(redecoded). + + Helper function for sys_displayhook(). */ +static int +sys_displayhook_unencodable(PyObject *outf, PyObject *o) +{ + PyObject *stdout_encoding = NULL; + PyObject *encoded, *escaped_str, *repr_str, *buffer, *result; + char *stdout_encoding_str; + int ret; + + stdout_encoding = PyObject_GetAttrString(outf, "encoding"); + if (stdout_encoding == NULL) + goto error; + stdout_encoding_str = _PyUnicode_AsString(stdout_encoding); + if (stdout_encoding_str == NULL) + goto error; + + repr_str = PyObject_Repr(o); + if (repr_str == NULL) + goto error; + encoded = PyUnicode_AsEncodedString(repr_str, + stdout_encoding_str, + "backslashreplace"); + Py_DECREF(repr_str); + if (encoded == NULL) + goto error; + + buffer = PyObject_GetAttrString(outf, "buffer"); + if (buffer) { + result = PyObject_CallMethod(buffer, "write", "(O)", encoded); + Py_DECREF(buffer); + Py_DECREF(encoded); + if (result == NULL) + goto error; + Py_DECREF(result); + } + else { + PyErr_Clear(); + escaped_str = PyUnicode_FromEncodedObject(encoded, + stdout_encoding_str, + "strict"); + Py_DECREF(encoded); + if (PyFile_WriteObject(escaped_str, outf, Py_PRINT_RAW) != 0) { + Py_DECREF(escaped_str); + goto error; + } + Py_DECREF(escaped_str); + } + ret = 0; + goto finally; + +error: + ret = -1; +finally: + Py_XDECREF(stdout_encoding); + return ret; +} + static PyObject * sys_displayhook(PyObject *self, PyObject *o) { @@ -74,6 +134,7 @@ sys_displayhook(PyObject *self, PyObject *o) PyInterpreterState *interp = PyThreadState_GET()->interp; PyObject *modules = interp->modules; PyObject *builtins = PyDict_GetItemString(modules, "builtins"); + int err; if (builtins == NULL) { PyErr_SetString(PyExc_RuntimeError, "lost builtins module"); @@ -94,8 +155,19 @@ sys_displayhook(PyObject *self, PyObject *o) PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); return NULL; } - if (PyFile_WriteObject(o, outf, 0) != 0) - return NULL; + if (PyFile_WriteObject(o, outf, 0) != 0) { + if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) { + /* repr(o) is not encodable to sys.stdout.encoding with + * sys.stdout.errors error handler (which is probably 'strict') */ + PyErr_Clear(); + err = sys_displayhook_unencodable(outf, o); + if (err) + return NULL; + } + else { + return NULL; + } + } if (PyFile_WriteString("\n", outf) != 0) return NULL; if (PyObject_SetAttrString(builtins, "_", o) != 0) @@ -183,24 +255,6 @@ implementation." ); static PyObject * -sys_setdefaultencoding(PyObject *self, PyObject *args) -{ - char *encoding; - if (!PyArg_ParseTuple(args, "s:setdefaultencoding", &encoding)) - return NULL; - if (PyUnicode_SetDefaultEncoding(encoding)) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(setdefaultencoding_doc, -"setdefaultencoding(encoding)\n\ -\n\ -Set the current default string encoding used by the Unicode implementation." -); - -static PyObject * sys_getfilesystemencoding(PyObject *self) { if (Py_FileSystemDefaultEncoding) @@ -217,25 +271,6 @@ operating system filenames." ); static PyObject * -sys_setfilesystemencoding(PyObject *self, PyObject *args) -{ - PyObject *new_encoding; - if (!PyArg_ParseTuple(args, "U:setfilesystemencoding", &new_encoding)) - return NULL; - if (_Py_SetFileSystemEncoding(new_encoding)) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(setfilesystemencoding_doc, -"setfilesystemencoding(string) -> None\n\ -\n\ -Set the encoding used to convert Unicode filenames in\n\ -operating system filenames." -); - -static PyObject * sys_intern(PyObject *self, PyObject *args) { PyObject *s; @@ -448,10 +483,17 @@ Return the profiling function set with sys.setprofile.\n\ See the profiler chapter in the library manual." ); +static int _check_interval = 100; + static PyObject * sys_setcheckinterval(PyObject *self, PyObject *args) { - if (!PyArg_ParseTuple(args, "i:setcheckinterval", &_Py_CheckInterval)) + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "sys.getcheckinterval() and sys.setcheckinterval() " + "are deprecated. Use sys.setswitchinterval() " + "instead.", 1) < 0) + return NULL; + if (!PyArg_ParseTuple(args, "i:setcheckinterval", &_check_interval)) return NULL; Py_INCREF(Py_None); return Py_None; @@ -467,13 +509,59 @@ n instructions. This also affects how often thread switches occur." static PyObject * sys_getcheckinterval(PyObject *self, PyObject *args) { - return PyLong_FromLong(_Py_CheckInterval); + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "sys.getcheckinterval() and sys.setcheckinterval() " + "are deprecated. Use sys.getswitchinterval() " + "instead.", 1) < 0) + return NULL; + return PyLong_FromLong(_check_interval); } PyDoc_STRVAR(getcheckinterval_doc, "getcheckinterval() -> current check interval; see setcheckinterval()." ); +#ifdef WITH_THREAD +static PyObject * +sys_setswitchinterval(PyObject *self, PyObject *args) +{ + double d; + if (!PyArg_ParseTuple(args, "d:setswitchinterval", &d)) + return NULL; + if (d <= 0.0) { + PyErr_SetString(PyExc_ValueError, + "switch interval must be strictly positive"); + return NULL; + } + _PyEval_SetSwitchInterval((unsigned long) (1e6 * d)); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setswitchinterval_doc, +"setswitchinterval(n)\n\ +\n\ +Set the ideal thread switching delay inside the Python interpreter\n\ +The actual frequency of switching threads can be lower if the\n\ +interpreter executes long sequences of uninterruptible code\n\ +(this is implementation-specific and workload-dependent).\n\ +\n\ +The parameter must represent the desired switching delay in seconds\n\ +A typical value is 0.005 (5 milliseconds)." +); + +static PyObject * +sys_getswitchinterval(PyObject *self, PyObject *args) +{ + return PyFloat_FromDouble(1e-6 * _PyEval_GetSwitchInterval()); +} + +PyDoc_STRVAR(getswitchinterval_doc, +"getswitchinterval() -> current thread switch interval; see setswitchinterval()." +); + +#endif /* WITH_THREAD */ + #ifdef WITH_TSC static PyObject * sys_settscdump(PyObject *self, PyObject *args) @@ -517,6 +605,57 @@ sys_setrecursionlimit(PyObject *self, PyObject *args) return Py_None; } +static PyTypeObject Hash_InfoType; + +PyDoc_STRVAR(hash_info_doc, +"hash_info\n\ +\n\ +A struct sequence providing parameters used for computing\n\ +numeric hashes. The attributes are read only."); + +static PyStructSequence_Field hash_info_fields[] = { + {"width", "width of the type used for hashing, in bits"}, + {"modulus", "prime number giving the modulus on which the hash " + "function is based"}, + {"inf", "value to be used for hash of a positive infinity"}, + {"nan", "value to be used for hash of a nan"}, + {"imag", "multiplier used for the imaginary part of a complex number"}, + {NULL, NULL} +}; + +static PyStructSequence_Desc hash_info_desc = { + "sys.hash_info", + hash_info_doc, + hash_info_fields, + 5, +}; + +static PyObject * +get_hash_info(void) +{ + PyObject *hash_info; + int field = 0; + hash_info = PyStructSequence_New(&Hash_InfoType); + if (hash_info == NULL) + return NULL; + PyStructSequence_SET_ITEM(hash_info, field++, + PyLong_FromLong(8*sizeof(Py_hash_t))); + PyStructSequence_SET_ITEM(hash_info, field++, + PyLong_FromSsize_t(_PyHASH_MODULUS)); + PyStructSequence_SET_ITEM(hash_info, field++, + PyLong_FromLong(_PyHASH_INF)); + PyStructSequence_SET_ITEM(hash_info, field++, + PyLong_FromLong(_PyHASH_NAN)); + PyStructSequence_SET_ITEM(hash_info, field++, + PyLong_FromLong(_PyHASH_IMAG)); + if (PyErr_Occurred()) { + Py_CLEAR(hash_info); + return NULL; + } + return hash_info; +} + + PyDoc_STRVAR(setrecursionlimit_doc, "setrecursionlimit(n)\n\ \n\ @@ -544,26 +683,65 @@ recursion from causing an overflow of the C stack and crashing Python." PyDoc_STRVAR(getwindowsversion_doc, "getwindowsversion()\n\ \n\ -Return information about the running version of Windows.\n\ -The result is a tuple of (major, minor, build, platform, text)\n\ -All elements are numbers, except text which is a string.\n\ -Platform may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP\n\ -" +Return information about the running version of Windows as a named tuple.\n\ +The members are named: major, minor, build, platform, service_pack,\n\ +service_pack_major, service_pack_minor, suite_mask, and product_type. For\n\ +backward compatibility, only the first 5 items are available by indexing.\n\ +All elements are numbers, except service_pack which is a string. Platform\n\ +may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP/Vista/7,\n\ +3 for Windows CE. Product_type may be 1 for a workstation, 2 for a domain\n\ +controller, 3 for a server." ); +static PyTypeObject WindowsVersionType = {0, 0, 0, 0, 0, 0}; + +static PyStructSequence_Field windows_version_fields[] = { + {"major", "Major version number"}, + {"minor", "Minor version number"}, + {"build", "Build number"}, + {"platform", "Operating system platform"}, + {"service_pack", "Latest Service Pack installed on the system"}, + {"service_pack_major", "Service Pack major version number"}, + {"service_pack_minor", "Service Pack minor version number"}, + {"suite_mask", "Bit mask identifying available product suites"}, + {"product_type", "System product type"}, + {0} +}; + +static PyStructSequence_Desc windows_version_desc = { + "sys.getwindowsversion", /* name */ + getwindowsversion_doc, /* doc */ + windows_version_fields, /* fields */ + 5 /* For backward compatibility, + only the first 5 items are accessible + via indexing, the rest are name only */ +}; + static PyObject * sys_getwindowsversion(PyObject *self) { - OSVERSIONINFO ver; + PyObject *version; + int pos = 0; + OSVERSIONINFOEX ver; ver.dwOSVersionInfoSize = sizeof(ver); - if (!GetVersionEx(&ver)) + if (!GetVersionEx((OSVERSIONINFO*) &ver)) return PyErr_SetFromWindowsErr(0); - return Py_BuildValue("HHHHs", - ver.dwMajorVersion, - ver.dwMinorVersion, - ver.dwBuildNumber, - ver.dwPlatformId, - ver.szCSDVersion); + + version = PyStructSequence_New(&WindowsVersionType); + if (version == NULL) + return NULL; + + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwMajorVersion)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwMinorVersion)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwBuildNumber)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwPlatformId)); + PyStructSequence_SET_ITEM(version, pos++, PyUnicode_FromString(ver.szCSDVersion)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wServicePackMajor)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wServicePackMinor)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask)); + PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wProductType)); + + return version; } #endif /* MS_WINDOWS */ @@ -887,14 +1065,16 @@ static PyMethodDef sys_methods[] = { #ifdef USE_MALLOPT {"mdebug", sys_mdebug, METH_VARARGS}, #endif - {"setdefaultencoding", sys_setdefaultencoding, METH_VARARGS, - setdefaultencoding_doc}, - {"setfilesystemencoding", sys_setfilesystemencoding, METH_VARARGS, - setfilesystemencoding_doc}, {"setcheckinterval", sys_setcheckinterval, METH_VARARGS, setcheckinterval_doc}, {"getcheckinterval", sys_getcheckinterval, METH_NOARGS, getcheckinterval_doc}, +#ifdef WITH_THREAD + {"setswitchinterval", sys_setswitchinterval, METH_VARARGS, + setswitchinterval_doc}, + {"getswitchinterval", sys_getswitchinterval, METH_NOARGS, + getswitchinterval_doc}, +#endif #ifdef HAVE_DLOPEN {"setdlopenflags", sys_setdlopenflags, METH_VARARGS, setdlopenflags_doc}, @@ -950,21 +1130,26 @@ PySys_ResetWarnOptions(void) } void -PySys_AddWarnOption(const wchar_t *s) +PySys_AddWarnOptionUnicode(PyObject *unicode) { - PyObject *str; - if (warnoptions == NULL || !PyList_Check(warnoptions)) { Py_XDECREF(warnoptions); warnoptions = PyList_New(0); if (warnoptions == NULL) return; } - str = PyUnicode_FromWideChar(s, -1); - if (str != NULL) { - PyList_Append(warnoptions, str); - Py_DECREF(str); - } + PyList_Append(warnoptions, unicode); +} + +void +PySys_AddWarnOption(const wchar_t *s) +{ + PyObject *unicode; + unicode = PyUnicode_FromWideChar(s, -1); + if (unicode == NULL) + return; + PySys_AddWarnOptionUnicode(unicode); + Py_DECREF(unicode); } int @@ -973,6 +1158,61 @@ PySys_HasWarnOptions(void) return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0; } +static PyObject *xoptions = NULL; + +static PyObject * +get_xoptions(void) +{ + if (xoptions == NULL || !PyDict_Check(xoptions)) { + Py_XDECREF(xoptions); + xoptions = PyDict_New(); + } + return xoptions; +} + +void +PySys_AddXOption(const wchar_t *s) +{ + PyObject *opts; + PyObject *name = NULL, *value = NULL; + const wchar_t *name_end; + int r; + + opts = get_xoptions(); + if (opts == NULL) + goto error; + + name_end = wcschr(s, L'='); + if (!name_end) { + name = PyUnicode_FromWideChar(s, -1); + value = Py_True; + Py_INCREF(value); + } + else { + name = PyUnicode_FromWideChar(s, name_end - s); + value = PyUnicode_FromWideChar(name_end + 1, -1); + } + if (name == NULL || value == NULL) + goto error; + r = PyDict_SetItem(opts, name, value); + Py_DECREF(name); + Py_DECREF(value); + return; + +error: + Py_XDECREF(name); + Py_XDECREF(value); + /* No return value, therefore clear error state if possible */ + if (_Py_atomic_load_relaxed(&_PyThreadState_Current)) + PyErr_Clear(); +} + +PyObject * +PySys_GetXOptions(void) +{ + return get_xoptions(); +} + /* XXX This doc string is too long to be a single string literal in VC++ 5.0. Two literals concatenated works just fine. If you have a K&R compiler or other abomination that however *does* understand longer strings, @@ -1177,7 +1417,8 @@ static PyStructSequence_Field flags_fields[] = { #endif /* {"unbuffered", "-u"}, */ /* {"skip_first", "-x"}, */ - {"bytes_warning", "-b"}, + {"bytes_warning", "-b"}, + {"quiet", "-q"}, {0} }; @@ -1186,9 +1427,9 @@ static PyStructSequence_Desc flags_desc = { flags__doc__, /* doc */ flags_fields, /* fields */ #ifdef RISCOS - 12 + 13 #else - 11 + 12 #endif }; @@ -1221,6 +1462,7 @@ make_flags(void) /* SetFlag(saw_unbuffered_flag); */ /* SetFlag(skipfirstline); */ SetFlag(Py_BytesWarningFlag); + SetFlag(Py_QuietFlag); #undef SetFlag if (PyErr_Occurred()) { @@ -1356,7 +1598,7 @@ _PySys_Init(void) PyLong_FromLong(PY_VERSION_HEX)); svnversion_init(); SET_SYS_FROM_STRING("subversion", - Py_BuildValue("(UUU)", "CPython", branch, + Py_BuildValue("(sss)", "CPython", branch, svn_revision)); SET_SYS_FROM_STRING("_mercurial", Py_BuildValue("(szz)", "CPython", _Py_hgidentifier(), @@ -1382,6 +1624,11 @@ _PySys_Init(void) PyFloat_GetInfo()); SET_SYS_FROM_STRING("int_info", PyLong_GetInfo()); + /* initialize hash_info */ + if (Hash_InfoType.tp_name == 0) + PyStructSequence_InitType(&Hash_InfoType, &hash_info_desc); + SET_SYS_FROM_STRING("hash_info", + get_hash_info()); SET_SYS_FROM_STRING("maxunicode", PyLong_FromLong(PyUnicode_GetMax())); SET_SYS_FROM_STRING("builtin_module_names", @@ -1406,6 +1653,10 @@ _PySys_Init(void) SET_SYS_FROM_STRING("winver", PyUnicode_FromString(PyWin_DLLVersionString)); #endif +#ifdef ABIFLAGS + SET_SYS_FROM_STRING("abiflags", + PyUnicode_FromString(ABIFLAGS)); +#endif if (warnoptions == NULL) { warnoptions = PyList_New(0); } @@ -1416,6 +1667,11 @@ _PySys_Init(void) PyDict_SetItemString(sysdict, "warnoptions", warnoptions); } + v = get_xoptions(); + if (v != NULL) { + PyDict_SetItemString(sysdict, "_xoptions", v); + } + /* version_info */ if (VersionInfoType.tp_name == 0) PyStructSequence_InitType(&VersionInfoType, &version_info_desc); @@ -1432,6 +1688,16 @@ _PySys_Init(void) FlagsType.tp_init = NULL; FlagsType.tp_new = NULL; + +#if defined(MS_WINDOWS) + /* getwindowsversion */ + if (WindowsVersionType.tp_name == 0) + PyStructSequence_InitType(&WindowsVersionType, &windows_version_desc); + /* prevent user from creating new instances */ + WindowsVersionType.tp_init = NULL; + WindowsVersionType.tp_new = NULL; +#endif + /* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */ #ifndef PY_NO_SHORT_FLOAT_REPR SET_SYS_FROM_STRING("float_repr_style", @@ -1532,130 +1798,122 @@ makeargvobject(int argc, wchar_t **argv) return av; } -#ifdef HAVE_REALPATH -static wchar_t* -_wrealpath(const wchar_t *path, wchar_t *resolved_path) -{ - char cpath[PATH_MAX]; - char cresolved_path[PATH_MAX]; - char *res; - size_t r; - r = wcstombs(cpath, path, PATH_MAX); - if (r == (size_t)-1 || r >= PATH_MAX) { - errno = EINVAL; - return NULL; - } - res = realpath(cpath, cresolved_path); - if (res == NULL) - return NULL; - r = mbstowcs(resolved_path, cresolved_path, PATH_MAX); - if (r == (size_t)-1 || r >= PATH_MAX) { - errno = EINVAL; - return NULL; - } - return resolved_path; -} -#endif +#define _HAVE_SCRIPT_ARGUMENT(argc, argv) \ + (argc > 0 && argv0 != NULL && \ + wcscmp(argv0, L"-c") != 0 && wcscmp(argv0, L"-m") != 0) -void -PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath) +static void +sys_update_path(int argc, wchar_t **argv) { + wchar_t *argv0; + wchar_t *p = NULL; + Py_ssize_t n = 0; + PyObject *a; + PyObject *path; +#ifdef HAVE_READLINK + wchar_t link[MAXPATHLEN+1]; + wchar_t argv0copy[2*MAXPATHLEN+1]; + int nr = 0; +#endif #if defined(HAVE_REALPATH) wchar_t fullpath[MAXPATHLEN]; #elif defined(MS_WINDOWS) && !defined(MS_WINCE) wchar_t fullpath[MAX_PATH]; #endif - PyObject *av = makeargvobject(argc, argv); - PyObject *path = PySys_GetObject("path"); - if (av == NULL) - Py_FatalError("no mem for sys.argv"); - if (PySys_SetObject("argv", av) != 0) - Py_FatalError("can't assign sys.argv"); - if (updatepath && path != NULL) { - wchar_t *argv0 = argv[0]; - wchar_t *p = NULL; - Py_ssize_t n = 0; - PyObject *a; - extern int _Py_wreadlink(const wchar_t *, wchar_t *, size_t); + + path = PySys_GetObject("path"); + if (path == NULL) + return; + + argv0 = argv[0]; + #ifdef HAVE_READLINK - wchar_t link[MAXPATHLEN+1]; - wchar_t argv0copy[2*MAXPATHLEN+1]; - int nr = 0; - if (argc > 0 && argv0 != NULL && wcscmp(argv0, L"-c") != 0) - nr = _Py_wreadlink(argv0, link, MAXPATHLEN); - if (nr > 0) { - /* It's a symlink */ - link[nr] = '\0'; - if (link[0] == SEP) - argv0 = link; /* Link to absolute path */ - else if (wcschr(link, SEP) == NULL) - ; /* Link without path */ + if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) + nr = _Py_wreadlink(argv0, link, MAXPATHLEN); + if (nr > 0) { + /* It's a symlink */ + link[nr] = '\0'; + if (link[0] == SEP) + argv0 = link; /* Link to absolute path */ + else if (wcschr(link, SEP) == NULL) + ; /* Link without path */ + else { + /* Must join(dirname(argv0), link) */ + wchar_t *q = wcsrchr(argv0, SEP); + if (q == NULL) + argv0 = link; /* argv0 without path */ else { - /* Must join(dirname(argv0), link) */ - wchar_t *q = wcsrchr(argv0, SEP); - if (q == NULL) - argv0 = link; /* argv0 without path */ - else { - /* Must make a copy */ - wcscpy(argv0copy, argv0); - q = wcsrchr(argv0copy, SEP); - wcscpy(q+1, link); - argv0 = argv0copy; - } + /* Must make a copy */ + wcscpy(argv0copy, argv0); + q = wcsrchr(argv0copy, SEP); + wcscpy(q+1, link); + argv0 = argv0copy; } } + } #endif /* HAVE_READLINK */ #if SEP == '\\' /* Special case for MS filename syntax */ - if (argc > 0 && argv0 != NULL && wcscmp(argv0, L"-c") != 0) { - wchar_t *q; + if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) { + wchar_t *q; #if defined(MS_WINDOWS) && !defined(MS_WINCE) - /* This code here replaces the first element in argv with the full - path that it represents. Under CE, there are no relative paths so - the argument must be the full path anyway. */ - wchar_t *ptemp; - if (GetFullPathNameW(argv0, - sizeof(fullpath)/sizeof(fullpath[0]), - fullpath, - &ptemp)) { - argv0 = fullpath; - } + /* This code here replaces the first element in argv with the full + path that it represents. Under CE, there are no relative paths so + the argument must be the full path anyway. */ + wchar_t *ptemp; + if (GetFullPathNameW(argv0, + sizeof(fullpath)/sizeof(fullpath[0]), + fullpath, + &ptemp)) { + argv0 = fullpath; + } #endif - p = wcsrchr(argv0, SEP); - /* Test for alternate separator */ - q = wcsrchr(p ? p : argv0, '/'); - if (q != NULL) - p = q; - if (p != NULL) { - n = p + 1 - argv0; - if (n > 1 && p[-1] != ':') - n--; /* Drop trailing separator */ - } + p = wcsrchr(argv0, SEP); + /* Test for alternate separator */ + q = wcsrchr(p ? p : argv0, '/'); + if (q != NULL) + p = q; + if (p != NULL) { + n = p + 1 - argv0; + if (n > 1 && p[-1] != ':') + n--; /* Drop trailing separator */ } + } #else /* All other filename syntaxes */ - if (argc > 0 && argv0 != NULL && wcscmp(argv0, L"-c") != 0) { + if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) { #if defined(HAVE_REALPATH) - if (_wrealpath(argv0, fullpath)) { - argv0 = fullpath; - } -#endif - p = wcsrchr(argv0, SEP); + if (_Py_wrealpath(argv0, fullpath, PATH_MAX)) { + argv0 = fullpath; } - if (p != NULL) { - n = p + 1 - argv0; +#endif + p = wcsrchr(argv0, SEP); + } + if (p != NULL) { + n = p + 1 - argv0; #if SEP == '/' /* Special case for Unix filename syntax */ - if (n > 1) - n--; /* Drop trailing separator */ + if (n > 1) + n--; /* Drop trailing separator */ #endif /* Unix */ - } -#endif /* All others */ - a = PyUnicode_FromWideChar(argv0, n); - if (a == NULL) - Py_FatalError("no mem for sys.path insertion"); - if (PyList_Insert(path, 0, a) < 0) - Py_FatalError("sys.path.insert(0) failed"); - Py_DECREF(a); } +#endif /* All others */ + a = PyUnicode_FromWideChar(argv0, n); + if (a == NULL) + Py_FatalError("no mem for sys.path insertion"); + if (PyList_Insert(path, 0, a) < 0) + Py_FatalError("sys.path.insert(0) failed"); + Py_DECREF(a); +} + +void +PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath) +{ + PyObject *av = makeargvobject(argc, argv); + if (av == NULL) + Py_FatalError("no mem for sys.argv"); + if (PySys_SetObject("argv", av) != 0) + Py_FatalError("can't assign sys.argv"); Py_DECREF(av); + if (updatepath) + sys_update_path(argc, argv); } void @@ -1668,18 +1926,14 @@ PySys_SetArgv(int argc, wchar_t **argv) PyErr_CheckSignals(): avoid the call to PyObject_Str(). */ static int -sys_pyfile_write(const char *text, PyObject *file) +sys_pyfile_write_unicode(PyObject *unicode, PyObject *file) { - PyObject *unicode = NULL, *writer = NULL, *args = NULL, *result = NULL; + PyObject *writer = NULL, *args = NULL, *result = NULL; int err; if (file == NULL) return -1; - unicode = PyUnicode_FromString(text); - if (unicode == NULL) - goto error; - writer = PyObject_GetAttrString(file, "write"); if (writer == NULL) goto error; @@ -1699,13 +1953,29 @@ sys_pyfile_write(const char *text, PyObject *file) error: err = -1; finally: - Py_XDECREF(unicode); Py_XDECREF(writer); Py_XDECREF(args); Py_XDECREF(result); return err; } +static int +sys_pyfile_write(const char *text, PyObject *file) +{ + PyObject *unicode = NULL; + int err; + + if (file == NULL) + return -1; + + unicode = PyUnicode_FromString(text); + if (unicode == NULL) + return -1; + + err = sys_pyfile_write_unicode(unicode, file); + Py_DECREF(unicode); + return err; +} /* APIs to write to sys.stdout or sys.stderr using a printf-like interface. Adapted from code submitted by Just van Rossum. @@ -1718,8 +1988,8 @@ finally: no exceptions are raised. PyErr_CheckSignals() is not called to avoid the execution of the Python - signal handlers: they may raise a new exception whereas mywrite() ignores - all exceptions. + signal handlers: they may raise a new exception whereas sys_write() + ignores all exceptions. Both take a printf-style format string as their first argument followed by a variable length argument list determined by the format string. @@ -1736,7 +2006,7 @@ finally: */ static void -mywrite(char *name, FILE *fp, const char *format, va_list va) +sys_write(char *name, FILE *fp, const char *format, va_list va) { PyObject *file; PyObject *error_type, *error_value, *error_traceback; @@ -1752,10 +2022,8 @@ mywrite(char *name, FILE *fp, const char *format, va_list va) } if (written < 0 || (size_t)written >= sizeof(buffer)) { const char *truncated = "... truncated"; - if (sys_pyfile_write(truncated, file) != 0) { - PyErr_Clear(); + if (sys_pyfile_write(truncated, file) != 0) fputs(truncated, fp); - } } PyErr_Restore(error_type, error_value, error_traceback); } @@ -1766,7 +2034,7 @@ PySys_WriteStdout(const char *format, ...) va_list va; va_start(va, format); - mywrite("stdout", stdout, format, va); + sys_write("stdout", stdout, format, va); va_end(va); } @@ -1776,6 +2044,48 @@ PySys_WriteStderr(const char *format, ...) va_list va; va_start(va, format); - mywrite("stderr", stderr, format, va); + sys_write("stderr", stderr, format, va); + va_end(va); +} + +static void +sys_format(char *name, FILE *fp, const char *format, va_list va) +{ + PyObject *file, *message; + PyObject *error_type, *error_value, *error_traceback; + char *utf8; + + PyErr_Fetch(&error_type, &error_value, &error_traceback); + file = PySys_GetObject(name); + message = PyUnicode_FromFormatV(format, va); + if (message != NULL) { + if (sys_pyfile_write_unicode(message, file) != 0) { + PyErr_Clear(); + utf8 = _PyUnicode_AsString(message); + if (utf8 != NULL) + fputs(utf8, fp); + } + Py_DECREF(message); + } + PyErr_Restore(error_type, error_value, error_traceback); +} + +void +PySys_FormatStdout(const char *format, ...) +{ + va_list va; + + va_start(va, format); + sys_format("stdout", stdout, format, va); + va_end(va); +} + +void +PySys_FormatStderr(const char *format, ...) +{ + va_list va; + + va_start(va, format); + sys_format("stderr", stderr, format, va); va_end(va); } diff --git a/Python/thread.c b/Python/thread.c index 4a9b4368ac..d224046e64 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -23,12 +23,6 @@ #include <stdlib.h> -#ifdef __sgi -#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.in */ -#undef _POSIX_THREADS -#endif -#endif - #include "pythread.h" #ifndef _POSIX_THREADS @@ -101,6 +95,7 @@ PyThread_init_thread(void) static size_t _pythread_stacksize = 0; #ifdef SGI_THREADS +#error SGI Irix threads are now unsupported, and code will be removed in 3.3. #include "thread_sgi.h" #endif @@ -109,10 +104,12 @@ static size_t _pythread_stacksize = 0; #endif #ifdef SUN_LWP +#error SunOS lightweight processes are now unsupported, and code will be removed in 3.3. #include "thread_lwp.h" #endif #ifdef HAVE_PTH +#error GNU pth threads are now unsupported, and code will be removed in 3.3. #include "thread_pth.h" #undef _POSIX_THREADS #endif @@ -122,6 +119,7 @@ static size_t _pythread_stacksize = 0; #endif #ifdef C_THREADS +#error Mach C Threads are now unsupported, and code will be removed in 3.3. #include "thread_cthread.h" #endif @@ -137,10 +135,6 @@ static size_t _pythread_stacksize = 0; #include "thread_plan9.h" #endif -#ifdef ATHEOS_THREADS -#include "thread_atheos.h" -#endif - /* #ifdef FOOBAR_THREADS #include "thread_foobar.h" diff --git a/Python/thread_atheos.h b/Python/thread_atheos.h deleted file mode 100644 index c390b57d4a..0000000000 --- a/Python/thread_atheos.h +++ /dev/null @@ -1,300 +0,0 @@ -/* Threading for AtheOS. - Based on thread_beos.h. */ - -#include <atheos/threads.h> -#include <atheos/semaphore.h> -#include <atheos/atomic.h> -#include <errno.h> -#include <string.h> - -/* Missing decl from threads.h */ -extern int exit_thread(int); - - -/* Undefine FASTLOCK to play with simple semaphores. */ -#define FASTLOCK - - -#ifdef FASTLOCK - -/* Use an atomic counter and a semaphore for maximum speed. */ -typedef struct fastmutex { - sem_id sem; - atomic_t count; -} fastmutex_t; - - -static int fastmutex_create(const char *name, fastmutex_t * mutex); -static int fastmutex_destroy(fastmutex_t * mutex); -static int fastmutex_lock(fastmutex_t * mutex); -static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout); -static int fastmutex_unlock(fastmutex_t * mutex); - - -static int fastmutex_create(const char *name, fastmutex_t * mutex) -{ - mutex->count = 0; - mutex->sem = create_semaphore(name, 0, 0); - return (mutex->sem < 0) ? -1 : 0; -} - - -static int fastmutex_destroy(fastmutex_t * mutex) -{ - if (fastmutex_timedlock(mutex, 0) == 0 || errno == EWOULDBLOCK) { - return delete_semaphore(mutex->sem); - } - return 0; -} - - -static int fastmutex_lock(fastmutex_t * mutex) -{ - atomic_t prev = atomic_add(&mutex->count, 1); - if (prev > 0) - return lock_semaphore(mutex->sem); - return 0; -} - - -static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout) -{ - atomic_t prev = atomic_add(&mutex->count, 1); - if (prev > 0) - return lock_semaphore_x(mutex->sem, 1, 0, timeout); - return 0; -} - - -static int fastmutex_unlock(fastmutex_t * mutex) -{ - atomic_t prev = atomic_add(&mutex->count, -1); - if (prev > 1) - return unlock_semaphore(mutex->sem); - return 0; -} - - -#endif /* FASTLOCK */ - - -/* - * Initialization. - * - */ -static void PyThread__init_thread(void) -{ - /* Do nothing. */ - return; -} - - -/* - * Thread support. - * - */ - -static atomic_t thread_count = 0; - -long PyThread_start_new_thread(void (*func) (void *), void *arg) -{ - status_t success = -1; - thread_id tid; - char name[OS_NAME_LENGTH]; - atomic_t this_thread; - - dprintf(("PyThread_start_new_thread called\n")); - - this_thread = atomic_add(&thread_count, 1); - PyOS_snprintf(name, sizeof(name), "python thread (%d)", this_thread); - - tid = spawn_thread(name, func, NORMAL_PRIORITY, 0, arg); - if (tid < 0) { - dprintf(("PyThread_start_new_thread spawn_thread failed: %s\n", strerror(errno))); - } else { - success = resume_thread(tid); - if (success < 0) { - dprintf(("PyThread_start_new_thread resume_thread failed: %s\n", strerror(errno))); - } - } - - return (success < 0 ? -1 : tid); -} - - -long PyThread_get_thread_ident(void) -{ - return get_thread_id(NULL); -} - - -static void do_PyThread_exit_thread(int no_cleanup) -{ - dprintf(("PyThread_exit_thread called\n")); - - /* Thread-safe way to read a variable without a mutex: */ - if (atomic_add(&thread_count, 0) == 0) { - /* No threads around, so exit main(). */ - if (no_cleanup) - _exit(0); - else - exit(0); - } else { - /* We're a thread */ - exit_thread(0); - } -} - - -void PyThread_exit_thread(void) -{ - do_PyThread_exit_thread(0); -} - - -void PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - - -#ifndef NO_EXIT_PROG -static void do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); - - /* No need to do anything, the threads get torn down if main()exits. */ - if (no_cleanup) - _exit(status); - else - exit(status); -} - - -void PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - - -void PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); -} -#endif /* NO_EXIT_PROG */ - - -/* - * Lock support. - * - */ - -static atomic_t lock_count = 0; - -PyThread_type_lock PyThread_allocate_lock(void) -{ -#ifdef FASTLOCK - fastmutex_t *lock; -#else - sem_id sema; -#endif - char name[OS_NAME_LENGTH]; - atomic_t this_lock; - - dprintf(("PyThread_allocate_lock called\n")); - -#ifdef FASTLOCK - lock = (fastmutex_t *) malloc(sizeof(fastmutex_t)); - if (lock == NULL) { - dprintf(("PyThread_allocate_lock failed: out of memory\n")); - return (PyThread_type_lock) NULL; - } -#endif - this_lock = atomic_add(&lock_count, 1); - PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock); - -#ifdef FASTLOCK - if (fastmutex_create(name, lock) < 0) { - dprintf(("PyThread_allocate_lock failed: %s\n", - strerror(errno))); - free(lock); - lock = NULL; - } - dprintf(("PyThread_allocate_lock()-> %p\n", lock)); - return (PyThread_type_lock) lock; -#else - sema = create_semaphore(name, 1, 0); - if (sema < 0) { - dprintf(("PyThread_allocate_lock failed: %s\n", - strerror(errno))); - sema = 0; - } - dprintf(("PyThread_allocate_lock()-> %p\n", sema)); - return (PyThread_type_lock) sema; -#endif -} - - -void PyThread_free_lock(PyThread_type_lock lock) -{ - dprintf(("PyThread_free_lock(%p) called\n", lock)); - -#ifdef FASTLOCK - if (fastmutex_destroy((fastmutex_t *) lock) < 0) { - dprintf(("PyThread_free_lock(%p) failed: %s\n", lock, - strerror(errno))); - } - free(lock); -#else - if (delete_semaphore((sem_id) lock) < 0) { - dprintf(("PyThread_free_lock(%p) failed: %s\n", lock, - strerror(errno))); - } -#endif -} - - -int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) -{ - int retval; - - dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, - waitflag)); - -#ifdef FASTLOCK - if (waitflag) - retval = fastmutex_lock((fastmutex_t *) lock); - else - retval = fastmutex_timedlock((fastmutex_t *) lock, 0); -#else - if (waitflag) - retval = lock_semaphore((sem_id) lock); - else - retval = lock_semaphore_x((sem_id) lock, 1, 0, 0); -#endif - if (retval < 0) { - dprintf(("PyThread_acquire_lock(%p, %d) failed: %s\n", - lock, waitflag, strerror(errno))); - } - dprintf(("PyThread_acquire_lock(%p, %d)-> %d\n", lock, waitflag, - retval)); - return retval < 0 ? 0 : 1; -} - - -void PyThread_release_lock(PyThread_type_lock lock) -{ - dprintf(("PyThread_release_lock(%p) called\n", lock)); - -#ifdef FASTLOCK - if (fastmutex_unlock((fastmutex_t *) lock) < 0) { - dprintf(("PyThread_release_lock(%p) failed: %s\n", lock, - strerror(errno))); - } -#else - if (unlock_semaphore((sem_id) lock) < 0) { - dprintf(("PyThread_release_lock(%p) failed: %s\n", lock, - strerror(errno))); - } -#endif -} diff --git a/Python/thread_cthread.h b/Python/thread_cthread.h index 8cb504459f..1b3e3904cd 100644 --- a/Python/thread_cthread.h +++ b/Python/thread_cthread.h @@ -50,58 +50,14 @@ PyThread_get_thread_ident(void) return (long) cthread_self(); } -static void -do_PyThread_exit_thread(int no_cleanup) -{ - dprintf(("PyThread_exit_thread called\n")); - if (!initialized) - if (no_cleanup) - _exit(0); - else - exit(0); - cthread_exit(0); -} - void PyThread_exit_thread(void) { - do_PyThread_exit_thread(0); -} - -void -PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static -void do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); + dprintf(("PyThread_exit_thread called\n")); if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); - if (no_cleanup) - _exit(status); - else - exit(status); -} - -void -PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void -PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); + exit(0); + cthread_exit(0); } -#endif /* NO_EXIT_PROG */ /* * Lock support. diff --git a/Python/thread_foobar.h b/Python/thread_foobar.h index c2dffa66c1..d2b78c5cae 100644 --- a/Python/thread_foobar.h +++ b/Python/thread_foobar.h @@ -29,53 +29,13 @@ PyThread_get_thread_ident(void) PyThread_init_thread(); } -static -void do_PyThread_exit_thread(int no_cleanup) -{ - dprintf(("PyThread_exit_thread called\n")); - if (!initialized) - if (no_cleanup) - _exit(0); - else - exit(0); -} - void PyThread_exit_thread(void) { - do_PyThread_exit_thread(0); -} - -void -PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static -void do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); + dprintf(("PyThread_exit_thread called\n")); if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); -} - -void -PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void -PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); + exit(0); } -#endif /* NO_EXIT_PROG */ /* * Lock support. diff --git a/Python/thread_lwp.h b/Python/thread_lwp.h index 7519cd454e..ba7b37ad7e 100644 --- a/Python/thread_lwp.h +++ b/Python/thread_lwp.h @@ -47,50 +47,14 @@ long PyThread_get_thread_ident(void) return tid.thread_id; } -static void do_PyThread_exit_thread(int no_cleanup) +void PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); if (!initialized) - if (no_cleanup) - _exit(0); - else - exit(0); + exit(0); lwp_destroy(SELF); } -void PyThread_exit_thread(void) -{ - do_PyThread_exit_thread(0); -} - -void PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static void do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); - if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); - pod_exit(status); -} - -void PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); -} -#endif /* NO_EXIT_PROG */ - /* * Lock support. */ diff --git a/Python/thread_nt.h b/Python/thread_nt.h index e3a3387f8d..684b54598d 100644 --- a/Python/thread_nt.h +++ b/Python/thread_nt.h @@ -34,13 +34,13 @@ DeleteNonRecursiveMutex(PNRMUTEX mutex) } DWORD -EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait) +EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds) { /* Assume that the thread waits successfully */ DWORD ret ; /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */ - if (!wait) + if (milliseconds == 0) { if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1) return WAIT_TIMEOUT ; @@ -49,7 +49,7 @@ EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait) else ret = InterlockedIncrement(&mutex->owned) ? /* Some thread owns the mutex, let's wait... */ - WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ; + WaitForSingleObject(mutex->hevent, milliseconds) : WAIT_OBJECT_0 ; mutex->thread_id = GetCurrentThreadId() ; /* We own it */ return ret ; @@ -203,16 +203,6 @@ PyThread_exit_thread(void) #endif } -#ifndef NO_EXIT_PROG -void -PyThread_exit_prog(int status) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); - if (!initialized) - exit(status); -} -#endif /* NO_EXIT_PROG */ - /* * Lock support. It has too be implemented as semaphores. * I [Dag] tried to implement it with mutex but I could find a way to @@ -248,19 +238,47 @@ PyThread_free_lock(PyThread_type_lock aLock) * and 0 if the lock was not acquired. This means a 0 is returned * if the lock has already been acquired by this thread! */ -int -PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) +PyLockStatus +PyThread_acquire_lock_timed(PyThread_type_lock aLock, + PY_TIMEOUT_T microseconds, int intr_flag) { - int success ; + /* Fow now, intr_flag does nothing on Windows, and lock acquires are + * uninterruptible. */ + PyLockStatus success; + PY_TIMEOUT_T milliseconds; + + if (microseconds >= 0) { + milliseconds = microseconds / 1000; + if (microseconds % 1000 > 0) + ++milliseconds; + if ((DWORD) milliseconds != milliseconds) + Py_FatalError("Timeout too large for a DWORD, " + "please check PY_TIMEOUT_MAX"); + } + else + milliseconds = INFINITE; - dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag)); + dprintf(("%ld: PyThread_acquire_lock_timed(%p, %lld) called\n", + PyThread_get_thread_ident(), aLock, microseconds)); - success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ; + if (aLock && EnterNonRecursiveMutex((PNRMUTEX)aLock, + (DWORD)milliseconds) == WAIT_OBJECT_0) { + success = PY_LOCK_ACQUIRED; + } + else { + success = PY_LOCK_FAILURE; + } - dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success)); + dprintf(("%ld: PyThread_acquire_lock(%p, %lld) -> %d\n", + PyThread_get_thread_ident(), aLock, microseconds, success)); return success; } +int +PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) +{ + return PyThread_acquire_lock_timed(aLock, waitflag ? -1 : 0, 0); +} void PyThread_release_lock(PyThread_type_lock aLock) @@ -306,7 +324,10 @@ _pythread_nt_set_stacksize(size_t size) int PyThread_create_key(void) { - return (int) TlsAlloc(); + DWORD result= TlsAlloc(); + if (result == TLS_OUT_OF_INDEXES) + return -1; + return (int)result; } void diff --git a/Python/thread_os2.h b/Python/thread_os2.h index 28284bbc06..1b264b5ad5 100644 --- a/Python/thread_os2.h +++ b/Python/thread_os2.h @@ -68,56 +68,16 @@ PyThread_get_thread_ident(void) #endif } -static void -do_PyThread_exit_thread(int no_cleanup) +void +PyThread_exit_thread(void) { dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident())); if (!initialized) - if (no_cleanup) - _exit(0); - else - exit(0); + exit(0); _endthread(); } -void -PyThread_exit_thread(void) -{ - do_PyThread_exit_thread(0); -} - -void -PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static void -do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); - if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); -} - -void -PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void -PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); -} -#endif /* NO_EXIT_PROG */ - /* * Lock support. This is implemented with an event semaphore and critical * sections to make it behave more like a posix mutex than its OS/2 diff --git a/Python/thread_pth.h b/Python/thread_pth.h index 1f1694a4d4..82a00e72ba 100644 --- a/Python/thread_pth.h +++ b/Python/thread_pth.h @@ -74,49 +74,14 @@ long PyThread_get_thread_ident(void) return (long) *(long *) &threadid; } -static void do_PyThread_exit_thread(int no_cleanup) +void PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); if (!initialized) { - if (no_cleanup) - _exit(0); - else - exit(0); + exit(0); } } -void PyThread_exit_thread(void) -{ - do_PyThread_exit_thread(0); -} - -void PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static void do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); - if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); -} - -void PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); -} -#endif /* NO_EXIT_PROG */ - /* * Lock support. */ diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 32fd2d0ef7..ffc791c578 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -64,7 +64,8 @@ /* Whether or not to use semaphores directly rather than emulating them with * mutexes and condition variables: */ -#if defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) +#if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \ + defined(HAVE_SEM_TIMEDWAIT)) # define USE_SEMAPHORES #else # undef USE_SEMAPHORES @@ -83,6 +84,26 @@ #endif +/* We assume all modern POSIX systems have gettimeofday() */ +#ifdef GETTIMEOFDAY_NO_TZ +#define GETTIMEOFDAY(ptv) gettimeofday(ptv) +#else +#define GETTIMEOFDAY(ptv) gettimeofday(ptv, (struct timezone *)NULL) +#endif + +#define MICROSECONDS_TO_TIMESPEC(microseconds, ts) \ +do { \ + struct timeval tv; \ + GETTIMEOFDAY(&tv); \ + tv.tv_usec += microseconds % 1000000; \ + tv.tv_sec += microseconds / 1000000; \ + tv.tv_sec += tv.tv_usec / 1000000; \ + tv.tv_usec %= 1000000; \ + ts.tv_sec = tv.tv_sec; \ + ts.tv_nsec = tv.tv_usec * 1000; \ +} while(0) + + /* A pthread mutex isn't sufficient to model the Python lock type * because, according to Draft 5 of the docs (P1003.4a/D5), both of the * following are undefined: @@ -225,55 +246,15 @@ PyThread_get_thread_ident(void) #endif } -static void -do_PyThread_exit_thread(int no_cleanup) +void +PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); if (!initialized) { - if (no_cleanup) - _exit(0); - else - exit(0); + exit(0); } } -void -PyThread_exit_thread(void) -{ - do_PyThread_exit_thread(0); -} - -void -PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static void -do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); - if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); -} - -void -PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void -PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); -} -#endif /* NO_EXIT_PROG */ - #ifdef USE_SEMAPHORES /* @@ -335,31 +316,56 @@ fix_status(int status) return (status == -1) ? errno : status; } -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +PyLockStatus +PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, + int intr_flag) { - int success; + PyLockStatus success; sem_t *thelock = (sem_t *)lock; int status, error = 0; + struct timespec ts; - dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", + lock, microseconds, intr_flag)); + if (microseconds > 0) + MICROSECONDS_TO_TIMESPEC(microseconds, ts); do { - if (waitflag) - status = fix_status(sem_wait(thelock)); - else + if (microseconds > 0) + status = fix_status(sem_timedwait(thelock, &ts)); + else if (microseconds == 0) status = fix_status(sem_trywait(thelock)); - } while (status == EINTR); /* Retry if interrupted by a signal */ - - if (waitflag) { - CHECK_STATUS("sem_wait"); - } else if (status != EAGAIN) { - CHECK_STATUS("sem_trywait"); + else + status = fix_status(sem_wait(thelock)); + /* Retry if interrupted by a signal, unless the caller wants to be + notified. */ + } while (!intr_flag && status == EINTR); + + /* Don't check the status if we're stopping because of an interrupt. */ + if (!(intr_flag && status == EINTR)) { + if (microseconds > 0) { + if (status != ETIMEDOUT) + CHECK_STATUS("sem_timedwait"); + } + else if (microseconds == 0) { + if (status != EAGAIN) + CHECK_STATUS("sem_trywait"); + } + else { + CHECK_STATUS("sem_wait"); + } } - success = (status == 0) ? 1 : 0; + if (status == 0) { + success = PY_LOCK_ACQUIRED; + } else if (intr_flag && status == EINTR) { + success = PY_LOCK_INTR; + } else { + success = PY_LOCK_FAILURE; + } - dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", + lock, microseconds, intr_flag, success)); return success; } @@ -398,6 +404,12 @@ PyThread_allocate_lock(void) status = pthread_mutex_init(&lock->mut, pthread_mutexattr_default); CHECK_STATUS("pthread_mutex_init"); + /* Mark the pthread mutex underlying a Python mutex as + pure happens-before. We can't simply mark the + Python-level mutex as a mutex because it can be + acquired and released in different threads, which + will cause errors. */ + _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut); status = pthread_cond_init(&lock->lock_released, pthread_condattr_default); @@ -430,37 +442,69 @@ PyThread_free_lock(PyThread_type_lock lock) free((void *)thelock); } -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +PyLockStatus +PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, + int intr_flag) { - int success; + PyLockStatus success; pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; - dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", + lock, microseconds, intr_flag)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[1]"); - success = thelock->locked == 0; - if ( !success && waitflag ) { + if (thelock->locked == 0) { + success = PY_LOCK_ACQUIRED; + } else if (microseconds == 0) { + success = PY_LOCK_FAILURE; + } else { + struct timespec ts; + if (microseconds > 0) + MICROSECONDS_TO_TIMESPEC(microseconds, ts); /* continue trying until we get the lock */ /* mut must be locked by me -- part of the condition * protocol */ - while ( thelock->locked ) { - status = pthread_cond_wait(&thelock->lock_released, - &thelock->mut); - CHECK_STATUS("pthread_cond_wait"); + success = PY_LOCK_FAILURE; + while (success == PY_LOCK_FAILURE) { + if (microseconds > 0) { + status = pthread_cond_timedwait( + &thelock->lock_released, + &thelock->mut, &ts); + if (status == ETIMEDOUT) + break; + CHECK_STATUS("pthread_cond_timed_wait"); + } + else { + status = pthread_cond_wait( + &thelock->lock_released, + &thelock->mut); + CHECK_STATUS("pthread_cond_wait"); + } + + if (intr_flag && status == 0 && thelock->locked) { + /* We were woken up, but didn't get the lock. We probably received + * a signal. Return PY_LOCK_INTR to allow the caller to handle + * it and retry. */ + success = PY_LOCK_INTR; + break; + } else if (status == 0 && !thelock->locked) { + success = PY_LOCK_ACQUIRED; + } else { + success = PY_LOCK_FAILURE; + } } - success = 1; } - if (success) thelock->locked = 1; + if (success == PY_LOCK_ACQUIRED) thelock->locked = 1; status = pthread_mutex_unlock( &thelock->mut ); CHECK_STATUS("pthread_mutex_unlock[1]"); - if (error) success = 0; - dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + if (error) success = PY_LOCK_FAILURE; + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", + lock, microseconds, intr_flag, success)); return success; } @@ -487,6 +531,12 @@ PyThread_release_lock(PyThread_type_lock lock) #endif /* USE_SEMAPHORES */ +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0); +} + /* set the thread stack size. * Return 0 if size is valid, -1 if size is invalid, * -2 if setting stack size is not supported. @@ -531,3 +581,46 @@ _pythread_pthread_set_stacksize(size_t size) } #define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x) + +#define Py_HAVE_NATIVE_TLS + +int +PyThread_create_key(void) +{ + pthread_key_t key; + int fail = pthread_key_create(&key, NULL); + return fail ? -1 : key; +} + +void +PyThread_delete_key(int key) +{ + pthread_key_delete(key); +} + +void +PyThread_delete_key_value(int key) +{ + pthread_setspecific(key, NULL); +} + +int +PyThread_set_key_value(int key, void *value) +{ + int fail; + void *oldValue = pthread_getspecific(key); + if (oldValue != NULL) + return 0; + fail = pthread_setspecific(key, value); + return fail ? -1 : 0; +} + +void * +PyThread_get_key_value(int key) +{ + return pthread_getspecific(key); +} + +void +PyThread_ReInitTLS(void) +{} diff --git a/Python/thread_sgi.h b/Python/thread_sgi.h index 679d113583..771ab2cc60 100644 --- a/Python/thread_sgi.h +++ b/Python/thread_sgi.h @@ -17,9 +17,6 @@ static ulock_t wait_lock; /* lock used to wait for other threads */ static int waiting_for_threads; /* protected by count_lock */ static int nthreads; /* protected by count_lock */ static int exit_status; -#ifndef NO_EXIT_PROG -static int do_exit; /* indicates that the program is to exit */ -#endif static int exiting; /* we're already exiting (for maybe_exit) */ static pid_t my_pid; /* PID of main thread */ static struct pidlist { @@ -27,53 +24,11 @@ static struct pidlist { pid_t child; } pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */ static int maxpidindex; /* # of PIDs in pidlist */ - -#ifndef NO_EXIT_PROG -/* - * This routine is called as a signal handler when another thread - * exits. When that happens, we must see whether we have to exit as - * well (because of an PyThread_exit_prog()) or whether we should continue on. - */ -static void exit_sig(void) -{ - d2printf(("exit_sig called\n")); - if (exiting && getpid() == my_pid) { - d2printf(("already exiting\n")); - return; - } - if (do_exit) { - d2printf(("exiting in exit_sig\n")); -#ifdef Py_DEBUG - if ((thread_debug & 8) == 0) - thread_debug &= ~1; /* don't produce debug messages */ -#endif - PyThread_exit_thread(); - } -} - -/* - * This routine is called when a process calls exit(). If that wasn't - * done from the library, we do as if an PyThread_exit_prog() was intended. - */ -static void maybe_exit(void) -{ - dprintf(("maybe_exit called\n")); - if (exiting) { - dprintf(("already exiting\n")); - return; - } - PyThread_exit_prog(0); -} -#endif /* NO_EXIT_PROG */ - /* * Initialization. */ static void PyThread__init_thread(void) { -#ifndef NO_EXIT_PROG - struct sigaction s; -#endif /* NO_EXIT_PROG */ #ifdef USE_DL long addr, size; #endif /* USE_DL */ @@ -93,16 +48,6 @@ static void PyThread__init_thread(void) if (usconfig(CONF_INITUSERS, 16) < 0) perror("usconfig - CONF_INITUSERS"); my_pid = getpid(); /* so that we know which is the main thread */ -#ifndef NO_EXIT_PROG - atexit(maybe_exit); - s.sa_handler = exit_sig; - sigemptyset(&s.sa_mask); - /*sigaddset(&s.sa_mask, SIGUSR1);*/ - s.sa_flags = 0; - sigaction(SIGUSR1, &s, 0); - if (prctl(PR_SETEXITSIG, SIGUSR1) < 0) - perror("prctl - PR_SETEXITSIG"); -#endif /* NO_EXIT_PROG */ if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) perror("usconfig - CONF_ARENATYPE"); usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */ @@ -227,46 +172,24 @@ long PyThread_get_thread_ident(void) return getpid(); } -static void do_PyThread_exit_thread(int no_cleanup) +void PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); if (!initialized) - if (no_cleanup) - _exit(0); - else - exit(0); + exit(0); if (ussetlock(count_lock) < 0) perror("ussetlock (count_lock)"); nthreads--; if (getpid() == my_pid) { /* main thread; wait for other threads to exit */ exiting = 1; -#ifndef NO_EXIT_PROG - if (do_exit) { - int i; - - /* notify other threads */ - clean_threads(); - if (nthreads >= 0) { - dprintf(("kill other threads\n")); - for (i = 0; i < maxpidindex; i++) - if (pidlist[i].child > 0) - (void) kill(pidlist[i].child, - SIGKILL); - _exit(exit_status); - } - } -#endif /* NO_EXIT_PROG */ waiting_for_threads = 1; if (ussetlock(wait_lock) < 0) perror("ussetlock (wait_lock)"); for (;;) { if (nthreads < 0) { dprintf(("really exit (%d)\n", exit_status)); - if (no_cleanup) - _exit(exit_status); - else - exit(exit_status); + exit(exit_status); } if (usunsetlock(count_lock) < 0) perror("usunsetlock (count_lock)"); @@ -283,50 +206,11 @@ static void do_PyThread_exit_thread(int no_cleanup) if (usunsetlock(wait_lock) < 0) perror("usunsetlock (wait_lock)"); } -#ifndef NO_EXIT_PROG - else if (do_exit) - (void) kill(my_pid, SIGUSR1); -#endif /* NO_EXIT_PROG */ if (usunsetlock(count_lock) < 0) perror("usunsetlock (count_lock)"); _exit(0); } -void PyThread_exit_thread(void) -{ - do_PyThread_exit_thread(0); -} - -void PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static void do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); - if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); - do_exit = 1; - exit_status = status; - do_PyThread_exit_thread(no_cleanup); -} - -void PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); -} -#endif /* NO_EXIT_PROG */ - /* * Lock support. */ diff --git a/Python/thread_solaris.h b/Python/thread_solaris.h index 56ac8ae40f..1ce1cfcba9 100644 --- a/Python/thread_solaris.h +++ b/Python/thread_solaris.h @@ -64,58 +64,14 @@ PyThread_get_thread_ident(void) return thr_self(); } -static void -do_PyThread_exit_thread(int no_cleanup) -{ - dprintf(("PyThread_exit_thread called\n")); - if (!initialized) - if (no_cleanup) - _exit(0); - else - exit(0); - thr_exit(0); -} - void PyThread_exit_thread(void) { - do_PyThread_exit_thread(0); -} - -void -PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static void -do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); + dprintf(("PyThread_exit_thread called\n")); if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); - if (no_cleanup) - _exit(status); - else - exit(status); -} - -void -PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void -PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); + exit(0); + thr_exit(0); } -#endif /* NO_EXIT_PROG */ /* * Lock support. diff --git a/Python/thread_wince.h b/Python/thread_wince.h index 33cf5a4fad..51ddc02f9a 100644 --- a/Python/thread_wince.h +++ b/Python/thread_wince.h @@ -53,48 +53,13 @@ long PyThread_get_thread_ident(void) return GetCurrentThreadId(); } -static void do_PyThread_exit_thread(int no_cleanup) -{ - dprintf(("%ld: do_PyThread_exit_thread called\n", PyThread_get_thread_ident())); - if (!initialized) - if (no_cleanup) - exit(0); /* XXX - was _exit()!! */ - else - exit(0); - _endthread(); -} - void PyThread_exit_thread(void) { - do_PyThread_exit_thread(0); -} - -void PyThread__exit_thread(void) -{ - do_PyThread_exit_thread(1); -} - -#ifndef NO_EXIT_PROG -static void do_PyThread_exit_prog(int status, int no_cleanup) -{ - dprintf(("PyThread_exit_prog(%d) called\n", status)); + dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident())); if (!initialized) - if (no_cleanup) - _exit(status); - else - exit(status); -} - -void PyThread_exit_prog(int status) -{ - do_PyThread_exit_prog(status, 0); -} - -void PyThread__exit_prog(int status) -{ - do_PyThread_exit_prog(status, 1); + exit(0); + _endthread(); } -#endif /* NO_EXIT_PROG */ /* * Lock support. It has to be implemented using Mutexes, as diff --git a/Python/traceback.c b/Python/traceback.c index 2f1c213fa3..59bb3f0d15 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -7,7 +7,6 @@ #include "frameobject.h" #include "structmember.h" #include "osdefs.h" -#include "traceback.h" #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif @@ -114,8 +113,7 @@ newtracebackobject(PyTracebackObject *next, PyFrameObject *frame) Py_XINCREF(frame); tb->tb_frame = frame; tb->tb_lasti = frame->f_lasti; - tb->tb_lineno = PyCode_Addr2Line(frame->f_code, - frame->f_lasti); + tb->tb_lineno = PyFrame_GetLineNumber(frame); PyObject_GC_Track(tb); } return tb; @@ -150,8 +148,7 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * Py_ssize_t len; PyObject* result; - filebytes = PyUnicode_AsEncodedObject(filename, - Py_FileSystemDefaultEncoding, "surrogateescape"); + filebytes = PyUnicode_EncodeFSDefault(filename); if (filebytes == NULL) { PyErr_Clear(); return NULL; @@ -179,9 +176,7 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * } if (!PyUnicode_Check(v)) continue; - - path = PyUnicode_AsEncodedObject(v, Py_FileSystemDefaultEncoding, - "surrogateescape"); + path = PyUnicode_EncodeFSDefault(v); if (path == NULL) { PyErr_Clear(); continue; |