[3.8] bpo-36974: separate vectorcall functions for each calling conve… · python/cpython@bf8e82f (original) (raw)

`@@ -226,80 +226,199 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)

`

226

226

`return -1;

`

227

227

`}

`

228

228

``

229

``

`-

static PyObject *

`

230

``

`-

methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)

`

231

``

`-

{

`

232

``

`-

Py_ssize_t nargs;

`

233

``

`-

PyObject *self, *result;

`

234

229

``

235

``

`-

/* Make sure that the first argument is acceptable as 'self' */

`

236

``

`-

assert(PyTuple_Check(args));

`

237

``

`-

nargs = PyTuple_GET_SIZE(args);

`

``

230

`+

/* Vectorcall functions for each of the PyMethodDescr calling conventions.

`

``

231

`+

`

``

232

`+

`

``

233

`+

*/

`

``

234

`+

static const char *

`

``

235

`+

get_name(PyObject *func) {

`

``

236

`+

assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));

`

``

237

`+

return ((PyMethodDescrObject *)func)->d_method->ml_name;

`

``

238

`+

}

`

``

239

+

``

240

`+

typedef void (*funcptr)(void);

`

``

241

+

``

242

`+

static inline int

`

``

243

`+

method_check_args(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)

`

``

244

`+

{

`

``

245

`+

assert(!PyErr_Occurred());

`

``

246

`+

assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));

`

238

247

`if (nargs < 1) {

`

239

248

`PyErr_Format(PyExc_TypeError,

`

240

``

`-

"descriptor '%V' of '%.100s' "

`

``

249

`+

"descriptor '%.200s' of '%.100s' "

`

241

250

`"object needs an argument",

`

242

``

`-

descr_name((PyDescrObject *)descr), "?",

`

243

``

`-

PyDescr_TYPE(descr)->tp_name);

`

244

``

`-

return NULL;

`

``

251

`+

get_name(func), PyDescr_TYPE(func)->tp_name);

`

``

252

`+

return -1;

`

245

253

` }

`

246

``

`-

self = PyTuple_GET_ITEM(args, 0);

`

``

254

`+

PyObject *self = args[0];

`

247

255

`if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),

`

248

``

`-

(PyObject *)PyDescr_TYPE(descr))) {

`

``

256

`+

(PyObject *)PyDescr_TYPE(func)))

`

``

257

`+

{

`

249

258

`PyErr_Format(PyExc_TypeError,

`

250

``

`-

"descriptor '%V' for '%.100s' objects "

`

``

259

`+

"descriptor '%.200s' for '%.100s' objects "

`

251

260

`"doesn't apply to a '%.100s' object",

`

252

``

`-

descr_name((PyDescrObject *)descr), "?",

`

253

``

`-

PyDescr_TYPE(descr)->tp_name,

`

254

``

`-

self->ob_type->tp_name);

`

``

261

`+

get_name(func), PyDescr_TYPE(func)->tp_name,

`

``

262

`+

Py_TYPE(self)->tp_name);

`

``

263

`+

return -1;

`

``

264

`+

}

`

``

265

`+

if (kwnames && PyTuple_GET_SIZE(kwnames)) {

`

``

266

`+

PyErr_Format(PyExc_TypeError,

`

``

267

`+

"%.200s() takes no keyword arguments", get_name(func));

`

``

268

`+

return -1;

`

``

269

`+

}

`

``

270

`+

return 0;

`

``

271

`+

}

`

``

272

+

``

273

`+

static inline funcptr

`

``

274

`+

method_enter_call(PyObject *func)

`

``

275

`+

{

`

``

276

`+

if (Py_EnterRecursiveCall(" while calling a Python object")) {

`

255

277

`return NULL;

`

256

278

` }

`

``

279

`+

return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth;

`

``

280

`+

}

`

257

281

``

258

``

`-

result = _PyMethodDef_RawFastCallDict(descr->d_method, self,

`

259

``

`-

&_PyTuple_ITEMS(args)[1], nargs - 1,

`

260

``

`-

kwargs);

`

261

``

`-

result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);

`

``

282

`+

/* Now the actual vectorcall functions */

`

``

283

`+

static PyObject *

`

``

284

`+

method_vectorcall_VARARGS(

`

``

285

`+

PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)

`

``

286

`+

{

`

``

287

`+

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);

`

``

288

`+

if (method_check_args(func, args, nargs, kwnames)) {

`

``

289

`+

return NULL;

`

``

290

`+

}

`

``

291

`+

PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);

`

``

292

`+

if (argstuple == NULL) {

`

``

293

`+

return NULL;

`

``

294

`+

}

`

``

295

`+

PyCFunction meth = (PyCFunction)method_enter_call(func);

`

``

296

`+

if (meth == NULL) {

`

``

297

`+

Py_DECREF(argstuple);

`

``

298

`+

return NULL;

`

``

299

`+

}

`

``

300

`+

PyObject *result = meth(args[0], argstuple);

`

