this repo has no description
at trunk 656 lines 26 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "object-builtins.h" 3 4#include <cinttypes> 5 6#include "attributedict.h" 7#include "builtins.h" 8#include "descriptor-builtins.h" 9#include "dict-builtins.h" 10#include "frame.h" 11#include "globals.h" 12#include "ic.h" 13#include "module-builtins.h" 14#include "objects.h" 15#include "runtime.h" 16#include "thread.h" 17#include "type-builtins.h" 18 19namespace py { 20 21RawObject objectRaiseAttributeError(Thread* thread, const Object& object, 22 const Object& name) { 23 return thread->raiseWithFmt(LayoutId::kAttributeError, 24 "'%T' object has no attribute '%S'", &object, 25 &name); 26} 27 28RawObject objectDeleteAttribute(Thread* thread, const Object& object, 29 const Object& name) { 30 HandleScope scope(thread); 31 Runtime* runtime = thread->runtime(); 32 33 // Check for a descriptor with __delete__ 34 Type type(&scope, runtime->typeOf(*object)); 35 Object type_attr(&scope, typeLookupInMro(thread, *type, *name)); 36 if (!type_attr.isError() && runtime->isDeleteDescriptor(thread, type_attr)) { 37 return Interpreter::callDescriptorDelete(thread, type_attr, object); 38 } 39 40 // No delete descriptor found, delete from the instance 41 if (object.isInstance()) { 42 Instance instance(&scope, *object); 43 Object result(&scope, instanceDelAttr(thread, instance, name)); 44 if (!result.isErrorNotFound()) return *result; 45 } 46 return thread->raiseWithFmt(LayoutId::kAttributeError, 47 "'%T' object has no attribute '%S'", &object, 48 &name); 49} 50 51RawObject instanceDelAttr(Thread* thread, const Instance& instance, 52 const Object& name) { 53 HandleScope scope(thread); 54 55 // Remove the reference to the attribute value from the instance 56 Runtime* runtime = thread->runtime(); 57 Layout layout(&scope, runtime->layoutOf(*instance)); 58 AttributeInfo info; 59 if (!Runtime::layoutFindAttribute(*layout, name, &info)) { 60 if (layout.hasDictOverflow()) { 61 word offset = layout.dictOverflowOffset(); 62 Object overflow_dict_obj(&scope, instance.instanceVariableAt(offset)); 63 if (!overflow_dict_obj.isNoneType()) { 64 Dict overflow_dict(&scope, *overflow_dict_obj); 65 Object result(&scope, dictRemoveByStr(thread, overflow_dict, name)); 66 if (result.isError()) return *result; 67 return NoneType::object(); 68 } 69 } 70 return Error::notFound(); 71 } 72 73 if (info.isHidden()) { 74 return Error::notFound(); 75 } 76 77 if (info.isReadOnly()) { 78 return thread->raiseWithFmt(LayoutId::kAttributeError, 79 "'%S' attribute is read-only", &name); 80 } 81 82 // Make the attribute invisible 83 Layout new_layout(&scope, 84 runtime->layoutDeleteAttribute(thread, layout, name, info)); 85 LayoutId new_layout_id = new_layout.id(); 86 instance.setHeader(instance.header().withLayoutId(new_layout_id)); 87 88 if (info.isInObject()) { 89 instance.instanceVariableAtPut(info.offset(), NoneType::object()); 90 } else { 91 MutableTuple overflow( 92 &scope, instance.instanceVariableAt(new_layout.overflowOffset())); 93 overflow.atPut(info.offset(), NoneType::object()); 94 } 95 96 return NoneType::object(); 97} 98 99RawObject instanceGetAttributeSetLocation(Thread* thread, 100 const Instance& instance, 101 const Object& name, 102 Object* location_out) { 103 HandleScope scope(thread); 104 Runtime* runtime = thread->runtime(); 105 Layout layout(&scope, runtime->layoutOf(*instance)); 106 AttributeInfo info; 107 if (Runtime::layoutFindAttribute(*layout, name, &info)) { 108 if (info.isHidden()) { 109 return Error::notFound(); 110 } 111 if (info.isInObject()) { 112 if (location_out != nullptr) { 113 *location_out = SmallInt::fromWord(info.offset()); 114 } 115 return instance.instanceVariableAt(info.offset()); 116 } 117 word offset = info.offset(); 118 if (location_out != nullptr) { 119 *location_out = SmallInt::fromWord(-offset - 1); 120 } 121 word tuple_offset = layout.overflowOffset(); 122 return Tuple::cast(instance.instanceVariableAt(tuple_offset)).at(offset); 123 } 124 if (layout.hasDictOverflow()) { 125 word offset = layout.dictOverflowOffset(); 126 Object overflow_dict_obj(&scope, instance.instanceVariableAt(offset)); 127 if (!overflow_dict_obj.isNoneType()) { 128 Dict overflow_dict(&scope, *overflow_dict_obj); 129 return dictAtByStr(thread, overflow_dict, name); 130 } 131 } 132 return Error::notFound(); 133} 134 135RawObject instanceGetAttribute(Thread* thread, const Instance& instance, 136 const Object& name) { 137 return instanceGetAttributeSetLocation(thread, instance, name, nullptr); 138} 139 140void instanceGrowOverflow(Thread* thread, const Instance& instance, 141 word length) { 142 HandleScope scope(thread); 143 Layout layout(&scope, thread->runtime()->layoutOf(*instance)); 144 Tuple overflow(&scope, instance.instanceVariableAt(layout.overflowOffset())); 145 DCHECK(overflow.length() < length, "unexpected overflow"); 146 MutableTuple new_overflow(&scope, thread->runtime()->newMutableTuple(length)); 147 new_overflow.replaceFromWith(0, *overflow, overflow.length()); 148 instance.instanceVariableAtPut(layout.overflowOffset(), *new_overflow); 149} 150 151static RawObject instanceSetAttrSetLocation(Thread* thread, 152 const Instance& instance, 153 const Object& name, 154 const Object& value, 155 Object* location_out) { 156 HandleScope scope(thread); 157 158 // If the attribute doesn't exist we'll need to transition the layout 159 Runtime* runtime = thread->runtime(); 160 Layout layout(&scope, runtime->layoutOf(*instance)); 161 AttributeInfo info; 162 if (!Runtime::layoutFindAttribute(*layout, name, &info)) { 163 if (!layout.hasTupleOverflow()) { 164 if (layout.hasDictOverflow()) { 165 word offset = layout.dictOverflowOffset(); 166 Object overflow_dict_obj(&scope, instance.instanceVariableAt(offset)); 167 if (overflow_dict_obj.isNoneType()) { 168 overflow_dict_obj = runtime->newDict(); 169 instance.instanceVariableAtPut(offset, *overflow_dict_obj); 170 } 171 Dict overflow_dict(&scope, *overflow_dict_obj); 172 dictAtPutByStr(thread, overflow_dict, name, value); 173 return NoneType::object(); 174 } 175 if (layout.isSealed()) { 176 return thread->raiseWithFmt( 177 LayoutId::kAttributeError, 178 "Cannot set attribute '%S' on sealed class '%T'", &name, &instance); 179 } 180 } 181 // Transition the layout. 182 183 Layout new_layout( 184 &scope, runtime->layoutAddAttribute(thread, layout, name, 0, &info)); 185 if (info.isOverflow() && 186 info.offset() >= 187 Tuple::cast(instance.instanceVariableAt(layout.overflowOffset())) 188 .length()) { 189 instanceGrowOverflow(thread, instance, info.offset() + 1); 190 } 191 instance.setLayoutId(new_layout.id()); 192 layout = *new_layout; 193 } else if (info.isReadOnly()) { 194 return thread->raiseWithFmt(LayoutId::kAttributeError, 195 "'%T.%S' attribute is read-only", &instance, 196 &name); 197 } else if (info.isHidden()) { 198 return thread->raiseWithFmt(LayoutId::kAttributeError, 199 "'%T.%S' attribute cannot be set", &instance, 200 &name); 201 } 202 DCHECK(!thread->runtime()->isInstanceOfType(*instance), 203 "must not cache type attributes"); 204 // Store the attribute 205 if (info.isInObject()) { 206 instance.instanceVariableAtPut(info.offset(), *value); 207 if (location_out != nullptr) { 208 *location_out = SmallInt::fromWord(info.offset()); 209 } 210 } else { 211 MutableTuple::cast(instance.instanceVariableAt(layout.overflowOffset())) 212 .atPut(info.offset(), *value); 213 if (location_out != nullptr) { 214 *location_out = SmallInt::fromWord(-info.offset() - 1); 215 } 216 } 217 return NoneType::object(); 218} 219 220RawObject instanceSetAttr(Thread* thread, const Instance& instance, 221 const Object& name, const Object& value) { 222 return instanceSetAttrSetLocation(thread, instance, name, value, nullptr); 223} 224 225RawObject objectGetAttributeSetLocation(Thread* thread, const Object& object, 226 const Object& name, 227 Object* location_out, 228 LoadAttrKind* kind) { 229 // Look for the attribute in the class 230 HandleScope scope(thread); 231 Runtime* runtime = thread->runtime(); 232 Type type(&scope, runtime->typeOf(*object)); 233 Object type_attr_location(&scope, NoneType::object()); 234 Object type_attr(&scope, typeLookupInMroSetLocation(thread, *type, *name, 235 &type_attr_location)); 236 if (!type_attr.isError()) { 237 // TODO(T56252621): Remove this once property gets cached. 238 if (type_attr.isProperty()) { 239 Object getter(&scope, Property::cast(*type_attr).getter()); 240 DCHECK(!object.isNoneType(), "object cannot be NoneType"); 241 if (getter.isFunction()) { 242 // We cache only function objects as a getter to simplify its usage. 243 if (location_out != nullptr) { 244 *location_out = *getter; 245 if (type.hasFlag(Type::Flag::kHasObjectDunderClass) && 246 *name == runtime->symbols()->at(ID(__class__))) { 247 *kind = LoadAttrKind::kDunderClass; 248 } else { 249 *kind = LoadAttrKind::kInstanceProperty; 250 } 251 } 252 return Interpreter::call1(thread, getter, object); 253 } 254 } 255 if (type_attr.isSlotDescriptor()) { 256 SlotDescriptor slot_descriptor(&scope, *type_attr); 257 Object owner(&scope, NoneType::object()); 258 Object result(&scope, 259 slotDescriptorGet(thread, slot_descriptor, object, owner)); 260 if (!result.isErrorException() && location_out != nullptr) { 261 // Cache slot_descriptor at success only to avoid type checking 262 // afterwards. However, unbound check should be performed when 263 // cache is hit. 264 *location_out = SmallInt::fromWord(slot_descriptor.offset()); 265 *kind = LoadAttrKind::kInstanceSlotDescr; 266 } 267 return *result; 268 } 269 Type type_attr_type(&scope, runtime->typeOf(*type_attr)); 270 if (typeIsDataDescriptor(*type_attr_type)) { 271 if (location_out != nullptr) { 272 *location_out = *type_attr; 273 *kind = LoadAttrKind::kInstanceTypeDescr; 274 } 275 return Interpreter::callDescriptorGet(thread, type_attr, object, type); 276 } 277 } 278 279 // No data descriptor found on the class, look at the instance. 280 if (object.isInstance()) { 281 Instance instance(&scope, *object); 282 Object result(&scope, instanceGetAttributeSetLocation(thread, instance, 283 name, location_out)); 284 if (!result.isError()) { 285 if (location_out != nullptr) *kind = LoadAttrKind::kInstanceOffset; 286 return *result; 287 } 288 } 289 290 // Nothing found in the instance, if we found a non-data descriptor via the 291 // class search, use it. 292 if (!type_attr.isError()) { 293 if (type_attr.isFunction()) { 294 if (location_out != nullptr) { 295 *location_out = *type_attr; 296 *kind = LoadAttrKind::kInstanceFunction; 297 } 298 return runtime->newBoundMethod(type_attr, object); 299 } 300 301 Type type_attr_type(&scope, thread->runtime()->typeOf(*type_attr)); 302 if (!typeIsNonDataDescriptor(*type_attr_type)) { 303 if (location_out != nullptr) { 304 *location_out = *type_attr; 305 *kind = LoadAttrKind::kInstanceType; 306 } 307 return *type_attr; 308 } 309 if (location_out != nullptr) { 310 *location_out = *type_attr; 311 *kind = LoadAttrKind::kInstanceTypeDescr; 312 } 313 return Interpreter::callDescriptorGet(thread, type_attr, object, type); 314 } 315 return Error::notFound(); 316} 317 318RawObject objectGetAttribute(Thread* thread, const Object& object, 319 const Object& name) { 320 return objectGetAttributeSetLocation(thread, object, name, nullptr, nullptr); 321} 322 323RawObject objectNew(Thread* thread, const Type& type) { 324 HandleScope scope(thread); 325 if (!type.hasFlag(Type::Flag::kIsAbstract)) { 326 Layout layout(&scope, type.instanceLayout()); 327 LayoutId id = layout.id(); 328 Runtime* runtime = thread->runtime(); 329 if (!isInstanceLayout(id)) { 330 Object type_name(&scope, type.name()); 331 return thread->raiseWithFmt( 332 LayoutId::kTypeError, 333 "object.__new__(%S) is not safe. Use %S.__new__()", &type_name, 334 &type_name); 335 } 336 Instance result(&scope, runtime->newInstance(layout)); 337 if (type.hasFlag(Type::Flag::kHasSlots)) { 338 Tuple attributes(&scope, layout.inObjectAttributes()); 339 for (word i = 0, length = attributes.length(); i < length; i++) { 340 AttributeInfo info(Tuple::cast(attributes.at(i)).at(1)); 341 if (info.isInitWithUnbound()) { 342 DCHECK(info.isInObject(), "in-object is expected"); 343 result.instanceVariableAtPut(info.offset(), Unbound::object()); 344 } 345 } 346 } 347 return *result; 348 } 349 // `type` is an abstract class and cannot be instantiated. 350 Object name(&scope, type.name()); 351 Object comma(&scope, SmallStr::fromCStr(", ")); 352 Object methods(&scope, type.abstractMethods()); 353 Object sorted(&scope, 354 thread->invokeFunction1(ID(builtins), ID(sorted), methods)); 355 if (sorted.isError()) return *sorted; 356 Object joined(&scope, thread->invokeMethod2(comma, ID(join), sorted)); 357 if (joined.isError()) return *joined; 358 return thread->raiseWithFmt( 359 LayoutId::kTypeError, 360 "Can't instantiate abstract class %S with abstract methods %S", &name, 361 &joined); 362} 363 364RawObject objectSetAttrSetLocation(Thread* thread, const Object& object, 365 const Object& name, const Object& value, 366 Object* location_out) { 367 Runtime* runtime = thread->runtime(); 368 // Check for a data descriptor 369 HandleScope scope(thread); 370 Type type(&scope, runtime->typeOf(*object)); 371 Object type_attr(&scope, typeLookupInMro(thread, *type, *name)); 372 if (!type_attr.isError()) { 373 if (type_attr.isSlotDescriptor()) { 374 SlotDescriptor slot_descriptor(&scope, *type_attr); 375 Object result(&scope, 376 slotDescriptorSet(thread, slot_descriptor, object, value)); 377 if (!result.isErrorException() && location_out != nullptr) { 378 // Cache slot_descriptor at success only to avoid type checking 379 // afterwards. Note that writes via slot_descriptor are treated equally 380 // as ones to in-object instance attributes since the same cache 381 // invalidation rule applies to them. 382 *location_out = SmallInt::fromWord(slot_descriptor.offset()); 383 } 384 return *result; 385 } 386 Type type_attr_type(&scope, runtime->typeOf(*type_attr)); 387 if (typeIsDataDescriptor(*type_attr_type)) { 388 // Do not cache data descriptors. 389 Object set_result(&scope, Interpreter::callDescriptorSet( 390 thread, type_attr, object, value)); 391 if (set_result.isError()) return *set_result; 392 return NoneType::object(); 393 } 394 } 395 396 // No data descriptor found, store on the instance. 397 if (object.isInstance()) { 398 Instance instance(&scope, *object); 399 return instanceSetAttrSetLocation(thread, instance, name, value, 400 location_out); 401 } 402 return objectRaiseAttributeError(thread, object, name); 403} 404 405RawObject objectSetAttr(Thread* thread, const Object& object, 406 const Object& name, const Object& value) { 407 return objectSetAttrSetLocation(thread, object, name, value, nullptr); 408} 409 410RawObject objectDelItem(Thread* thread, const Object& object, 411 const Object& key) { 412 HandleScope scope(thread); 413 Object result(&scope, thread->invokeMethod2(object, ID(__delitem__), key)); 414 if (result.isErrorNotFound()) { 415 return thread->raiseWithFmt(LayoutId::kTypeError, 416 "'%T' object does not support item deletion", 417 &object); 418 } 419 return *result; 420} 421 422RawObject objectGetItem(Thread* thread, const Object& object, 423 const Object& key) { 424 HandleScope scope(thread); 425 // This logic is replicated in Interpreter::binarySubscrUpdateCache for 426 // optimization. 427 Object result(&scope, thread->invokeMethod2(object, ID(__getitem__), key)); 428 if (result.isErrorNotFound()) { 429 Runtime* runtime = thread->runtime(); 430 if (runtime->isInstanceOfType(*object)) { 431 Type object_as_type(&scope, *object); 432 Str dunder_class_getitem_name( 433 &scope, runtime->symbols()->at(ID(__class_getitem__))); 434 Object class_getitem(&scope, typeGetAttribute(thread, object_as_type, 435 dunder_class_getitem_name)); 436 if (!class_getitem.isErrorNotFound()) { 437 return Interpreter::call1(thread, class_getitem, key); 438 } 439 } 440 return thread->raiseWithFmt(LayoutId::kTypeError, 441 "'%T' object is not subscriptable", &object); 442 } 443 return *result; 444} 445 446RawObject objectSetItem(Thread* thread, const Object& object, const Object& key, 447 const Object& value) { 448 HandleScope scope(thread); 449 // Short-cut for the common case of dict. This also helps during bootstrapping 450 // as it allows us to use `objectSetItem` before `dict.__setitem__` is added. 451 if (object.isDict()) { 452 Dict object_dict(&scope, *object); 453 RawObject hash = Interpreter::hash(thread, key); 454 if (hash.isErrorException()) return hash; 455 dictAtPut(thread, object_dict, key, SmallInt::cast(hash).value(), value); 456 return NoneType::object(); 457 } 458 Object result(&scope, 459 thread->invokeMethod3(object, ID(__setitem__), key, value)); 460 if (result.isErrorNotFound()) { 461 return thread->raiseWithFmt(LayoutId::kTypeError, 462 "'%T' object does not support item assignment", 463 &object); 464 } 465 return *result; 466} 467 468RawObject METH(object, __delattr__)(Thread* thread, Arguments args) { 469 HandleScope scope(thread); 470 Runtime* runtime = thread->runtime(); 471 Object self(&scope, args.get(0)); 472 Object name(&scope, args.get(1)); 473 name = attributeName(thread, name); 474 if (name.isErrorException()) return *name; 475 Object result(&scope, objectDeleteAttribute(thread, self, name)); 476 if (!result.isErrorException()) return *result; 477 if (runtime->isInstanceOfType(*self) || runtime->isInstanceOfModule(*self)) { 478 thread->clearPendingException(); 479 return thread->raiseWithFmt(LayoutId::kTypeError, 480 "can't apply this __delattr__ to type '%T'", 481 &self); 482 } 483 return *result; 484} 485 486bool METH(object, __eq___intrinsic)(Thread* thread) { 487 RawObject result = Bool::trueObj(); 488 if (thread->stackTop() != thread->stackPeek(1)) { 489 result = NotImplementedType::object(); 490 } 491 thread->stackDrop(2); 492 thread->stackSetTop(result); 493 return true; 494} 495 496RawObject METH(object, __getattribute__)(Thread* thread, Arguments args) { 497 HandleScope scope(thread); 498 Object self(&scope, args.get(0)); 499 Object name(&scope, args.get(1)); 500 name = attributeName(thread, name); 501 if (name.isErrorException()) return *name; 502 Object result(&scope, objectGetAttribute(thread, self, name)); 503 if (result.isErrorNotFound()) { 504 return objectRaiseAttributeError(thread, self, name); 505 } 506 return *result; 507} 508 509RawObject METH(object, __hash__)(Thread* thread, Arguments args) { 510 return SmallInt::fromWord(thread->runtime()->hash(args.get(0))); 511} 512 513RawObject METH(object, __init__)(Thread* thread, Arguments args) { 514 // Too many arguments were given. Determine if the __new__ was not overwritten 515 // or the __init__ was to throw a TypeError. 516 HandleScope scope(thread); 517 Runtime* runtime = thread->runtime(); 518 Object self(&scope, args.get(0)); 519 Tuple starargs(&scope, args.get(1)); 520 Dict kwargs(&scope, args.get(2)); 521 if (starargs.length() == 0 && kwargs.numItems() == 0) { 522 // object.__init__ doesn't do anything except throw a TypeError if the 523 // wrong number of arguments are given. It only throws if __new__ is not 524 // overloaded or __init__ was overloaded, else it allows the excess 525 // arguments. 526 return NoneType::object(); 527 } 528 Type type(&scope, runtime->typeOf(*self)); 529 if ((typeLookupInMroById(thread, *type, ID(__new__)) == 530 runtime->objectDunderNew()) || 531 (typeLookupInMroById(thread, *type, ID(__init__)) != 532 runtime->objectDunderInit())) { 533 // Throw a TypeError if extra arguments were passed, and __new__ was not 534 // overwritten by self, or __init__ was overloaded by self. 535 return thread->raiseWithFmt(LayoutId::kTypeError, 536 "object.__init__() takes no parameters"); 537 } 538 // Else it's alright to have extra arguments. 539 return NoneType::object(); 540} 541 542RawObject METH(object, __new__)(Thread* thread, Arguments args) { 543 HandleScope scope(thread); 544 Object type_obj(&scope, args.get(0)); 545 if (!thread->runtime()->isInstanceOfType(*type_obj)) { 546 return thread->raiseRequiresType(type_obj, ID(type)); 547 } 548 Type type(&scope, args.get(0)); 549 return objectNew(thread, type); 550} 551 552RawObject METH(object, __setattr__)(Thread* thread, Arguments args) { 553 HandleScope scope(thread); 554 Object self(&scope, args.get(0)); 555 Object name(&scope, args.get(1)); 556 name = attributeName(thread, name); 557 if (name.isErrorException()) return *name; 558 Object value(&scope, args.get(2)); 559 return objectSetAttr(thread, self, name, value); 560} 561 562RawObject METH(object, __sizeof__)(Thread* thread, Arguments args) { 563 HandleScope scope(thread); 564 Object obj(&scope, args.get(0)); 565 if (obj.isHeapObject()) { 566 HeapObject heap_obj(&scope, *obj); 567 return SmallInt::fromWord(heap_obj.size()); 568 } 569 return SmallInt::fromWord(kPointerSize); 570} 571 572RawObject METH(NoneType, __new__)(Thread*, Arguments) { 573 return NoneType::object(); 574} 575 576RawObject METH(NoneType, __repr__)(Thread* thread, Arguments args) { 577 if (!args.get(0).isNoneType()) { 578 return thread->raiseWithFmt(LayoutId::kTypeError, 579 "__repr__ expects None as first argument"); 580 } 581 return thread->runtime()->symbols()->at(ID(None)); 582} 583 584static const BuiltinAttribute kInstanceProxyAttributes[] = { 585 {ID(_instance), RawInstanceProxy::kInstanceOffset}, 586}; 587 588static const BuiltinAttribute kEnumerateAttributes[] = { 589 {ID(iterator), RawEnumerate::kIteratorOffset}, 590 {ID(index), RawEnumerate::kIndexOffset}}; 591 592static void addObjectType(Thread* thread) { 593 HandleScope scope(thread); 594 Runtime* runtime = thread->runtime(); 595 Layout layout(&scope, runtime->newLayout(LayoutId::kObject)); 596 runtime->layoutAtPut(LayoutId::kObject, *layout); 597 Type type(&scope, runtime->newType()); 598 layout.setDescribedType(*type); 599 type.setName(runtime->symbols()->at(ID(object))); 600 Tuple mro(&scope, runtime->newTupleWith1(type)); 601 type.setMro(*mro); 602 type.setInstanceLayout(*layout); 603 type.setInstanceLayoutId(layout.id()); 604 type.setBases(runtime->emptyTuple()); 605 word flags = Type::Flag::kIsBasetype | Type::Flag::kIsFixedAttributeBase; 606 type.setFlagsAndBuiltinBase(static_cast<Type::Flag>(flags), 607 LayoutId::kObject); 608 609 // Manually create `__getattribute__` method to avoid bootstrap problems. 610 MutableTuple parameter_names(&scope, runtime->newMutableTuple(2)); 611 parameter_names.atPut(0, runtime->symbols()->at(ID(self))); 612 parameter_names.atPut(1, runtime->symbols()->at(ID(name))); 613 Object name(&scope, runtime->symbols()->at(ID(__getattribute__))); 614 Object parameter_names_tuple(&scope, parameter_names.becomeImmutable()); 615 Code code(&scope, 616 runtime->newBuiltinCode( 617 /*argcount=*/2, /*posonlyargcount=*/2, /*kwonlyargcount=*/0, 618 /*flags=*/0, METH(object, __getattribute__), 619 parameter_names_tuple, name)); 620 Object qualname( 621 &scope, Runtime::internStrFromCStr(thread, "object.__getattribute__")); 622 Object module_obj(&scope, NoneType::object()); 623 Function dunder_getattribute( 624 &scope, runtime->newFunctionWithCode(thread, qualname, code, module_obj)); 625 typeAtPutById(thread, type, ID(__getattribute__), dunder_getattribute); 626} 627 628void initializeObjectTypes(Thread* thread) { 629 addObjectType(thread); 630 631 addImmediateBuiltinType(thread, ID(NoneType), LayoutId::kNoneType, 632 /*builtin_base=*/LayoutId::kNoneType, 633 /*superclass_id=*/LayoutId::kObject, 634 /*basetype=*/false); 635 636 addImmediateBuiltinType(thread, ID(NotImplementedType), 637 LayoutId::kNotImplementedType, 638 /*builtin_base=*/LayoutId::kNotImplementedType, 639 /*superclass_id=*/LayoutId::kObject, 640 /*basetype=*/false); 641 642 addImmediateBuiltinType(thread, ID(_UnboundType), LayoutId::kUnbound, 643 /*builtin_base=*/LayoutId::kUnbound, 644 /*superclass_id=*/LayoutId::kObject, 645 /*basetype=*/false); 646 647 addBuiltinType(thread, ID(instance_proxy), LayoutId::kInstanceProxy, 648 /*superclass_id=*/LayoutId::kObject, kInstanceProxyAttributes, 649 RawInstanceProxy::kSize, /*basetype=*/false); 650 651 addBuiltinType(thread, ID(enumerate), LayoutId::kEnumerate, 652 /*superclass_id=*/LayoutId::kObject, kEnumerateAttributes, 653 RawEnumerate::kSize, /*basetype=*/true); 654} 655 656} // namespace py