Add API for static strings, primarily good for identifiers.
Thanks to Konrad Schöbel and Jasper Schulz for helping with the mass-editing.
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 9105769..57424a6 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2082,10 +2082,11 @@
 {
     PyObject *keys;
     PyObject *fast;
+    _Py_identifier(keys);
 
     if (PyDict_CheckExact(o))
         return PyDict_Keys(o);
-    keys = PyObject_CallMethod(o, "keys", NULL);
+    keys = _PyObject_CallMethodId(o, &PyId_keys, NULL);
     if (keys == NULL)
         return NULL;
     fast = PySequence_Fast(keys, "o.keys() are not iterable");
@@ -2098,10 +2099,11 @@
 {
     PyObject *items;
     PyObject *fast;
+    _Py_identifier(items);
 
     if (PyDict_CheckExact(o))
         return PyDict_Items(o);
-    items = PyObject_CallMethod(o, "items", NULL);
+    items = _PyObject_CallMethodId(o, &PyId_items, NULL);
     if (items == NULL)
         return NULL;
     fast = PySequence_Fast(items, "o.items() are not iterable");
@@ -2114,10 +2116,11 @@
 {
     PyObject *values;
     PyObject *fast;
+    _Py_identifier(values);
 
     if (PyDict_CheckExact(o))
         return PyDict_Values(o);
-    values = PyObject_CallMethod(o, "values", NULL);
+    values = _PyObject_CallMethodId(o, &PyId_values, NULL);
     if (values == NULL)
         return NULL;
     fast = PySequence_Fast(values, "o.values() are not iterable");
@@ -2223,11 +2226,39 @@
     return call_function_tail(callable, args);
 }
 
+static PyObject*
+callmethod(PyObject* func, char *format, va_list va, int is_size_t)
+{
+    PyObject *retval = NULL;
+    PyObject *args;
+
+    if (!PyCallable_Check(func)) {
+        type_error("attribute of type '%.200s' is not callable", func);
+        goto exit;
+    }
+
+    if (format && *format) {
+        if (is_size_t)
+            args = _Py_VaBuildValue_SizeT(format, va);
+        else
+            args = Py_VaBuildValue(format, va);
+    }
+    else
+        args = PyTuple_New(0);
+
+    retval = call_function_tail(func, args);
+
+  exit:
+    /* args gets consumed in call_function_tail */
+    Py_XDECREF(func);
+
+    return retval;
+}
+
 PyObject *
 PyObject_CallMethod(PyObject *o, char *name, char *format, ...)
 {
     va_list va;
-    PyObject *args;
     PyObject *func = NULL;
     PyObject *retval = NULL;
 
@@ -2240,25 +2271,31 @@
         return 0;
     }
 
-    if (!PyCallable_Check(func)) {
-        type_error("attribute of type '%.200s' is not callable", func);
-        goto exit;
+    va_start(va, format);
+    retval = callmethod(func, format, va, 0);
+    va_end(va);
+    return retval;
+}
+
+PyObject *
+_PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, char *format, ...)
+{
+    va_list va;
+    PyObject *func = NULL;
+    PyObject *retval = NULL;
+
+    if (o == NULL || name == NULL)
+        return null_error();
+
+    func = _PyObject_GetAttrId(o, name);
+    if (func == NULL) {
+        PyErr_SetString(PyExc_AttributeError, name->string);
+        return 0;
     }
 
-    if (format && *format) {
-        va_start(va, format);
-        args = Py_VaBuildValue(format, va);
-        va_end(va);
-    }
-    else
-        args = PyTuple_New(0);
-
-    retval = call_function_tail(func, args);
-
-  exit:
-    /* args gets consumed in call_function_tail */
-    Py_XDECREF(func);
-
+    va_start(va, format);
+    retval = callmethod(func, format, va, 0);
+    va_end(va);
     return retval;
 }
 
@@ -2266,9 +2303,8 @@
 _PyObject_CallMethod_SizeT(PyObject *o, char *name, char *format, ...)
 {
     va_list va;
-    PyObject *args;
     PyObject *func = NULL;
-    PyObject *retval = NULL;
+    PyObject *retval;
 
     if (o == NULL || name == NULL)
         return null_error();
@@ -2278,29 +2314,32 @@
         PyErr_SetString(PyExc_AttributeError, name);
         return 0;
     }
-
-    if (!PyCallable_Check(func)) {
-        type_error("attribute of type '%.200s' is not callable", func);
-        goto exit;
-    }
-
-    if (format && *format) {
-        va_start(va, format);
-        args = _Py_VaBuildValue_SizeT(format, va);
-        va_end(va);
-    }
-    else
-        args = PyTuple_New(0);
-
-    retval = call_function_tail(func, args);
-
-  exit:
-    /* args gets consumed in call_function_tail */
-    Py_XDECREF(func);
-
+    va_start(va, format);
+    retval = callmethod(func, format, va, 1);
+    va_end(va);
     return retval;
 }
 