``

301

`+

Py_DECREF(argstuple);

`

``

302

`+

Py_LeaveRecursiveCall();

`

262

303

`return result;

`

263

304

`}

`

264

305

``

265

``

`-

// same to methoddescr_call(), but use FASTCALL convention.

`

266

``

`-

PyObject *

`

267

``

`-

_PyMethodDescr_Vectorcall(PyObject *descrobj,

`

268

``

`-

PyObject *const *args, size_t nargsf,

`

269

``

`-

PyObject *kwnames)

`

``

306

`+

static PyObject *

`

``

307

`+

method_vectorcall_VARARGS_KEYWORDS(

`

``

308

`+

PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)

`

270

309

`{

`

271

``

`-

assert(Py_TYPE(descrobj) == &PyMethodDescr_Type);

`

272

``

`-

PyMethodDescrObject *descr = (PyMethodDescrObject *)descrobj;

`

273

``

`-

PyObject *self, *result;

`

``

310

`+

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);

`

``

311

`+

if (method_check_args(func, args, nargs, NULL)) {

`

``

312

`+

return NULL;

`

``

313

`+

}

`

``

314

`+

PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);

`

``

315

`+

if (argstuple == NULL) {

`

``

316

`+

return NULL;

`

``

317

`+

}

`

``

318

`+

PyObject *result = NULL;

`

``

319

`+

/* Create a temporary dict for keyword arguments */

`

``

320

`+

PyObject *kwdict = NULL;

`

``

321

`+

if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) > 0) {

`

``

322

`+

kwdict = _PyStack_AsDict(args + nargs, kwnames);

`

``

323

`+

if (kwdict == NULL) {

`

``

324

`+

goto exit;

`

``

325

`+

}

`

``

326

`+

}

`

``

327

`+

PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)

`

``

328

`+

method_enter_call(func);

`

``

329

`+

if (meth == NULL) {

`

``

330

`+

goto exit;

`

``

331

`+

}

`

``

332

`+

result = meth(args[0], argstuple, kwdict);

`

``

333

`+

Py_LeaveRecursiveCall();

`

``

334

`+

exit:

`

``

335

`+

Py_DECREF(argstuple);

`

``

336

`+

Py_XDECREF(kwdict);

`

``

337

`+

return result;

`

``

338

`+

}

`

274

339

``

``

340

`+

static PyObject *

`

``

341

`+

method_vectorcall_FASTCALL(

`

``

342

`+

PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)

`

``

343

`+

{

`

275

344

`Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);

`

276

``

`-

/* Make sure that the first argument is acceptable as 'self' */

`

277

``

`-

if (nargs < 1) {

`

278

``

`-

PyErr_Format(PyExc_TypeError,

`

279

``

`-

"descriptor '%V' of '%.100s' "

`

280

``

`-

"object needs an argument",

`

281

``

`-

descr_name((PyDescrObject *)descr), "?",

`

282

``

`-

PyDescr_TYPE(descr)->tp_name);

`

``

345

`+

if (method_check_args(func, args, nargs, kwnames)) {

`

283

346

`return NULL;

`

284

347

` }

`

285

``

`-

self = args[0];

`

286

``

`-

if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),

`

287

``

`-

(PyObject *)PyDescr_TYPE(descr))) {

`

``

348

`+

_PyCFunctionFast meth = (_PyCFunctionFast)

`

``

349

`+

method_enter_call(func);

`

``

350

`+

if (meth == NULL) {

`

``

351

`+

return NULL;

`

``

352

`+

}

`

``

353

`+

PyObject *result = meth(args[0], args+1, nargs-1);

`

``

354

`+

Py_LeaveRecursiveCall();

`

``

355

`+

return result;

`

``

356

`+

}

`

``

357

+

``

358

`+

static PyObject *

`

``

359

`+

method_vectorcall_FASTCALL_KEYWORDS(

`

``

360

`+

PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)

`

``

361

`+

{

`

``

362

`+

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);

`

``

363

`+

if (method_check_args(func, args, nargs, NULL)) {

`

``

364

`+

return NULL;

`

``

365

`+

}

`

``

366

`+

_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)

`

``

367

`+

method_enter_call(func);

`

``

368

`+

if (meth == NULL) {

`

``

369

`+

return NULL;

`

``

370

`+

}

`

``

371

`+

PyObject *result = meth(args[0], args+1, nargs-1, kwnames);

`

``

372

`+

Py_LeaveRecursiveCall();

`

``

373

`+

return result;

`

``

374

`+

}

`

``

375

+

``

376

`+

static PyObject *

`

``

377

`+

method_vectorcall_NOARGS(

`

``

378

`+

PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)

`

``

379

`+

{

`

``

380

`+

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);

`

``

381

`+

if (method_check_args(func, args, nargs, kwnames)) {

`

``

382

`+

return NULL;

`

``

383

`+

}

`

``

384

`+

if (nargs != 1) {

`

288

385

`PyErr_Format(PyExc_TypeError,

`

289

``

`-

"descriptor '%V' for '%.100s' objects "

`

290

``

`-

"doesn't apply to a '%.100s' object",

`

291

``

`-

descr_name((PyDescrObject *)descr), "?",

`

292

``

`-

PyDescr_TYPE(descr)->tp_name,

`

293

``

`-

self->ob_type->tp_name);

`

``

386

`+

"%.200s() takes no arguments (%zd given)", get_name(func), nargs-1);

`

294

387

`return NULL;

`

295

388

` }

`

``

389

`+

PyCFunction meth = (PyCFunction)method_enter_call(func);

`

``

390

`+

if (meth == NULL) {

`

``

391

`+

return NULL;

`

``

392

`+

}

`

``

393

`+

PyObject *result = meth(args[0], NULL);

`

``

394

`+

Py_LeaveRecursiveCall();

`

``

395

`+

return result;

`

``

396

`+

}

`

296

397

``

297

``

`-

result = _PyMethodDef_RawFastCallKeywords(descr->d_method, self,

`

298

``

`-

args+1, nargs-1, kwnames);

`

299

``

`-

result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);

`

``

398

`+

static PyObject *

`

``

399

`+

method_vectorcall_O(

`

``

400

`+

PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)

`

``

401

`+

{

`

``

402

`+

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);

`

``

403

`+

if (method_check_args(func, args, nargs, kwnames)) {

`

``

404

`+

return NULL;

`

``

405

`+

}

`

``

406

`+

if (nargs != 2) {

`

``

407

`+

PyErr_Format(PyExc_TypeError,

`

``

408

`+

"%.200s() takes exactly one argument (%zd given)",

`

``

409

`+

get_name(func), nargs-1);

`

``

410

`+

return NULL;

`

``

411

`+

}

`

``

412

`+

PyCFunction meth = (PyCFunction)method_enter_call(func);

`

``

413

`+

if (meth == NULL) {

`

``

414

`+

return NULL;

`

``

415

`+

}

`

``

416

`+

PyObject *result = meth(args[0], args[1]);

`

``

417

`+

Py_LeaveRecursiveCall();

`

300

418

`return result;

`

301

419

`}

`

302

420

``

``

421

+

303

422

`static PyObject *

`

304

423

`classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,

`

305

424

`PyObject *kwds)

`

`@@ -552,7 +671,7 @@ PyTypeObject PyMethodDescr_Type = {

`

552

671

`0, /* tp_as_sequence */

`

553

672

`0, /* tp_as_mapping */

`

554

673

`0, /* tp_hash */

`

555

``

`-

(ternaryfunc)methoddescr_call, /* tp_call */

`

``

674

`+

PyVectorcall_Call, /* tp_call */

`

556

675

`0, /* tp_str */

`

557

676

`PyObject_GenericGetAttr, /* tp_getattro */

`

558

677

`0, /* tp_setattro */

`

`@@ -750,13 +869,40 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)

`

750

869

`PyObject *

`

751

870

`PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)

`

752

871

`{

`

``

872

`+

/* Figure out correct vectorcall function to use */

`

``

873

`+

vectorcallfunc vectorcall;

`

``

874

`+

switch (method->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS))

`

``

875

`+

{

`

``

876

`+

case METH_VARARGS:

`

``

877

`+

vectorcall = method_vectorcall_VARARGS;

`

``

878

`+

break;

`

``

879

`+

case METH_VARARGS | METH_KEYWORDS:

`

``

880

`+

vectorcall = method_vectorcall_VARARGS_KEYWORDS;

`

``

881

`+

break;

`

``

882

`+

case METH_FASTCALL:

`

``

883

`+

vectorcall = method_vectorcall_FASTCALL;

`

``

884

`+

break;

`

``

885

`+

case METH_FASTCALL | METH_KEYWORDS:

`

``

886

`+

vectorcall = method_vectorcall_FASTCALL_KEYWORDS;

`

``

887

`+

break;

`

``

888

`+

case METH_NOARGS:

`

``

889

`+

vectorcall = method_vectorcall_NOARGS;

`

``

890

`+

break;

`

``

891

`+

case METH_O:

`

``

892

`+

vectorcall = method_vectorcall_O;

`

``

893

`+

break;

`

``

894

`+

default:

`

``

895

`+

PyErr_SetString(PyExc_SystemError, "bad call flags");

`

``

896

`+

return NULL;

`

``

897

`+

}

`

``

898

+

753

899

`PyMethodDescrObject *descr;

`

754

900

``

755

901

`descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,

`

756

902

`type, method->ml_name);

`

757

903

`if (descr != NULL) {

`

758

904

`descr->d_method = method;

`

759

``

`-

descr->vectorcall = _PyMethodDescr_Vectorcall;

`

``

905

`+

descr->vectorcall = vectorcall;

`

760

906

` }

`

761

907

`return (PyObject *)descr;

`

762

908

`}

`