this repo has no description
at trunk 1331 lines 51 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "type-builtins.h" 3 4#include "attributedict.h" 5#include "builtins.h" 6#include "bytecode.h" 7#include "capi.h" 8#include "compile-utils.h" 9#include "dict-builtins.h" 10#include "frame.h" 11#include "globals.h" 12#include "ic.h" 13#include "list-builtins.h" 14#include "module-builtins.h" 15#include "mro.h" 16#include "object-builtins.h" 17#include "objects.h" 18#include "runtime.h" 19#include "str-builtins.h" 20#include "thread.h" 21#include "typeslots.h" 22 23namespace py { 24 25static RawObject addBuiltinTypeWithLayout(Thread* thread, const Layout& layout, 26 SymbolId name, LayoutId builtin_base, 27 LayoutId superclass_id, word flags) { 28 HandleScope scope(thread); 29 Runtime* runtime = thread->runtime(); 30 Type type(&scope, runtime->newType()); 31 type.setName(runtime->symbols()->at(name)); 32 Type superclass(&scope, runtime->typeAt(superclass_id)); 33 type.setInstanceLayout(*layout); 34 type.setInstanceLayoutId(layout.id()); 35 flags |= superclass.flags() & Type::kInheritableFlags; 36 if (builtin_base == layout.id()) { 37 flags |= Type::Flag::kIsFixedAttributeBase; 38 } 39 type.setFlagsAndBuiltinBase(static_cast<Type::Flag>(flags), builtin_base); 40 type.setBases(runtime->newTupleWith1(superclass)); 41 layout.setDescribedType(*type); 42 return *type; 43} 44 45RawObject addBuiltinType(Thread* thread, SymbolId name, LayoutId layout_id, 46 LayoutId superclass_id, View<BuiltinAttribute> attrs, 47 word size, bool basetype) { 48 HandleScope scope(thread); 49 Runtime* runtime = thread->runtime(); 50 Layout layout(&scope, runtime->layoutCreateSubclassWithBuiltins( 51 thread, layout_id, superclass_id, attrs, size)); 52 runtime->layoutAtPut(layout_id, *layout); 53 LayoutId builtin_base = attrs.length() == 0 ? superclass_id : layout_id; 54 word flags = basetype ? Type::Flag::kIsBasetype : Type::Flag::kNone; 55 return addBuiltinTypeWithLayout(thread, layout, name, builtin_base, 56 superclass_id, flags); 57} 58 59RawObject addImmediateBuiltinType(Thread* thread, SymbolId name, 60 LayoutId layout_id, LayoutId builtin_base, 61 LayoutId superclass_id, bool basetype) { 62 HandleScope scope(thread); 63 Runtime* runtime = thread->runtime(); 64 Layout layout(&scope, runtime->newLayout(layout_id)); 65 runtime->layoutAtPut(layout_id, *layout); 66 word flags = basetype ? Type::Flag::kIsBasetype : Type::Flag::kNone; 67 return addBuiltinTypeWithLayout(thread, layout, name, builtin_base, 68 superclass_id, flags); 69} 70 71void builtinTypeEnableTupleOverflow(Thread* thread, const Type& type) { 72 DCHECK(type.mro().isNoneType(), 73 "Enabling overflow is unsafe after initialization"); 74 thread->runtime()->layoutSetTupleOverflow( 75 Layout::cast(type.instanceLayout())); 76} 77 78RawObject findBuiltinTypeWithName(Thread* thread, const Object& name) { 79 DCHECK(Runtime::isInternedStr(thread, name), "must be interned str"); 80 HandleScope scope(thread); 81 Runtime* runtime = thread->runtime(); 82 Object layout(&scope, NoneType::object()); 83 Object type_obj(&scope, NoneType::object()); 84 for (int i = 0; i <= static_cast<int>(LayoutId::kLastBuiltinId); i++) { 85 layout = runtime->layoutAtSafe(static_cast<LayoutId>(i)); 86 if (layout.isErrorNotFound()) continue; 87 type_obj = Layout::cast(*layout).describedType(); 88 if (!type_obj.isType()) continue; 89 if (Type::cast(*type_obj).name() == name) { 90 return *type_obj; 91 } 92 } 93 return Error::notFound(); 94} 95 96RawObject raiseTypeErrorCannotSetImmutable(Thread* thread, const Type& type) { 97 HandleScope scope(thread); 98 Object type_name(&scope, type.name()); 99 return thread->raiseWithFmt( 100 LayoutId::kTypeError, 101 "can't set attributes of built-in/extension type '%S'", &type_name); 102} 103 104RawObject typeAt(const Type& type, const Object& name) { 105 RawObject result = NoneType::object(); 106 if (!attributeAt(*type, *name, &result)) return Error::notFound(); 107 return result; 108} 109 110RawObject typeAtById(Thread* thread, const Type& type, SymbolId id) { 111 RawObject name = thread->runtime()->symbols()->at(id); 112 RawObject result = NoneType::object(); 113 if (!attributeAt(*type, name, &result)) return Error::notFound(); 114 return result; 115} 116 117// Returns type flags updated with the given attribute. 118static word computeAttributeTypeFlags(Thread* thread, const Type& type, 119 SymbolId name, word flags) { 120 Runtime* runtime = thread->runtime(); 121 // Custom MROs can contain types that are not part of the subclass hierarchy 122 // which does not fit our cache invalidation strategy for the flags. Be safe 123 // and do not set any! 124 if (flags & Type::Flag::kHasCustomMro) { 125 return flags & ~Type::kAttributeFlags; 126 } 127 if (name == ID(__getattribute__)) { 128 RawObject value = typeLookupInMroById(thread, *type, name); 129 if (value == runtime->objectDunderGetattribute()) { 130 flags |= Type::Flag::kHasObjectDunderGetattribute; 131 } else { 132 flags &= ~Type::Flag::kHasObjectDunderGetattribute; 133 } 134 if (value == runtime->typeDunderGetattribute()) { 135 flags |= Type::Flag::kHasTypeDunderGetattribute; 136 } else { 137 flags &= ~Type::Flag::kHasTypeDunderGetattribute; 138 } 139 if (value == runtime->moduleDunderGetattribute()) { 140 flags |= Type::Flag::kHasModuleDunderGetattribute; 141 } else { 142 flags &= ~Type::Flag::kHasModuleDunderGetattribute; 143 } 144 return flags; 145 } 146 if (name == ID(__new__)) { 147 RawObject value = typeLookupInMroById(thread, *type, name); 148 if (value == runtime->objectDunderNew()) { 149 flags |= Type::Flag::kHasObjectDunderNew; 150 } else { 151 flags &= ~Type::Flag::kHasObjectDunderNew; 152 } 153 return flags; 154 } 155 if (name == ID(__hash__)) { 156 RawObject value = typeLookupInMroById(thread, *type, name); 157 if (value == runtime->objectDunderHash()) { 158 flags |= Type::Flag::kHasObjectDunderHash; 159 } else if (value == runtime->strDunderHash()) { 160 flags |= Type::Flag::kHasStrDunderHash; 161 } else { 162 flags &= 163 ~(Type::Flag::kHasObjectDunderHash | Type::Flag::kHasStrDunderHash); 164 } 165 return flags; 166 } 167 if (name == ID(__bool__)) { 168 RawObject value = typeLookupInMroById(thread, *type, name); 169 if (!value.isErrorNotFound()) { 170 flags |= Type::Flag::kHasDunderBool; 171 } else { 172 flags &= ~Type::Flag::kHasDunderBool; 173 } 174 return flags; 175 } 176 if (name == ID(__len__)) { 177 RawObject value = typeLookupInMroById(thread, *type, name); 178 if (!value.isErrorNotFound()) { 179 flags |= Type::Flag::kHasDunderLen; 180 } else { 181 flags &= ~Type::Flag::kHasDunderLen; 182 } 183 return flags; 184 } 185 if (name == ID(__class__)) { 186 RawObject value = typeLookupInMroById(thread, *type, name); 187 if (value == runtime->objectDunderClass()) { 188 flags |= Type::Flag::kHasObjectDunderClass; 189 } else { 190 flags &= ~Type::Flag::kHasObjectDunderClass; 191 } 192 return flags; 193 } 194 if (name == ID(__eq__)) { 195 RawObject value = typeLookupInMroById(thread, *type, name); 196 if (value == runtime->objectDunderEq()) { 197 flags |= Type::Flag::kHasObjectDunderEq; 198 } else { 199 flags &= ~Type::Flag::kHasObjectDunderEq; 200 } 201 return flags; 202 } 203 if (name == ID(__get__)) { 204 RawObject value = typeLookupInMroById(thread, *type, name); 205 if (!value.isErrorNotFound()) { 206 flags |= Type::Flag::kHasDunderGet; 207 } else { 208 flags &= ~Type::Flag::kHasDunderGet; 209 } 210 return flags; 211 } 212 if (name == ID(__set__)) { 213 RawObject value = typeLookupInMroById(thread, *type, name); 214 if (!value.isErrorNotFound()) { 215 flags |= Type::Flag::kHasDunderSet; 216 } else { 217 flags &= ~Type::Flag::kHasDunderSet; 218 } 219 return flags; 220 } 221 if (name == ID(__delete__)) { 222 RawObject value = typeLookupInMroById(thread, *type, name); 223 if (!value.isErrorNotFound()) { 224 flags |= Type::Flag::kHasDunderDelete; 225 } else { 226 flags &= ~Type::Flag::kHasDunderDelete; 227 } 228 return flags; 229 } 230 return flags; 231} 232 233// Propagate attribute type flags through `type`'s descendents. 234static void typePropagateAttributeTypeFlag(Thread* thread, const Type& type, 235 SymbolId attr_name) { 236 Type::Flag new_flags = Type::Flag::kNone; 237 new_flags = static_cast<Type::Flag>( 238 computeAttributeTypeFlags(thread, type, attr_name, type.flags())); 239 if (new_flags == type.flags()) { 240 // Stop tree traversal since flags doesn't change for this type and its 241 // subclases. 242 return; 243 } 244 type.setFlags(new_flags); 245 if (type.subclasses().isNoneType()) { 246 return; 247 } 248 HandleScope scope(thread); 249 List subclasses(&scope, type.subclasses()); 250 Type subclass(&scope, thread->runtime()->typeAt(LayoutId::kObject)); 251 for (word i = 0, length = subclasses.numItems(); i < length; ++i) { 252 RawObject referent = WeakRef::cast(subclasses.at(i)).referent(); 253 if (referent.isNoneType()) continue; 254 subclass = referent.rawCast<RawType>(); 255 if (typeAtById(thread, subclass, attr_name).isErrorNotFound()) { 256 // subclass inherits the attribute for `attr_name`. 257 typePropagateAttributeTypeFlag(thread, subclass, attr_name); 258 } 259 } 260} 261 262static const SymbolId kAttributesForTypeFlags[] = { 263 ID(__getattribute__), ID(__new__), ID(__hash__), ID(__bool__), 264 ID(__len__), ID(__class__), ID(__get__), ID(__set__), 265 ID(__delete__), ID(__eq__), 266}; 267 268// Returns `SymbolId` for `attr_name` if given `attr_name` is marked in 269// Type::Flags. Returns `SymbolId::kInvalid` otherwise. See Type::Flags. 270static SymbolId attributeForTypeFlag(Thread* thread, const Object& attr_name) { 271 Symbols* symbols = thread->runtime()->symbols(); 272 for (SymbolId id : kAttributesForTypeFlags) { 273 if (attr_name == symbols->at(id)) return id; 274 } 275 return SymbolId::kInvalid; 276} 277 278RawObject typeAtPut(Thread* thread, const Type& type, const Object& name, 279 const Object& value) { 280 DCHECK(thread->runtime()->isInternedStr(thread, name), 281 "name should be an interned str"); 282 RawValueCell value_cell = 283 ValueCell::cast(attributeValueCellAtPut(thread, type, name)); 284 value_cell.setValue(*value); 285 if (!value_cell.dependencyLink().isNoneType()) { 286 HandleScope scope(thread); 287 ValueCell value_cell_obj(&scope, value_cell); 288 icInvalidateAttr(thread, type, name, value_cell_obj); 289 return *value_cell_obj; 290 } 291 SymbolId attr_name_for_type_flag = attributeForTypeFlag(thread, name); 292 if (attributeForTypeFlag(thread, name) != SymbolId::kInvalid) { 293 typePropagateAttributeTypeFlag(thread, type, attr_name_for_type_flag); 294 } 295 return value_cell; 296} 297 298RawObject typeAtPutById(Thread* thread, const Type& type, SymbolId id, 299 const Object& value) { 300 HandleScope scope(thread); 301 Object name(&scope, thread->runtime()->symbols()->at(id)); 302 return typeAtPut(thread, type, name, value); 303} 304 305RawObject typeAtSetLocation(RawType type, RawObject name, word hash, 306 Object* location) { 307 RawObject result = NoneType::object(); 308 if (!attributeValueCellAtWithHash(type, name, hash, &result) || 309 ValueCell::cast(result).isPlaceholder()) { 310 return Error::notFound(); 311 } 312 if (location != nullptr) { 313 *location = result; 314 } 315 return ValueCell::cast(result).value(); 316} 317 318bool typeIsDataDescriptor(RawType type) { 319 word flags = type.flags(); 320 return (flags & Type::Flag::kHasDunderSet) || 321 (flags & Type::Flag::kHasDunderDelete); 322} 323 324bool typeIsNonDataDescriptor(RawType type) { 325 word flags = type.flags(); 326 return flags & Type::Flag::kHasDunderGet; 327} 328 329RawObject resolveDescriptorGet(Thread* thread, const Object& descr, 330 const Object& instance, 331 const Object& instance_type) { 332 if (!typeIsNonDataDescriptor( 333 thread->runtime()->typeOf(*descr).rawCast<RawType>())) { 334 return *descr; 335 } 336 return Interpreter::callDescriptorGet(thread, descr, instance, instance_type); 337} 338 339RawObject typeAssignFromDict(Thread* thread, const Type& type, 340 const Dict& dict) { 341 HandleScope scope(thread); 342 Object key(&scope, NoneType::object()); 343 Object value(&scope, NoneType::object()); 344 for (word i = 0; dictNextItem(dict, &i, &key, &value);) { 345 DCHECK(!(value.isValueCell() && ValueCell::cast(*value).isPlaceholder()), 346 "value should not be a placeholder value cell"); 347 key = attributeName(thread, key); 348 if (key.isErrorException()) return *key; 349 typeAtPut(thread, type, key, value); 350 } 351 return NoneType::object(); 352} 353 354RawObject typeLookupInMroSetLocation(Thread* thread, RawType type, 355 RawObject name, Object* location) { 356 RawTuple mro = Tuple::cast(type.mro()); 357 word hash = internedStrHash(name); 358 for (word i = 0, length = mro.length(); i < length; i++) { 359 DCHECK(thread->runtime()->isInstanceOfType(mro.at(i)), "non-type in MRO"); 360 RawType mro_type = mro.at(i).rawCast<RawType>(); 361 RawObject result = typeAtSetLocation(mro_type, name, hash, location); 362 if (!result.isErrorNotFound()) { 363 return result; 364 } 365 } 366 return Error::notFound(); 367} 368 369RawObject typeDeleteAttribute(Thread* thread, const Type& type, 370 const Object& name) { 371 HandleScope scope(thread); 372 Runtime* runtime = thread->runtime(); 373 terminateIfUnimplementedTypeAttrCacheInvalidation(thread, type, name); 374 if (!type.hasMutableDict()) { 375 return raiseTypeErrorCannotSetImmutable(thread, type); 376 } 377 378 // Check for a delete descriptor 379 Type metatype(&scope, runtime->typeOf(*type)); 380 Object meta_attr(&scope, typeLookupInMro(thread, *metatype, *name)); 381 if (!meta_attr.isError() && runtime->isDeleteDescriptor(thread, meta_attr)) { 382 return Interpreter::callDescriptorDelete(thread, meta_attr, type); 383 } 384 385 // No delete descriptor found, attempt to delete from the type dict 386 if (typeRemove(thread, type, name).isErrorNotFound()) { 387 Str type_name(&scope, type.name()); 388 return thread->raiseWithFmt(LayoutId::kAttributeError, 389 "type object '%S' has no attribute '%S'", 390 &type_name, &name); 391 } 392 return NoneType::object(); 393} 394 395RawObject typeLookupInMroById(Thread* thread, RawType type, SymbolId id) { 396 return typeLookupInMro(thread, type, thread->runtime()->symbols()->at(id)); 397} 398 399RawObject typeRemove(Thread* thread, const Type& type, const Object& name) { 400 DCHECK(Runtime::isInternedStr(thread, name), "expected interned str"); 401 HandleScope scope(thread); 402 word index; 403 Object value_cell_obj(&scope, NoneType::object()); 404 if (!attributeFindForRemoval(type, name, &value_cell_obj, &index)) { 405 return Error::notFound(); 406 } 407 ValueCell value_cell(&scope, *value_cell_obj); 408 icInvalidateAttr(thread, type, name, value_cell); 409 attributeRemove(type, index); 410 if (value_cell.isPlaceholder()) return Error::notFound(); 411 SymbolId attr_name_for_type_flag = attributeForTypeFlag(thread, name); 412 if (attributeForTypeFlag(thread, name) != SymbolId::kInvalid) { 413 typePropagateAttributeTypeFlag(thread, type, attr_name_for_type_flag); 414 } 415 return value_cell.value(); 416} 417 418RawObject typeRemoveById(Thread* thread, const Type& type, SymbolId id) { 419 HandleScope scope(thread); 420 Object name(&scope, thread->runtime()->symbols()->at(id)); 421 return typeRemove(thread, type, name); 422} 423 424RawObject typeKeys(Thread* thread, const Type& type) { 425 return attributeKeys(thread, type); 426} 427 428word typeLen(Thread* thread, const Type& type) { 429 return attributeLen(thread, type); 430} 431 432RawObject typeValues(Thread* thread, const Type& type) { 433 return attributeValues(thread, type); 434} 435 436RawObject typeGetAttribute(Thread* thread, const Type& type, 437 const Object& name) { 438 return typeGetAttributeSetLocation(thread, type, name, nullptr); 439} 440 441RawObject typeGetAttributeSetLocation(Thread* thread, const Type& type, 442 const Object& name, 443 Object* location_out) { 444 // Look for the attribute in the meta class 445 HandleScope scope(thread); 446 Runtime* runtime = thread->runtime(); 447 Type meta_type(&scope, runtime->typeOf(*type)); 448 Object meta_attr(&scope, typeLookupInMro(thread, *meta_type, *name)); 449 if (!meta_attr.isError()) { 450 // TODO(T56002494): Remove this once type.__getattribute__ gets cached. 451 if (meta_attr.isProperty()) { 452 Object getter(&scope, Property::cast(*meta_attr).getter()); 453 if (!getter.isNoneType()) { 454 return Interpreter::call1(thread, getter, type); 455 } 456 } 457 Type meta_attr_type(&scope, runtime->typeOf(*meta_attr)); 458 if (typeIsDataDescriptor(*meta_attr_type)) { 459 return Interpreter::callDescriptorGet(thread, meta_attr, type, meta_type); 460 } 461 } 462 463 // No data descriptor found on the meta class, look in the mro of the type 464 Object attr(&scope, 465 typeLookupInMroSetLocation(thread, *type, *name, location_out)); 466 if (!attr.isError()) { 467 // TODO(T56002494): Remove this once type.__getattribute__ gets cached. 468 if (attr.isFunction()) { 469 // We always return the function object itself instead of a BoundMethod 470 // due to the exception made below and another exception for NoneType in 471 // function.__get__. 472 return *attr; 473 } 474 Type attr_type(&scope, runtime->typeOf(*attr)); 475 if (typeIsNonDataDescriptor(*attr_type)) { 476 // Unfortunately calling `__get__` for a lookup on `type(None)` will look 477 // exactly the same as calling it for a lookup on the `None` object. 478 // To solve the ambiguity we add a special case for `type(None)` here. 479 // Luckily it is impossible for the user to change the type so we can 480 // special case the desired lookup behavior here. 481 // Also see `METH(function, __get__)` for the related special casing 482 // of lookups on the `None` object. 483 if (type.builtinBase() == LayoutId::kNoneType) { 484 return *attr; 485 } 486 if (location_out != nullptr) { 487 *location_out = NoneType::object(); 488 } 489 Object none(&scope, NoneType::object()); 490 return Interpreter::callDescriptorGet(thread, attr, none, type); 491 } 492 return *attr; 493 } 494 495 // No data descriptor found on the meta class, look on the type 496 Object result(&scope, instanceGetAttribute(thread, type, name)); 497 if (!result.isError()) { 498 return *result; 499 } 500 501 // No attr found in type or its mro, use the non-data descriptor found in 502 // the metaclass (if any). 503 if (!meta_attr.isError()) { 504 return resolveDescriptorGet(thread, meta_attr, type, meta_type); 505 } 506 507 return Error::notFound(); 508} 509 510static void addSubclass(Thread* thread, const Type& base, const Type& type) { 511 HandleScope scope(thread); 512 Runtime* runtime = thread->runtime(); 513 if (base.subclasses().isNoneType()) { 514 base.setSubclasses(runtime->newList()); 515 } 516 List subclasses(&scope, base.subclasses()); 517 Object value(&scope, runtime->newWeakRef(thread, type)); 518 runtime->listAdd(thread, subclasses, value); 519} 520 521void typeAddDocstring(Thread* thread, const Type& type) { 522 // If the type dictionary doesn't contain a __doc__, set it from the doc 523 // slot 524 if (typeAtById(thread, type, ID(__doc__)).isErrorNotFound()) { 525 HandleScope scope(thread); 526 Object doc(&scope, type.doc()); 527 typeAtPutById(thread, type, ID(__doc__), doc); 528 } 529} 530 531void typeAddInstanceDict(Thread* thread, const Type& type) { 532 HandleScope scope(thread); 533 Runtime* runtime = thread->runtime(); 534 Object instance_proxy(&scope, runtime->typeAt(LayoutId::kInstanceProxy)); 535 CHECK(instance_proxy.isType(), "instance_proxy not found"); 536 Module under_builtins(&scope, runtime->findModuleById(ID(_builtins))); 537 Function under_instance_dunder_dict_set( 538 &scope, 539 moduleAtById(thread, under_builtins, ID(_instance_dunder_dict_set))); 540 Object none(&scope, NoneType::object()); 541 Object property(&scope, 542 runtime->newProperty(instance_proxy, 543 under_instance_dunder_dict_set, none)); 544 typeAtPutById(thread, type, ID(__dict__), property); 545} 546 547static RawObject fixedAttributeBaseOfType(Thread* thread, const Type& type); 548 549// This searches recursively through `bases` for classes with the 550// `kIsFixedAttributeBase` flag set. The algorithm picks the entry in bases 551// which leads to a fixed attribute base class that is equal or a superclass of 552// the fixed attribute bases found by the other bases entries. 553// If `get_fixed_attr_base` is false, then the fixed attribute base is returned. 554// If it is true, then the first entry in `bases` that is superclass of the 555// fixed attribute base is returned. 556static RawObject computeFixedAttributeBaseImpl(Thread* thread, 557 const Tuple& bases, 558 bool get_fixed_attr_base) { 559 HandleScope scope(thread); 560 Type result(&scope, bases.at(0)); 561 if (!result.isBasetype()) { 562 Object type_name(&scope, result.name()); 563 return thread->raiseWithFmt(LayoutId::kTypeError, 564 "type '%S' is not an acceptable base type", 565 &type_name); 566 } 567 word bases_length = bases.length(); 568 if (!get_fixed_attr_base && bases_length == 1) { 569 return *result; 570 } 571 572 Type result_fixed_attr_base(&scope, fixedAttributeBaseOfType(thread, result)); 573 Type base(&scope, *result); 574 Type fixed_attr_base(&scope, *result); 575 for (word i = 1, length = bases.length(); i < length; i++) { 576 base = bases.at(i); 577 if (!base.isBasetype()) { 578 Object type_name(&scope, base.name()); 579 return thread->raiseWithFmt(LayoutId::kTypeError, 580 "type '%S' is not an acceptable base type", 581 &type_name); 582 } 583 584 fixed_attr_base = fixedAttributeBaseOfType(thread, base); 585 if (typeIsSubclass(*result_fixed_attr_base, *fixed_attr_base)) { 586 continue; 587 } 588 if (typeIsSubclass(*fixed_attr_base, *result_fixed_attr_base)) { 589 result = *base; 590 result_fixed_attr_base = *fixed_attr_base; 591 } else { 592 return thread->raiseWithFmt( 593 LayoutId::kTypeError, 594 "multiple bases have instance lay-out conflict"); 595 } 596 } 597 return get_fixed_attr_base ? *result_fixed_attr_base : *result; 598} 599 600// Returns the most generic base of `type` on `type's type hierarchy that 601// contains all in-object attributes of `type`. Note that this is designed to 602// simulate `solid_base` from CPython's typeobject.c. 603static RawObject fixedAttributeBaseOfType(Thread* thread, const Type& type) { 604 if (type.hasFlag(Type::Flag::kIsFixedAttributeBase)) { 605 return *type; 606 } 607 HandleScope scope(thread); 608 Tuple bases(&scope, type.bases()); 609 return computeFixedAttributeBaseImpl(thread, bases, true); 610} 611 612RawObject computeFixedAttributeBase(Thread* thread, const Tuple& bases) { 613 return computeFixedAttributeBaseImpl(thread, bases, false); 614} 615 616static RawObject validateSlots(Thread* thread, const Type& type, 617 const Tuple& slots, bool base_has_instance_dict, 618 bool* add_instance_dict) { 619 HandleScope scope(thread); 620 word slots_len = slots.length(); 621 Runtime* runtime = thread->runtime(); 622 Str dunder_dict(&scope, runtime->symbols()->at(ID(__dict__))); 623 *add_instance_dict = false; 624 List result(&scope, runtime->newList()); 625 Object slot_obj(&scope, NoneType::object()); 626 Str slot_str(&scope, Str::empty()); 627 Object type_name(&scope, type.name()); 628 for (word i = 0; i < slots_len; i++) { 629 slot_obj = slots.at(i); 630 if (!runtime->isInstanceOfStr(*slot_obj)) { 631 return thread->raiseWithFmt(LayoutId::kTypeError, 632 "__slots__ items must be strings, not '%T'", 633 &slot_obj); 634 } 635 slot_str = strUnderlying(*slot_obj); 636 if (!strIsIdentifier(slot_str)) { 637 return thread->raiseWithFmt(LayoutId::kTypeError, 638 "__slots__ must be identifiers"); 639 } 640 slot_str = mangle(thread, type_name, slot_str); 641 slot_str = Runtime::internStr(thread, slot_str); 642 if (slot_str == dunder_dict) { 643 if (base_has_instance_dict || *add_instance_dict) { 644 return thread->raiseWithFmt( 645 LayoutId::kTypeError, 646 "__dict__ slot disallowed: we already got one"); 647 } 648 *add_instance_dict = true; 649 continue; 650 } 651 if (!typeAt(type, slot_str).isErrorNotFound()) { 652 return thread->raiseWithFmt( 653 LayoutId::kValueError, 654 "'%S' in __slots__ conflicts with class variable", &slot_str); 655 } 656 runtime->listAdd(thread, result, slot_str); 657 } 658 if (result.numItems() == 0) return NoneType::object(); 659 listSort(thread, result); 660 return *result; 661} 662 663static word estimateNumAttributes(Thread* thread, const Type& type) { 664 HandleScope scope(thread); 665 Runtime* runtime = thread->runtime(); 666 // Collect set of in-object attributes by scanning the __init__ method of 667 // each class in the MRO. This is used to determine the number of slots 668 // allocated for in-object attributes when instances are created. 669 Tuple mro(&scope, type.mro()); 670 Dict attr_names(&scope, runtime->newDict()); 671 for (word i = 0; i < mro.length(); i++) { 672 Type mro_type(&scope, mro.at(i)); 673 Object maybe_init(&scope, runtime->classConstructor(mro_type)); 674 if (!maybe_init.isFunction()) { 675 continue; 676 } 677 Function init(&scope, *maybe_init); 678 RawObject maybe_code = init.code(); 679 if (!maybe_code.isCode()) { 680 continue; // native trampoline 681 } 682 Code code(&scope, maybe_code); 683 if (code.code().isSmallInt()) { 684 continue; // builtin trampoline 685 } 686 runtime->collectAttributes(code, attr_names); 687 } 688 return attr_names.numItems(); 689} 690 691static void setSlotAttributes(Thread* thread, const MutableTuple& dst, 692 word start_index, const List& slots) { 693 HandleScope scope(thread); 694 Object descriptor(&scope, NoneType::object()); 695 Object name(&scope, NoneType::object()); 696 Runtime* runtime = thread->runtime(); 697 for (word i = 0, offset = start_index * kPointerSize; i < slots.numItems(); 698 i++, offset += kPointerSize) { 699 descriptor = slots.at(i); 700 AttributeInfo info(offset, AttributeFlags::kInObject | 701 AttributeFlags::kFixedOffset | 702 AttributeFlags::kInitWithUnbound); 703 name = SlotDescriptor::cast(*descriptor).name(); 704 dst.atPut(start_index + i, runtime->layoutNewAttribute(name, info)); 705 SlotDescriptor::cast(*descriptor).setOffset(offset); 706 } 707} 708 709static RawObject typeComputeLayout(Thread* thread, const Type& type, 710 const Type& fixed_attr_base, 711 bool enable_overflow, const Object& slots) { 712 HandleScope scope(thread); 713 Runtime* runtime = thread->runtime(); 714 Tuple bases(&scope, type.bases()); 715 716 // Create new layout. 717 DCHECK(type.instanceLayout().isNoneType(), 718 "must not set layout multiple times"); 719 LayoutId layout_id = runtime->reserveLayoutId(thread); 720 Layout layout(&scope, runtime->newLayout(layout_id)); 721 722 // Compute in-object attributes. 723 Layout base_layout(&scope, fixed_attr_base.instanceLayout()); 724 Tuple base_attributes(&scope, base_layout.inObjectAttributes()); 725 word num_base_attributes = base_attributes.length(); 726 word num_slots = slots.isList() ? List::cast(*slots).numItems() : 0; 727 word num_initial_attributes = num_base_attributes + num_slots; 728 if (num_initial_attributes == 0) { 729 layout.setInObjectAttributes(runtime->emptyTuple()); 730 } else { 731 MutableTuple attributes(&scope, 732 runtime->newMutableTuple(num_initial_attributes)); 733 attributes.replaceFromWith(0, *base_attributes, num_base_attributes); 734 if (num_slots > 0) { 735 List slots_list(&scope, *slots); 736 setSlotAttributes(thread, attributes, /*start_index=*/num_base_attributes, 737 slots_list); 738 } 739 layout.setInObjectAttributes(attributes.becomeImmutable()); 740 } 741 742 word num_extra_attributes = estimateNumAttributes(thread, type); 743 layout.setNumInObjectAttributes(num_initial_attributes + 744 num_extra_attributes); 745 746 // Determine overflow mode. 747 Type base(&scope, *type); 748 Object overflow(&scope, base_layout.overflowAttributes()); 749 Object base_overflow(&scope, NoneType::object()); 750 bool bases_have_custom_dict = false; 751 for (word i = 0, length = bases.length(); i < length; i++) { 752 base = bases.at(i); 753 if (base.hasCustomDict()) bases_have_custom_dict = true; 754 base_overflow = Layout::cast(base.instanceLayout()).overflowAttributes(); 755 if (overflow == base_overflow || base_overflow.isNoneType()) continue; 756 if (overflow.isNoneType() && base_overflow.isTuple()) { 757 overflow = *base_overflow; 758 continue; 759 } 760 UNIMPLEMENTED("Mixing dict and tuple overflow"); 761 } 762 DCHECK(!overflow.isTuple() || Tuple::cast(*overflow).length() == 0, 763 "base layout must not have tuple overflow attributes assigned"); 764 if (enable_overflow && !bases_have_custom_dict && overflow.isNoneType()) { 765 overflow = runtime->emptyTuple(); 766 } 767 layout.setOverflowAttributes(*overflow); 768 769 runtime->layoutAtPut(layout_id, *layout); 770 layout.setDescribedType(*type); 771 type.setInstanceLayout(*layout); 772 type.setInstanceLayoutId(layout.id()); 773 type.setBuiltinBase(fixed_attr_base.builtinBase()); 774 return NoneType::object(); 775} 776 777static RawObject getModuleNameAtFrame(Thread* thread, int depth) { 778 HandleScope scope(thread); 779 Frame* frame = thread->currentFrame(); 780 for (int i = 0; i < depth && !frame->isSentinel(); i++) { 781 frame = frame->previousFrame(); 782 } 783 if (frame->isSentinel()) return Error::notFound(); 784 Object module_obj(&scope, frame->function().moduleObject()); 785 // Some functions (e.g C-API extension functions) have no associated module. 786 if (module_obj.isNoneType()) return Error::notFound(); 787 Module module(&scope, *module_obj); 788 return moduleAtById(thread, module, ID(__name__)); 789} 790 791static RawObject typeSetNames(Thread* thread, const Type& type, 792 const Dict& dict) { 793 HandleScope scope(thread); 794 Runtime* runtime = thread->runtime(); 795 Object key(&scope, NoneType::object()); 796 Object value(&scope, NoneType::object()); 797 Object result(&scope, NoneType::object()); 798 Object set_name(&scope, NoneType::object()); 799 800 for (word i = 0; dictNextItem(dict, &i, &key, &value);) { 801 // If a method is looked up during bootstrapping (which we do during 802 // typeNew(), there is a chance that the MRO won't be present yet. This 803 // check allows dealing with that case gracefully. 804 if (runtime->typeOf(*value).mro().isNoneType()) { 805 continue; 806 } 807 808 set_name = Interpreter::lookupMethod(thread, value, ID(__set_name__)); 809 if (set_name.isError()) { 810 if (set_name.isErrorException()) { 811 return *set_name; 812 } 813 DCHECK(set_name.isErrorNotFound(), "expected not found"); 814 continue; 815 } 816 817 result = Interpreter::callMethod3(thread, set_name, value, type, key); 818 if (result.isErrorException()) { 819 Str type_name(&scope, type.name()); 820 return thread->raiseWithFmtChainingPendingAsCause( 821 LayoutId::kRuntimeError, 822 "Error calling __set_name__ on '%T' instance in %S", &value, 823 &type_name); 824 } 825 } 826 return NoneType::object(); 827} 828 829RawObject typeNew(Thread* thread, const Type& metaclass, const Str& name, 830 const Tuple& bases, const Dict& dict, word flags, 831 bool inherit_slots, bool add_instance_dict) { 832 HandleScope scope(thread); 833 Runtime* runtime = thread->runtime(); 834 835 LayoutId metaclass_id = Layout::cast(metaclass.instanceLayout()).id(); 836 Type type(&scope, runtime->newTypeWithMetaclass(metaclass_id)); 837 type.setName(*name); 838 type.setBases(*bases); 839 840 Object fixed_attr_base_obj(&scope, computeFixedAttributeBase(thread, bases)); 841 if (fixed_attr_base_obj.isErrorException()) return *fixed_attr_base_obj; 842 Type fixed_attr_base(&scope, *fixed_attr_base_obj); 843 844 // Determine metaclass.mro method. Set `mro_method` to `None` if it is the 845 // default `type.mro`. 846 Object mro_method(&scope, Unbound::object()); 847 if (metaclass_id != LayoutId::kType) { 848 mro_method = Interpreter::lookupMethod(thread, type, ID(mro)); 849 if (mro_method.isErrorException()) return *mro_method; 850 if (mro_method.isErrorNotFound()) { 851 Object mro_name(&scope, runtime->symbols()->at(ID(mro))); 852 return objectRaiseAttributeError(thread, metaclass, mro_name); 853 } 854 Type builtin_type(&scope, runtime->typeAt(LayoutId::kType)); 855 if (mro_method == typeAtById(thread, builtin_type, ID(mro))) { 856 mro_method = Unbound::object(); 857 } 858 } 859 Object mro_obj(&scope, NoneType::object()); 860 if (mro_method.isUnbound()) { 861 mro_obj = computeMro(thread, type); 862 if (mro_obj.isErrorException()) return *mro_obj; 863 } else { 864 flags |= Type::Flag::kHasCustomMro; 865 mro_obj = Interpreter::callMethod1(thread, mro_method, type); 866 if (mro_obj.isErrorException()) return *mro_obj; 867 if (!mro_obj.isTuple()) { 868 mro_obj = thread->invokeFunction1(ID(builtins), ID(tuple), mro_obj); 869 if (mro_obj.isErrorException()) return *mro_obj; 870 CHECK(mro_obj.isTuple(), "Result of builtins.tuple should be tuple"); 871 } 872 } 873 874 Tuple mro(&scope, *mro_obj); 875 type.setMro(*mro); 876 877 Object result(&scope, typeAssignFromDict(thread, type, dict)); 878 if (result.isErrorException()) return *result; 879 880 if (flags & Type::Flag::kIsCPythonHeaptype) { 881 if (typeAtById(thread, type, ID(__module__)).isErrorNotFound()) { 882 // Use depth=3 to skip over frame of `_type_init`, `type.__new__` 883 // and `type.__call__`. 884 Object module_name(&scope, getModuleNameAtFrame(thread, /*depth=*/3)); 885 if (!module_name.isErrorNotFound()) { 886 typeAtPutById(thread, type, ID(__module__), module_name); 887 } 888 } 889 } else { 890 // Non-heap-types in CPython have no `__module__` unless there is a 891 // "." in `tp_name`. Remove the attribute when it equals "builtins". 892 Object module_name(&scope, typeAtById(thread, type, ID(__module__))); 893 if (module_name.isStr() && 894 Str::cast(*module_name).equals(runtime->symbols()->at(ID(builtins)))) { 895 typeRemoveById(thread, type, ID(__module__)); 896 } 897 } 898 899 Object qualname(&scope, typeRemoveById(thread, type, ID(__qualname__))); 900 if (qualname.isErrorNotFound()) { 901 qualname = *name; 902 } else if (!runtime->isInstanceOfStr(*qualname)) { 903 return thread->raiseWithFmt(LayoutId::kTypeError, 904 "type __qualname__ must be a str, not %T", 905 &qualname); 906 } 907 type.setQualname(*qualname); 908 909 // TODO(T53997177): Centralize type initialization 910 typeAddDocstring(thread, type); 911 912 // Special-case __new__ to be a staticmethod 913 Object dunder_new(&scope, typeAtById(thread, type, ID(__new__))); 914 if (dunder_new.isFunction()) { 915 StaticMethod dunder_new_method(&scope, runtime->newStaticMethod()); 916 dunder_new_method.setFunction(*dunder_new); 917 typeAtPutById(thread, type, ID(__new__), dunder_new_method); 918 } 919 920 // Special-case __init_subclass__ to be a classmethod 921 Object init_subclass(&scope, typeAtById(thread, type, ID(__init_subclass__))); 922 if (init_subclass.isFunction()) { 923 ClassMethod init_subclass_method(&scope, runtime->newClassMethod()); 924 init_subclass_method.setFunction(*init_subclass); 925 typeAtPutById(thread, type, ID(__init_subclass__), init_subclass_method); 926 } 927 928 // Special-case __class_getitem__ to be a classmethod 929 Object class_getitem(&scope, typeAtById(thread, type, ID(__class_getitem__))); 930 if (class_getitem.isFunction()) { 931 ClassMethod class_getitem_method(&scope, runtime->newClassMethod()); 932 class_getitem_method.setFunction(*class_getitem); 933 typeAtPutById(thread, type, ID(__class_getitem__), class_getitem_method); 934 } 935 936 Object class_cell(&scope, typeAtById(thread, type, ID(__classcell__))); 937 if (!class_cell.isErrorNotFound()) { 938 DCHECK(class_cell.isCell(), "class cell must be a cell"); 939 Cell::cast(*class_cell).setValue(*type); 940 Object class_cell_name(&scope, runtime->symbols()->at(ID(__classcell__))); 941 typeRemove(thread, type, class_cell_name); 942 } 943 944 // Analyze bases: Merge flags; add to subclasses lists; check for attribute 945 // dictionaries. 946 Type base_type(&scope, *type); 947 bool bases_have_instance_dict = false; 948 bool bases_have_type_slots = false; 949 word bases_flags = 0; 950 for (word i = 0; i < bases.length(); i++) { 951 base_type = bases.at(i); 952 bases_flags |= base_type.flags(); 953 addSubclass(thread, base_type, type); 954 bases_have_type_slots |= typeHasSlots(base_type); 955 if (base_type.hasCustomDict()) bases_have_instance_dict = true; 956 if (!Layout::cast(base_type.instanceLayout()).isSealed()) { 957 bases_have_instance_dict = true; 958 } 959 } 960 if (bases_have_instance_dict) add_instance_dict = false; 961 flags |= (bases_flags & Type::kInheritableFlags); 962 // Attribute flags are set explicitly here since `typeAssignFromDict` cannot 963 // compute it properly with a partially created type object: 964 // Computing this properly depends if Type::Flag::kHasCustomMro is set or not. 965 for (SymbolId id : kAttributesForTypeFlags) { 966 flags = computeAttributeTypeFlags(thread, type, id, flags); 967 } 968 // TODO(T66646764): This is a hack to make `type` look finalized. Remove this. 969 type.setFlags(static_cast<Type::Flag>(flags)); 970 971 if (bases_have_type_slots) { 972 if (inherit_slots) { 973 result = typeInheritSlots(thread, type, fixed_attr_base); 974 if (result.isErrorException()) return *result; 975 } 976 } 977 978 Object dunder_slots_obj(&scope, typeAtById(thread, type, ID(__slots__))); 979 Object slots_obj(&scope, NoneType::object()); 980 if (!dunder_slots_obj.isErrorNotFound()) { 981 // NOTE: CPython raises an exception when slots are given to a subtype of a 982 // type with type.tp_itemsize != 0, which means having a variable length. 983 // For example, __slots__ in int's subtype or str's type is disallowed. 984 // This behavior is ignored in Pyro since all objects' size in RawObject is 985 // fixed in Pyro. 986 if (runtime->isInstanceOfStr(*dunder_slots_obj)) { 987 dunder_slots_obj = runtime->newTupleWith1(dunder_slots_obj); 988 } else if (!runtime->isInstanceOfTuple(*dunder_slots_obj)) { 989 Type tuple_type(&scope, runtime->typeAt(LayoutId::kTuple)); 990 dunder_slots_obj = 991 Interpreter::call1(thread, tuple_type, dunder_slots_obj); 992 if (dunder_slots_obj.isErrorException()) { 993 return *dunder_slots_obj; 994 } 995 CHECK(dunder_slots_obj.isTuple(), "Converting __slots__ to tuple failed"); 996 } 997 Tuple slots_tuple(&scope, *dunder_slots_obj); 998 slots_obj = validateSlots(thread, type, slots_tuple, 999 bases_have_instance_dict, &add_instance_dict); 1000 if (slots_obj.isErrorException()) { 1001 return *slots_obj; 1002 } 1003 if (!slots_obj.isNoneType()) { 1004 List slots(&scope, *slots_obj); 1005 // Add descriptors that mediate access to __slots__ attributes. 1006 Object slot_descriptor(&scope, NoneType::object()); 1007 Object slot_name(&scope, NoneType::object()); 1008 for (word i = 0, num_items = slots.numItems(); i < num_items; i++) { 1009 slot_name = slots.at(i); 1010 slot_descriptor = runtime->newSlotDescriptor(type, slot_name); 1011 typeAtPut(thread, type, slot_name, slot_descriptor); 1012 slots.atPut(i, *slot_descriptor); 1013 } 1014 } 1015 } 1016 1017 if (!slots_obj.isNoneType()) { 1018 flags |= Type::Flag::kHasSlots; 1019 flags |= Type::Flag::kIsFixedAttributeBase; 1020 } 1021 1022 type.setFlags(static_cast<Type::Flag>(flags)); 1023 1024 // Add a `__dict__` descriptor when we added an instance dict. 1025 if (add_instance_dict && 1026 typeAtById(thread, type, ID(__dict__)).isErrorNotFound()) { 1027 typeAddInstanceDict(thread, type); 1028 } 1029 1030 Function type_dunder_call(&scope, 1031 runtime->lookupNameInModule(thread, ID(_builtins), 1032 ID(_type_dunder_call))); 1033 type.setCtor(*type_dunder_call); 1034 1035 result = typeComputeLayout(thread, type, fixed_attr_base, add_instance_dict, 1036 slots_obj); 1037 if (result.isErrorException()) return *result; 1038 1039 result = typeSetNames(thread, type, dict); 1040 if (result.isErrorException()) return *result; 1041 1042 return *type; 1043} 1044 1045// NOTE: Keep the order of these type attributes same as the one from 1046// rewriteOperation. 1047static const SymbolId kUnimplementedTypeAttrUpdates[] = { 1048 // LOAD_ATTR, LOAD_METHOD 1049 ID(__getattribute__), 1050 // STORE_ATTR 1051 ID(__setattr__)}; 1052 1053void terminateIfUnimplementedTypeAttrCacheInvalidation( 1054 Thread* thread, const Type& type, const Object& attr_name) { 1055 RawObject unused = NoneType::object(); 1056 if (!attributeValueCellAt(*type, *attr_name, &unused)) { 1057 // No need for cache invalidation due to the absence of the attribute. 1058 return; 1059 } 1060 Runtime* runtime = thread->runtime(); 1061 DCHECK(Runtime::isInternedStr(thread, attr_name), "expected interned str"); 1062 for (uword i = 0; i < ARRAYSIZE(kUnimplementedTypeAttrUpdates); ++i) { 1063 if (attr_name == runtime->symbols()->at(kUnimplementedTypeAttrUpdates[i])) { 1064 UNIMPLEMENTED("unimplemented cache invalidation for type.%s update", 1065 Str::cast(*attr_name).toCStr()); 1066 } 1067 } 1068} 1069 1070RawObject typeSetAttr(Thread* thread, const Type& type, const Object& name, 1071 const Object& value) { 1072 Runtime* runtime = thread->runtime(); 1073 DCHECK(runtime->isInternedStr(thread, name), 1074 "name must be an interned string"); 1075 // Make sure cache invalidation is correctly done for this. 1076 terminateIfUnimplementedTypeAttrCacheInvalidation(thread, type, name); 1077 HandleScope scope(thread); 1078 if (!type.hasMutableDict()) { 1079 return raiseTypeErrorCannotSetImmutable(thread, type); 1080 } 1081 1082 // Check for a data descriptor 1083 Type metatype(&scope, runtime->typeOf(*type)); 1084 Object meta_attr(&scope, typeLookupInMro(thread, *metatype, *name)); 1085 if (!meta_attr.isError()) { 1086 Type meta_attr_type(&scope, runtime->typeOf(*meta_attr)); 1087 if (typeIsDataDescriptor(*meta_attr_type)) { 1088 Object set_result(&scope, Interpreter::callDescriptorSet( 1089 thread, meta_attr, type, value)); 1090 if (set_result.isError()) return *set_result; 1091 return NoneType::object(); 1092 } 1093 } 1094 1095 // No data descriptor found, store the attribute in the type dict 1096 typeAtPut(thread, type, name, value); 1097 return NoneType::object(); 1098} 1099 1100RawObject typeSetDunderClass(Thread* thread, const Object& self, 1101 const Type& new_type) { 1102 Runtime* runtime = thread->runtime(); 1103 // TODO(T60761420): A module can't change its type since its attributes are 1104 // cached based on object identity (and not layout id). This needs extra 1105 // cache invalidation code here to support it. 1106 if (runtime->isInstanceOfModule(*self)) { 1107 UNIMPLEMENTED("Cannot change type of modules"); 1108 } 1109 1110 HandleScope scope(thread); 1111 Type instance_type(&scope, runtime->typeOf(*self)); 1112 // Builtin base type must match 1113 if (instance_type.builtinBase() != new_type.builtinBase()) { 1114 Str type_name(&scope, new_type.name()); 1115 return thread->raiseWithFmt( 1116 LayoutId::kTypeError, 1117 "__class__ assignment '%T' object layout differs from '%S'", &self, 1118 &type_name); 1119 } 1120 1121 // Handle C Extension types 1122 if (instance_type.hasFlag(RawType::Flag::kHasNativeData) && 1123 new_type.hasFlag(RawType::Flag::kHasNativeData)) { 1124 // TODO(T60752528): Handle __class__ setter for C Extension Types 1125 UNIMPLEMENTED("Check if native memory is compatible"); 1126 } else if (instance_type.hasFlag(RawType::Flag::kHasNativeData) != 1127 new_type.hasFlag(RawType::Flag::kHasNativeData)) { 1128 Str type_name(&scope, new_type.name()); 1129 return thread->raiseWithFmt( 1130 LayoutId::kTypeError, 1131 "__class__ assignment '%T' object layout differs from '%S'", &self, 1132 &type_name); 1133 } 1134 1135 // LOAD_ATTR_TYPE caches attributes based on the instance layout id of the 1136 // type. Create a copy of the layout with a new id, to avoid incorrectly 1137 // hitting the cache. 1138 if (runtime->isInstanceOfType(*self)) { 1139 Type type(&scope, *self); 1140 Layout instance_layout(&scope, type.instanceLayout()); 1141 Layout new_layout(&scope, 1142 runtime->layoutCreateCopy(thread, instance_layout)); 1143 type.setInstanceLayout(*new_layout); 1144 type.setInstanceLayoutId(new_layout.id()); 1145 } 1146 1147 // Transition the layout 1148 Instance instance(&scope, *self); 1149 Layout from_layout(&scope, runtime->layoutOf(*instance)); 1150 Layout new_layout( 1151 &scope, runtime->layoutSetDescribedType(thread, from_layout, new_type)); 1152 instance.setLayoutId(new_layout.id()); 1153 return NoneType::object(); 1154} 1155 1156static const BuiltinAttribute kTypeAttributes[] = { 1157 {ID(_type__attributes), RawType::kAttributesOffset, 1158 AttributeFlags::kHidden}, 1159 {ID(_type__attributes_remaining), RawType::kAttributesRemainingOffset, 1160 AttributeFlags::kHidden}, 1161 {ID(__mro__), RawType::kMroOffset, AttributeFlags::kReadOnly}, 1162 {ID(_type__bases), RawType::kBasesOffset, AttributeFlags::kHidden}, 1163 {ID(_type__instance_layout), RawType::kInstanceLayoutOffset, 1164 AttributeFlags::kHidden}, 1165 {ID(_type__instance_layout_id), RawType::kInstanceLayoutIdOffset, 1166 AttributeFlags::kHidden}, 1167 {ID(_type__name), RawType::kNameOffset, AttributeFlags::kHidden}, 1168 {ID(__doc__), RawType::kDocOffset}, 1169 {ID(_type__flags), RawType::kFlagsOffset, AttributeFlags::kHidden}, 1170 {ID(_type__slots), RawType::kSlotsOffset, AttributeFlags::kHidden}, 1171 {ID(_type__abstract_methods), RawType::kAbstractMethodsOffset, 1172 AttributeFlags::kHidden}, 1173 {ID(_type__subclasses), RawType::kSubclassesOffset, 1174 AttributeFlags::kHidden}, 1175 {ID(_type__proxy), RawType::kProxyOffset, AttributeFlags::kHidden}, 1176 {ID(_type__ctor), RawType::kCtorOffset, AttributeFlags::kHidden}, 1177 {ID(_type__qualname), RawType::kQualnameOffset, AttributeFlags::kHidden}, 1178}; 1179 1180static const BuiltinAttribute kTypeProxyAttributes[] = { 1181 {ID(_type_proxy__type), TypeProxy::kTypeOffset, AttributeFlags::kHidden}, 1182}; 1183 1184void initializeTypeTypes(Thread* thread) { 1185 HandleScope scope(thread); 1186 Type type(&scope, addBuiltinType(thread, ID(type), LayoutId::kType, 1187 /*superclass_id=*/LayoutId::kObject, 1188 kTypeAttributes, Type::kSize, 1189 /*basetype=*/true)); 1190 word flags = static_cast<word>(type.flags()); 1191 flags |= RawType::Flag::kHasCustomDict; 1192 type.setFlags(static_cast<Type::Flag>(flags)); 1193 1194 addBuiltinType(thread, ID(type_proxy), LayoutId::kTypeProxy, 1195 /*superclass_id=*/LayoutId::kObject, kTypeProxyAttributes, 1196 TypeProxy::kSize, /*basetype=*/false); 1197} 1198 1199RawObject METH(type, __base__)(Thread* thread, Arguments args) { 1200 HandleScope scope(thread); 1201 Object self_obj(&scope, args.get(0)); 1202 if (!thread->runtime()->isInstanceOfType(*self_obj)) { 1203 return thread->raiseRequiresType(self_obj, ID(type)); 1204 } 1205 Type self(&scope, *self_obj); 1206 Tuple bases(&scope, self.bases()); 1207 if (bases.length() == 0) { 1208 return NoneType::object(); 1209 } 1210 return computeFixedAttributeBase(thread, bases); 1211} 1212 1213RawObject METH(type, __basicsize__)(Thread* thread, Arguments args) { 1214 HandleScope scope(thread); 1215 Runtime* runtime = thread->runtime(); 1216 Object self_obj(&scope, args.get(0)); 1217 if (!runtime->isInstanceOfType(*self_obj)) { 1218 return thread->raiseRequiresType(self_obj, ID(type)); 1219 } 1220 Type self(&scope, *self_obj); 1221 uword basicsize = typeGetBasicSize(self); 1222 return runtime->newIntFromUnsigned(basicsize); 1223} 1224 1225RawObject METH(type, __delattr__)(Thread* thread, Arguments args) { 1226 HandleScope scope(thread); 1227 Object self_obj(&scope, args.get(0)); 1228 if (!thread->runtime()->isInstanceOfType(*self_obj)) { 1229 return thread->raiseRequiresType(self_obj, ID(type)); 1230 } 1231 Type self(&scope, *self_obj); 1232 Object name(&scope, args.get(1)); 1233 name = attributeName(thread, name); 1234 if (name.isErrorException()) return *name; 1235 return typeDeleteAttribute(thread, self, name); 1236} 1237 1238RawObject METH(type, __flags__)(Thread* thread, Arguments args) { 1239 HandleScope scope(thread); 1240 Object self_obj(&scope, args.get(0)); 1241 Runtime* runtime = thread->runtime(); 1242 if (!runtime->isInstanceOfType(*self_obj)) { 1243 return thread->raiseRequiresType(self_obj, ID(type)); 1244 } 1245 Type self(&scope, *self_obj); 1246 uword cpython_flags = typeGetFlags(self); 1247 return runtime->newIntFromUnsigned(cpython_flags); 1248} 1249 1250RawObject METH(type, __getattribute__)(Thread* thread, Arguments args) { 1251 HandleScope scope(thread); 1252 Object self_obj(&scope, args.get(0)); 1253 Runtime* runtime = thread->runtime(); 1254 if (!runtime->isInstanceOfType(*self_obj)) { 1255 return thread->raiseRequiresType(self_obj, ID(type)); 1256 } 1257 Type self(&scope, *self_obj); 1258 Object name(&scope, args.get(1)); 1259 name = attributeName(thread, name); 1260 if (name.isErrorException()) return *name; 1261 Object result(&scope, typeGetAttribute(thread, self, name)); 1262 if (result.isErrorNotFound()) { 1263 Object type_name(&scope, self.name()); 1264 return thread->raiseWithFmt(LayoutId::kAttributeError, 1265 "type object '%S' has no attribute '%S'", 1266 &type_name, &name); 1267 } 1268 return *result; 1269} 1270 1271RawObject METH(type, __setattr__)(Thread* thread, Arguments args) { 1272 HandleScope scope(thread); 1273 Object self_obj(&scope, args.get(0)); 1274 Runtime* runtime = thread->runtime(); 1275 if (!runtime->isInstanceOfType(*self_obj)) { 1276 return thread->raiseRequiresType(self_obj, ID(type)); 1277 } 1278 Type self(&scope, *self_obj); 1279 Object name(&scope, args.get(1)); 1280 name = attributeName(thread, name); 1281 if (name.isErrorException()) return *name; 1282 Object value(&scope, args.get(2)); 1283 return typeSetAttr(thread, self, name, value); 1284} 1285 1286RawObject METH(type, __subclasses__)(Thread* thread, Arguments args) { 1287 HandleScope scope(thread); 1288 Object self_obj(&scope, args.get(0)); 1289 Runtime* runtime = thread->runtime(); 1290 if (!runtime->isInstanceOfType(*self_obj)) { 1291 return thread->raiseRequiresType(self_obj, ID(type)); 1292 } 1293 Type self(&scope, *self_obj); 1294 Object subclasses_obj(&scope, self.subclasses()); 1295 if (subclasses_obj.isNoneType()) { 1296 return runtime->newList(); 1297 } 1298 1299 // Check list for `None` and compact it. 1300 List subclasses(&scope, *subclasses_obj); 1301 word num_items = subclasses.numItems(); 1302 Object ref(&scope, NoneType::object()); 1303 Object value(&scope, NoneType::object()); 1304 word compact_shift = 0; 1305 for (word i = 0; i < num_items; i++) { 1306 ref = subclasses.at(i); 1307 value = WeakRef::cast(*ref).referent(); 1308 if (value.isNoneType()) { 1309 compact_shift++; 1310 continue; 1311 } 1312 if (compact_shift > 0) { 1313 subclasses.atPut(i - compact_shift, *ref); 1314 } 1315 } 1316 if (compact_shift > 0) { 1317 num_items -= compact_shift; 1318 subclasses.setNumItems(num_items); 1319 } 1320 1321 List result(&scope, runtime->newList()); 1322 runtime->listEnsureCapacity(thread, result, num_items); 1323 for (word i = 0; i < num_items; i++) { 1324 ref = subclasses.at(i); 1325 value = WeakRef::cast(*ref).referent(); 1326 runtime->listAdd(thread, result, value); 1327 } 1328 return *result; 1329} 1330 1331} // namespace py