mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-10 03:40:29 +00:00
LOAD_METHOD support for C methods
refer python/cpython@5566bbb8d5 refer python/cpython@93fac8dd35 refer python/cpython@7638eb892a refer python/cpython@25b87d3567 useful to keep the latest tag of 3.7 nearby when small things like function signatures change, helps to view the final form.
This commit is contained in:
parent
7328c09cd4
commit
281e84da03
4 changed files with 77 additions and 3 deletions
2
third_party/python/Include/descrobject.h
vendored
2
third_party/python/Include/descrobject.h
vendored
|
@ -91,6 +91,8 @@ PyObject * PyDescr_NewMember(PyTypeObject *,
|
||||||
PyObject * PyDescr_NewGetSet(PyTypeObject *,
|
PyObject * PyDescr_NewGetSet(PyTypeObject *,
|
||||||
struct PyGetSetDef *);
|
struct PyGetSetDef *);
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
|
PyObject * _PyMethodDescr_FastCallKeywords(
|
||||||
|
PyObject *descrobj, PyObject *const *stack, Py_ssize_t nargs, PyObject *kwnames);
|
||||||
PyObject * PyDescr_NewWrapper(PyTypeObject *,
|
PyObject * PyDescr_NewWrapper(PyTypeObject *,
|
||||||
struct wrapperbase *, void *);
|
struct wrapperbase *, void *);
|
||||||
#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)
|
#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)
|
||||||
|
|
8
third_party/python/Include/methodobject.h
vendored
8
third_party/python/Include/methodobject.h
vendored
|
@ -95,12 +95,20 @@ typedef struct {
|
||||||
PyObject *m_module; /* The __module__ attribute, can be anything */
|
PyObject *m_module; /* The __module__ attribute, can be anything */
|
||||||
PyObject *m_weakreflist; /* List of weak references */
|
PyObject *m_weakreflist; /* List of weak references */
|
||||||
} PyCFunctionObject;
|
} PyCFunctionObject;
|
||||||
|
|
||||||
PyObject * _PyMethodDef_RawFastCallDict(
|
PyObject * _PyMethodDef_RawFastCallDict(
|
||||||
PyMethodDef *method,
|
PyMethodDef *method,
|
||||||
PyObject *self,
|
PyObject *self,
|
||||||
PyObject **args,
|
PyObject **args,
|
||||||
Py_ssize_t nargs,
|
Py_ssize_t nargs,
|
||||||
PyObject *kwargs);
|
PyObject *kwargs);
|
||||||
|
|
||||||
|
PyObject * _PyMethodDef_RawFastCallKeywords(
|
||||||
|
PyMethodDef *method,
|
||||||
|
PyObject *self,
|
||||||
|
PyObject **args,
|
||||||
|
Py_ssize_t nargs,
|
||||||
|
PyObject *kwnames);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int PyCFunction_ClearFreeList(void);
|
int PyCFunction_ClearFreeList(void);
|
||||||
|
|
38
third_party/python/Objects/descrobject.c
vendored
38
third_party/python/Objects/descrobject.c
vendored
|
@ -264,6 +264,44 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same to methoddescr_call(), but use FASTCALL convention.
|
||||||
|
PyObject *
|
||||||
|
_PyMethodDescr_FastCallKeywords(PyObject *descrobj,
|
||||||
|
PyObject *const *args, Py_ssize_t nargs,
|
||||||
|
PyObject *kwnames)
|
||||||
|
{
|
||||||
|
assert(Py_TYPE(descrobj) == &PyMethodDescr_Type);
|
||||||
|
PyMethodDescrObject *descr = (PyMethodDescrObject *)descrobj;
|
||||||
|
PyObject *self, *result;
|
||||||
|
|
||||||
|
/* Make sure that the first argument is acceptable as 'self' */
|
||||||
|
if (nargs < 1) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"descriptor '%V' of '%.100s' "
|
||||||
|
"object needs an argument",
|
||||||
|
descr_name((PyDescrObject *)descr), "?",
|
||||||
|
PyDescr_TYPE(descr)->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
self = args[0];
|
||||||
|
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
|
||||||
|
(PyObject *)PyDescr_TYPE(descr))) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"descriptor '%V' "
|
||||||
|
"requires a '%.100s' object "
|
||||||
|
"but received a '%.100s'",
|
||||||
|
descr_name((PyDescrObject *)descr), "?",
|
||||||
|
PyDescr_TYPE(descr)->tp_name,
|
||||||
|
self->ob_type->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = _PyMethodDef_RawFastCallKeywords(descr->d_method, self,
|
||||||
|
args+1, nargs-1, kwnames);
|
||||||
|
result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
|
classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
|
||||||
PyObject *kwds)
|
PyObject *kwds)
|
||||||
|
|
32
third_party/python/Python/ceval.c
vendored
32
third_party/python/Python/ceval.c
vendored
|
@ -13,6 +13,7 @@
|
||||||
#include "third_party/python/Include/ceval.h"
|
#include "third_party/python/Include/ceval.h"
|
||||||
#include "third_party/python/Include/classobject.h"
|
#include "third_party/python/Include/classobject.h"
|
||||||
#include "third_party/python/Include/code.h"
|
#include "third_party/python/Include/code.h"
|
||||||
|
#include "third_party/python/Include/descrobject.h"
|
||||||
#include "third_party/python/Include/dictobject.h"
|
#include "third_party/python/Include/dictobject.h"
|
||||||
#include "third_party/python/Include/eval.h"
|
#include "third_party/python/Include/eval.h"
|
||||||
#include "third_party/python/Include/frameobject.h"
|
#include "third_party/python/Include/frameobject.h"
|
||||||
|
@ -4820,16 +4821,41 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
|
||||||
PyObject *x, *w;
|
PyObject *x, *w;
|
||||||
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
||||||
Py_ssize_t nargs = oparg - nkwargs;
|
Py_ssize_t nargs = oparg - nkwargs;
|
||||||
PyObject **stack;
|
PyObject **stack = (*pp_stack) - nargs - nkwargs;
|
||||||
/* Always dispatch PyCFunction first, because these are
|
/* Always dispatch PyCFunction first, because these are
|
||||||
presumed to be the most frequent callable object.
|
presumed to be the most frequent callable object.
|
||||||
*/
|
*/
|
||||||
if (PyCFunction_Check(func)) {
|
if (PyCFunction_Check(func)) {
|
||||||
PyThreadState *tstate = PyThreadState_GET();
|
PyThreadState *tstate = PyThreadState_GET();
|
||||||
PCALL(PCALL_CFUNCTION);
|
PCALL(PCALL_CFUNCTION);
|
||||||
stack = (*pp_stack) - nargs - nkwargs;
|
|
||||||
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
|
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
|
||||||
}
|
}
|
||||||
|
else if (Py_TYPE(func) == &PyMethodDescr_Type) {
|
||||||
|
PyThreadState *tstate = PyThreadState_GET();
|
||||||
|
if (nargs > 0 && tstate->use_tracing) {
|
||||||
|
/* We need to create a temporary bound method as argument
|
||||||
|
for profiling.
|
||||||
|
|
||||||
|
If nargs == 0, then this cannot work because we have no
|
||||||
|
"self". In any case, the call itself would raise
|
||||||
|
TypeError (foo needs an argument), so we just skip
|
||||||
|
profiling. */
|
||||||
|
PyObject *self = stack[0];
|
||||||
|
func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
|
||||||
|
if (func != NULL) {
|
||||||
|
C_TRACE(x, _PyCFunction_FastCallKeywords(func,
|
||||||
|
stack+1, nargs-1,
|
||||||
|
kwnames));
|
||||||
|
Py_DECREF(func);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = _PyMethodDescr_FastCallKeywords(func, stack, nargs, kwnames);
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
|
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
|
||||||
/* optimize access to bound methods */
|
/* optimize access to bound methods */
|
||||||
|
@ -4841,11 +4867,11 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
|
||||||
Py_INCREF(func);
|
Py_INCREF(func);
|
||||||
Py_SETREF(*pfunc, self);
|
Py_SETREF(*pfunc, self);
|
||||||
nargs++;
|
nargs++;
|
||||||
|
stack--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Py_INCREF(func);
|
Py_INCREF(func);
|
||||||
}
|
}
|
||||||
stack = (*pp_stack) - nargs - nkwargs;
|
|
||||||
if (PyFunction_Check(func)) {
|
if (PyFunction_Check(func)) {
|
||||||
x = _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
|
x = _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue