this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2// typeobject.c implementation
3
4#include <cinttypes>
5
6#include "cpython-data.h"
7#include "cpython-func.h"
8#include "cpython-types.h"
9#include "structmember.h"
10
11#include "api-handle.h"
12#include "attributedict.h"
13#include "builtins-module.h"
14#include "capi-typeslots.h"
15#include "capi.h"
16#include "dict-builtins.h"
17#include "extension-object.h"
18#include "function-builtins.h"
19#include "function-utils.h"
20#include "handles.h"
21#include "int-builtins.h"
22#include "mro.h"
23#include "object-utils.h"
24#include "objects.h"
25#include "runtime.h"
26#include "str-builtins.h"
27#include "trampolines.h"
28#include "type-builtins.h"
29#include "type-utils.h"
30#include "utils.h"
31
32namespace py {
33
34PY_EXPORT PyTypeObject* PySuper_Type_Ptr() {
35 Runtime* runtime = Thread::current()->runtime();
36 return reinterpret_cast<PyTypeObject*>(
37 ApiHandle::borrowedReference(runtime, runtime->typeAt(LayoutId::kSuper)));
38}
39
40PY_EXPORT int PyType_CheckExact_Func(PyObject* obj) {
41 return ApiHandle::asObject(ApiHandle::fromPyObject(obj)).isType();
42}
43
44PY_EXPORT int PyType_Check_Func(PyObject* obj) {
45 return Thread::current()->runtime()->isInstanceOfType(
46 ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
47}
48
49PY_EXPORT unsigned long PyType_GetFlags(PyTypeObject* type_obj) {
50 ApiHandle* handle = ApiHandle::fromPyTypeObject(type_obj);
51
52 HandleScope scope(Thread::current());
53 Type type(&scope, ApiHandle::asObjectNoImmediate(handle));
54 if (type.isBuiltin()) return Py_TPFLAGS_DEFAULT;
55
56 if (!typeHasSlots(type)) {
57 UNIMPLEMENTED("GetFlags from types initialized through Python code");
58 }
59
60 return typeSlotUWordAt(type, kSlotFlags);
61}
62
63// PyType_FromSpec() operator support
64//
65// The functions and data in this namespace, culminating in addOperators(), are
66// used to add Python-visible wrappers for type slot C functions (e.g., passing
67// a Py_nb_add slot will result in a __add__() method being added to the type).
68// The wrapper functions (wrapUnaryfunc(), wrapBinaryfunc(), etc...) handle
69// translating between incoming/outgoing RawObject/PyObject* values, along with
70// various bits of slot-specific logic.
71//
72// As other builtins the function's Code object has a pointer to the
73// appropriate wrapper function as its code field, and its consts field
74// is a 1-element tuple containing a pointer to the slot function provided by
75// the user. If this multi-step lookup ever becomes a performance problem, we
76// can easily template the trampolines and/or the wrapper functions, but this
77// keeps the code compact for now.
78
79static ALIGN_16 RawObject wrapUnaryfunc(Thread* thread, Arguments args) {
80 unaryfunc func = reinterpret_cast<unaryfunc>(getNativeFunc(thread));
81 PyObject* o = ApiHandle::newReference(thread->runtime(), args.get(0));
82 PyObject* result = (*func)(o);
83 Py_DECREF(o);
84 return ApiHandle::checkFunctionResult(thread, result);
85}
86
87// Common work for hashfunc, lenfunc, and inquiry, all of which take a single
88// PyObject* and return an integral value.
89template <typename cfunc, typename RetFunc>
90static RawObject wrapIntegralfunc(Thread* thread, Arguments args, RetFunc ret) {
91 cfunc func = reinterpret_cast<cfunc>(getNativeFunc(thread));
92 PyObject* o = ApiHandle::newReference(thread->runtime(), args.get(0));
93 auto result = func(o);
94 Py_DECREF(o);
95 if (result == -1 && thread->hasPendingException()) return Error::exception();
96 return ret(result);
97}
98
99static ALIGN_16 RawObject wrapHashfunc(Thread* thread, Arguments args) {
100 return wrapIntegralfunc<hashfunc>(thread, args, [thread](Py_hash_t hash) {
101 return thread->runtime()->newInt(hash);
102 });
103}
104
105static ALIGN_16 RawObject wrapLenfunc(Thread* thread, Arguments args) {
106 return wrapIntegralfunc<lenfunc>(thread, args, [thread](Py_ssize_t len) {
107 return thread->runtime()->newInt(len);
108 });
109}
110
111static ALIGN_16 RawObject wrapInquirypred(Thread* thread, Arguments args) {
112 return wrapIntegralfunc<inquiry>(
113 thread, args, [](int result) { return Bool::fromBool(result); });
114}
115
116static ALIGN_16 RawObject wrapBinaryfunc(Thread* thread, Arguments args) {
117 binaryfunc func = reinterpret_cast<binaryfunc>(getNativeFunc(thread));
118 Runtime* runtime = thread->runtime();
119 PyObject* o1 = ApiHandle::newReference(runtime, args.get(0));
120 PyObject* o2 = ApiHandle::newReference(runtime, args.get(1));
121 PyObject* result = (*func)(o1, o2);
122 Py_DECREF(o2);
123 Py_DECREF(o1);
124 return ApiHandle::checkFunctionResult(thread, result);
125}
126
127static ALIGN_16 RawObject wrapBinaryfuncSwapped(Thread* thread,
128 Arguments args) {
129 binaryfunc func = reinterpret_cast<binaryfunc>(getNativeFunc(thread));
130 Runtime* runtime = thread->runtime();
131 PyObject* o1 = ApiHandle::newReference(runtime, args.get(0));
132 PyObject* o2 = ApiHandle::newReference(runtime, args.get(1));
133 PyObject* result = (*func)(o2, o1);
134 Py_DECREF(o2);
135 Py_DECREF(o1);
136 return ApiHandle::checkFunctionResult(thread, result);
137}
138
139static RawObject wrapTernaryfuncImpl(Thread* thread, Arguments args,
140 bool swap) {
141 ternaryfunc func = reinterpret_cast<ternaryfunc>(getNativeFunc(thread));
142 Runtime* runtime = thread->runtime();
143 PyObject* self = ApiHandle::newReference(runtime, args.get(swap ? 1 : 0));
144 PyObject* value = ApiHandle::newReference(runtime, args.get(swap ? 0 : 1));
145 PyObject* mod = ApiHandle::newReference(runtime, args.get(2));
146 PyObject* result = (*func)(self, value, mod);
147 Py_DECREF(mod);
148 Py_DECREF(value);
149 Py_DECREF(self);
150 return ApiHandle::checkFunctionResult(thread, result);
151}
152
153// wrapTernaryfunc() vs. wrapVarkwTernaryfunc():
154// - wrapTernaryfunc(Swapped)(): Wraps a C function expecting exactly 3
155// normal arguments, with the 3rd argument defaulting to None.
156// - wrapVarkwTernaryfunc(): Wraps a C function expecting a self argument, a
157// tuple of positional arguments and an optional dict of keyword arguments.
158static ALIGN_16 RawObject wrapTernaryfunc(Thread* thread, Arguments args) {
159 return wrapTernaryfuncImpl(thread, args, false);
160}
161
162static ALIGN_16 RawObject wrapTernaryfuncSwapped(Thread* thread,
163 Arguments args) {
164 return wrapTernaryfuncImpl(thread, args, true);
165}
166
167static ALIGN_16 RawObject wrapTpNew(Thread* thread, Arguments args) {
168 ternaryfunc func = reinterpret_cast<ternaryfunc>(getNativeFunc(thread));
169
170 HandleScope scope(thread);
171 Runtime* runtime = thread->runtime();
172 Object self_obj(&scope, args.get(0));
173 if (!runtime->isInstanceOfType(*self_obj)) {
174 return thread->raiseWithFmt(LayoutId::kTypeError,
175 "'__new__' requires 'type' but got '%T'",
176 &self_obj);
177 }
178 Function function(&scope, thread->currentFrame()->function());
179 Type expected_type(&scope, slotWrapperFunctionType(function));
180 if (!typeIsSubclass(*self_obj, *expected_type)) {
181 Str expected_type_name(&scope, strUnderlying(expected_type.name()));
182 return thread->raiseWithFmt(LayoutId::kTypeError,
183 "'__new__' requires '%S' but got '%T'",
184 &expected_type_name, &self_obj);
185 }
186 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
187 PyObject* varargs = ApiHandle::newReference(runtime, args.get(1));
188 PyObject* kwargs = Dict::cast(args.get(2)).numItems() == 0
189 ? nullptr
190 : ApiHandle::newReference(runtime, args.get(2));
191 PyObject* result = (*func)(self, varargs, kwargs);
192 Py_XDECREF(kwargs);
193 Py_DECREF(varargs);
194 Py_DECREF(self);
195 return ApiHandle::checkFunctionResult(thread, result);
196}
197
198static bool checkSelfWithSlotType(Thread* thread, const Object& self) {
199 HandleScope scope(thread);
200 Function function(&scope, thread->currentFrame()->function());
201 Type expected_type(&scope, slotWrapperFunctionType(function));
202 if (!typeIsSubclass(thread->runtime()->typeOf(*self), *expected_type)) {
203 Str slot_name(&scope, function.name());
204 Str expected_type_name(&scope, strUnderlying(expected_type.name()));
205 thread->raiseWithFmt(LayoutId::kTypeError,
206 "'%S' requires '%S' but got '%T'", &slot_name,
207 &expected_type_name, &self);
208 return false;
209 }
210 return true;
211}
212
213static ALIGN_16 RawObject wrapVarkwTernaryfunc(Thread* thread, Arguments args) {
214 ternaryfunc func = reinterpret_cast<ternaryfunc>(getNativeFunc(thread));
215
216 HandleScope scope(thread);
217 Object self_obj(&scope, args.get(0));
218 if (!checkSelfWithSlotType(thread, self_obj)) {
219 return Error::exception();
220 }
221 Runtime* runtime = thread->runtime();
222 PyObject* self = ApiHandle::newReference(runtime, *self_obj);
223 PyObject* varargs = ApiHandle::newReference(runtime, args.get(1));
224 PyObject* kwargs = Dict::cast(args.get(2)).numItems() == 0
225 ? nullptr
226 : ApiHandle::newReference(runtime, args.get(2));
227 PyObject* result = (*func)(self, varargs, kwargs);
228 Py_XDECREF(kwargs);
229 Py_DECREF(varargs);
230 Py_DECREF(self);
231 return ApiHandle::checkFunctionResult(thread, result);
232}
233
234static ALIGN_16 RawObject wrapSetattr(Thread* thread, Arguments args) {
235 setattrofunc func = reinterpret_cast<setattrofunc>(getNativeFunc(thread));
236
237 Runtime* runtime = thread->runtime();
238 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
239 PyObject* name = ApiHandle::newReference(runtime, args.get(1));
240 PyObject* value = ApiHandle::newReference(runtime, args.get(2));
241 int result = func(self, name, value);
242 Py_DECREF(value);
243 Py_DECREF(name);
244 Py_DECREF(self);
245 if (result < 0) return Error::exception();
246 return NoneType::object();
247}
248
249static ALIGN_16 RawObject wrapDelattr(Thread* thread, Arguments args) {
250 setattrofunc func = reinterpret_cast<setattrofunc>(getNativeFunc(thread));
251 Runtime* runtime = thread->runtime();
252 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
253 PyObject* name = ApiHandle::newReference(runtime, args.get(1));
254 int result = func(self, name, nullptr);
255 Py_DECREF(name);
256 Py_DECREF(self);
257 if (result < 0) return Error::exception();
258 return NoneType::object();
259}
260
261template <CompareOp op>
262static ALIGN_16 RawObject wrapRichcompare(Thread* thread, Arguments args) {
263 richcmpfunc func = reinterpret_cast<richcmpfunc>(getNativeFunc(thread));
264 Runtime* runtime = thread->runtime();
265 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
266 PyObject* other = ApiHandle::newReference(runtime, args.get(1));
267 PyObject* result = (*func)(self, other, op);
268 Py_DECREF(other);
269 Py_DECREF(self);
270 return ApiHandle::checkFunctionResult(thread, result);
271}
272
273static ALIGN_16 RawObject wrapNext(Thread* thread, Arguments args) {
274 unaryfunc func = reinterpret_cast<unaryfunc>(getNativeFunc(thread));
275 PyObject* self = ApiHandle::newReference(thread->runtime(), args.get(0));
276 PyObject* result = (*func)(self);
277 Py_DECREF(self);
278 if (result == nullptr && !thread->hasPendingException()) {
279 return thread->raise(LayoutId::kStopIteration, NoneType::object());
280 }
281 return ApiHandle::checkFunctionResult(thread, result);
282}
283
284static ALIGN_16 RawObject wrapDescrGet(Thread* thread, Arguments args) {
285 descrgetfunc func = reinterpret_cast<descrgetfunc>(getNativeFunc(thread));
286 Runtime* runtime = thread->runtime();
287 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
288 PyObject* obj = nullptr;
289 if (!args.get(1).isNoneType()) {
290 obj = ApiHandle::newReference(runtime, args.get(1));
291 }
292 PyObject* type = nullptr;
293 if (!args.get(2).isNoneType()) {
294 type = ApiHandle::newReference(runtime, args.get(2));
295 }
296 if (obj == nullptr && type == nullptr) {
297 return thread->raiseWithFmt(LayoutId::kTypeError,
298 "__get__(None, None), is invalid");
299 }
300 PyObject* result = (*func)(self, obj, type);
301 Py_DECREF(self);
302 Py_XDECREF(obj);
303 Py_XDECREF(type);
304 return ApiHandle::checkFunctionResult(thread, result);
305}
306
307static ALIGN_16 RawObject wrapDescrSet(Thread* thread, Arguments args) {
308 descrsetfunc func = reinterpret_cast<descrsetfunc>(getNativeFunc(thread));
309 Runtime* runtime = thread->runtime();
310 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
311 PyObject* obj = ApiHandle::newReference(runtime, args.get(1));
312 PyObject* value = ApiHandle::newReference(runtime, args.get(2));
313 int result = func(self, obj, value);
314 Py_DECREF(value);
315 Py_DECREF(obj);
316 Py_DECREF(self);
317 if (result < 0) return Error::exception();
318 return NoneType::object();
319}
320
321static ALIGN_16 RawObject wrapDescrDelete(Thread* thread, Arguments args) {
322 descrsetfunc func = reinterpret_cast<descrsetfunc>(getNativeFunc(thread));
323 Runtime* runtime = thread->runtime();
324 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
325 PyObject* obj = ApiHandle::newReference(runtime, args.get(1));
326 int result = func(self, obj, nullptr);
327 Py_DECREF(obj);
328 Py_DECREF(self);
329 if (result < 0) return Error::exception();
330 return NoneType::object();
331}
332
333static ALIGN_16 RawObject wrapInit(Thread* thread, Arguments args) {
334 initproc func = reinterpret_cast<initproc>(getNativeFunc(thread));
335 Runtime* runtime = thread->runtime();
336 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
337 PyObject* varargs = ApiHandle::newReference(runtime, args.get(1));
338 PyObject* kwargs = Dict::cast(args.get(2)).numItems() == 0
339 ? nullptr
340 : ApiHandle::newReference(runtime, args.get(2));
341 int result = func(self, varargs, kwargs);
342 Py_XDECREF(kwargs);
343 Py_DECREF(varargs);
344 Py_DECREF(self);
345 if (result < 0) return Error::exception();
346 return NoneType::object();
347}
348
349static ALIGN_16 RawObject wrapDel(Thread* thread, Arguments args) {
350 destructor func = reinterpret_cast<destructor>(getNativeFunc(thread));
351 PyObject* self = ApiHandle::newReference(thread->runtime(), args.get(0));
352 func(self);
353 Py_DECREF(self);
354 return NoneType::object();
355}
356
357static ALIGN_16 RawObject wrapObjobjargproc(Thread* thread, Arguments args) {
358 objobjargproc func = reinterpret_cast<objobjargproc>(getNativeFunc(thread));
359 Runtime* runtime = thread->runtime();
360 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
361 PyObject* key = ApiHandle::newReference(runtime, args.get(1));
362 PyObject* value = ApiHandle::newReference(runtime, args.get(2));
363 int res = func(self, key, value);
364 Py_DECREF(value);
365 Py_DECREF(key);
366 Py_DECREF(self);
367 if (res == -1 && thread->hasPendingException()) return Error::exception();
368 return NoneType::object();
369}
370
371static ALIGN_16 RawObject wrapObjobjproc(Thread* thread, Arguments args) {
372 objobjproc func = reinterpret_cast<objobjproc>(getNativeFunc(thread));
373 Runtime* runtime = thread->runtime();
374 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
375 PyObject* value = ApiHandle::newReference(runtime, args.get(1));
376 int res = func(self, value);
377 Py_DECREF(value);
378 Py_DECREF(self);
379 if (res == -1 && thread->hasPendingException()) return Error::exception();
380 return Bool::fromBool(res);
381}
382
383static ALIGN_16 RawObject wrapDelitem(Thread* thread, Arguments args) {
384 objobjargproc func = reinterpret_cast<objobjargproc>(getNativeFunc(thread));
385 Runtime* runtime = thread->runtime();
386 PyObject* self = ApiHandle::newReference(runtime, args.get(0));
387 PyObject* key = ApiHandle::newReference(runtime, args.get(1));
388 int res = func(self, key, nullptr);
389 Py_DECREF(key);
390 Py_DECREF(self);
391 if (res == -1 && thread->hasPendingException()) return Error::exception();
392 return NoneType::object();
393}
394
395// Convert obj into a word-sized int or raise an OverflowError, in the style of
396// PyNumber_AsSsize_t().
397static RawObject makeIndex(Thread* thread, const Object& obj) {
398 HandleScope scope(thread);
399 Object converted(&scope, intFromIndex(thread, obj));
400 if (converted.isError()) return *converted;
401 Int i(&scope, intUnderlying(*converted));
402 if (i.numDigits() != 1) {
403 return thread->raiseWithFmt(LayoutId::kOverflowError,
404 "cannot fit '%T' into an index-sized integer",
405 &obj);
406 }
407 return *i;
408}
409
410static ALIGN_16 RawObject wrapIndexargfunc(Thread* thread, Arguments args) {
411 ssizeargfunc func = reinterpret_cast<ssizeargfunc>(getNativeFunc(thread));
412
413 HandleScope scope(thread);
414 PyObject* self = ApiHandle::newReference(thread->runtime(), args.get(0));
415 Object arg(&scope, args.get(1));
416 arg = makeIndex(thread, arg);
417 if (arg.isError()) {
418 Py_DECREF(self);
419 return *arg;
420 }
421 PyObject* result = (*func)(self, Int::cast(*arg).asWord());
422 Py_DECREF(self);
423 return ApiHandle::checkFunctionResult(thread, result);
424}
425
426// First, convert arg to a word-sized int using makeIndex(). Then, if the result
427// is negative, add len(self) to normalize it.
428static RawObject normalizeIndex(Thread* thread, const Object& self,
429 const Object& arg) {
430 HandleScope scope(thread);
431 Object index(&scope, makeIndex(thread, arg));
432 if (index.isError()) return *index;
433 word i = Int::cast(*index).asWord();
434 if (i >= 0) {
435 return *index;
436 }
437 Object len(&scope, thread->invokeFunction1(ID(builtins), ID(len), self));
438 if (len.isError()) return *len;
439 len = makeIndex(thread, len);
440 if (len.isError()) return *len;
441 i += Int::cast(*len).asWord();
442 return thread->runtime()->newInt(i);
443}
444
445static ALIGN_16 RawObject wrapSqItem(Thread* thread, Arguments args) {
446 ssizeargfunc func = reinterpret_cast<ssizeargfunc>(getNativeFunc(thread));
447
448 HandleScope scope(thread);
449 Object self(&scope, args.get(0));
450 Object arg(&scope, args.get(1));
451 arg = normalizeIndex(thread, self, arg);
452 if (arg.isError()) return *arg;
453 PyObject* py_self = ApiHandle::newReference(thread->runtime(), *self);
454 PyObject* result = (*func)(py_self, Int::cast(*arg).asWord());
455 Py_DECREF(py_self);
456 return ApiHandle::checkFunctionResult(thread, result);
457}
458
459static ALIGN_16 RawObject wrapSqSetitem(Thread* thread, Arguments args) {
460 ssizeobjargproc func =
461 reinterpret_cast<ssizeobjargproc>(getNativeFunc(thread));
462
463 HandleScope scope(thread);
464 Object self(&scope, args.get(0));
465 Object arg(&scope, args.get(1));
466 arg = normalizeIndex(thread, self, arg);
467 if (arg.isError()) return *arg;
468 Runtime* runtime = thread->runtime();
469 PyObject* py_self = ApiHandle::newReference(runtime, *self);
470 PyObject* py_value = ApiHandle::newReference(runtime, args.get(2));
471 int result = func(py_self, Int::cast(*arg).asWord(), py_value);
472 Py_DECREF(py_value);
473 Py_DECREF(py_self);
474 if (result == -1 && thread->hasPendingException()) return Error::exception();
475 return NoneType::object();
476}
477
478static ALIGN_16 RawObject wrapSqDelitem(Thread* thread, Arguments args) {
479 ssizeobjargproc func =
480 reinterpret_cast<ssizeobjargproc>(getNativeFunc(thread));
481
482 HandleScope scope(thread);
483 Object self(&scope, args.get(0));
484 Object arg(&scope, args.get(1));
485 arg = normalizeIndex(thread, self, arg);
486 if (arg.isError()) return *arg;
487 PyObject* py_self = ApiHandle::newReference(thread->runtime(), *self);
488 int result = func(py_self, Int::cast(*arg).asWord(), nullptr);
489 Py_DECREF(py_self);
490 if (result == -1 && thread->hasPendingException()) return Error::exception();
491 return NoneType::object();
492}
493
494// Information about a single type slot.
495struct SlotDef {
496 // The name of the method in managed code.
497 SymbolId name;
498
499 // type slot it.
500 int id;
501
502 // List of parameter names/symbols.
503 View<SymbolId> parameters;
504
505 // The wrapper function for this slot.
506 BuiltinFunction wrapper;
507
508 // RawCode::Flags to be set on slot function.
509 word flags;
510
511 // Doc string for the function.
512 const char* doc;
513};
514
515static const SymbolId kParamsSelfArgsKwargs[] = {ID(self), ID(args),
516 ID(kwargs)};
517static const SymbolId kParamsSelfInstanceOwner[] = {ID(self), ID(instance),
518 ID(owner)};
519static const SymbolId kParamsSelfInstanceValue[] = {ID(self), ID(instance),
520 ID(value)};
521static const SymbolId kParamsSelfInstance[] = {ID(self), ID(instance)};
522static const SymbolId kParamsSelfKeyValue[] = {ID(self), ID(key), ID(value)};
523static const SymbolId kParamsSelfKey[] = {ID(self), ID(key)};
524static const SymbolId kParamsSelfNameValue[] = {ID(self), ID(name), ID(value)};
525static const SymbolId kParamsSelfName[] = {ID(self), ID(name)};
526static const SymbolId kParamsSelfValueMod[] = {ID(self), ID(value), ID(mod)};
527static const SymbolId kParamsSelfValue[] = {ID(self), ID(value)};
528static const SymbolId kParamsSelf[] = {ID(self)};
529static const SymbolId kParamsTypeArgsKwargs[] = {ID(type), ID(args),
530 ID(kwargs)};
531
532// These macros currently ignore the FUNCTION argument, which is still the
533// function name inherited from CPython. This will be cleaned up when we add
534// default slot implementations that delegate to the corresponding Python
535// method, along with logic to update slots as needed when a user assigns to a
536// type dict.
537#define TPSLOT(NAME, SLOT, PARAMETERS, FUNCTION, WRAPPER, DOC) \
538 { NAME, SLOT, PARAMETERS, WRAPPER, 0, DOC }
539#define KWSLOT(NAME, SLOT, PARAMETERS, FUNCTION, WRAPPER, DOC) \
540 { \
541 NAME, SLOT, PARAMETERS, WRAPPER, \
542 Code::Flags::kVarargs | Code::Flags::kVarkeyargs, DOC, \
543 }
544#define UNSLOT(NAME, C_NAME, SLOT, FUNCTION, DOC) \
545 TPSLOT(NAME, SLOT, kParamsSelf, FUNCTION, wrapUnaryfunc, \
546 C_NAME "($self, /)\n--\n\n" DOC)
547#define IBSLOT(NAME, C_NAME, SLOT, FUNCTION, WRAPPER, DOC) \
548 TPSLOT(NAME, SLOT, kParamsSelfValue, FUNCTION, WRAPPER, \
549 C_NAME "($self, value, /)\n--\n\nReturn self" DOC "value.")
550#define BINSLOT(NAME, C_NAME, SLOT, FUNCTION, DOC) \
551 TPSLOT(NAME, SLOT, kParamsSelfValue, FUNCTION, wrapBinaryfunc, \
552 C_NAME "($self, value, /)\n--\n\nReturn self" DOC "value.")
553#define RBINSLOT(NAME, C_NAME, SLOT, FUNCTION, DOC) \
554 TPSLOT(NAME, SLOT, kParamsSelfValue, FUNCTION, wrapBinaryfuncSwapped, \
555 C_NAME "($self, value, /)\n--\n\nReturn value" DOC "self.")
556#define BINSLOTNOTINFIX(NAME, C_NAME, SLOT, FUNCTION, DOC) \
557 TPSLOT(NAME, SLOT, kParamsSelfValue, FUNCTION, wrapBinaryfunc, \
558 C_NAME "($self, value, /)\n--\n\n" DOC)
559#define RBINSLOTNOTINFIX(NAME, C_NAME, SLOT, FUNCTION, DOC) \
560 TPSLOT(NAME, SLOT, kParamsSelfValue, FUNCTION, wrapBinaryfuncSwapped, \
561 C_NAME "($self, value, /)\n--\n\n" DOC)
562
563static const SlotDef kSlotdefs[] = {
564 TPSLOT(ID(__getattribute__), Py_tp_getattr, kParamsSelfName, nullptr,
565 nullptr, ""),
566 TPSLOT(ID(__getattr__), Py_tp_getattr, kParamsSelfName, nullptr, nullptr,
567 ""),
568 TPSLOT(ID(__setattr__), Py_tp_setattr, kParamsSelfNameValue, nullptr,
569 nullptr, ""),
570 TPSLOT(ID(__delattr__), Py_tp_setattr, kParamsSelfName, nullptr, nullptr,
571 ""),
572 UNSLOT(ID(__repr__), "__repr__", Py_tp_repr, slot_tp_repr,
573 "Return repr(self)."),
574 TPSLOT(ID(__hash__), Py_tp_hash, kParamsSelf, slot_tp_hash, wrapHashfunc,
575 "__hash__($self, /)\n--\n\nReturn hash(self)."),
576 KWSLOT(
577 ID(__call__), Py_tp_call, kParamsSelfArgsKwargs, slot_tp_call,
578 wrapVarkwTernaryfunc,
579 "__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function."),
580 UNSLOT(ID(__str__), "__str__", Py_tp_str, slot_tp_str, "Return str(self)."),
581 TPSLOT(ID(__getattribute__), Py_tp_getattro, kParamsSelfName,
582 slot_tp_getattr_hook, wrapBinaryfunc,
583 "__getattribute__($self, name, /)\n--\n\nReturn getattr(self, "
584 "name)."),
585 TPSLOT(ID(__getattr__), Py_tp_getattro, kParamsSelfName,
586 slot_tp_getattr_hook, nullptr, ""),
587 TPSLOT(ID(__setattr__), Py_tp_setattro, kParamsSelfNameValue,
588 slot_tp_setattro, wrapSetattr,
589 "__setattr__($self, name, value, /)\n--\n\nImplement setattr(self, "
590 "name, value)."),
591 TPSLOT(ID(__delattr__), Py_tp_setattro, kParamsSelfName, slot_tp_setattro,
592 wrapDelattr,
593 "__delattr__($self, name, /)\n--\n\nImplement delattr(self, name)."),
594 TPSLOT(ID(__lt__), Py_tp_richcompare, kParamsSelfValue, slot_tp_richcompare,
595 wrapRichcompare<LT>,
596 "__lt__($self, value, /)\n--\n\nReturn self<value."),
597 TPSLOT(ID(__le__), Py_tp_richcompare, kParamsSelfValue, slot_tp_richcompare,
598 wrapRichcompare<LE>,
599 "__le__($self, value, /)\n--\n\nReturn self<=value."),
600 TPSLOT(ID(__eq__), Py_tp_richcompare, kParamsSelfValue, slot_tp_richcompare,
601 wrapRichcompare<EQ>,
602 "__eq__($self, value, /)\n--\n\nReturn self==value."),
603 TPSLOT(ID(__ne__), Py_tp_richcompare, kParamsSelfValue, slot_tp_richcompare,
604 wrapRichcompare<NE>,
605 "__ne__($self, value, /)\n--\n\nReturn self!=value."),
606 TPSLOT(ID(__gt__), Py_tp_richcompare, kParamsSelfValue, slot_tp_richcompare,
607 wrapRichcompare<GT>,
608 "__gt__($self, value, /)\n--\n\nReturn self>value."),
609 TPSLOT(ID(__ge__), Py_tp_richcompare, kParamsSelfValue, slot_tp_richcompare,
610 wrapRichcompare<GE>,
611 "__ge__($self, value, /)\n--\n\nReturn self>=value."),
612 UNSLOT(ID(__iter__), "__iter__", Py_tp_iter, slot_tp_iter,
613 "Implement iter(self)."),
614 TPSLOT(ID(__next__), Py_tp_iternext, kParamsSelf, slot_tp_iternext,
615 wrapNext, "__next__($self, /)\n--\n\nImplement next(self)."),
616 TPSLOT(ID(__get__), Py_tp_descr_get, kParamsSelfInstanceOwner,
617 slot_tp_descr_get, wrapDescrGet,
618 "__get__($self, instance, owner, /)\n--\n\nReturn an attribute of "
619 "instance, which is of type owner."),
620 TPSLOT(ID(__set__), Py_tp_descr_set, kParamsSelfInstanceValue,
621 slot_tp_descr_set, wrapDescrSet,
622 "__set__($self, instance, value, /)\n--\n\nSet an attribute of "
623 "instance to value."),
624 TPSLOT(ID(__delete__), Py_tp_descr_set, kParamsSelfInstance,
625 slot_tp_descr_set, wrapDescrDelete,
626 "__delete__($self, instance, /)\n--\n\nDelete an attribute of "
627 "instance."),
628 KWSLOT(ID(__init__), Py_tp_init, kParamsSelfArgsKwargs, slot_tp_init,
629 wrapInit,
630 "__init__($self, /, *args, **kwargs)\n--\n\nInitialize self. See "
631 "help(type(self)) for accurate signature."),
632 KWSLOT(ID(__new__), Py_tp_new, kParamsTypeArgsKwargs, slot_tp_new,
633 wrapTpNew,
634 "__new__(type, /, *args, **kwargs)\n--\n\n"
635 "Create and return new object. See help(type) for accurate "
636 "signature."),
637 TPSLOT(ID(__del__), Py_tp_finalize, kParamsSelf, slot_tp_finalize, wrapDel,
638 ""),
639 UNSLOT(ID(__await__), "__await__", Py_am_await, slot_am_await,
640 "Return an iterator to be used in await expression."),
641 UNSLOT(ID(__aiter__), "__aiter__", Py_am_aiter, slot_am_aiter,
642 "Return an awaitable, that resolves in asynchronous iterator."),
643 UNSLOT(ID(__anext__), "__anext__", Py_am_anext, slot_am_anext,
644 "Return a value or raise StopAsyncIteration."),
645 BINSLOT(ID(__add__), "__add__", Py_nb_add, slot_nb_add, "+"),
646 RBINSLOT(ID(__radd__), "__radd__", Py_nb_add, slot_nb_add, "+"),
647 BINSLOT(ID(__sub__), "__sub__", Py_nb_subtract, slot_nb_subtract, "-"),
648 RBINSLOT(ID(__rsub__), "__rsub__", Py_nb_subtract, slot_nb_subtract, "-"),
649 BINSLOT(ID(__mul__), "__mul__", Py_nb_multiply, slot_nb_multiply, "*"),
650 RBINSLOT(ID(__rmul__), "__rmul__", Py_nb_multiply, slot_nb_multiply, "*"),
651 BINSLOT(ID(__mod__), "__mod__", Py_nb_remainder, slot_nb_remainder, "%"),
652 RBINSLOT(ID(__rmod__), "__rmod__", Py_nb_remainder, slot_nb_remainder, "%"),
653 BINSLOTNOTINFIX(ID(__divmod__), "__divmod__", Py_nb_divmod, slot_nb_divmod,
654 "Return divmod(self, value)."),
655 RBINSLOTNOTINFIX(ID(__rdivmod__), "__rdivmod__", Py_nb_divmod,
656 slot_nb_divmod, "Return divmod(value, self)."),
657 TPSLOT(ID(__pow__), Py_nb_power, kParamsSelfValueMod, slot_nb_power,
658 wrapTernaryfunc,
659 "__pow__($self, value, mod=None, /)\n--\n\nReturn pow(self, value, "
660 "mod)."),
661 TPSLOT(ID(__rpow__), Py_nb_power, kParamsSelfValueMod, slot_nb_power,
662 wrapTernaryfuncSwapped,
663 "__rpow__($self, value, mod=None, /)\n--\n\nReturn pow(value, self, "
664 "mod)."),
665 UNSLOT(ID(__neg__), "__neg__", Py_nb_negative, slot_nb_negative, "-self"),
666 UNSLOT(ID(__pos__), "__pos__", Py_nb_positive, slot_nb_positive, "+self"),
667 UNSLOT(ID(__abs__), "__abs__", Py_nb_absolute, slot_nb_absolute,
668 "abs(self)"),
669 TPSLOT(ID(__bool__), Py_nb_bool, kParamsSelf, slot_nb_bool, wrapInquirypred,
670 "__bool__($self, /)\n--\n\nself != 0"),
671 UNSLOT(ID(__invert__), "__invert__", Py_nb_invert, slot_nb_invert, "~self"),
672 BINSLOT(ID(__lshift__), "__lshift__", Py_nb_lshift, slot_nb_lshift, "<<"),
673 RBINSLOT(ID(__rlshift__), "__rlshift__", Py_nb_lshift, slot_nb_lshift,
674 "<<"),
675 BINSLOT(ID(__rshift__), "__rshift__", Py_nb_rshift, slot_nb_rshift, ">>"),
676 RBINSLOT(ID(__rrshift__), "__rrshift__", Py_nb_rshift, slot_nb_rshift,
677 ">>"),
678 BINSLOT(ID(__and__), "__and__", Py_nb_and, slot_nb_and, "&"),
679 RBINSLOT(ID(__rand__), "__rand__", Py_nb_and, slot_nb_and, "&"),
680 BINSLOT(ID(__xor__), "__xor__", Py_nb_xor, slot_nb_xor, "^"),
681 RBINSLOT(ID(__rxor__), "__rxor__", Py_nb_xor, slot_nb_xor, "^"),
682 BINSLOT(ID(__or__), "__or__", Py_nb_or, slot_nb_or, "|"),
683 RBINSLOT(ID(__ror__), "__ror__", Py_nb_or, slot_nb_or, "|"),
684 UNSLOT(ID(__int__), "__int__", Py_nb_int, slot_nb_int, "int(self)"),
685 UNSLOT(ID(__float__), "__float__", Py_nb_float, slot_nb_float,
686 "float(self)"),
687 IBSLOT(ID(__iadd__), "__iadd__", Py_nb_inplace_add, slot_nb_inplace_add,
688 wrapBinaryfunc, "+="),
689 IBSLOT(ID(__isub__), "__isub__", Py_nb_inplace_subtract,
690 slot_nb_inplace_subtract, wrapBinaryfunc, "-="),
691 IBSLOT(ID(__imul__), "__imul__", Py_nb_inplace_multiply,
692 slot_nb_inplace_multiply, wrapBinaryfunc, "*="),
693 IBSLOT(ID(__imod__), "__imod__", Py_nb_inplace_remainder,
694 slot_nb_inplace_remainder, wrapBinaryfunc, "%="),
695 IBSLOT(ID(__ipow__), "__ipow__", Py_nb_inplace_power, slot_nb_inplace_power,
696 wrapBinaryfunc, "**="),
697 IBSLOT(ID(__ilshift__), "__ilshift__", Py_nb_inplace_lshift,
698 slot_nb_inplace_lshift, wrapBinaryfunc, "<<="),
699 IBSLOT(ID(__irshift__), "__irshift__", Py_nb_inplace_rshift,
700 slot_nb_inplace_rshift, wrapBinaryfunc, ">>="),
701 IBSLOT(ID(__iand__), "__iand__", Py_nb_inplace_and, slot_nb_inplace_and,
702 wrapBinaryfunc, "&="),
703 IBSLOT(ID(__ixor__), "__ixor__", Py_nb_inplace_xor, slot_nb_inplace_xor,
704 wrapBinaryfunc, "^="),
705 IBSLOT(ID(__ior__), "__ior__", Py_nb_inplace_or, slot_nb_inplace_or,
706 wrapBinaryfunc, "|="),
707 BINSLOT(ID(__floordiv__), "__floordiv__", Py_nb_floor_divide,
708 slot_nb_floor_divide, "//"),
709 RBINSLOT(ID(__rfloordiv__), "__rfloordiv__", Py_nb_floor_divide,
710 slot_nb_floor_divide, "//"),
711 BINSLOT(ID(__truediv__), "__truediv__", Py_nb_true_divide,
712 slot_nb_true_divide, "/"),
713 RBINSLOT(ID(__rtruediv__), "__rtruediv__", Py_nb_true_divide,
714 slot_nb_true_divide, "/"),
715 IBSLOT(ID(__ifloordiv__), "__ifloordiv__", Py_nb_inplace_floor_divide,
716 slot_nb_inplace_floor_divide, wrapBinaryfunc, "//="),
717 IBSLOT(ID(__itruediv__), "__itruediv__", Py_nb_inplace_true_divide,
718 slot_nb_inplace_true_divide, wrapBinaryfunc, "/="),
719 UNSLOT(ID(__index__), "__index__", Py_nb_index, slot_nb_index,
720 "Return self converted to an integer, if self is suitable "
721 "for use as an index into a list."),
722 BINSLOT(ID(__matmul__), "__matmul__", Py_nb_matrix_multiply,
723 slot_nb_matrix_multiply, "@"),
724 RBINSLOT(ID(__rmatmul__), "__rmatmul__", Py_nb_matrix_multiply,
725 slot_nb_matrix_multiply, "@"),
726 IBSLOT(ID(__imatmul__), "__imatmul__", Py_nb_inplace_matrix_multiply,
727 slot_nb_inplace_matrix_multiply, wrapBinaryfunc, "@="),
728 TPSLOT(ID(__len__), Py_mp_length, kParamsSelf, slot_mp_length, wrapLenfunc,
729 "__len__($self, /)\n--\n\nReturn len(self)."),
730 TPSLOT(ID(__getitem__), Py_mp_subscript, kParamsSelfKey, slot_mp_subscript,
731 wrapBinaryfunc,
732 "__getitem__($self, key, /)\n--\n\nReturn self[key]."),
733 TPSLOT(ID(__setitem__), Py_mp_ass_subscript, kParamsSelfKeyValue,
734 slot_mp_ass_subscript, wrapObjobjargproc,
735 "__setitem__($self, key, value, /)\n--\n\nSet self[key] to value."),
736 TPSLOT(ID(__delitem__), Py_mp_ass_subscript, kParamsSelfKey,
737 slot_mp_ass_subscript, wrapDelitem,
738 "__delitem__($self, key, /)\n--\n\nDelete self[key]."),
739 TPSLOT(ID(__len__), Py_sq_length, kParamsSelf, slot_sq_length, wrapLenfunc,
740 "__len__($self, /)\n--\n\nReturn len(self)."),
741 TPSLOT(ID(__add__), Py_sq_concat, kParamsSelfValue, nullptr, wrapBinaryfunc,
742 "__add__($self, value, /)\n--\n\nReturn self+value."),
743 TPSLOT(ID(__mul__), Py_sq_repeat, kParamsSelfValue, nullptr,
744 wrapIndexargfunc,
745 "__mul__($self, value, /)\n--\n\nReturn self*value."),
746 TPSLOT(ID(__rmul__), Py_sq_repeat, kParamsSelfValue, nullptr,
747 wrapIndexargfunc,
748 "__rmul__($self, value, /)\n--\n\nReturn value*self."),
749 TPSLOT(ID(__getitem__), Py_sq_item, kParamsSelfKey, slot_sq_item,
750 wrapSqItem, "__getitem__($self, key, /)\n--\n\nReturn self[key]."),
751 TPSLOT(ID(__setitem__), Py_sq_ass_item, kParamsSelfKeyValue,
752 slot_sq_ass_item, wrapSqSetitem,
753 "__setitem__($self, key, value, /)\n--\n\nSet self[key] to value."),
754 TPSLOT(ID(__delitem__), Py_sq_ass_item, kParamsSelfKey, slot_sq_ass_item,
755 wrapSqDelitem,
756 "__delitem__($self, key, /)\n--\n\nDelete self[key]."),
757 TPSLOT(ID(__contains__), Py_sq_contains, kParamsSelfKey, slot_sq_contains,
758 wrapObjobjproc,
759 "__contains__($self, key, /)\n--\n\nReturn key in self."),
760 TPSLOT(ID(__iadd__), Py_sq_inplace_concat, kParamsSelfValue, nullptr,
761 wrapBinaryfunc,
762 "__iadd__($self, value, /)\n--\n\nImplement self+=value."),
763 TPSLOT(ID(__imul__), Py_sq_inplace_repeat, kParamsSelfValue, nullptr,
764 wrapIndexargfunc,
765 "__imul__($self, value, /)\n--\n\nImplement self*=value."),
766};
767
768// For every entry in kSlotdefs with a non-null wrapper function, a slot id
769// that was provided by the user, and no preexisting entry in the type dict, add
770// a wrapper function to call the slot from Python.
771//
772// Returns Error if an exception was raised at any point, None otherwise.
773static RawObject addOperators(Thread* thread, const Type& type) {
774 Runtime* runtime = thread->runtime();
775 HandleScope scope(thread);
776 Str type_name(&scope, type.name());
777
778 for (const SlotDef& slot : kSlotdefs) {
779 if (slot.wrapper == nullptr) continue;
780 void* slot_value = typeSlotAt(type, slot.id);
781 if (slot_value == nullptr) continue;
782
783 // Unlike most slots, we always allow __new__ to be overwritten by a subtype
784 if (slot.id != Py_tp_new &&
785 !typeAtById(thread, type, slot.name).isErrorNotFound()) {
786 continue;
787 }
788
789 // When given PyObject_HashNotImplemented, put None in the type dict
790 // rather than a wrapper. CPython does this regardless of which slot it
791 // was given for, so we do too.
792 if (slot_value == reinterpret_cast<void*>(&PyObject_HashNotImplemented)) {
793 Object none(&scope, NoneType::object());
794 typeAtPutById(thread, type, slot.name, none);
795 return NoneType::object();
796 }
797
798 Object func_obj(&scope, NoneType::object());
799 if (slot_value == reinterpret_cast<void*>(&PyObject_GenericGetAttr)) {
800 func_obj = runtime->objectDunderGetattribute();
801 } else if (slot_value ==
802 reinterpret_cast<void*>(&PyObject_GenericSetAttr)) {
803 func_obj = runtime->objectDunderSetattr();
804 } else {
805 // Create the wrapper function.
806 Str slot_name(&scope, runtime->symbols()->at(slot.name));
807 Str qualname(&scope,
808 runtime->newStrFromFmt("%S.%S", &type_name, &slot_name));
809 Code code(&scope, newExtCode(thread, slot_name, slot.parameters,
810 slot.flags, slot.wrapper, slot_value));
811 Object globals(&scope, NoneType::object());
812 Function func(&scope, runtime->newFunctionWithCode(thread, qualname, code,
813 globals));
814 slotWrapperFunctionSetType(func, type);
815 if (slot.id == Py_nb_power) {
816 Object none(&scope, NoneType::object());
817 func.setDefaults(runtime->newTupleWith1(none));
818 }
819
820 // __new__ is the one special-case static method, so wrap it
821 // appropriately.
822 func_obj = *func;
823 if (slot.id == Py_tp_new) {
824 func_obj =
825 thread->invokeFunction1(ID(builtins), ID(staticmethod), func);
826 if (func_obj.isError()) return *func_obj;
827 }
828 }
829
830 // Finally, put the wrapper in the type dict.
831 typeAtPutById(thread, type, slot.name, func_obj);
832 }
833
834 return NoneType::object();
835}
836
837static PyObject* allocatePyObject(const Type& type, Py_ssize_t nitems) {
838 uword basic_size = typeSlotUWordAt(type, kSlotBasicSize);
839 uword item_size = typeSlotUWordAt(type, kSlotItemSize);
840 Py_ssize_t size = Utils::roundUp(nitems * item_size + basic_size, kWordSize);
841
842 PyObject* result = nullptr;
843 if (type.hasFlag(Type::Flag::kHasCycleGC)) {
844 result = static_cast<PyObject*>(_PyObject_GC_Calloc(size));
845 } else {
846 result = static_cast<PyObject*>(PyObject_Calloc(1, size));
847 }
848 // Track object in native GC queue
849 if (type.hasFlag(Type::Flag::kHasCycleGC)) {
850 PyObject_GC_Track(result);
851 }
852 return result;
853}
854
855static PyObject* superclassTpNew(PyTypeObject* typeobj, PyObject* args,
856 PyObject* kwargs) {
857 Thread* thread = Thread::current();
858 HandleScope scope(thread);
859 Runtime* runtime = thread->runtime();
860
861 Type type(&scope, ApiHandle::asObject(ApiHandle::fromPyTypeObject(typeobj)));
862 Object args_obj(&scope, args == nullptr
863 ? runtime->emptyTuple()
864 : ApiHandle::asObject(ApiHandle::fromPyObject(args)));
865 DCHECK(runtime->isInstanceOfTuple(*args_obj),
866 "Slot __new__ expected tuple args");
867 Object kwargs_obj(&scope, kwargs == nullptr
868 ? NoneType::object()
869 : ApiHandle::asObject(ApiHandle::fromPyObject(kwargs)));
870 DCHECK(kwargs == nullptr || runtime->isInstanceOfDict(*kwargs_obj),
871 "Slot __new__ expected nullptr or dict kwargs");
872
873 Tuple type_mro(&scope, type.mro());
874 word i = 0;
875 Type superclass(&scope, type_mro.at(i++));
876 while (typeHasSlots(superclass)) {
877 superclass = type_mro.at(i++);
878 }
879 Object dunder_new(&scope,
880 typeLookupInMroById(thread, *superclass, ID(__new__)));
881 Object none(&scope, NoneType::object());
882 dunder_new = resolveDescriptorGet(thread, dunder_new, none, type);
883 dunder_new = runtime->newBoundMethod(dunder_new, type);
884 thread->stackPush(*dunder_new);
885 thread->stackPush(*args_obj);
886 word flags = 0;
887 if (kwargs != nullptr) {
888 thread->stackPush(*kwargs_obj);
889 flags = CallFunctionExFlag::VAR_KEYWORDS;
890 }
891 Object instance(&scope, Interpreter::callEx(thread, flags));
892 if (instance.isErrorException()) return nullptr;
893
894 // If the type doesn't require NativeData, we don't need to allocate or
895 // create a NativeProxy for the instance
896 if (!type.hasNativeData()) {
897 return ApiHandle::newReference(runtime, *instance);
898 }
899
900 PyObject* result = allocatePyObject(type, 0);
901 if (result == nullptr) {
902 thread->raiseMemoryError();
903 return nullptr;
904 }
905 return initializeExtensionObject(thread, result, typeobj, instance);
906}
907
908// tp_new slot implementation that delegates to a Type's __new__ attribute.
909static PyObject* slotTpNew(PyObject* type, PyObject* args, PyObject* kwargs) {
910 Thread* thread = Thread::current();
911 Runtime* runtime = thread->runtime();
912 HandleScope scope(thread);
913
914 Object type_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(type)));
915 Object args_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(args)));
916 DCHECK(runtime->isInstanceOfTuple(*args_obj),
917 "Slot __new__ expected tuple args");
918 Object kwargs_obj(&scope, kwargs ? ApiHandle::asObject(ApiHandle::fromPyObject(kwargs))
919 : NoneType::object());
920 DCHECK(kwargs == nullptr || runtime->isInstanceOfDict(*kwargs_obj),
921 "Slot __new__ expected nullptr or dict kwargs");
922
923 // Construct a new args tuple with type at the front.
924 Tuple args_tuple(&scope, tupleUnderlying(*args_obj));
925 MutableTuple new_args(&scope,
926 runtime->newMutableTuple(args_tuple.length() + 1));
927 new_args.atPut(0, *type_obj);
928 new_args.replaceFromWith(1, *args_tuple, args_tuple.length());
929
930 // Call type.__new__(type, *args, **kwargs)
931 Object dunder_new(&scope,
932 runtime->attributeAtById(thread, type_obj, ID(__new__)));
933 if (dunder_new.isError()) return nullptr;
934 thread->stackPush(*dunder_new);
935 thread->stackPush(new_args.becomeImmutable());
936 word flags = 0;
937 if (kwargs != nullptr) {
938 thread->stackPush(*kwargs_obj);
939 flags = CallFunctionExFlag::VAR_KEYWORDS;
940 }
941 Object result(&scope, Interpreter::callEx(thread, flags));
942 if (result.isError()) return nullptr;
943 return ApiHandle::newReference(runtime, *result);
944}
945
946// Return a default slot wrapper for the given slot, or abort if it's not yet
947// supported.
948//
949// This performs similar duties to update_one_slot() in CPython, but it's
950// drastically simpler. This is intentional, and will only change if a real C
951// extension exercises slots in a way that exposes the differences.
952static void* defaultSlot(int slot_id) {
953 switch (slot_id) {
954 case Py_tp_new:
955 return reinterpret_cast<void*>(&slotTpNew);
956 default:
957 UNIMPLEMENTED("Unsupported default slot %d", slot_id);
958 }
959}
960
961static int emptyClear(PyObject*) { return 0; }
962
963static int emptyTraverse(PyObject*, visitproc, void*) { return 0; }
964
965static void builtinDealloc(PyObject* self) {
966 // This function is called for instances of non-heaptypes (most builtin types)
967 // or subclasses of them. There is nothing to deallocate/free for
968 // instances of builtin types. However subclasses may have extra data
969 // allocated that needs to be freed with `PyObject_Del`.
970 Thread* thread = Thread::current();
971 Runtime* runtime = thread->runtime();
972 HandleScope scope(thread);
973 Object self_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(self)));
974 Type type(&scope, runtime->typeOf(*self_obj));
975 if (type.hasNativeData()) {
976 PyObject_Del(self);
977 }
978}
979
980PY_EXPORT void* PyType_GetSlot(PyTypeObject* type_obj, int slot_id) {
981 Thread* thread = Thread::current();
982 if (slot_id < 0) {
983 thread->raiseBadInternalCall();
984 return nullptr;
985 }
986
987 HandleScope scope(thread);
988 ApiHandle* handle = ApiHandle::fromPyTypeObject(type_obj);
989 Type type(&scope, ApiHandle::asObjectNoImmediate(handle));
990 if (!type.isCPythonHeaptype()) {
991 if (slot_id == Py_tp_new) {
992 return reinterpret_cast<void*>(&superclassTpNew);
993 }
994 if (slot_id == Py_tp_clear) {
995 return reinterpret_cast<void*>(&emptyClear);
996 }
997 if (slot_id == Py_tp_traverse) {
998 return reinterpret_cast<void*>(&emptyTraverse);
999 }
1000 if (slot_id == Py_tp_dealloc) {
1001 return reinterpret_cast<void*>(&builtinDealloc);
1002 }
1003 thread->raiseBadInternalCall();
1004 return nullptr;
1005 }
1006
1007 // Extension module requesting slot from a future version
1008 if (!isValidSlotId(slot_id)) {
1009 return nullptr;
1010 }
1011
1012 if (!typeHasSlots(type)) {
1013 // The Type was not created by PyType_FromSpec(), so return a default slot
1014 // implementation that delegates to managed methods.
1015 return defaultSlot(slot_id);
1016 }
1017 if (isObjectSlotId(slot_id)) {
1018 return ApiHandle::borrowedReference(thread->runtime(),
1019 typeSlotObjectAt(type, slot_id));
1020 }
1021
1022 return typeSlotAt(type, slot_id);
1023}
1024
1025PY_EXPORT int PyType_Ready(PyTypeObject*) {
1026 UNIMPLEMENTED("This function will never be implemented");
1027}
1028
1029PY_EXPORT PyObject* PyType_FromSpec(PyType_Spec* spec) {
1030 return PyType_FromSpecWithBases(spec, nullptr);
1031}
1032
1033static RawObject memberGetter(Thread* thread, PyMemberDef* member) {
1034 HandleScope scope(thread);
1035 Runtime* runtime = thread->runtime();
1036 Object name(&scope, runtime->newStrFromCStr(member->name));
1037 Int offset(&scope, runtime->newInt(member->offset));
1038 switch (member->type) {
1039 case T_BOOL:
1040 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_bool),
1041 offset);
1042 case T_BYTE:
1043 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_byte),
1044 offset);
1045 case T_UBYTE:
1046 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_ubyte),
1047 offset);
1048 case T_SHORT:
1049 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_short),
1050 offset);
1051 case T_USHORT:
1052 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_ushort),
1053 offset);
1054 case T_INT:
1055 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_int),
1056 offset);
1057 case T_UINT:
1058 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_uint),
1059 offset);
1060 case T_LONG:
1061 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_long),
1062 offset);
1063 case T_ULONG:
1064 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_ulong),
1065 offset);
1066 case T_PYSSIZET:
1067 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_ulong),
1068 offset);
1069 case T_FLOAT:
1070 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_float),
1071 offset);
1072 case T_DOUBLE:
1073 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_double),
1074 offset);
1075 case T_LONGLONG:
1076 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_long),
1077 offset);
1078 case T_ULONGLONG:
1079 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_ulong),
1080 offset);
1081 case T_STRING:
1082 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_string),
1083 offset);
1084 case T_STRING_INPLACE:
1085 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_string),
1086 offset);
1087 case T_CHAR:
1088 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_char),
1089 offset);
1090 case T_OBJECT:
1091 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_pyobject),
1092 offset);
1093 case T_OBJECT_EX:
1094 return thread->invokeFunction2(ID(builtins), ID(_new_member_get_pyobject),
1095 offset, name);
1096 case T_NONE:
1097 return thread->invokeFunction1(ID(builtins), ID(_new_member_get_pyobject),
1098 offset);
1099 default:
1100 return thread->raiseWithFmt(LayoutId::kSystemError,
1101 "bad member name type");
1102 }
1103}
1104
1105static RawObject memberSetter(Thread* thread, PyMemberDef* member) {
1106 HandleScope scope(thread);
1107 Runtime* runtime = thread->runtime();
1108 if (member->flags & READONLY) {
1109 Object name(&scope, runtime->newStrFromCStr(member->name));
1110 Function setter(
1111 &scope, thread->invokeFunction1(ID(builtins),
1112 ID(_new_member_set_readonly), name));
1113 return *setter;
1114 }
1115
1116 Int offset(&scope, runtime->newInt(member->offset));
1117 switch (member->type) {
1118 case T_BOOL:
1119 return thread->invokeFunction1(ID(builtins), ID(_new_member_set_bool),
1120 offset);
1121 case T_BYTE: {
1122 Int num_bytes(&scope, runtime->newInt(sizeof(char)));
1123 Int min_value(&scope, runtime->newInt(std::numeric_limits<char>::min()));
1124 Int max_value(&scope, runtime->newInt(std::numeric_limits<char>::max()));
1125 Str primitive_type(&scope, runtime->newStrFromCStr("char"));
1126 Function setter(&scope,
1127 thread->invokeFunction5(
1128 ID(builtins), ID(_new_member_set_integral), offset,
1129 num_bytes, min_value, max_value, primitive_type));
1130 return *setter;
1131 }
1132 case T_UBYTE: {
1133 Int num_bytes(&scope, runtime->newInt(sizeof(unsigned char)));
1134 Int max_value(&scope, runtime->newIntFromUnsigned(
1135 std::numeric_limits<unsigned char>::max()));
1136 Str primitive_type(&scope, runtime->newStrFromCStr("unsigned char"));
1137 Function setter(&scope,
1138 thread->invokeFunction4(
1139 ID(builtins), ID(_new_member_set_integral_unsigned),
1140 offset, num_bytes, max_value, primitive_type));
1141 return *setter;
1142 }
1143 case T_SHORT: {
1144 Int num_bytes(&scope, runtime->newInt(sizeof(short)));
1145 Int min_value(&scope, runtime->newInt(std::numeric_limits<short>::min()));
1146 Int max_value(&scope, runtime->newInt(std::numeric_limits<short>::max()));
1147 Str primitive_type(&scope, runtime->newStrFromCStr("short"));
1148 Function setter(&scope,
1149 thread->invokeFunction5(
1150 ID(builtins), ID(_new_member_set_integral), offset,
1151 num_bytes, min_value, max_value, primitive_type));
1152 return *setter;
1153 }
1154 case T_USHORT: {
1155 Int num_bytes(&scope, runtime->newInt(sizeof(unsigned short)));
1156 Int max_value(&scope, runtime->newIntFromUnsigned(
1157 std::numeric_limits<unsigned short>::max()));
1158 Str primitive_type(&scope, runtime->newStrFromCStr("unsigned short"));
1159 Function setter(&scope,
1160 thread->invokeFunction4(
1161 ID(builtins), ID(_new_member_set_integral_unsigned),
1162 offset, num_bytes, max_value, primitive_type));
1163 return *setter;
1164 }
1165 case T_INT: {
1166 Int num_bytes(&scope, runtime->newInt(sizeof(int)));
1167 Int min_value(&scope, runtime->newInt(std::numeric_limits<int>::min()));
1168 Int max_value(&scope, runtime->newInt(std::numeric_limits<int>::max()));
1169 Str primitive_type(&scope, runtime->newStrFromCStr("int"));
1170 Function setter(&scope,
1171 thread->invokeFunction5(
1172 ID(builtins), ID(_new_member_set_integral), offset,
1173 num_bytes, min_value, max_value, primitive_type));
1174 return *setter;
1175 }
1176 case T_UINT: {
1177 Int num_bytes(&scope, runtime->newInt(sizeof(unsigned int)));
1178 Int max_value(&scope, runtime->newIntFromUnsigned(
1179 std::numeric_limits<unsigned int>::max()));
1180 Str primitive_type(&scope, runtime->newStrFromCStr("unsigned int"));
1181 Function setter(&scope,
1182 thread->invokeFunction4(
1183 ID(builtins), ID(_new_member_set_integral_unsigned),
1184 offset, num_bytes, max_value, primitive_type));
1185 return *setter;
1186 }
1187 case T_LONG: {
1188 Int num_bytes(&scope, runtime->newInt(sizeof(long)));
1189 Int min_value(&scope, runtime->newInt(std::numeric_limits<long>::min()));
1190 Int max_value(&scope, runtime->newInt(std::numeric_limits<long>::max()));
1191 Str primitive_type(&scope, runtime->newStrFromCStr("long"));
1192 Function setter(&scope,
1193 thread->invokeFunction5(
1194 ID(builtins), ID(_new_member_set_integral), offset,
1195 num_bytes, min_value, max_value, primitive_type));
1196 return *setter;
1197 }
1198 case T_ULONG: {
1199 Int num_bytes(&scope, runtime->newInt(sizeof(unsigned long)));
1200 Int max_value(&scope, runtime->newIntFromUnsigned(
1201 std::numeric_limits<unsigned long>::max()));
1202 Str primitive_type(&scope, runtime->newStrFromCStr("unsigned long"));
1203 Function setter(&scope,
1204 thread->invokeFunction4(
1205 ID(builtins), ID(_new_member_set_integral_unsigned),
1206 offset, num_bytes, max_value, primitive_type));
1207 return *setter;
1208 }
1209 case T_PYSSIZET: {
1210 Int num_bytes(&scope, runtime->newInt(sizeof(Py_ssize_t)));
1211 Int min_value(&scope, SmallInt::fromWord(0));
1212 Int max_value(&scope,
1213 runtime->newInt(std::numeric_limits<Py_ssize_t>::max()));
1214 Str primitive_type(&scope, runtime->newStrFromCStr("Py_ssize_t"));
1215 Function setter(&scope,
1216 thread->invokeFunction5(
1217 ID(builtins), ID(_new_member_set_integral), offset,
1218 num_bytes, min_value, max_value, primitive_type));
1219 return *setter;
1220 }
1221 case T_FLOAT: {
1222 return thread->invokeFunction1(ID(builtins), ID(_new_member_set_float),
1223 offset);
1224 }
1225 case T_DOUBLE: {
1226 return thread->invokeFunction1(ID(builtins), ID(_new_member_set_double),
1227 offset);
1228 }
1229 case T_STRING: {
1230 Object name(&scope, runtime->newStrFromCStr(member->name));
1231 Function setter(&scope, thread->invokeFunction1(
1232 ID(builtins),
1233 ID(_new_member_set_readonly_strings), name));
1234 return *setter;
1235 }
1236 case T_STRING_INPLACE: {
1237 Object name(&scope, runtime->newStrFromCStr(member->name));
1238 Function setter(&scope, thread->invokeFunction1(
1239 ID(builtins),
1240 ID(_new_member_set_readonly_strings), name));
1241 return *setter;
1242 }
1243 case T_CHAR: {
1244 Function setter(
1245 &scope, thread->invokeFunction1(ID(builtins),
1246 ID(_new_member_set_char), offset));
1247 return *setter;
1248 }
1249 case T_OBJECT: {
1250 Function setter(&scope,
1251 thread->invokeFunction1(
1252 ID(builtins), ID(_new_member_set_pyobject), offset));
1253 return *setter;
1254 }
1255 case T_OBJECT_EX: {
1256 Function setter(&scope,
1257 thread->invokeFunction1(
1258 ID(builtins), ID(_new_member_set_pyobject), offset));
1259 return *setter;
1260 }
1261 case T_LONGLONG: {
1262 Int num_bytes(&scope, runtime->newInt(sizeof(long long)));
1263 Int min_value(&scope,
1264 runtime->newInt(std::numeric_limits<long long>::min()));
1265 Int max_value(&scope,
1266 runtime->newInt(std::numeric_limits<long long>::max()));
1267 Str primitive_type(&scope, runtime->newStrFromCStr("long long"));
1268 Function setter(&scope,
1269 thread->invokeFunction5(
1270 ID(builtins), ID(_new_member_set_integral), offset,
1271 num_bytes, min_value, max_value, primitive_type));
1272 return *setter;
1273 }
1274 case T_ULONGLONG: {
1275 Int num_bytes(&scope, runtime->newInt(sizeof(unsigned long long)));
1276 Int max_value(&scope,
1277 runtime->newIntFromUnsigned(
1278 std::numeric_limits<unsigned long long>::max()));
1279 Str primitive_type(&scope, runtime->newStrFromCStr("unsigned long long"));
1280 Function setter(&scope,
1281 thread->invokeFunction4(
1282 ID(builtins), ID(_new_member_set_integral_unsigned),
1283 offset, num_bytes, max_value, primitive_type));
1284 return *setter;
1285 }
1286 default:
1287 return thread->raiseWithFmt(LayoutId::kSystemError,
1288 "bad member name type");
1289 }
1290}
1291
1292static RawObject addMethods(Thread* thread, const Type& type) {
1293 HandleScope scope(thread);
1294 PyMethodDef* methods =
1295 static_cast<PyMethodDef*>(typeSlotAt(type, Py_tp_methods));
1296 if (methods == nullptr) return NoneType::object();
1297 Object none(&scope, NoneType::object());
1298 Object unbound(&scope, Unbound::object());
1299 Object name(&scope, NoneType::object());
1300 Object member(&scope, NoneType::object());
1301 for (PyMethodDef* method = methods; method->ml_name != nullptr; method++) {
1302 name = Runtime::internStrFromCStr(thread, method->ml_name);
1303 int flags = method->ml_flags;
1304 if (!(flags & METH_COEXIST) && !typeAt(type, name).isErrorNotFound()) {
1305 continue;
1306 }
1307 if (flags & METH_CLASS) {
1308 if (flags & METH_STATIC) {
1309 return thread->raiseWithFmt(LayoutId::kValueError,
1310 "method cannot be both class and static");
1311 }
1312 member = newClassMethod(thread, method, name, type);
1313 } else if (flags & METH_STATIC) {
1314 member = newCFunction(thread, method, name, unbound, none);
1315 } else {
1316 member = newMethod(thread, method, name, type);
1317 }
1318 typeAtPut(thread, type, name, member);
1319 }
1320 return NoneType::object();
1321}
1322
1323static RawObject addMembers(Thread* thread, const Type& type,
1324 PyMemberDef* members) {
1325 if (members == nullptr) return NoneType::object();
1326 HandleScope scope(thread);
1327 Object none(&scope, NoneType::object());
1328 Runtime* runtime = thread->runtime();
1329 Object getter(&scope, NoneType::object());
1330 Object setter(&scope, NoneType::object());
1331 Object property(&scope, NoneType::object());
1332 Object name_obj(&scope, NoneType::object());
1333 for (PyMemberDef* member = members; member->name != nullptr; member++) {
1334 const char* name = member->name;
1335 if (std::strcmp(name, "__dictoffset__") == 0 ||
1336 std::strcmp(name, "__weaklistoffset__") == 0) {
1337 continue;
1338 }
1339 getter = memberGetter(thread, member);
1340 if (getter.isErrorException()) return *getter;
1341 setter = memberSetter(thread, member);
1342 if (setter.isErrorException()) return *setter;
1343 property = runtime->newProperty(getter, setter, none);
1344 name_obj = Runtime::internStrFromCStr(thread, name);
1345 typeAtPut(thread, type, name_obj, property);
1346 }
1347 return NoneType::object();
1348}
1349
1350static RawObject addGetSet(Thread* thread, const Type& type) {
1351 HandleScope scope(thread);
1352 PyGetSetDef* getsets =
1353 static_cast<PyGetSetDef*>(typeSlotAt(type, Py_tp_getset));
1354 if (getsets == nullptr) return NoneType::object();
1355 for (word i = 0; getsets[i].name != nullptr; i++) {
1356 Object name(&scope, Runtime::internStrFromCStr(thread, getsets[i].name));
1357 Object property(&scope, newGetSet(thread, name, &getsets[i]));
1358 typeAtPut(thread, type, name, property);
1359 }
1360 return NoneType::object();
1361}
1362
1363// The default tp_dealloc slot for all C Types. This loosely follows CPython's
1364// subtype_dealloc.
1365static void subtypeDealloc(PyObject* self) {
1366 Thread* thread = Thread::current();
1367 Runtime* runtime = thread->runtime();
1368 HandleScope scope(thread);
1369 Object self_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(self)));
1370 Type type(&scope, runtime->typeOf(*self_obj));
1371
1372 DCHECK(type.isCPythonHeaptype(), "must be called with heaptype");
1373
1374 void* finalize_func = typeSlotAt(type, Py_tp_finalize);
1375 if (finalize_func != nullptr) {
1376 if (PyObject_CallFinalizerFromDealloc(self) < 0) {
1377 // Resurrected
1378 return;
1379 }
1380 }
1381
1382 destructor del_func =
1383 reinterpret_cast<destructor>(typeSlotAt(type, Py_tp_del));
1384 if (del_func != nullptr) {
1385 (*del_func)(self);
1386 if (Py_REFCNT(self) > 1) {
1387 // Resurrected
1388 return;
1389 }
1390 }
1391 destructor base_dealloc = subtypeDealloc;
1392 Type base_type(&scope, *type);
1393 while (base_dealloc == subtypeDealloc) {
1394 base_type = typeSlotObjectAt(base_type, Py_tp_base);
1395 if (typeHasSlots(base_type)) {
1396 base_dealloc =
1397 reinterpret_cast<destructor>(typeSlotAt(base_type, Py_tp_dealloc));
1398 } else {
1399 base_dealloc = reinterpret_cast<destructor>(PyObject_Del);
1400 }
1401 }
1402 type = runtime->typeOf(*self_obj);
1403 (*base_dealloc)(self);
1404 if (type.isCPythonHeaptype() && !base_type.isCPythonHeaptype()) {
1405 ApiHandle::decref(ApiHandle::borrowedReference(runtime, *type));
1406 }
1407}
1408
1409// Copy the slot from the base type if it defined.
1410static void copySlot(Thread* thread, const Type& type, const Type& base,
1411 int slot_id) {
1412 if (typeSlotAt(type, slot_id) != nullptr) return;
1413 void* base_slot = typeSlotAt(base, slot_id);
1414 typeSlotAtPut(thread, type, slot_id, base_slot);
1415}
1416
1417static void* baseBaseSlot(Thread* thread, const Type& base, int slot_id) {
1418 if (typeSlotObjectAt(base, Py_tp_base) != SmallInt::fromWord(0)) {
1419 return nullptr;
1420 }
1421 HandleScope scope(thread);
1422 Type basebase(&scope, typeSlotObjectAt(base, Py_tp_base));
1423 if (!typeHasSlots(basebase)) return nullptr;
1424 return typeSlotAt(basebase, slot_id);
1425}
1426
1427// Copy the slot from the base type if defined and it is the first type that
1428// defines it. If base's base type defines the same slot, then base inherited
1429// it. Thus, it is not the first type to define it.
1430static void copySlotIfImplementedInBase(Thread* thread, const Type& type,
1431 const Type& base, int slot_id) {
1432 if (typeSlotAt(type, slot_id) != nullptr) return;
1433 void* base_slot = typeSlotAt(base, slot_id);
1434 if (base_slot != nullptr) {
1435 void* basebase_slot = baseBaseSlot(thread, base, slot_id);
1436 if (basebase_slot == nullptr || base_slot != basebase_slot) {
1437 typeSlotAtPut(thread, type, slot_id, base_slot);
1438 }
1439 }
1440}
1441
1442static void inheritFree(Thread* thread, const Type& type,
1443 unsigned long type_flags, const Type& base,
1444 unsigned long base_flags) {
1445 // Both child and base are GC or non GC
1446 if ((type_flags & Py_TPFLAGS_HAVE_GC) == (base_flags & Py_TPFLAGS_HAVE_GC)) {
1447 copySlotIfImplementedInBase(thread, type, base, Py_tp_free);
1448 return;
1449 }
1450
1451 DCHECK(!(base_flags & Py_TPFLAGS_HAVE_GC), "The child should not remove GC");
1452
1453 // Only the child is GC
1454 // Set the free function if the base has a default free
1455 if ((type_flags & Py_TPFLAGS_HAVE_GC) &&
1456 typeSlotAt(type, Py_tp_free) == nullptr) {
1457 if (typeSlotAt(base, Py_tp_free) ==
1458 reinterpret_cast<void*>(&PyObject_Free)) {
1459 typeSlotAtPut(thread, type, Py_tp_free,
1460 reinterpret_cast<void*>(&PyObject_GC_Del));
1461 }
1462 }
1463}
1464
1465static void inheritGCFlagsAndSlots(Thread* thread, const Type& type,
1466 const Type& base) {
1467 unsigned long type_flags = typeSlotUWordAt(type, kSlotFlags);
1468 unsigned long base_flags = typeSlotUWordAt(base, kSlotFlags);
1469 if (!(type_flags & Py_TPFLAGS_HAVE_GC) && (base_flags & Py_TPFLAGS_HAVE_GC) &&
1470 typeSlotAt(type, Py_tp_traverse) == nullptr &&
1471 typeSlotAt(type, Py_tp_clear) == nullptr) {
1472 typeSlotUWordAtPut(thread, type, kSlotFlags,
1473 type_flags | Py_TPFLAGS_HAVE_GC);
1474 copySlot(thread, type, base, Py_tp_traverse);
1475 copySlot(thread, type, base, Py_tp_clear);
1476 }
1477}
1478
1479static void inheritNonFunctionSlots(Thread* thread, const Type& type,
1480 const Type& base) {
1481 if (typeSlotUWordAt(type, kSlotBasicSize) == 0) {
1482 typeSlotUWordAtPut(thread, type, kSlotBasicSize,
1483 typeSlotUWordAt(base, kSlotBasicSize));
1484 }
1485 typeSlotUWordAtPut(thread, type, kSlotItemSize,
1486 typeSlotUWordAt(base, kSlotItemSize));
1487}
1488
1489// clang-format off
1490static const int kInheritableSlots[] = {
1491 // Number slots
1492 Py_nb_add,
1493 Py_nb_subtract,
1494 Py_nb_multiply,
1495 Py_nb_remainder,
1496 Py_nb_divmod,
1497 Py_nb_power,
1498 Py_nb_negative,
1499 Py_nb_positive,
1500 Py_nb_absolute,
1501 Py_nb_bool,
1502 Py_nb_invert,
1503 Py_nb_lshift,
1504 Py_nb_rshift,
1505 Py_nb_and,
1506 Py_nb_xor,
1507 Py_nb_or,
1508 Py_nb_int,
1509 Py_nb_float,
1510 Py_nb_inplace_add,
1511 Py_nb_inplace_subtract,
1512 Py_nb_inplace_multiply,
1513 Py_nb_inplace_remainder,
1514 Py_nb_inplace_power,
1515 Py_nb_inplace_lshift,
1516 Py_nb_inplace_rshift,
1517 Py_nb_inplace_and,
1518 Py_nb_inplace_xor,
1519 Py_nb_inplace_or,
1520 Py_nb_true_divide,
1521 Py_nb_floor_divide,
1522 Py_nb_inplace_true_divide,
1523 Py_nb_inplace_floor_divide,
1524 Py_nb_index,
1525 Py_nb_matrix_multiply,
1526 Py_nb_inplace_matrix_multiply,
1527
1528 // Await slots
1529 Py_am_await,
1530 Py_am_aiter,
1531 Py_am_anext,
1532
1533 // Sequence slots
1534 Py_sq_length,
1535 Py_sq_concat,
1536 Py_sq_repeat,
1537 Py_sq_item,
1538 Py_sq_ass_item,
1539 Py_sq_contains,
1540 Py_sq_inplace_concat,
1541 Py_sq_inplace_repeat,
1542
1543 // Mapping slots
1544 Py_mp_length,
1545 Py_mp_subscript,
1546 Py_mp_ass_subscript,
1547
1548 // Buffer protocol is not part of PEP-384
1549
1550 // Type slots
1551 Py_tp_dealloc,
1552 Py_tp_repr,
1553 Py_tp_call,
1554 Py_tp_str,
1555 Py_tp_iter,
1556 Py_tp_iternext,
1557 Py_tp_descr_get,
1558 Py_tp_descr_set,
1559 Py_tp_init,
1560 Py_tp_alloc,
1561 Py_tp_is_gc,
1562 Py_tp_finalize,
1563
1564 // Instance dictionary is not part of PEP-384
1565
1566 // Weak reference support is not part of PEP-384
1567};
1568// clang-format on
1569
1570static int typeSetattro(PyTypeObject* type, PyObject* name, PyObject* value) {
1571 DCHECK(PyType_GetFlags(type) & Py_TPFLAGS_HEAPTYPE,
1572 "typeSetattro requires an instance from a heap allocated C "
1573 "extension type");
1574 Thread* thread = Thread::current();
1575 HandleScope scope(thread);
1576 Type type_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyTypeObject(type)));
1577 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(name)));
1578 Object value_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(value)));
1579 if (thread
1580 ->invokeMethodStatic3(LayoutId::kType, ID(__setattr__), type_obj,
1581 name_obj, value_obj)
1582 .isError()) {
1583 return -1;
1584 }
1585 return 0;
1586}
1587
1588static void inheritSlots(Thread* thread, const Type& type, const Type& base) {
1589 // Heap allocated types are guaranteed to have slot space, no check is needed
1590 // i.e. CPython does: `if (type->tp_as_number != NULL)`
1591 // Only static types need to do this type of check.
1592 for (int slot_id : kInheritableSlots) {
1593 copySlotIfImplementedInBase(thread, type, base, slot_id);
1594 }
1595
1596 // Inherit conditional type slots
1597 if (typeSlotAt(type, Py_tp_getattr) == nullptr &&
1598 typeSlotAt(type, Py_tp_getattro) == nullptr) {
1599 copySlot(thread, type, base, Py_tp_getattr);
1600 copySlot(thread, type, base, Py_tp_getattro);
1601 }
1602 if (typeSlotAt(type, Py_tp_setattr) == nullptr &&
1603 typeSlotAt(type, Py_tp_setattro) == nullptr) {
1604 copySlot(thread, type, base, Py_tp_setattr);
1605 copySlot(thread, type, base, Py_tp_setattro);
1606 }
1607 if (typeSlotAt(type, Py_tp_richcompare) == nullptr &&
1608 typeSlotAt(type, Py_tp_hash) == nullptr) {
1609 copySlot(thread, type, base, Py_tp_richcompare);
1610 copySlot(thread, type, base, Py_tp_hash);
1611 }
1612
1613 unsigned long type_flags = typeSlotUWordAt(type, kSlotFlags);
1614 unsigned long base_flags = typeSlotUWordAt(base, kSlotFlags);
1615 inheritFree(thread, type, type_flags, base, base_flags);
1616}
1617
1618static int objectInit(PyObject*, PyObject*, PyObject*) {
1619 UNIMPLEMENTED("should not directly call tp_init");
1620}
1621
1622static RawObject addDefaultsForRequiredSlots(Thread* thread, const Type& type,
1623 const Type& base) {
1624 Runtime* runtime = thread->runtime();
1625 HandleScope scope(thread);
1626 Str type_name(&scope, type.name());
1627
1628 // tp_basicsize -> sizeof(PyObject)
1629 uword basic_size = typeSlotUWordAt(type, kSlotBasicSize);
1630 if (basic_size == 0) {
1631 basic_size = sizeof(PyObject);
1632 typeSlotUWordAtPut(thread, type, kSlotBasicSize, basic_size);
1633 }
1634 DCHECK(basic_size >= sizeof(PyObject),
1635 "sizeof(PyObject) is the minimum size required for an extension "
1636 "instance");
1637
1638 // tp_repr -> PyObject_Repr
1639 if (typeSlotAt(type, Py_tp_repr) == nullptr) {
1640 typeSlotAtPut(thread, type, Py_tp_repr,
1641 reinterpret_cast<void*>(&PyObject_Repr));
1642 // PyObject_Repr delegates its job to type.__repr__().
1643 DCHECK(!typeLookupInMroById(thread, *type, ID(__repr__)).isErrorNotFound(),
1644 "__repr__ is expected");
1645 }
1646
1647 // tp_str -> object_str
1648 if (typeSlotAt(type, Py_tp_str) == nullptr) {
1649 typeSlotAtPut(thread, type, Py_tp_str,
1650 reinterpret_cast<void*>(&PyObject_Str));
1651 // PyObject_Str delegates its job to type.__str__().
1652 DCHECK(!typeLookupInMroById(thread, *type, ID(__str__)).isErrorNotFound(),
1653 "__str__ is expected");
1654 }
1655
1656 // tp_init -> object_init
1657 if (typeSlotAt(type, Py_tp_init) == nullptr) {
1658 typeSlotAtPut(thread, type, Py_tp_init,
1659 reinterpret_cast<void*>(&objectInit));
1660 }
1661
1662 // tp_alloc -> PyType_GenericAlloc
1663 if (typeSlotAt(type, Py_tp_alloc) == nullptr) {
1664 typeSlotAtPut(thread, type, Py_tp_alloc,
1665 reinterpret_cast<void*>(&PyType_GenericAlloc));
1666 }
1667
1668 // tp_new -> PyType_GenericNew
1669 if (typeSlotAt(type, Py_tp_new) == nullptr) {
1670 void* new_func = reinterpret_cast<void*>(&superclassTpNew);
1671 typeSlotAtPut(thread, type, Py_tp_new, new_func);
1672
1673 Str dunder_new_name(&scope, runtime->symbols()->at(ID(__new__)));
1674 Str qualname(&scope,
1675 runtime->newStrFromFmt("%S.%S", &type_name, &dunder_new_name));
1676 Code code(&scope,
1677 newExtCode(thread, dunder_new_name, kParamsTypeArgsKwargs,
1678 Code::Flags::kVarargs | Code::Flags::kVarkeyargs,
1679 wrapTpNew, new_func));
1680 Object globals(&scope, NoneType::object());
1681 Function func(
1682 &scope, runtime->newFunctionWithCode(thread, qualname, code, globals));
1683 slotWrapperFunctionSetType(func, type);
1684 Object func_obj(
1685 &scope, thread->invokeFunction1(ID(builtins), ID(staticmethod), func));
1686 if (func_obj.isError()) return *func;
1687 typeAtPutById(thread, type, ID(__new__), func_obj);
1688 }
1689
1690 // tp_free.
1691 if (typeSlotAt(type, Py_tp_free) == nullptr) {
1692 unsigned long type_flags = typeSlotUWordAt(type, kSlotFlags);
1693 freefunc func =
1694 (type_flags & Py_TPFLAGS_HAVE_GC) ? &PyObject_GC_Del : &PyObject_Del;
1695 typeSlotAtPut(thread, type, Py_tp_free, reinterpret_cast<void*>(func));
1696 }
1697
1698 // tp_setattro
1699 if (typeSlotAt(type, Py_tp_setattr) == nullptr &&
1700 typeSlotAt(type, Py_tp_setattro) == nullptr) {
1701 if (typeIsSubclass(*base, runtime->typeAt(LayoutId::kType))) {
1702 typeSlotAtPut(thread, type, Py_tp_setattro,
1703 reinterpret_cast<void*>(typeSetattro));
1704 }
1705 }
1706
1707 return NoneType::object();
1708}
1709
1710RawObject typeInheritSlots(Thread* thread, const Type& type, const Type& base) {
1711 HandleScope scope(thread);
1712
1713 if (!typeHasSlots(type)) {
1714 typeSlotsAllocate(thread, type);
1715 unsigned long flags = typeGetFlags(base);
1716 if (type.hasFlag(Type::Flag::kHasCycleGC)) flags |= Py_TPFLAGS_HAVE_GC;
1717 if (type.hasFlag(Type::Flag::kIsBasetype)) flags |= Py_TPFLAGS_BASETYPE;
1718 if (type.hasFlag(Type::Flag::kIsCPythonHeaptype)) {
1719 flags |= Py_TPFLAGS_HEAPTYPE;
1720 }
1721 typeSlotUWordAtPut(thread, type, kSlotFlags, flags);
1722 uword basicsize = typeGetBasicSize(base);
1723 typeSlotUWordAtPut(thread, type, kSlotBasicSize, basicsize);
1724 typeSlotUWordAtPut(thread, type, kSlotItemSize, 0);
1725 typeSlotObjectAtPut(type, Py_tp_base, *base);
1726 }
1727
1728 // Inherit special slots from dominant base
1729 if (typeHasSlots(base)) {
1730 inheritGCFlagsAndSlots(thread, type, base);
1731 if (typeSlotAt(type, Py_tp_new) == nullptr) {
1732 copySlot(thread, type, base, Py_tp_new);
1733 }
1734 inheritNonFunctionSlots(thread, type, base);
1735 }
1736
1737 // Inherit slots from the MRO
1738 Tuple mro(&scope, type.mro());
1739 for (word i = 1; i < mro.length(); i++) {
1740 Type mro_entry(&scope, mro.at(i));
1741 // Skip inheritance if mro_entry does not define slots
1742 if (!typeHasSlots(mro_entry)) continue;
1743 inheritSlots(thread, type, mro_entry);
1744 }
1745
1746 // Inherit all the default slots that would have been inherited
1747 // through the base object type in CPython
1748 Object result(&scope, addDefaultsForRequiredSlots(thread, type, base));
1749 if (result.isError()) return *result;
1750
1751 return NoneType::object();
1752}
1753
1754PY_EXPORT PyObject* PyType_FromSpecWithBases(PyType_Spec* spec,
1755 PyObject* bases) {
1756 Thread* thread = Thread::current();
1757 Runtime* runtime = thread->runtime();
1758 HandleScope scope(thread);
1759
1760 // Define the type name
1761 Object module_name(&scope, NoneType::object());
1762 const char* class_name = strrchr(spec->name, '.');
1763 if (class_name == nullptr) {
1764 class_name = spec->name;
1765 } else {
1766 module_name = Runtime::internStrFromAll(
1767 thread, View<byte>(reinterpret_cast<const byte*>(spec->name),
1768 class_name - spec->name));
1769 class_name++;
1770 }
1771 Str type_name(&scope, Runtime::internStrFromCStr(thread, class_name));
1772
1773 // Create a new type for the PyTypeObject with an instance layout
1774 // matching the layout of RawNativeProxy
1775 // TODO(T54277314): Fill the dictionary before creating the type
1776 Tuple bases_obj(&scope, runtime->implicitBases());
1777 if (bases != nullptr) bases_obj = ApiHandle::asObject(ApiHandle::fromPyObject(bases));
1778 Dict dict(&scope, runtime->newDict());
1779 if (!module_name.isNoneType()) {
1780 dictAtPutById(thread, dict, ID(__module__), module_name);
1781 }
1782 dictAtPutById(thread, dict, ID(__qualname__), type_name);
1783
1784 bool has_default_dealloc = true;
1785 for (PyType_Slot* slot = spec->slots; slot->slot; slot++) {
1786 int slot_id = slot->slot;
1787 if (!isValidSlotId(slot_id)) {
1788 thread->raiseWithFmt(LayoutId::kRuntimeError, "invalid slot offset");
1789 return nullptr;
1790 }
1791 switch (slot_id) {
1792 case Py_tp_dealloc:
1793 case Py_tp_del:
1794 case Py_tp_finalize:
1795 has_default_dealloc = false;
1796 break;
1797 case Py_tp_setattr:
1798 UNIMPLEMENTED("Py_tp_setattr not supported");
1799 }
1800 }
1801
1802 word flags = Type::Flag::kIsCPythonHeaptype;
1803 // We allocate a heap object in the C heap space only when 1) we need to
1804 // execute a custom finalizer with it or 2) the type explicitly uses non-zero
1805 // sizes to store a user-specified structure.
1806 if (!has_default_dealloc ||
1807 static_cast<size_t>(spec->basicsize) > sizeof(PyObject) ||
1808 spec->itemsize > 0) {
1809 flags |= Type::Flag::kHasNativeData;
1810 }
1811 if (spec->flags & Py_TPFLAGS_HAVE_GC) {
1812 flags |= Type::Flag::kHasCycleGC;
1813 }
1814 if (spec->flags & Py_TPFLAGS_BASETYPE) {
1815 flags |= Type::Flag::kIsBasetype;
1816 }
1817
1818 Object fixed_attr_base_obj(&scope,
1819 computeFixedAttributeBase(thread, bases_obj));
1820 if (fixed_attr_base_obj.isErrorException()) return nullptr;
1821 Type fixed_attr_base(&scope, *fixed_attr_base_obj);
1822
1823 word base_size = typeGetBasicSize(fixed_attr_base);
1824 if (spec->basicsize > base_size) {
1825 flags |= Type::Flag::kIsFixedAttributeBase;
1826 }
1827
1828 PyMemberDef* members = nullptr;
1829 word dictoffset = 0;
1830 for (PyType_Slot* slot = spec->slots; slot->slot != 0; slot++) {
1831 if (slot->slot != Py_tp_members) continue;
1832 members = static_cast<PyMemberDef*>(slot->pfunc);
1833 for (PyMemberDef* member = members; member->name != nullptr; member++) {
1834 const char* name = member->name;
1835 if (std::strcmp(name, "__weaklistoffset__") == 0) {
1836 DCHECK(member->type == T_PYSSIZET, "must be T_PYSSIZET");
1837 DCHECK(member->flags == READONLY, "must be readonly");
1838 // weaklistoffset not used yet.
1839 } else if (std::strcmp(name, "__dictoffset__") == 0) {
1840 DCHECK(member->type == T_PYSSIZET, "must be T_PYSSIZET");
1841 DCHECK(member->flags == READONLY, "must be readonly");
1842 dictoffset = member->offset;
1843 }
1844 }
1845 }
1846
1847 bool add_instance_dict = (dictoffset != 0);
1848 Type metaclass(&scope, runtime->typeAt(LayoutId::kType));
1849 Object type_obj(&scope, typeNew(thread, metaclass, type_name, bases_obj, dict,
1850 static_cast<Type::Flag>(flags),
1851 /*inherit_slots=*/false,
1852 /*add_instance_dict=*/add_instance_dict));
1853 if (type_obj.isError()) return nullptr;
1854 Type type(&scope, *type_obj);
1855
1856 // Initialize the extension slots tuple
1857 typeSlotsAllocate(thread, type);
1858
1859 typeSlotObjectAtPut(type, Py_tp_bases, *bases_obj);
1860 typeSlotObjectAtPut(type, Py_tp_base, *fixed_attr_base);
1861 unsigned long extension_flags =
1862 spec->flags | Py_TPFLAGS_READY | Py_TPFLAGS_HEAPTYPE;
1863 typeSlotUWordAtPut(thread, type, kSlotFlags, extension_flags);
1864 typeSlotUWordAtPut(thread, type, kSlotBasicSize, spec->basicsize);
1865 typeSlotUWordAtPut(thread, type, kSlotItemSize, spec->itemsize);
1866
1867 // Set the type slots
1868 for (PyType_Slot* slot = spec->slots; slot->slot; slot++) {
1869 typeSlotAtPut(thread, type, slot->slot, slot->pfunc);
1870 }
1871 if (has_default_dealloc) {
1872 type.setFlags(
1873 static_cast<Type::Flag>(type.flags() | Type::Flag::kHasDefaultDealloc));
1874 }
1875
1876 // If no custom tp_dealloc is defined set subtypeDealloc
1877 if (typeSlotAt(type, Py_tp_dealloc) == nullptr) {
1878 typeSlotAtPut(thread, type, Py_tp_dealloc,
1879 reinterpret_cast<void*>(&subtypeDealloc));
1880 }
1881
1882 if (addOperators(thread, type).isError()) return nullptr;
1883
1884 if (addMethods(thread, type).isError()) return nullptr;
1885
1886 if (addMembers(thread, type, members).isErrorException()) return nullptr;
1887
1888 if (addGetSet(thread, type).isError()) return nullptr;
1889
1890 if (typeInheritSlots(thread, type, fixed_attr_base).isError()) return nullptr;
1891
1892 return ApiHandle::newReferenceWithManaged(runtime, *type);
1893}
1894
1895PY_EXPORT PyObject* PyType_GenericAlloc(PyTypeObject* type_obj,
1896 Py_ssize_t nitems) {
1897 Thread* thread = Thread::current();
1898 HandleScope scope(thread);
1899 Type type(&scope,
1900 ApiHandle::asObjectNoImmediate(ApiHandle::fromPyTypeObject(type_obj)));
1901 DCHECK(!type.isBuiltin(),
1902 "Type is unmanaged. Please initialize using PyType_FromSpec");
1903 DCHECK(typeHasSlots(type),
1904 "GenericAlloc from types initialized through Python code");
1905
1906 if (!type.hasNativeData()) {
1907 // Since the type will be pointed to by the layout as long as there are any
1908 // objects of its type, we don't need to INCREF the type object if it
1909 // doesn't have NativeData.
1910 Layout layout(&scope, type.instanceLayout());
1911 Runtime* runtime = thread->runtime();
1912 return ApiHandle::newReference(runtime, runtime->newInstance(layout));
1913 }
1914 PyObject* result = allocatePyObject(type, nitems);
1915 if (result == nullptr) {
1916 thread->raiseMemoryError();
1917 return nullptr;
1918 }
1919
1920 // Initialize the newly-allocated instance
1921 if (typeSlotUWordAt(type, kSlotItemSize) == 0) {
1922 PyObject_Init(result, type_obj);
1923 } else {
1924 PyObject_InitVar(reinterpret_cast<PyVarObject*>(result), type_obj, nitems);
1925 }
1926
1927 return result;
1928}
1929
1930PY_EXPORT Py_ssize_t _PyObject_SIZE_Func(PyObject* obj) {
1931 HandleScope scope(Thread::current());
1932 Type type(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
1933 return typeSlotUWordAt(type, kSlotBasicSize);
1934}
1935
1936PY_EXPORT Py_ssize_t _PyObject_VAR_SIZE_Func(PyObject* obj, Py_ssize_t nitems) {
1937 HandleScope scope(Thread::current());
1938 Type type(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
1939 uword basic_size = typeSlotUWordAt(type, kSlotBasicSize);
1940 uword item_size = typeSlotUWordAt(type, kSlotItemSize);
1941 return Utils::roundUp(nitems * item_size + basic_size, kWordSize);
1942}
1943
1944PY_EXPORT unsigned int PyType_ClearCache() {
1945 UNIMPLEMENTED("PyType_ClearCache");
1946}
1947
1948PY_EXPORT PyObject* PyType_GenericNew(PyTypeObject* type, PyObject*,
1949 PyObject*) {
1950 auto alloc_func =
1951 reinterpret_cast<allocfunc>(PyType_GetSlot(type, Py_tp_alloc));
1952 return alloc_func(type, 0);
1953}
1954
1955PY_EXPORT int PyObject_TypeCheck_Func(PyObject* obj, PyTypeObject* type) {
1956 PyTypeObject* obj_type = reinterpret_cast<PyTypeObject*>(PyObject_Type(obj));
1957 int res = PyType_IsSubtype(obj_type, type);
1958 Py_DECREF(obj_type);
1959 return res;
1960}
1961
1962PY_EXPORT int PyType_IsSubtype(PyTypeObject* a, PyTypeObject* b) {
1963 return a == b || typeIsSubclass(ApiHandle::asObject(ApiHandle::fromPyTypeObject(a)),
1964 ApiHandle::asObject(ApiHandle::fromPyTypeObject(b)))
1965 ? 1
1966 : 0;
1967}
1968
1969PY_EXPORT void PyType_Modified(PyTypeObject* /* e */) {
1970 // We invalidate caches incrementally, so do nothing.
1971}
1972
1973PY_EXPORT PyTypeObject* PyType_Type_Ptr() {
1974 Runtime* runtime = Thread::current()->runtime();
1975 return reinterpret_cast<PyTypeObject*>(
1976 ApiHandle::borrowedReference(runtime, runtime->typeAt(LayoutId::kType)));
1977}
1978
1979PY_EXPORT PyObject* _PyObject_LookupSpecial(PyObject* /* f */,
1980 _Py_Identifier* /* d */) {
1981 UNIMPLEMENTED("_Py_Identifiers are not supported");
1982}
1983
1984PY_EXPORT const char* _PyType_Name(PyTypeObject* type) {
1985 Thread* thread = Thread::current();
1986 if (type == nullptr) {
1987 thread->raiseBadInternalCall();
1988 return nullptr;
1989 }
1990 HandleScope scope(thread);
1991 Runtime* runtime = thread->runtime();
1992 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyTypeObject(type)));
1993 if (!runtime->isInstanceOfType(*obj)) {
1994 thread->raiseBadInternalCall();
1995 return nullptr;
1996 }
1997 Type type_obj(&scope, *obj);
1998 return PyUnicode_AsUTF8(
1999 ApiHandle::borrowedReference(runtime, type_obj.name()));
2000}
2001
2002PY_EXPORT PyObject* _PyType_Lookup(PyTypeObject* type, PyObject* name) {
2003 Thread* thread = Thread::current();
2004 HandleScope scope(thread);
2005 Type type_obj(
2006 &scope,
2007 ApiHandle::asObject(ApiHandle::fromPyObject(reinterpret_cast<PyObject*>(type))));
2008 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(name)));
2009 name_obj = attributeNameNoException(thread, name_obj);
2010 if (name_obj.isErrorError()) return nullptr;
2011 Object res(&scope, typeLookupInMro(thread, *type_obj, *name_obj));
2012 if (res.isErrorNotFound()) {
2013 return nullptr;
2014 }
2015 return ApiHandle::borrowedReference(thread->runtime(), *res);
2016}
2017
2018uword typeGetBasicSize(const Type& type) {
2019 if (typeHasSlots(type)) {
2020 return typeSlotUWordAt(type, kSlotBasicSize);
2021 }
2022 DCHECK(!type.hasNativeData(), "Types with native data should have slots");
2023 // Return just the size needed for a pure `PyObject`/`PyObject_HEAD`.
2024 return sizeof(PyObject);
2025}
2026
2027uword typeGetFlags(const Type& type) {
2028 if (typeHasSlots(type)) {
2029 return typeSlotUWordAt(type, kSlotFlags);
2030 }
2031 uword result = Py_TPFLAGS_READY | Py_TPFLAGS_DEFAULT;
2032 Type::Flag internal_flags = type.flags();
2033 if (internal_flags & Type::Flag::kHasCycleGC) {
2034 result |= Py_TPFLAGS_HAVE_GC;
2035 }
2036 if (internal_flags & Type::Flag::kIsAbstract) {
2037 result |= Py_TPFLAGS_IS_ABSTRACT;
2038 }
2039 if (internal_flags & Type::Flag::kIsCPythonHeaptype) {
2040 result |= Py_TPFLAGS_HEAPTYPE;
2041 }
2042 if (internal_flags & Type::Flag::kIsBasetype) {
2043 result |= Py_TPFLAGS_BASETYPE;
2044 }
2045 switch (type.builtinBase()) {
2046 case LayoutId::kInt:
2047 result |= Py_TPFLAGS_LONG_SUBCLASS;
2048 break;
2049 case LayoutId::kList:
2050 result |= Py_TPFLAGS_LIST_SUBCLASS;
2051 break;
2052 case LayoutId::kTuple:
2053 result |= Py_TPFLAGS_TUPLE_SUBCLASS;
2054 break;
2055 case LayoutId::kBytes:
2056 result |= Py_TPFLAGS_BYTES_SUBCLASS;
2057 break;
2058 case LayoutId::kStr:
2059 result |= Py_TPFLAGS_UNICODE_SUBCLASS;
2060 break;
2061 case LayoutId::kDict:
2062 result |= Py_TPFLAGS_DICT_SUBCLASS;
2063 break;
2064 // BaseException is handled separately down below
2065 case LayoutId::kType:
2066 result |= Py_TPFLAGS_TYPE_SUBCLASS;
2067 break;
2068 default:
2069 if (type.isBaseExceptionSubclass()) {
2070 result |= Py_TPFLAGS_BASE_EXC_SUBCLASS;
2071 }
2072 break;
2073 }
2074 return result;
2075}
2076
2077} // namespace py