this repo has no description
at trunk 250 lines 11 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <cmath> 3 4#include "cpython-data.h" 5#include "cpython-func.h" 6 7#include "api-handle.h" 8#include "runtime.h" 9#include "set-builtins.h" 10#include "tuple-builtins.h" 11 12namespace py { 13 14static_assert(RawCode::Flags::kOptimized == CO_OPTIMIZED, ""); 15static_assert(RawCode::Flags::kNewlocals == CO_NEWLOCALS, ""); 16static_assert(RawCode::Flags::kVarargs == CO_VARARGS, ""); 17static_assert(RawCode::Flags::kVarkeyargs == CO_VARKEYWORDS, ""); 18static_assert(RawCode::Flags::kNested == CO_NESTED, ""); 19static_assert(RawCode::Flags::kGenerator == CO_GENERATOR, ""); 20static_assert(RawCode::Flags::kNofree == CO_NOFREE, ""); 21static_assert(RawCode::Flags::kCoroutine == CO_COROUTINE, ""); 22static_assert(RawCode::Flags::kIterableCoroutine == CO_ITERABLE_COROUTINE, ""); 23static_assert(RawCode::Flags::kAsyncGenerator == CO_ASYNC_GENERATOR, ""); 24static_assert(RawCode::Flags::kFutureDivision == CO_FUTURE_DIVISION, ""); 25static_assert(RawCode::Flags::kFutureAbsoluteImport == 26 CO_FUTURE_ABSOLUTE_IMPORT, 27 ""); 28static_assert(RawCode::Flags::kFutureWithStatement == CO_FUTURE_WITH_STATEMENT, 29 ""); 30static_assert(RawCode::Flags::kFuturePrintFunction == CO_FUTURE_PRINT_FUNCTION, 31 ""); 32static_assert(RawCode::Flags::kFutureUnicodeLiterals == 33 CO_FUTURE_UNICODE_LITERALS, 34 ""); 35static_assert(RawCode::Flags::kFutureBarryAsBdfl == CO_FUTURE_BARRY_AS_BDFL, 36 ""); 37static_assert(RawCode::Flags::kFutureGeneratorStop == CO_FUTURE_GENERATOR_STOP, 38 ""); 39 40PY_EXPORT int PyCode_Check_Func(PyObject* obj) { 41 return ApiHandle::asObject(ApiHandle::fromPyObject(obj)).isCode(); 42} 43 44PY_EXPORT PyCodeObject* PyCode_NewWithPosOnlyArgs( 45 int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, 46 int stacksize, int flags, PyObject* code, PyObject* consts, PyObject* names, 47 PyObject* varnames, PyObject* freevars, PyObject* cellvars, 48 PyObject* filename, PyObject* name, int firstlineno, PyObject* lnotab) { 49 Thread* thread = Thread::current(); 50 if (argcount < 0 || posonlyargcount < 0 || kwonlyargcount < 0 || 51 nlocals < 0 || code == nullptr || consts == nullptr || names == nullptr || 52 varnames == nullptr || freevars == nullptr || cellvars == nullptr || 53 name == nullptr || filename == nullptr || lnotab == nullptr) { 54 thread->raiseBadInternalCall(); 55 return nullptr; 56 } 57 HandleScope scope(thread); 58 Object consts_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(consts))); 59 Object names_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(names))); 60 Object varnames_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(varnames))); 61 Object freevars_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(freevars))); 62 Object cellvars_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(cellvars))); 63 Object name_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(name))); 64 Object filename_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(filename))); 65 Object lnotab_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(lnotab))); 66 Object code_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(code))); 67 Runtime* runtime = thread->runtime(); 68 // Check argument types 69 // TODO(emacs): Call equivalent of PyObject_CheckReadBuffer(code) instead of 70 // isInstanceOfBytes 71 if (!runtime->isInstanceOfBytes(*code_obj) || 72 !runtime->isInstanceOfTuple(*consts_obj) || 73 !runtime->isInstanceOfTuple(*names_obj) || 74 !runtime->isInstanceOfTuple(*varnames_obj) || 75 !runtime->isInstanceOfTuple(*freevars_obj) || 76 !runtime->isInstanceOfTuple(*cellvars_obj) || 77 !runtime->isInstanceOfStr(*name_obj) || 78 !runtime->isInstanceOfStr(*filename_obj) || 79 !runtime->isInstanceOfBytes(*lnotab_obj)) { 80 thread->raiseBadInternalCall(); 81 return nullptr; 82 } 83 84 return reinterpret_cast<PyCodeObject*>(ApiHandle::newReferenceWithManaged( 85 runtime, 86 runtime->newCode(argcount, posonlyargcount, kwonlyargcount, nlocals, 87 stacksize, flags, code_obj, consts_obj, names_obj, 88 varnames_obj, freevars_obj, cellvars_obj, filename_obj, 89 name_obj, firstlineno, lnotab_obj))); 90} 91 92PY_EXPORT PyCodeObject* PyCode_New(int argcount, int kwonlyargcount, 93 int nlocals, int stacksize, int flags, 94 PyObject* code, PyObject* consts, 95 PyObject* names, PyObject* varnames, 96 PyObject* freevars, PyObject* cellvars, 97 PyObject* filename, PyObject* name, 98 int firstlineno, PyObject* lnotab) { 99 return PyCode_NewWithPosOnlyArgs( 100 argcount, /*posonlyargcount=*/0, kwonlyargcount, nlocals, stacksize, 101 flags, code, consts, names, varnames, freevars, cellvars, filename, name, 102 firstlineno, lnotab); 103} 104 105PY_EXPORT PyCodeObject* PyCode_NewEmpty(const char* filename, 106 const char* funcname, int firstlineno) { 107 Thread* thread = Thread::current(); 108 HandleScope scope(thread); 109 Runtime* runtime = thread->runtime(); 110 Object empty_bytes(&scope, Bytes::empty()); 111 Object empty_tuple(&scope, runtime->emptyTuple()); 112 Object filename_obj(&scope, Runtime::internStrFromCStr(thread, filename)); 113 Object name_obj(&scope, Runtime::internStrFromCStr(thread, funcname)); 114 return reinterpret_cast<PyCodeObject*>(ApiHandle::newReferenceWithManaged( 115 runtime, runtime->newCode(/*argcount=*/0, 116 /*posonlyargcount=*/0, 117 /*kwonlyargcount=*/0, 118 /*nlocals=*/0, 119 /*stacksize=*/0, 120 /*flags=*/0, 121 /*code=*/empty_bytes, 122 /*consts=*/empty_tuple, 123 /*names=*/empty_tuple, 124 /*varnames=*/empty_tuple, 125 /*freevars=*/empty_tuple, 126 /*cellvars=*/empty_tuple, 127 /*filename=*/filename_obj, 128 /*name=*/name_obj, 129 /*firstlineno=*/firstlineno, 130 /*lnotab=*/empty_bytes))); 131} 132 133PY_EXPORT PyTypeObject* PyCode_Type_Ptr() { 134 Runtime* runtime = Thread::current()->runtime(); 135 return reinterpret_cast<PyTypeObject*>( 136 ApiHandle::borrowedReference(runtime, runtime->typeAt(LayoutId::kCode))); 137} 138 139PY_EXPORT Py_ssize_t PyCode_GetNumFree_Func(PyObject* code) { 140 DCHECK(code != nullptr, "code must not be null"); 141 Thread* thread = Thread::current(); 142 HandleScope scope(thread); 143 Object code_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(code))); 144 DCHECK(code_obj.isCode(), "code must be a code object"); 145 Code code_code(&scope, *code_obj); 146 Tuple freevars(&scope, code_code.freevars()); 147 return freevars.length(); 148} 149 150static RawObject constantKey(Thread* thread, const Object& obj) { 151 HandleScope scope(thread); 152 Runtime* runtime = thread->runtime(); 153 if (obj.isNoneType() || obj.isEllipsis() || obj.isSmallInt() || 154 obj.isLargeInt() || obj.isStr() || obj.isCode()) { 155 return *obj; 156 } 157 if (obj.isBool() || obj.isBytes()) { 158 Object type(&scope, runtime->typeOf(*obj)); 159 return runtime->newTupleWith2(type, obj); 160 } 161 if (obj.isFloat()) { 162 double d = Float::cast(*obj).value(); 163 Object type(&scope, runtime->typeOf(*obj)); 164 if (d == 0.0 && std::signbit(d)) { 165 Object none(&scope, NoneType::object()); 166 return runtime->newTupleWith3(type, obj, none); 167 } 168 return runtime->newTupleWith2(type, obj); 169 } 170 if (obj.isComplex()) { 171 Complex c(&scope, *obj); 172 Py_complex z; 173 z.real = c.real(); 174 z.imag = c.imag(); 175 // For the complex case we must make complex(x, 0.) 176 // different from complex(x, -0.) and complex(0., y) 177 // different from complex(-0., y), for any x and y. 178 // All four complex zeros must be distinguished. 179 bool real_negzero = z.real == 0.0 && std::signbit(z.real); 180 bool imag_negzero = z.imag == 0.0 && std::signbit(z.imag); 181 // use True, False and None singleton as tags for the real and imag sign, 182 // to make tuples different 183 Object type(&scope, runtime->typeOf(*obj)); 184 if (real_negzero && imag_negzero) { 185 Object tru(&scope, Bool::trueObj()); 186 return runtime->newTupleWith3(type, obj, tru); 187 } 188 if (imag_negzero) { 189 Object fals(&scope, Bool::falseObj()); 190 return runtime->newTupleWith3(type, obj, fals); 191 } 192 if (real_negzero) { 193 Object none(&scope, NoneType::object()); 194 return runtime->newTupleWith3(type, obj, none); 195 } 196 return runtime->newTupleWith2(type, obj); 197 } 198 if (obj.isTuple()) { 199 Tuple tuple(&scope, *obj); 200 Object result_obj(&scope, NoneType::object()); 201 word length = tuple.length(); 202 if (length > 0) { 203 MutableTuple result(&scope, runtime->newMutableTuple(length)); 204 Object item(&scope, NoneType::object()); 205 Object item_key(&scope, NoneType::object()); 206 for (word i = 0; i < length; i++) { 207 item = tuple.at(i); 208 item_key = constantKey(thread, item); 209 if (item_key.isError()) return *item_key; 210 result.atPut(i, *item_key); 211 } 212 result_obj = result.becomeImmutable(); 213 } else { 214 result_obj = runtime->emptyTuple(); 215 } 216 return runtime->newTupleWith2(result_obj, obj); 217 } 218 if (obj.isFrozenSet()) { 219 FrozenSet set(&scope, *obj); 220 FrozenSet result(&scope, runtime->newFrozenSet()); 221 Object item(&scope, NoneType::object()); 222 Object item_key(&scope, NoneType::object()); 223 Object hash_obj(&scope, NoneType::object()); 224 for (word idx = 0; setNextItem(set, &idx, &item);) { 225 item_key = constantKey(thread, item); 226 if (item_key.isError()) return *item_key; 227 hash_obj = Interpreter::hash(thread, item_key); 228 if (hash_obj.isErrorException()) return *hash_obj; 229 setAdd(thread, result, item_key, SmallInt::cast(*hash_obj).value()); 230 } 231 return runtime->newTupleWith2(result, obj); 232 } 233 PyObject* ptr = ApiHandle::borrowedReference(runtime, *obj); 234 Object obj_id(&scope, runtime->newInt(reinterpret_cast<word>(ptr))); 235 return runtime->newTupleWith2(obj_id, obj); 236} 237 238PY_EXPORT PyObject* _PyCode_ConstantKey(PyObject* op) { 239 DCHECK(op != nullptr, "op must not be null"); 240 Thread* thread = Thread::current(); 241 HandleScope scope(thread); 242 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(op))); 243 Object result(&scope, constantKey(thread, obj)); 244 if (result.isError()) { 245 return nullptr; 246 } 247 return ApiHandle::newReference(thread->runtime(), *result); 248} 249 250} // namespace py