this repo has no description
at trunk 457 lines 16 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2// dictobject.c implementation 3 4#include "cpython-func.h" 5 6#include "api-handle.h" 7#include "dict-builtins.h" 8#include "handles.h" 9#include "int-builtins.h" 10#include "object-builtins.h" 11#include "objects.h" 12#include "runtime.h" 13#include "str-builtins.h" 14 15namespace py { 16 17PY_EXPORT PyTypeObject* PyDictItems_Type_Ptr() { 18 Runtime* runtime = Thread::current()->runtime(); 19 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference( 20 runtime, runtime->typeAt(LayoutId::kDictItems))); 21} 22 23PY_EXPORT PyTypeObject* PyDictIterItem_Type_Ptr() { 24 Runtime* runtime = Thread::current()->runtime(); 25 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference( 26 runtime, runtime->typeAt(LayoutId::kDictItemIterator))); 27} 28 29PY_EXPORT PyTypeObject* PyDictIterKey_Type_Ptr() { 30 Runtime* runtime = Thread::current()->runtime(); 31 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference( 32 runtime, runtime->typeAt(LayoutId::kDictKeyIterator))); 33} 34 35PY_EXPORT PyTypeObject* PyDictIterValue_Type_Ptr() { 36 Runtime* runtime = Thread::current()->runtime(); 37 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference( 38 runtime, runtime->typeAt(LayoutId::kDictValueIterator))); 39} 40 41PY_EXPORT PyTypeObject* PyDictKeys_Type_Ptr() { 42 Runtime* runtime = Thread::current()->runtime(); 43 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference( 44 runtime, runtime->typeAt(LayoutId::kDictKeys))); 45} 46 47PY_EXPORT PyTypeObject* PyDictValues_Type_Ptr() { 48 Runtime* runtime = Thread::current()->runtime(); 49 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference( 50 runtime, runtime->typeAt(LayoutId::kDictValues))); 51} 52 53PY_EXPORT int PyDict_CheckExact_Func(PyObject* obj) { 54 return ApiHandle::asObject(ApiHandle::fromPyObject(obj)).isDict(); 55} 56 57PY_EXPORT int PyDict_Check_Func(PyObject* obj) { 58 return Thread::current()->runtime()->isInstanceOfDict( 59 ApiHandle::asObject(ApiHandle::fromPyObject(obj))); 60} 61 62PY_EXPORT Py_ssize_t PyDict_GET_SIZE_Func(PyObject* dict) { 63 HandleScope scope(Thread::current()); 64 Dict dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(dict))); 65 return dict_obj.numItems(); 66} 67 68PY_EXPORT int _PyDict_SetItem_KnownHash(PyObject* pydict, PyObject* key, 69 PyObject* value, Py_hash_t pyhash) { 70 Thread* thread = Thread::current(); 71 HandleScope scope(thread); 72 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 73 Runtime* runtime = thread->runtime(); 74 if (!runtime->isInstanceOfDict(*dict_obj)) { 75 thread->raiseBadInternalCall(); 76 return -1; 77 } 78 Dict dict(&scope, *dict_obj); 79 Object key_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(key))); 80 Object value_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(value))); 81 word hash = SmallInt::truncate(pyhash); 82 if (dictAtPut(thread, dict, key_obj, hash, value_obj).isErrorException()) { 83 return -1; 84 } 85 return 0; 86} 87 88PY_EXPORT int PyDict_SetItem(PyObject* pydict, PyObject* key, PyObject* value) { 89 Thread* thread = Thread::current(); 90 HandleScope scope(thread); 91 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 92 if (!thread->runtime()->isInstanceOfDict(*dict_obj)) { 93 thread->raiseBadInternalCall(); 94 return -1; 95 } 96 Dict dict(&scope, *dict_obj); 97 Object key_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(key))); 98 Object value_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(value))); 99 Object hash_obj(&scope, Interpreter::hash(thread, key_obj)); 100 if (hash_obj.isError()) return -1; 101 word hash = SmallInt::cast(*hash_obj).value(); 102 if (dictAtPut(thread, dict, key_obj, hash, value_obj).isErrorException()) { 103 return -1; 104 } 105 return 0; 106} 107 108PY_EXPORT int PyDict_SetItemString(PyObject* pydict, const char* key, 109 PyObject* value) { 110 Thread* thread = Thread::current(); 111 HandleScope scope(thread); 112 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 113 Runtime* runtime = thread->runtime(); 114 if (!runtime->isInstanceOfDict(*dict_obj)) { 115 thread->raiseBadInternalCall(); 116 return -1; 117 } 118 Dict dict(&scope, *dict_obj); 119 Str key_obj(&scope, Runtime::internStrFromCStr(thread, key)); 120 Object value_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(value))); 121 word hash = strHash(thread, *key_obj); 122 if (dictAtPut(thread, dict, key_obj, hash, value_obj).isErrorException()) { 123 return -1; 124 } 125 return 0; 126} 127 128PY_EXPORT PyTypeObject* PyDict_Type_Ptr() { 129 Runtime* runtime = Thread::current()->runtime(); 130 return reinterpret_cast<PyTypeObject*>( 131 ApiHandle::borrowedReference(runtime, runtime->typeAt(LayoutId::kDict))); 132} 133 134PY_EXPORT PyObject* PyDict_New() { 135 Runtime* runtime = Thread::current()->runtime(); 136 return ApiHandle::newReferenceWithManaged(runtime, runtime->newDict()); 137} 138 139static PyObject* getItem(Thread* thread, const Object& dict_obj, 140 const Object& key) { 141 HandleScope scope(thread); 142 // For historical reasons, PyDict_GetItem supresses all errors that may occur. 143 Runtime* runtime = thread->runtime(); 144 if (!runtime->isInstanceOfDict(*dict_obj)) { 145 return nullptr; 146 } 147 Dict dict(&scope, *dict_obj); 148 Object hash_obj(&scope, Interpreter::hash(thread, key)); 149 if (hash_obj.isError()) { 150 thread->clearPendingException(); 151 return nullptr; 152 } 153 word hash = SmallInt::cast(*hash_obj).value(); 154 Object result(&scope, dictAt(thread, dict, key, hash)); 155 if (result.isErrorException()) { 156 thread->clearPendingException(); 157 return nullptr; 158 } 159 if (result.isErrorNotFound()) { 160 return nullptr; 161 } 162 return ApiHandle::borrowedReference(runtime, *result); 163} 164 165PY_EXPORT PyObject* _PyDict_GetItem_KnownHash(PyObject* pydict, PyObject* key, 166 Py_hash_t pyhash) { 167 Thread* thread = Thread::current(); 168 HandleScope scope(thread); 169 Object dictobj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 170 Runtime* runtime = thread->runtime(); 171 if (!runtime->isInstanceOfDict(*dictobj)) { 172 thread->raiseBadInternalCall(); 173 return nullptr; 174 } 175 Dict dict(&scope, *dictobj); 176 Object key_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(key))); 177 word hash = SmallInt::truncate(pyhash); 178 Object value(&scope, dictAt(thread, dict, key_obj, hash)); 179 if (value.isError()) return nullptr; 180 return ApiHandle::borrowedReference(runtime, *value); 181} 182 183PY_EXPORT PyObject* PyDict_GetItem(PyObject* pydict, PyObject* key) { 184 Thread* thread = Thread::current(); 185 HandleScope scope(thread); 186 Object dict(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 187 Object key_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(key))); 188 return getItem(thread, dict, key_obj); 189} 190 191PY_EXPORT PyObject* PyDict_GetItemString(PyObject* pydict, const char* key) { 192 Thread* thread = Thread::current(); 193 HandleScope scope(thread); 194 Object dict(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 195 Object key_obj(&scope, thread->runtime()->newStrFromCStr(key)); 196 return getItem(thread, dict, key_obj); 197} 198 199PY_EXPORT void PyDict_Clear(PyObject* pydict) { 200 Thread* thread = Thread::current(); 201 HandleScope scope(thread); 202 Runtime* runtime = thread->runtime(); 203 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 204 if (!runtime->isInstanceOfDict(*dict_obj)) { 205 return; 206 } 207 Dict dict(&scope, *dict_obj); 208 dict.setNumItems(0); 209 dict.setData(runtime->emptyTuple()); 210} 211 212PY_EXPORT int PyDict_Contains(PyObject* pydict, PyObject* key) { 213 Thread* thread = Thread::current(); 214 HandleScope scope(thread); 215 Dict dict(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 216 Object key_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(key))); 217 Object hash_obj(&scope, Interpreter::hash(thread, key_obj)); 218 if (hash_obj.isErrorException()) return -1; 219 word hash = SmallInt::cast(*hash_obj).value(); 220 Object result(&scope, dictIncludes(thread, dict, key_obj, hash)); 221 if (result.isErrorException()) return -1; 222 return Bool::cast(*result).value(); 223} 224 225PY_EXPORT PyObject* PyDict_Copy(PyObject* pydict) { 226 Thread* thread = Thread::current(); 227 if (pydict == nullptr) { 228 thread->raiseBadInternalCall(); 229 return nullptr; 230 } 231 HandleScope scope(thread); 232 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 233 Runtime* runtime = thread->runtime(); 234 if (!runtime->isInstanceOfDict(*dict_obj)) { 235 thread->raiseBadInternalCall(); 236 return nullptr; 237 } 238 Dict dict(&scope, *dict_obj); 239 return ApiHandle::newReferenceWithManaged(runtime, dictCopy(thread, dict)); 240} 241 242PY_EXPORT int PyDict_DelItem(PyObject* pydict, PyObject* key) { 243 Thread* thread = Thread::current(); 244 HandleScope scope(thread); 245 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 246 Runtime* runtime = thread->runtime(); 247 if (!runtime->isInstanceOfDict(*dict_obj)) { 248 thread->raiseBadInternalCall(); 249 return -1; 250 } 251 Dict dict(&scope, *dict_obj); 252 Object key_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(key))); 253 Object hash_obj(&scope, Interpreter::hash(thread, key_obj)); 254 if (hash_obj.isErrorException()) return -1; 255 word hash = SmallInt::cast(*hash_obj).value(); 256 if (dictRemove(thread, dict, key_obj, hash).isError()) { 257 thread->raise(LayoutId::kKeyError, *key_obj); 258 return -1; 259 } 260 return 0; 261} 262 263PY_EXPORT int PyDict_DelItemString(PyObject* pydict, const char* key) { 264 PyObject* str = PyUnicode_FromString(key); 265 if (str == nullptr) return -1; 266 int result = PyDict_DelItem(pydict, str); 267 Py_DECREF(str); 268 return result; 269} 270 271PY_EXPORT PyObject* PyDict_GetItemWithError(PyObject* pydict, PyObject* key) { 272 Thread* thread = Thread::current(); 273 HandleScope scope(thread); 274 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 275 Runtime* runtime = thread->runtime(); 276 if (!runtime->isInstanceOfDict(*dict_obj)) { 277 thread->raiseBadInternalCall(); 278 return nullptr; 279 } 280 281 Object key_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(key))); 282 Object hash_obj(&scope, Interpreter::hash(thread, key_obj)); 283 if (hash_obj.isErrorException()) return nullptr; 284 word hash = SmallInt::cast(*hash_obj).value(); 285 Dict dict(&scope, *dict_obj); 286 Object value(&scope, dictAt(thread, dict, key_obj, hash)); 287 if (value.isError()) { 288 return nullptr; 289 } 290 return ApiHandle::borrowedReference(runtime, *value); 291} 292 293PY_EXPORT PyObject* PyDict_Items(PyObject* pydict) { 294 Thread* thread = Thread::current(); 295 HandleScope scope(thread); 296 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 297 Runtime* runtime = thread->runtime(); 298 if (!runtime->isInstanceOfDict(*dict_obj)) { 299 thread->raiseBadInternalCall(); 300 return nullptr; 301 } 302 Dict dict(&scope, *dict_obj); 303 word len = dict.numItems(); 304 if (len == 0) { 305 return ApiHandle::newReferenceWithManaged(runtime, runtime->newList()); 306 } 307 308 List result(&scope, runtime->newList()); 309 MutableTuple items(&scope, runtime->newMutableTuple(len)); 310 Object key(&scope, NoneType::object()); 311 Object value(&scope, NoneType::object()); 312 for (word i = 0, j = 0; dictNextItem(dict, &i, &key, &value);) { 313 items.atPut(j++, runtime->newTupleWith2(key, value)); 314 } 315 result.setItems(*items); 316 result.setNumItems(len); 317 return ApiHandle::newReferenceWithManaged(runtime, *result); 318} 319 320PY_EXPORT PyObject* PyDict_Keys(PyObject* pydict) { 321 Thread* thread = Thread::current(); 322 HandleScope scope(thread); 323 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 324 Runtime* runtime = thread->runtime(); 325 if (!runtime->isInstanceOfDict(*dict_obj)) { 326 thread->raiseBadInternalCall(); 327 return nullptr; 328 } 329 Dict dict(&scope, *dict_obj); 330 return ApiHandle::newReferenceWithManaged(runtime, dictKeys(thread, dict)); 331} 332 333PY_EXPORT int PyDict_Merge(PyObject* left, PyObject* right, 334 int override_matching) { 335 CHECK_BOUND(override_matching, 2); 336 Thread* thread = Thread::current(); 337 if (left == nullptr || right == nullptr) { 338 thread->raiseBadInternalCall(); 339 return -1; 340 } 341 HandleScope scope(thread); 342 Object left_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(left))); 343 if (!thread->runtime()->isInstanceOfDict(*left_obj)) { 344 thread->raiseBadInternalCall(); 345 return -1; 346 } 347 Dict left_dict(&scope, *left_obj); 348 Object right_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(right))); 349 auto merge_func = override_matching ? dictMergeOverride : dictMergeIgnore; 350 if ((*merge_func)(thread, left_dict, right_obj).isError()) { 351 return -1; 352 } 353 return 0; 354} 355 356PY_EXPORT int PyDict_MergeFromSeq2(PyObject* /* d */, PyObject* /* 2 */, 357 int /* e */) { 358 UNIMPLEMENTED("PyDict_MergeFromSeq2"); 359} 360 361PY_EXPORT int _PyDict_Next(PyObject* dict, Py_ssize_t* ppos, PyObject** pkey, 362 PyObject** pvalue, Py_hash_t* phash) { 363 Thread* thread = Thread::current(); 364 HandleScope scope(thread); 365 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(dict))); 366 Runtime* runtime = thread->runtime(); 367 if (!runtime->isInstanceOfDict(*dict_obj)) { 368 return 0; 369 } 370 Dict dict_dict(&scope, *dict_obj); 371 // Below are all the possible statuses of ppos and what to do in each case. 372 // * If an index is out of bounds, we should not advance. 373 // * If an index does not point to a valid bucket, we should try and find the 374 // next bucket, or fail. 375 // * Read the contents of that bucket. 376 // * Advance the index. 377 Object key(&scope, NoneType::object()); 378 Object value(&scope, NoneType::object()); 379 word hash; 380 if (!dictNextItemHash(dict_dict, ppos, &key, &value, &hash)) { 381 return 0; 382 } 383 // At this point, we will always have a valid bucket index. 384 if (pkey != nullptr) *pkey = ApiHandle::borrowedReference(runtime, *key); 385 if (pvalue != nullptr) { 386 *pvalue = ApiHandle::borrowedReference(runtime, *value); 387 } 388 if (phash != nullptr) *phash = hash; 389 return true; 390} 391 392PY_EXPORT int PyDict_Next(PyObject* dict, Py_ssize_t* ppos, PyObject** pkey, 393 PyObject** pvalue) { 394 return _PyDict_Next(dict, ppos, pkey, pvalue, nullptr); 395} 396 397PY_EXPORT Py_ssize_t PyDict_Size(PyObject* p) { 398 Thread* thread = Thread::current(); 399 Runtime* runtime = thread->runtime(); 400 HandleScope scope(thread); 401 402 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(p))); 403 if (!runtime->isInstanceOfDict(*dict_obj)) { 404 thread->raiseBadInternalCall(); 405 return -1; 406 } 407 408 Dict dict(&scope, *dict_obj); 409 return dict.numItems(); 410} 411 412PY_EXPORT int PyDict_Update(PyObject* left, PyObject* right) { 413 return PyDict_Merge(left, right, 1); 414} 415 416PY_EXPORT PyObject* PyDict_Values(PyObject* pydict) { 417 Thread* thread = Thread::current(); 418 HandleScope scope(thread); 419 Object dict_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pydict))); 420 Runtime* runtime = thread->runtime(); 421 if (!runtime->isInstanceOfDict(*dict_obj)) { 422 thread->raiseBadInternalCall(); 423 return nullptr; 424 } 425 Dict dict(&scope, *dict_obj); 426 word len = dict.numItems(); 427 if (len == 0) { 428 return ApiHandle::newReferenceWithManaged(runtime, runtime->newList()); 429 } 430 431 List result(&scope, runtime->newList()); 432 MutableTuple values(&scope, runtime->newMutableTuple(len)); 433 Object value(&scope, NoneType::object()); 434 for (word i = 0, j = 0; dictNextValue(dict, &i, &value);) { 435 values.atPut(j++, *value); 436 } 437 result.setItems(*values); 438 result.setNumItems(len); 439 return ApiHandle::newReferenceWithManaged(runtime, *result); 440} 441 442PY_EXPORT PyObject* PyObject_GenericGetDict(PyObject* obj, void*) { 443 Thread* thread = Thread::current(); 444 HandleScope scope(thread); 445 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj))); 446 Runtime* runtime = thread->runtime(); 447 Object name(&scope, runtime->symbols()->at(ID(__dict__))); 448 Object dict(&scope, objectGetAttribute(thread, object, name)); 449 if (dict.isError()) { 450 thread->raiseWithFmt(LayoutId::kAttributeError, 451 "This object has no __dict__"); 452 return nullptr; 453 } 454 return ApiHandle::newReference(runtime, *dict); 455} 456 457} // namespace py