@@ -182,13 +182,105 @@ bool SplitMutator::ensureValueOffset(BorrowedRef<> name) {
182182 }
183183 }
184184#else
185- assert (val_offset != -1 );
185+ JIT_DCHECK (
186+ val_offset != -1 ,
187+ " Value offset not set for {} on split dict instance" ,
188+ repr (name));
186189#endif
187190 return true ;
188191}
189192
193+ #if PY_VERSION_HEX >= 0x030E0000
194+ PyObject* SplitMutator::getAttrInline (PyObject* obj, PyObject* name) {
195+ if (!ensureValueOffset (name)) {
196+ return PyObject_GetAttr (obj, name);
197+ }
198+ PyDictValues* values = _PyObject_InlineValues (obj);
199+ if (!values->valid ) {
200+ return getAttr (obj, name);
201+ }
202+ PyObject* result = values->values [val_offset];
203+ if (result == nullptr ) {
204+ return raise_attribute_error (obj, name);
205+ }
206+ return Py_NewRef (result);
207+ }
208+
209+ PyObject* SplitMutator::getAttr (PyObject* obj, PyObject* name) {
210+ BorrowedRef<PyDictObject> dict = _PyObject_GetManagedDict (obj);
211+
212+ JIT_DCHECK (
213+ PyDict_Check (dict), " Expected dict, got {}" , Py_TYPE (dict)->tp_name );
214+
215+ if (dict == nullptr ) {
216+ return PyObject_GetAttr (obj, name);
217+ }
218+ if (!ensureValueOffset (name) || dict->ma_keys != keys) {
219+ // Slow path
220+ PyObject* attr_o;
221+ int res = [&] {
222+ auto strong_ref = Ref<>::create (dict);
223+ return PyDict_GetItemRef (dict, name, &attr_o);
224+ }();
225+ if (res == 0 ) {
226+ return raise_attribute_error (obj, name);
227+ }
228+ if (res == -1 ) {
229+ return nullptr ;
230+ }
231+ return attr_o;
232+ }
233+ JIT_DCHECK (
234+ DK_IS_UNICODE (keys) && val_offset < keys->dk_nentries ,
235+ " Expected dictionary keys object to change" );
236+ PyObject* attr_o = dict->ma_values ->values [val_offset];
237+ if (attr_o == nullptr ) {
238+ return raise_attribute_error (obj, name);
239+ }
240+ return Py_NewRef (attr_o);
241+ }
242+
243+ int SplitMutator::setAttrInline (
244+ PyObject* obj,
245+ PyObject* name,
246+ PyObject* value) {
247+ if (!ensureValueOffset (name)) {
248+ return PyObject_SetAttr (obj, name, value);
249+ }
250+ PyDictValues* values = _PyObject_InlineValues (obj);
251+ PyDictObject* dict = _PyObject_GetManagedDict (obj);
252+ if (!values->valid || dict) {
253+ return setAttr (obj, name, value);
254+ }
255+ auto old_value = Ref<>::steal (values->values [val_offset]);
256+ values->values [val_offset] = Py_NewRef (value);
257+ if (!old_value) {
258+ _PyDictValues_AddToInsertionOrder (values, val_offset);
259+ }
260+ return 0 ;
261+ }
262+
263+ int SplitMutator::setAttr (PyObject* obj, PyObject* name, PyObject* value) {
264+ if (!ensureValueOffset (name)) {
265+ return PyObject_SetAttr (obj, name, value);
266+ }
267+ BorrowedRef<PyDictObject> dict = _PyObject_GetManagedDict (obj);
268+ if (dict == nullptr ) {
269+ return PyObject_SetAttr (obj, name, value);
270+ }
271+ if (keys != dict->ma_keys ) {
272+ // Slow path
273+ auto strong_ref = Ref<>::create (dict);
274+ return PyDict_SetItem (dict, name, value);
275+ }
276+ Cix_dict_insert_split_value (
277+ _PyInterpreterState_GET (), dict, name, value, val_offset);
278+ return 0 ;
279+ }
280+
281+ #else
282+
190283int SplitMutator::setAttr (PyObject* obj, PyObject* name, PyObject* value) {
191- #if PY_VERSION_HEX < 0x030E0000 // TASK(T229234686)
192284#if PY_VERSION_HEX >= 0x030C0000
193285 PyDictOrValues dorv = *_PyObject_DictOrValuesPointer (obj);
194286 if (_PyDictOrValues_IsValues (dorv)) {
@@ -212,7 +304,8 @@ int SplitMutator::setAttr(PyObject* obj, PyObject* name, PyObject* value) {
212304 // Dictionary has been materialized but may still be using shared keys.
213305 BorrowedRef<PyDictObject> dict = (PyDictObject*)_PyDictOrValues_GetDict (dorv);
214306 if (dict == nullptr ) {
215- dict = (PyDictObject*)PyObject_GenericGetDict (obj, nullptr );
307+ dict =
308+ reinterpret_cast <PyDictObject*>(PyObject_GenericGetDict (obj, nullptr ));
216309 if (dict == nullptr ) {
217310 return -1 ;
218311 }
@@ -255,16 +348,11 @@ int SplitMutator::setAttr(PyObject* obj, PyObject* name, PyObject* value) {
255348
256349 return 0 ;
257350 }
258-
259351 auto strong_ref = Ref<>::create (dict);
260352 return PyDict_SetItem (dict, name, value);
261- #else
262- return 0 ;
263- #endif
264353}
265354
266355PyObject* SplitMutator::getAttr (PyObject* obj, PyObject* name) {
267- #if PY_VERSION_HEX < 0x030E0000
268356#if PY_VERSION_HEX >= 0x030C0000
269357 PyDictOrValues dorv = *_PyObject_DictOrValuesPointer (obj);
270358 if (_PyDictOrValues_IsValues (dorv)) {
@@ -306,10 +394,8 @@ PyObject* SplitMutator::getAttr(PyObject* obj, PyObject* name) {
306394 }
307395 Py_INCREF (result);
308396 return result;
309- #else
310- return nullptr ;
311- #endif
312397}
398+ #endif // PY_VERSION_HEX < 0x030E0000
313399
314400int CombinedMutator::setAttr (PyObject* obj, PyObject* name, PyObject* value) {
315401 BorrowedRef<PyDictObject> dict = get_or_allocate_dict (obj, dict_offset);
@@ -470,17 +556,22 @@ void AttributeMutator::set_descr_or_classvar(
470556void AttributeMutator::set_split (
471557 PyTypeObject* type,
472558 Py_ssize_t val_offset,
473- PyDictKeysObject* keys) {
474- set_type (type, Kind::kSplit );
559+ [[maybe_unused]] PyDictKeysObject* keys,
560+ bool inline_values) {
561+ set_type (type, inline_values ? Kind::kSplitInline : Kind::kSplit );
562+ #if PY_VERSION_HEX >= 0x030C0000
563+ split_.val_offset = val_offset;
564+ split_.keys = keys;
565+ #else
475566 JIT_CHECK (
476567 type->tp_dictoffset <= std::numeric_limits<uint32_t >::max (),
477568 " Dict offset does not fit into a 32-bit int" );
569+ split_.dict_offset = static_cast <uint32_t >(type->tp_dictoffset );
478570 JIT_CHECK (
479- val_offset <= std::numeric_limits<uint32_t >::max (),
571+ val_offset <= std::numeric_limits<int32_t >::max (),
480572 " Val offset does not fit into a 32-bit int" );
481- split_.dict_offset = static_cast <uint32_t >(type->tp_dictoffset );
482- split_.val_offset = static_cast <uint32_t >(val_offset);
483- split_.keys = keys;
573+ split_.val_offset = static_cast <int32_t >(val_offset);
574+ #endif
484575}
485576
486577inline int
@@ -489,6 +580,10 @@ AttributeMutator::setAttr(PyObject* obj, PyObject* name, PyObject* value) {
489580 switch (kind) {
490581 case AttributeMutator::Kind::kSplit :
491582 return split_.setAttr (obj, name, value);
583+ #if PY_VERSION_HEX >= 0x030E0000
584+ case AttributeMutator::Kind::kSplitInline :
585+ return split_.setAttrInline (obj, name, value);
586+ #endif
492587 case AttributeMutator::Kind::kCombined :
493588 return combined_.setAttr (obj, name, value);
494589 case AttributeMutator::Kind::kDataDescr :
@@ -508,6 +603,10 @@ inline PyObject* AttributeMutator::getAttr(PyObject* obj, PyObject* name) {
508603 switch (kind) {
509604 case AttributeMutator::Kind::kSplit :
510605 return split_.getAttr (obj, name);
606+ #if PY_VERSION_HEX >= 0x030E0000
607+ case AttributeMutator::Kind::kSplitInline :
608+ return split_.getAttrInline (obj, name);
609+ #endif
511610 case AttributeMutator::Kind::kCombined :
512611 return combined_.getAttr (obj, name);
513612 case AttributeMutator::Kind::kDataDescr :
@@ -636,6 +735,10 @@ void AttributeCache::fill(
636735 }
637736
638737 if (descr != nullptr ) {
738+ // Not yet working.
739+ if (PY_VERSION_HEX >= 0x030E0000 ) {
740+ return ;
741+ }
639742 BorrowedRef<PyTypeObject> descr_type (Py_TYPE (descr));
640743 if (descr_type->tp_descr_get != nullptr &&
641744 descr_type->tp_descr_set != nullptr ) {
@@ -671,20 +774,21 @@ void AttributeCache::fill(
671774
672775 // Instance attribute with no shadowing. Specialize the lookup based on
673776 // whether or not the type is using split dictionaries.
674- #if PY_VERSION_HEX < 0x030E0000 // TASK(T229234686)
675777 PyDictKeysObject* keys = getSplitKeys (type);
676778#if PY_VERSION_HEX >= 0x030C0000
677779 if (PyType_HasFeature (type, Py_TPFLAGS_MANAGED_DICT)) {
678- assert (keys != nullptr );
679- mut->set_split (type, getDictKeysIndex (keys, name), keys);
780+ JIT_DCHECK (keys != nullptr , " Managed dict should have a split dict" );
781+ bool inline_values = false ;
782+ #if PY_VERSION_HEX >= 0x030E0000
783+ inline_values = type->tp_flags & Py_TPFLAGS_INLINE_VALUES;
784+ #endif
785+ mut->set_split (type, getDictKeysIndex (keys, name), keys, inline_values);
680786#else
681787 Py_ssize_t val_offset;
682788 if (keys != nullptr && (val_offset = getDictKeysIndex (keys, name)) != -1 ) {
683- mut->set_split (type, val_offset, keys);
789+ mut->set_split (type, val_offset, keys, false );
684790#endif
685- } else
686- #endif
687- {
791+ } else {
688792 mut->set_combined (type);
689793 }
690794 ac_watcher.watch (type, this );
0 commit comments