this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2// object.c implementation
3
4#include "cpython-data.h"
5#include "cpython-func.h"
6
7#include "api-handle.h"
8#include "attributedict.h"
9#include "builtins-module.h"
10#include "bytes-builtins.h"
11#include "capi-typeslots.h"
12#include "capi.h"
13#include "dict-builtins.h"
14#include "extension-object.h"
15#include "frame.h"
16#include "list-builtins.h"
17#include "module-builtins.h"
18#include "object-builtins.h"
19#include "object-utils.h"
20#include "runtime.h"
21#include "str-builtins.h"
22#include "type-builtins.h"
23
24namespace py {
25
26PY_EXPORT PyTypeObject* PyBaseObject_Type_Ptr() {
27 Runtime* runtime = Thread::current()->runtime();
28 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference(
29 runtime, runtime->typeAt(LayoutId::kObject)));
30}
31
32PY_EXPORT PyObject* PyEllipsis_Ptr() {
33 Runtime* runtime = Thread::current()->runtime();
34 return ApiHandle::borrowedReference(runtime, runtime->ellipsis());
35}
36
37PY_EXPORT PyTypeObject* PyEllipsis_Type_Ptr() {
38 Runtime* runtime = Thread::current()->runtime();
39 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference(
40 runtime, runtime->typeAt(LayoutId::kEllipsis)));
41}
42
43PY_EXPORT PyTypeObject* PyEnum_Type_Ptr() {
44 Runtime* runtime = Thread::current()->runtime();
45 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference(
46 runtime, runtime->typeAt(LayoutId::kEnumerate)));
47}
48
49PY_EXPORT PyObject* PyNone_Ptr() {
50 return ApiHandle::handleFromImmediate(NoneType::object());
51}
52
53PY_EXPORT PyObject* PyNotImplemented_Ptr() {
54 return ApiHandle::handleFromImmediate(NotImplementedType::object());
55}
56
57PY_EXPORT void _Py_Dealloc(PyObject* pyobj) {
58 Thread* thread = Thread::current();
59 Runtime* runtime = thread->runtime();
60 HandleScope scope(thread);
61 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyobj)));
62 if (!runtime->isInstanceOfNativeProxy(*obj)) return;
63 Type obj_type(&scope, runtime->typeOf(*obj));
64 // Do nothing for builtin types since we have our own GC to deallocate objects
65 if (typeHasSlots(obj_type)) {
66 destructor dealloc =
67 reinterpret_cast<destructor>(typeSlotAt(obj_type, Py_tp_dealloc));
68 (dealloc)(pyobj);
69 }
70}
71
72PY_EXPORT void _Py_NewReference(PyObject*) {
73 UNIMPLEMENTED("_Py_NewReference");
74}
75
76PY_EXPORT void Py_INCREF_Func(PyObject* obj) {
77 ApiHandle* handle = ApiHandle::fromPyObject(obj);
78 ApiHandle::incref(handle);
79}
80
81PY_EXPORT Py_ssize_t Py_REFCNT_Func(PyObject* obj) {
82 ApiHandle* handle = ApiHandle::fromPyObject(obj);
83 return ApiHandle::refcnt(handle);
84}
85
86PY_EXPORT void Py_SET_REFCNT_Func(PyObject* obj, Py_ssize_t refcnt) {
87 ApiHandle* handle = ApiHandle::fromPyObject(obj);
88 ApiHandle::setRefcnt(handle, refcnt);
89}
90
91PY_EXPORT void Py_DECREF_Func(PyObject* obj) {
92 ApiHandle* handle = ApiHandle::fromPyObject(obj);
93 if (ApiHandle::isImmediate(handle)) return;
94 ApiHandle::decrefNoImmediate(handle);
95 DCHECK(ApiHandle::refcnt(handle) > 0 ||
96 !Thread::current()->runtime()->isInstanceOfNativeProxy(
97 ApiHandle::asObjectNoImmediate(ApiHandle::fromPyObject(obj))),
98 "native proxies should not reach refcount 0 without GC");
99}
100
101PY_EXPORT Py_ssize_t* Py_SIZE_Func(PyVarObject* obj) {
102 // Cannot call this on builtin types like `int`.
103 DCHECK(Thread::current()->runtime()->isInstanceOfNativeProxy(
104 ApiHandle::asObject(ApiHandle::fromPyObject(reinterpret_cast<PyObject*>(obj)))
105),
106 "must only be called on extension object");
107 return &(obj->ob_size);
108}
109
110PY_EXPORT int PyCallable_Check(PyObject* obj) {
111 if (obj == nullptr) return 0;
112 Thread* thread = Thread::current();
113 HandleScope scope(thread);
114 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
115 return thread->runtime()->isCallable(thread, object);
116}
117
118PY_EXPORT PyObject* PyObject_ASCII(PyObject* pyobj) {
119 Thread* thread = Thread::current();
120 Runtime* runtime = thread->runtime();
121 if (pyobj == nullptr) {
122 return ApiHandle::newReference(runtime, SmallStr::fromCStr("<NULL>"));
123 }
124 HandleScope scope(thread);
125 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyobj)));
126 Object result(&scope, thread->invokeFunction1(ID(builtins), ID(ascii), obj));
127 if (result.isError()) {
128 return nullptr;
129 }
130 return ApiHandle::newReference(runtime, *result);
131}
132
133PY_EXPORT PyObject* PyObject_Bytes(PyObject* pyobj) {
134 Thread* thread = Thread::current();
135 HandleScope scope(thread);
136 Runtime* runtime = thread->runtime();
137 if (pyobj == nullptr) {
138 static const byte value[] = "<NULL>";
139 return ApiHandle::newReference(runtime, SmallBytes::fromBytes(value));
140 }
141
142 ApiHandle* handle = ApiHandle::fromPyObject(pyobj);
143 Object obj(&scope, ApiHandle::asObject(handle));
144 if (obj.isBytes()) {
145 ApiHandle::incref(handle);
146 return pyobj;
147 }
148
149 Object result(&scope, thread->invokeMethod1(obj, ID(__bytes__)));
150 if (result.isError()) {
151 if (result.isErrorException()) return nullptr;
152 // Attribute lookup failed
153 result = thread->invokeFunction1(ID(builtins), ID(_bytes_new), obj);
154 if (result.isErrorException()) return nullptr;
155 DCHECK(!result.isError(), "Couldn't call builtins._bytes_new");
156 } else if (!runtime->isInstanceOfBytes(*result)) {
157 thread->raiseWithFmt(LayoutId::kTypeError,
158 "__bytes__ returned non-bytes (type %T)", &result);
159 return nullptr;
160 }
161 return ApiHandle::newReference(runtime, *result);
162}
163
164PY_EXPORT void PyObject_CallFinalizer(PyObject* self) {
165 PyTypeObject* type = Py_TYPE(self);
166 auto finalizer =
167 reinterpret_cast<destructor>(PyType_GetSlot(type, Py_tp_finalize));
168 if (finalizer == nullptr) {
169 // Nothing to finalize.
170 return;
171 }
172 bool is_gc = (PyType_GetFlags(type) & Py_TPFLAGS_HAVE_GC) != 0;
173 if (is_gc) {
174 // TODO(T55208267): Support GC types
175 UNIMPLEMENTED(
176 "PyObject_CallFinalizer with finalizer and gc type is not "
177 "yet supported");
178 }
179 // TODO(T55208267): Check if the type has GC flags and the object is already
180 // finalized and return early. tp_finalize should only be called once.
181 (*finalizer)(self);
182 // TODO(T55208267): Check if the type has GC flags set a bit on the object to
183 // indicate that it has been finalized already.
184}
185
186PY_EXPORT int PyObject_CallFinalizerFromDealloc(PyObject* self) {
187 DCHECK(self != nullptr, "self cannot be null");
188 if (Py_REFCNT(self) != 0) {
189 Py_FatalError(
190 "PyObject_CallFinalizerFromDealloc called on "
191 "object with a non-zero refcount");
192 }
193 // Temporarily resurrect the object.
194 self->ob_refcnt = 1;
195 // Finalize the object.
196 PyObject_CallFinalizer(self);
197 if (self->ob_refcnt == 1) {
198 // tp_finalize did not resurrect the object, so undo the temporary
199 // resurrection and put it to rest.
200 self->ob_refcnt--;
201 return 0;
202 }
203 DCHECK(Py_REFCNT(self) > 0, "refcnt must be positive");
204 // If we get here, tp_finalize resurrected the object.
205 return -1;
206}
207
208PY_EXPORT int PyObject_DelAttr(PyObject* obj, PyObject* attr_name) {
209 Thread* thread = Thread::current();
210 HandleScope scope(thread);
211 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
212 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(attr_name)));
213 Object result(&scope, delAttribute(thread, object, name_obj));
214 return result.isErrorException() ? -1 : 0;
215}
216
217PY_EXPORT int PyObject_DelAttrString(PyObject* obj, const char* attr_name) {
218 PyObject* str = PyUnicode_FromString(attr_name);
219 if (str == nullptr) return -1;
220 int result = PyObject_DelAttr(obj, str);
221 Py_DECREF(str);
222 return result;
223}
224
225PY_EXPORT PyObject* PyObject_Dir(PyObject* obj) {
226 Thread* thread = Thread::current();
227 Frame* frame = thread->currentFrame();
228 if (obj == nullptr && frame->isSentinel()) {
229 return nullptr;
230 }
231 HandleScope scope(thread);
232 Runtime* runtime = thread->runtime();
233 if (obj == nullptr) {
234 Object locals(&scope, frameLocals(thread, frame));
235 Object list_obj(&scope, NoneType::object());
236 if (locals.isDict()) {
237 Dict locals_dict(&scope, *locals);
238 list_obj = dictKeys(thread, locals_dict);
239 } else if (locals.isModuleProxy()) {
240 ModuleProxy module_proxy(&scope, *locals);
241 Module module(&scope, module_proxy.module());
242 list_obj = moduleKeys(thread, module);
243 } else {
244 return nullptr;
245 }
246 List list(&scope, *list_obj);
247 listSort(thread, list);
248 return ApiHandle::newReference(runtime, *list);
249 }
250
251 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
252 Type type(&scope, runtime->typeOf(*object));
253 Object func(&scope, typeLookupInMroById(thread, *type, ID(__dir__)));
254 if (func.isError() || !func.isFunction()) {
255 return nullptr;
256 }
257 Object sequence(&scope, Interpreter::call1(thread, func, object));
258 if (sequence.isError()) {
259 return nullptr;
260 }
261 if (sequence.isList()) {
262 List list(&scope, *sequence);
263 listSort(thread, list);
264 return ApiHandle::newReference(runtime, *list);
265 }
266 List list(&scope, runtime->newList());
267 Object result(&scope, thread->invokeMethodStatic2(LayoutId::kList, ID(extend),
268 list, sequence));
269 if (result.isError()) {
270 return nullptr;
271 }
272 listSort(thread, list);
273 return ApiHandle::newReference(runtime, *list);
274}
275
276PY_EXPORT PyObject* PyObject_GenericGetAttr(PyObject* obj, PyObject* name) {
277 Thread* thread = Thread::current();
278 HandleScope scope(thread);
279 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
280 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(name)));
281 name_obj = attributeName(thread, name_obj);
282 if (name_obj.isErrorException()) return nullptr;
283 Object result(&scope, objectGetAttribute(thread, object, name_obj));
284 if (result.isError()) {
285 if (result.isErrorNotFound()) {
286 objectRaiseAttributeError(thread, object, name_obj);
287 }
288 return nullptr;
289 }
290 return ApiHandle::newReference(thread->runtime(), *result);
291}
292
293PY_EXPORT int _PyObject_LookupAttr(PyObject* obj, PyObject* name,
294 PyObject** result) {
295 // Replacements of PyObject_GetAttr() and _PyObject_GetAttrId() which don't
296 // raise AttributeError.
297 // Return 1 and set *result != NULL if an attribute is found.
298 // Return 0 and set *result == NULL if an attribute is not found; an
299 // AttributeError is silenced.
300 // Return -1 and set *result == NULL if an error other than AttributeError is
301 // raised.
302 Thread* thread = Thread::current();
303 HandleScope scope(thread);
304 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
305 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(name)));
306 Object name_str(&scope, attributeName(thread, name_obj));
307 if (name_str.isErrorException()) {
308 // name was not a str instance
309 *result = nullptr;
310 return -1;
311 }
312 Runtime* runtime = thread->runtime();
313 Object result_obj(&scope, runtime->attributeAt(thread, object, name_obj));
314 if (!result_obj.isError()) {
315 *result = ApiHandle::newReference(runtime, *result_obj);
316 return 1;
317 }
318 DCHECK(result_obj.isErrorException(), "result should only be an exception");
319 if (thread->pendingExceptionMatches(LayoutId::kAttributeError)) {
320 *result = nullptr;
321 thread->clearPendingException();
322 return 0;
323 }
324 *result = nullptr;
325 return -1;
326}
327
328PY_EXPORT int PyObject_GenericSetAttr(PyObject* obj, PyObject* name,
329 PyObject* value) {
330 Thread* thread = Thread::current();
331 HandleScope scope(thread);
332 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
333 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(name)));
334 name_obj = attributeName(thread, name_obj);
335 if (name_obj.isErrorException()) return -1;
336 Object value_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(value)));
337 Object result(&scope, objectSetAttr(thread, object, name_obj, value_obj));
338 if (result.isErrorException()) {
339 return -1;
340 }
341 return 0;
342}
343
344PY_EXPORT int PyObject_GenericSetDict(PyObject* /* j */, PyObject* /* e */,
345 void* /* t */) {
346 UNIMPLEMENTED("PyObject_GenericSetDict");
347}
348
349PY_EXPORT PyObject* PyObject_GetAttr(PyObject* obj, PyObject* name) {
350 Thread* thread = Thread::current();
351 HandleScope scope(thread);
352 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
353 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(name)));
354 Object result(&scope, getAttribute(thread, object, name_obj));
355 return result.isError() ? nullptr
356 : ApiHandle::newReference(thread->runtime(), *result);
357}
358
359PY_EXPORT PyObject* PyObject_GetAttrString(PyObject* pyobj, const char* name) {
360 DCHECK(pyobj != nullptr, "pyobj must not be nullptr");
361 DCHECK(name != nullptr, "name must not be nullptr");
362 Thread* thread = Thread::current();
363 HandleScope scope(thread);
364 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyobj)));
365 Runtime* runtime = thread->runtime();
366 Object result(&scope, runtime->attributeAtByCStr(thread, object, name));
367 if (result.isError()) return nullptr;
368 return ApiHandle::newReference(runtime, *result);
369}
370
371PY_EXPORT int PyObject_HasAttr(PyObject* pyobj, PyObject* pyname) {
372 Thread* thread = Thread::current();
373 HandleScope scope(thread);
374 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyobj)));
375 Object name(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyname)));
376 Object result(&scope, hasAttribute(thread, obj, name));
377 if (result.isBool()) return Bool::cast(*result).value();
378 thread->clearPendingException();
379 return false;
380}
381
382PY_EXPORT int PyObject_HasAttrString(PyObject* pyobj, const char* name) {
383 Thread* thread = Thread::current();
384 HandleScope scope(thread);
385 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyobj)));
386 Object name_str(&scope, Runtime::internStrFromCStr(thread, name));
387 Object result(&scope, thread->runtime()->attributeAt(thread, obj, name_str));
388 if (!result.isErrorException()) return true;
389 thread->clearPendingException();
390 return false;
391}
392
393PY_EXPORT Py_hash_t PyObject_Hash(PyObject* obj) {
394 DCHECK(obj != nullptr, "obj should not be nullptr");
395 Thread* thread = Thread::current();
396 HandleScope scope(thread);
397 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
398 Object result(&scope, Interpreter::hash(thread, object));
399 if (result.isErrorException()) return -1;
400 return SmallInt::cast(*result).value();
401}
402
403PY_EXPORT Py_hash_t PyObject_HashNotImplemented(PyObject* /* v */) {
404 Thread* thread = Thread::current();
405 thread->raiseWithFmt(LayoutId::kTypeError, "unhashable type");
406 return -1;
407}
408
409PY_EXPORT PyObject* PyObject_Init(PyObject* obj, PyTypeObject* typeobj) {
410 if (obj == nullptr) return PyErr_NoMemory();
411
412 // Create a managed proxy for the native instance
413 Thread* thread = Thread::current();
414 Runtime* runtime = thread->runtime();
415 HandleScope scope(thread);
416 Type type_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyTypeObject(typeobj)));
417 Layout layout(&scope, type_obj.instanceLayout());
418 Object instance(&scope, runtime->newInstance(layout));
419 return initializeExtensionObject(thread, obj, typeobj, instance);
420}
421
422PY_EXPORT PyVarObject* PyObject_InitVar(PyVarObject* obj, PyTypeObject* type,
423 Py_ssize_t size) {
424 if (obj == nullptr) return reinterpret_cast<PyVarObject*>(PyErr_NoMemory());
425 obj->ob_size = size;
426 PyObject_Init(reinterpret_cast<PyObject*>(obj), type);
427 return obj;
428}
429
430PY_EXPORT int PyObject_IsTrue(PyObject* obj) {
431 DCHECK(obj != nullptr, "nullptr passed into PyObject_IsTrue");
432 Thread* thread = Thread::current();
433 HandleScope scope(thread);
434 Object obj_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
435 Object result(&scope, Interpreter::isTrue(thread, *obj_obj));
436 if (result.isError()) {
437 return -1;
438 }
439 return Bool::cast(*result).value();
440}
441
442PY_EXPORT int PyObject_Not(PyObject* obj) {
443 int res = PyObject_IsTrue(obj);
444 if (res < 0) {
445 return res;
446 }
447 return res == 0;
448}
449
450PY_EXPORT int PyObject_Print(PyObject* obj, FILE* fp, int flags) {
451 if (PyErr_CheckSignals()) return -1;
452 std::clearerr(fp); // Clear any previous error condition
453 if (obj == nullptr) {
454 std::fprintf(fp, "<nil>");
455 } else {
456 PyObject* str =
457 flags & Py_PRINT_RAW ? PyObject_Str(obj) : PyObject_Repr(obj);
458 if (str == nullptr) return -1;
459 if (!PyUnicode_Check(str)) {
460 Thread::current()->raiseWithFmt(LayoutId::kTypeError,
461 "str() or repr() returned '%s'",
462 _PyType_Name(Py_TYPE(str)));
463 Py_DECREF(str);
464 return -1;
465 }
466 PyObject* bytes =
467 PyUnicode_AsEncodedString(str, "utf-8", "backslashreplace");
468 Py_DECREF(str);
469 if (bytes == nullptr) {
470 return -1;
471 }
472 char* c_str = PyBytes_AsString(bytes);
473 std::fputs(c_str, fp);
474 Py_DECREF(bytes);
475 }
476 if (std::ferror(fp)) {
477 PyErr_SetFromErrno(PyExc_IOError);
478 std::clearerr(fp);
479 return -1;
480 }
481 return 0;
482}
483
484// TODO(T38571506): Handle recursive objects safely.
485PY_EXPORT PyObject* PyObject_Repr(PyObject* obj) {
486 Thread* thread = Thread::current();
487 Runtime* runtime = thread->runtime();
488 if (obj == nullptr) {
489 return ApiHandle::newReference(runtime, SmallStr::fromCStr("<NULL>"));
490 }
491 HandleScope scope(thread);
492 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
493 Object result(&scope, thread->invokeMethod1(object, ID(__repr__)));
494 if (result.isError()) {
495 return nullptr;
496 }
497 if (!runtime->isInstanceOfStr(*result)) {
498 thread->raiseWithFmt(LayoutId::kTypeError,
499 "__repr__ returned non-str instance");
500 return nullptr;
501 }
502 return ApiHandle::newReference(runtime, *result);
503}
504
505PY_EXPORT PyObject* PyObject_RichCompare(PyObject* v, PyObject* w, int op) {
506 DCHECK(CompareOp::LT <= op && op <= CompareOp::GE, "Bad op");
507 Thread* thread = Thread::current();
508 if (v == nullptr || w == nullptr) {
509 if (!thread->hasPendingException()) {
510 thread->raiseBadInternalCall();
511 }
512 return nullptr;
513 }
514 // TODO(emacs): Recursive call check
515 HandleScope scope(thread);
516 Object left(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(v)));
517 Object right(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(w)));
518 Object result(&scope, Interpreter::compareOperation(
519 thread, static_cast<CompareOp>(op), left, right));
520 if (result.isError()) {
521 return nullptr;
522 }
523 return ApiHandle::newReference(thread->runtime(), *result);
524}
525
526PY_EXPORT int PyObject_RichCompareBool(PyObject* left, PyObject* right,
527 int op) {
528 // Quick result when objects are the same. Guarantees that identity implies
529 // equality.
530 if (left == right) {
531 if (op == Py_EQ) {
532 return 1;
533 }
534 if (op == Py_NE) {
535 return 0;
536 }
537 }
538 PyObject* res = PyObject_RichCompare(left, right, op);
539 if (res == nullptr) {
540 return -1;
541 }
542 int ok;
543 if (PyBool_Check(res)) {
544 ok = (res == Py_True);
545 } else {
546 ok = PyObject_IsTrue(res);
547 }
548 Py_DECREF(res);
549 return ok;
550}
551
552PY_EXPORT PyObject* PyObject_SelfIter(PyObject* obj) {
553 Py_INCREF(obj);
554 return obj;
555}
556
557PY_EXPORT int PyObject_SetAttr(PyObject* obj, PyObject* name, PyObject* value) {
558 if (value == nullptr) {
559 return PyObject_DelAttr(obj, name);
560 }
561 Thread* thread = Thread::current();
562 HandleScope scope(thread);
563 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
564 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(name)));
565 Object value_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(value)));
566 Object result(&scope, setAttribute(thread, object, name_obj, value_obj));
567 return result.isErrorException() ? -1 : 0;
568}
569
570PY_EXPORT int PyObject_SetAttrString(PyObject* v, const char* name,
571 PyObject* w) {
572 PyObject* str = PyUnicode_FromString(name);
573 if (str == nullptr) return -1;
574 int result = PyObject_SetAttr(v, str, w);
575 Py_DECREF(str);
576 return result;
577}
578
579// TODO(T38571506): Handle recursive objects safely.
580PY_EXPORT PyObject* PyObject_Str(PyObject* obj) {
581 Thread* thread = Thread::current();
582 Runtime* runtime = thread->runtime();
583 if (obj == nullptr) {
584 return ApiHandle::newReference(runtime, SmallStr::fromCStr("<NULL>"));
585 }
586 HandleScope scope(thread);
587 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
588 Object result(&scope, thread->invokeMethod1(object, ID(__str__)));
589 if (result.isError()) {
590 return nullptr;
591 }
592 if (!runtime->isInstanceOfStr(*result)) {
593 thread->raiseWithFmt(LayoutId::kTypeError,
594 "__str__ returned non-str instance");
595 return nullptr;
596 }
597 return ApiHandle::newReference(runtime, *result);
598}
599
600PY_EXPORT void Py_DecRef(PyObject* obj) {
601 if (obj == nullptr) return;
602 Py_DECREF_Func(obj);
603}
604
605PY_EXPORT void Py_IncRef(PyObject* obj) {
606 if (obj == nullptr) return;
607 Py_INCREF_Func(obj);
608}
609
610PY_EXPORT int Py_ReprEnter(PyObject* obj) {
611 Thread* thread = Thread::current();
612 HandleScope scope(thread);
613 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
614 Object result(&scope, thread->reprEnter(object));
615 if (result.isError()) {
616 return -1;
617 }
618 return Bool::cast(*result).value();
619}
620
621PY_EXPORT void Py_ReprLeave(PyObject* obj) {
622 Thread* thread = Thread::current();
623 HandleScope scope(thread);
624 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
625 thread->reprLeave(object);
626}
627
628PY_EXPORT PyObject* _PyObject_GetAttrId(PyObject* /* v */,
629 _Py_Identifier* /* e */) {
630 UNIMPLEMENTED("_PyObject_GetAttrId");
631}
632
633PY_EXPORT int _PyObject_HasAttrId(PyObject* /* v */, _Py_Identifier* /* e */) {
634 UNIMPLEMENTED("_PyObject_HasAttrId");
635}
636
637PY_EXPORT PyObject* _PyObject_New(PyTypeObject* type) {
638 Thread* thread = Thread::current();
639 HandleScope scope(thread);
640 Type type_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyTypeObject(type)));
641 if (!type_obj.hasNativeData()) {
642 // Since the type will be pointed to by the layout as long as there are any
643 // objects of its type, we don't need to INCREF the type object if it
644 // doesn't have NativeData.
645 Layout layout(&scope, type_obj.instanceLayout());
646 Runtime* runtime = thread->runtime();
647 return ApiHandle::newReference(runtime, runtime->newInstance(layout));
648 }
649 PyObject* obj = static_cast<PyObject*>(PyObject_MALLOC(_PyObject_SIZE(type)));
650 if (obj == nullptr) return PyErr_NoMemory();
651 return PyObject_INIT(obj, type);
652}
653
654PY_EXPORT PyVarObject* _PyObject_NewVar(PyTypeObject* type, Py_ssize_t nitems) {
655 PyObject* obj =
656 static_cast<PyObject*>(PyObject_MALLOC(_PyObject_VAR_SIZE(type, nitems)));
657 if (obj == nullptr) return reinterpret_cast<PyVarObject*>(PyErr_NoMemory());
658 return PyObject_INIT_VAR(obj, type, nitems);
659}
660
661PY_EXPORT PyTypeObject* _PyNone_Type_Ptr() {
662 Runtime* runtime = Thread::current()->runtime();
663 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference(
664 runtime, runtime->typeAt(LayoutId::kNoneType)));
665}
666
667PY_EXPORT PyTypeObject* _PyNotImplemented_Type_Ptr() {
668 Runtime* runtime = Thread::current()->runtime();
669 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference(
670 runtime, runtime->typeAt(LayoutId::kNotImplementedType)));
671}
672
673PY_EXPORT int _PyObject_SetAttrId(PyObject* /* v */, _Py_Identifier* /* e */,
674 PyObject* /* w */) {
675 UNIMPLEMENTED("_PyObject_SetAttrId");
676}
677
678PY_EXPORT void _PyTrash_deposit_object(PyObject* /* p */) {
679 UNIMPLEMENTED("_PyTrash_deposit_object");
680}
681
682PY_EXPORT void _PyTrash_destroy_chain() {
683 UNIMPLEMENTED("_PyTrash_destroy_chain");
684}
685
686PY_EXPORT void _PyTrash_thread_deposit_object(PyObject* /* p */) {
687 UNIMPLEMENTED("_PyTrash_thread_deposit_object");
688}
689
690PY_EXPORT void _PyTrash_thread_destroy_chain() {
691 UNIMPLEMENTED("_PyTrash_thread_destroy_chain");
692}
693
694} // namespace py