+PyObject *
+_PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, char *format, ...)
+{
+    va_list va;
+    PyObject *func = NULL;
+    PyObject *retval;
+
+    if (o == NULL || name == NULL)
+        return null_error();
+
+    func = _PyObject_GetAttrId(o, name);
+    if (func == NULL) {
+        PyErr_SetString(PyExc_AttributeError, name->string);
+        return NULL;
+    }
+    va_start(va, format);
+    retval = callmethod(func, format, va, 1);
+    va_end(va);
+    return retval;
+}
 
 static PyObject *
 objargs_mktuple(va_list va)
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index a786bae..046eebd 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -703,34 +703,39 @@
 proxy_get(proxyobject *pp, PyObject *args)
 {
     PyObject *key, *def = Py_None;
+    _Py_identifier(get);
 
     if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))
         return NULL;
-    return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
+    return _PyObject_CallMethodId(pp->dict, &PyId_get, "(OO)", key, def);
 }
 
 static PyObject *
 proxy_keys(proxyobject *pp)
 {
-    return PyObject_CallMethod(pp->dict, "keys", NULL);
+    _Py_identifier(keys);
+    return _PyObject_CallMethodId(pp->dict, &PyId_keys, NULL);
 }
 
 static PyObject *
 proxy_values(proxyobject *pp)
 {
-    return PyObject_CallMethod(pp->dict, "values", NULL);
+    _Py_identifier(values);
+    return _PyObject_CallMethodId(pp->dict, &PyId_values, NULL);
 }
 
 static PyObject *
 proxy_items(proxyobject *pp)
 {
-    return PyObject_CallMethod(pp->dict, "items", NULL);
+    _Py_identifier(items);
+    return _PyObject_CallMethodId(pp->dict, &PyId_items, NULL);
 }
 
 static PyObject *
 proxy_copy(proxyobject *pp)
 {
-    return PyObject_CallMethod(pp->dict, "copy", NULL);
+    _Py_identifier(copy);
+    return _PyObject_CallMethodId(pp->dict, &PyId_copy, NULL);
 }
 
 static PyMethodDef proxy_methods[] = {
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index c4265da..220e621 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2707,10 +2707,12 @@
 {
     PyObject *result = PySet_New(self);
     PyObject *tmp;
+    _Py_identifier(difference_update);
+
     if (result == NULL)
         return NULL;
 
-    tmp = PyObject_CallMethod(result, "difference_update", "O", other);
+    tmp = _PyObject_CallMethodId(result, &PyId_difference_update, "O", other);
     if (tmp == NULL) {
         Py_DECREF(result);
         return NULL;
@@ -2725,10 +2727,12 @@
 {
     PyObject *result = PySet_New(self);
     PyObject *tmp;
+    _Py_identifier(intersection_update);
+
     if (result == NULL)
         return NULL;
 
-    tmp = PyObject_CallMethod(result, "intersection_update", "O", other);
+    tmp = _PyObject_CallMethodId(result, &PyId_intersection_update, "O", other);
     if (tmp == NULL) {
         Py_DECREF(result);
         return NULL;
@@ -2761,10 +2765,12 @@
 {
     PyObject *result = PySet_New(self);
     PyObject *tmp;
+    _Py_identifier(symmetric_difference_update);
+
     if (result == NULL)
         return NULL;
 
-    tmp = PyObject_CallMethod(result, "symmetric_difference_update", "O",
+    tmp = _PyObject_CallMethodId(result, &PyId_symmetric_difference_update, "O",
                               other);
     if (tmp == NULL) {
         Py_DECREF(result);
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 6421543..f3006d0 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -30,11 +30,12 @@
               char *errors, char *newline, int closefd)
 {
     PyObject *io, *stream;
+    _Py_identifier(open);
 
     io = PyImport_ImportModule("io");
     if (io == NULL)
         return NULL;
-    stream = PyObject_CallMethod(io, "open", "isisssi", fd, mode,
+    stream = _PyObject_CallMethodId(io, &PyId_open, "isisssi", fd, mode,
                                  buffering, encoding, errors,
                                  newline, closefd);
     Py_DECREF(io);
diff --git a/Objects/object.c b/Objects/object.c
index aeaa4b5..7db60f3 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -811,6 +811,42 @@
 }
 
 PyObject *
+_PyObject_GetAttrId(PyObject *v, _Py_Identifier *name)
+{
+    PyObject *result;
+    PyObject *oname = _PyUnicode_FromId(name);
+    if (!oname)
+        return NULL;
+    result = PyObject_GetAttr(v, oname);
+    Py_DECREF(oname);
+    return result;
+}
+
+int
+_PyObject_HasAttrId(PyObject *v, _Py_Identifier *name)
+{
+    int result;
+    PyObject *oname = _PyUnicode_FromId(name);
+    if (!oname)
+        return -1;
+    result = PyObject_HasAttr(v, oname);
+    Py_DECREF(oname);
+    return result;
+}
+
+int
+_PyObject_SetAttrId(PyObject *v, _Py_Identifier *name, PyObject *w)
+{
+    int result;
+    PyObject *oname = _PyUnicode_FromId(name);
+    if (!oname)
+        return -1;
+    result = PyObject_SetAttr(v, oname, w);
+    Py_DECREF(oname);
+    return result;
+}
+
+PyObject *
 PyObject_GetAttr(PyObject *v, PyObject *name)
 {
     PyTypeObject *tp = Py_TYPE(v);
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 2e6eb0a..f94dfbf 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2897,6 +2897,7 @@
         PyObject *sorted;
         PyObject *sorted_methods = NULL;
         PyObject *joined = NULL;
+        _Py_identifier(join);
 
         /* Compute ", ".join(sorted(type.__abstractmethods__))
            into joined. */
@@ -2919,7 +2920,7 @@
             if (comma == NULL)
                 goto error;
         }
-        joined = PyObject_CallMethod(comma, "join",
+        joined = _PyObject_CallMethodId(comma, &PyId_join,
                                      "O",  sorted_methods);
         if (joined == NULL)
             goto error;
@@ -3184,6 +3185,7 @@
     PyObject *copyreg;
     PyObject *slotnames;
     static PyObject *str_slotnames;
+    _Py_identifier(_slotnames);
 
     if (str_slotnames == NULL) {
         str_slotnames = PyUnicode_InternFromString("__slotnames__");
@@ -3202,7 +3204,7 @@
     if (copyreg == NULL)
         return NULL;
 
-    slotnames = PyObject_CallMethod(copyreg, "_slotnames", "O", cls);
+    slotnames = _PyObject_CallMethodId(copyreg, &PyId__slotnames, "O", cls);
     Py_DECREF(copyreg);
     if (slotnames != NULL &&
         slotnames != Py_None &&
@@ -3323,7 +3325,8 @@
         Py_INCREF(dictitems);
     }
     else {
-        PyObject *items = PyObject_CallMethod(obj, "items", "");
+        _Py_identifier(items);
+        PyObject *items = _PyObject_CallMethodId(obj, &PyId_items, "");
         if (items == NULL)
             goto end;
         dictitems = PyObject_GetIter(items);
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index e904b6e..af92368 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -201,6 +201,9 @@
 /* The empty Unicode object is shared to improve performance. */
 static PyObject *unicode_empty;
 
+/* List of static strings. */
+static _Py_Identifier *static_strings;
+
 /* Single character Unicode strings in the Latin-1 range are being
    shared as well. */
 static PyObject *unicode_latin1[256];
@@ -1609,6 +1612,33 @@
     return PyUnicode_FromStringAndSize(u, size);
 }
 
+PyObject *
+_PyUnicode_FromId(_Py_Identifier *id)
+{
+    if (!id->object) {
+        id->object = PyUnicode_FromString(id->string);
+        if (!id->object)
+            return NULL;
+        PyUnicode_InternInPlace(&id->object);
+        assert(!id->next);
+        id->next = static_strings;
+        static_strings = id;
+    }
+    Py_INCREF(id->object);
+    return id->object;
+}
+
+void
+_PyUnicode_ClearStaticStrings()
+{
+    _Py_Identifier *i;
+    for (i = static_strings; i; i = i->next) {
+        Py_DECREF(i->object);
+        i->object = NULL;
+        i->next = NULL;
+    }
+}
+
 static PyObject*
 unicode_fromascii(const unsigned char* s, Py_ssize_t size)
 {
@@ -13523,6 +13553,7 @@
             unicode_latin1[i] = NULL;
         }
     }
+    _PyUnicode_ClearStaticStrings();
     (void)PyUnicode_ClearFreeList();
 }
 
diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c
index c99f6ba..594f0ea 100644
--- a/Objects/weakrefobject.c
+++ b/Objects/weakrefobject.c
@@ -440,8 +440,9 @@
 #define WRAP_METHOD(method, special) \
     static PyObject * \
     method(PyObject *proxy) { \
+            _Py_identifier(special); \
             UNWRAP(proxy); \
-                return PyObject_CallMethod(proxy, special, ""); \
+                return _PyObject_CallMethodId(proxy, &PyId_##special, ""); \
         }
 
 
@@ -584,7 +585,7 @@
 }
 
 
-WRAP_METHOD(proxy_bytes, "__bytes__")
+WRAP_METHOD(proxy_bytes, __bytes__)
 
 
 static PyMethodDef proxy_methods[] = {