this repo has no description
at trunk 250 lines 8.8 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "cpython-data.h" 3#include "cpython-func.h" 4 5#include "api-handle.h" 6#include "dict-builtins.h" 7#include "module-builtins.h" 8#include "runtime.h" 9 10namespace py { 11 12PY_EXPORT PyObject* PyEval_GetBuiltins() { 13 // TODO(T66852536): For full compatibility, try looking up on current frame 14 // first and then use the Runtime-cached builtins 15 Thread* thread = Thread::current(); 16 HandleScope scope(thread); 17 Runtime* runtime = thread->runtime(); 18 Module builtins(&scope, runtime->findModuleById(ID(builtins))); 19 return ApiHandle::borrowedReference(runtime, builtins.moduleProxy()); 20} 21 22PY_EXPORT PyObject* PyEval_GetGlobals() { UNIMPLEMENTED("PyEval_GetGlobals"); } 23 24PY_EXPORT void PyEval_AcquireLock() { UNIMPLEMENTED("PyEval_AcquireLock"); } 25 26PY_EXPORT void PyEval_AcquireThread(PyThreadState* /* e */) { 27 UNIMPLEMENTED("PyEval_AcquireThread"); 28} 29 30PY_EXPORT PyObject* PyEval_EvalCode(PyObject* code, PyObject* globals, 31 PyObject* locals) { 32 Thread* thread = Thread::current(); 33 if (globals == nullptr) { 34 thread->raiseWithFmt(LayoutId::kSystemError, 35 "PyEval_EvalCode: NULL globals"); 36 return nullptr; 37 } 38 // All of the below nullptr and type checks happen inside #ifdef Py_DEBUG in 39 // CPython (PyFrame_New) but we check no matter what. 40 if (code == nullptr) { 41 thread->raiseBadInternalCall(); 42 return nullptr; 43 } 44 HandleScope scope(thread); 45 Code code_code(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(code))); 46 Runtime* runtime = thread->runtime(); 47 Object globals_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(globals))); 48 Object module_obj(&scope, NoneType::object()); 49 bool must_update_globals = false; 50 if (globals_obj.isModuleProxy()) { 51 module_obj = ModuleProxy::cast(*globals_obj).module(); 52 } else if (globals_obj.isDict()) { 53 // Create a temporary module and fill it with the keys/values from globals 54 Str empty_name(&scope, Str::empty()); 55 Module tmp_module(&scope, runtime->newModule(empty_name)); 56 Dict globals_dict(&scope, *globals_obj); 57 Object key(&scope, NoneType::object()); 58 Object value(&scope, NoneType::object()); 59 Object result(&scope, NoneType::object()); 60 for (word i = 0; dictNextItem(globals_dict, &i, &key, &value);) { 61 result = moduleAtPut(thread, tmp_module, key, value); 62 if (result.isError()) return nullptr; 63 } 64 module_obj = *tmp_module; 65 must_update_globals = true; 66 } else if (runtime->isInstanceOfDict(*globals_obj)) { 67 UNIMPLEMENTED("PyEval_EvalCode with dict subclass globals"); 68 } else { 69 thread->raiseBadInternalCall(); 70 return nullptr; 71 } 72 73 Object implicit_globals(&scope, NoneType::object()); 74 if (locals != nullptr && globals != locals) { 75 implicit_globals = ApiHandle::asObject(ApiHandle::fromPyObject(locals)); 76 if (!runtime->isMapping(thread, implicit_globals)) { 77 thread->raiseBadInternalCall(); 78 return nullptr; 79 } 80 } 81 Module module(&scope, *module_obj); 82 Object result(&scope, thread->exec(code_code, module, implicit_globals)); 83 if (result.isErrorException()) return nullptr; 84 if (must_update_globals) { 85 // Update globals with the (potentially changed) contents of the module 86 // proxy 87 Dict globals_dict(&scope, *globals_obj); 88 Object module_proxy(&scope, module.moduleProxy()); 89 if (dictMergeOverride(thread, globals_dict, module_proxy).isError()) { 90 return nullptr; 91 } 92 } 93 return ApiHandle::newReference(runtime, *result); 94} 95 96PY_EXPORT PyObject* PyEval_EvalCodeEx(PyObject* /* o */, PyObject* /* s */, 97 PyObject* /* s */, PyObject** /* s */, 98 int /* t */, PyObject** /* s */, 99 int /* t */, PyObject** /* s */, 100 int /* t */, PyObject* /* s */, 101 PyObject* /* e */) { 102 UNIMPLEMENTED("PyEval_EvalCodeEx"); 103} 104 105PY_EXPORT PyObject* PyEval_EvalFrame(PyFrameObject* /* f */) { 106 UNIMPLEMENTED("PyEval_EvalFrame"); 107} 108 109PY_EXPORT PyObject* PyEval_EvalFrameEx(PyFrameObject* /* f */, int /* g */) { 110 UNIMPLEMENTED("PyEval_EvalFrameEx"); 111} 112 113PY_EXPORT PyFrameObject* PyEval_GetFrame() { UNIMPLEMENTED("PyEval_GetFrame"); } 114 115PY_EXPORT const char* PyEval_GetFuncDesc(PyObject* /* c */) { 116 UNIMPLEMENTED("PyEval_GetFuncDesc"); 117} 118 119PY_EXPORT const char* PyEval_GetFuncName(PyObject* /* c */) { 120 UNIMPLEMENTED("PyEval_GetFuncName"); 121} 122 123PY_EXPORT PyObject* PyEval_GetLocals() { UNIMPLEMENTED("PyEval_GetLocals"); } 124 125PY_EXPORT void PyEval_InitThreads() { 126 // TODO(T66337218): Implement this when there is actual threading support. 127} 128 129PY_EXPORT void PyEval_ReleaseLock() { UNIMPLEMENTED("PyEval_ReleaseLock"); } 130 131PY_EXPORT void PyEval_ReleaseThread(PyThreadState* /* e */) { 132 UNIMPLEMENTED("PyEval_ReleaseThread"); 133} 134 135PY_EXPORT void PyEval_RestoreThread(PyThreadState* /* e */) { 136 // TODO(T37761469): Implement instead of making it a noop 137} 138 139PY_EXPORT PyThreadState* PyEval_SaveThread() { 140 // TODO(T37761469): Implement instead of making it a noop 141 return nullptr; 142} 143 144PY_EXPORT int Py_AddPendingCall(int (*/* func */)(void*), void* /* g */) { 145 UNIMPLEMENTED("Py_AddPendingCall"); 146} 147 148PY_EXPORT int Py_GetRecursionLimit() { 149 return Thread::current()->recursionLimit(); 150} 151 152PY_EXPORT int Py_EnterRecursiveCall_Func(const char* where) { 153 Thread* thread = Thread::current(); 154 if (thread->recursionEnter() >= thread->recursionLimit()) { 155 thread->raiseWithFmt(LayoutId::kRecursionError, 156 "maximum recursion depth exceeded %s", where); 157 return -1; 158 } 159 return 0; 160} 161 162PY_EXPORT void Py_LeaveRecursiveCall_Func() { 163 Thread::current()->recursionLeave(); 164} 165 166PY_EXPORT int Py_MakePendingCalls() { UNIMPLEMENTED("Py_MakePendingCalls"); } 167 168PY_EXPORT int PyEval_MergeCompilerFlags(PyCompilerFlags* flags) { 169 Thread* thread = Thread::current(); 170 Frame* frame = thread->currentFrame(); 171 if (!frame->isSentinel()) { 172 word code_flags = Code::cast(frame->function().code()).flags(); 173 int compiler_flags = code_flags & PyCF_MASK; 174 flags->cf_flags |= compiler_flags; 175 } 176 return flags->cf_flags != 0; 177} 178 179PY_EXPORT void Py_SetRecursionLimit(int limit) { 180 Thread::current()->setRecursionLimit(limit); 181} 182 183PY_EXPORT int _Py_CheckRecursiveCall(const char* /* where */) { 184 // We don't implement this function because this recursion checking is left 185 // up to the runtime. 186 return 0; 187} 188 189PY_EXPORT void PyEval_SetProfile(Py_tracefunc /* c */, PyObject* /* g */) { 190 UNIMPLEMENTED("PyEval_SetProfile"); 191} 192 193PY_EXPORT void PyEval_SetTrace(Py_tracefunc /* c */, PyObject* /* g */) { 194 UNIMPLEMENTED("PyEval_SetTrace"); 195} 196 197PY_EXPORT PyObject* PyEval_CallObjectWithKeywords(PyObject* callable, 198 PyObject* args, 199 PyObject* kwargs) { 200 // PyEval_CallObjectWithKeywords() must not be called with an exception 201 // set. It raises a new exception if parameters are invalid or if 202 // PyTuple_New() fails, and so the original exception is lost. 203 Thread* thread = Thread::current(); 204 DCHECK(!thread->hasPendingException(), 205 "must not be called with an exception set"); 206 207 HandleScope scope(thread); 208 word flags = 0; 209 thread->stackPush(ApiHandle::asObject(ApiHandle::fromPyObject(callable))); 210 211 Runtime* runtime = thread->runtime(); 212 if (args != nullptr) { 213 Object args_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(args))); 214 if (!runtime->isInstanceOfTuple(*args_obj)) { 215 thread->raiseWithFmt(LayoutId::kTypeError, 216 "argument list must be a tuple"); 217 return nullptr; 218 } 219 thread->stackPush(*args_obj); 220 } else { 221 thread->stackPush(runtime->emptyTuple()); 222 } 223 224 if (kwargs != nullptr) { 225 Object kwargs_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(kwargs))); 226 if (!runtime->isInstanceOfDict(*kwargs_obj)) { 227 thread->raiseWithFmt(LayoutId::kTypeError, 228 "keyword list must be a dictionary"); 229 return nullptr; 230 } 231 thread->stackPush(*kwargs_obj); 232 flags |= CallFunctionExFlag::VAR_KEYWORDS; 233 } 234 235 // TODO(T30925218): Protect against native stack overflow. 236 Object result(&scope, Interpreter::callEx(thread, flags)); 237 if (result.isError()) return nullptr; 238 return ApiHandle::newReference(runtime, *result); 239} 240 241PY_EXPORT PyObject* _PyEval_EvalFrameDefault(PyFrameObject* /* f */, 242 int /* g */) { 243 UNIMPLEMENTED("_PyEval_EvalFrameDefault"); 244} 245 246PY_EXPORT void _PyEval_ReInitThreads(_PyRuntimeState*) { 247 // TODO(T87097565): Implement instead of making it a noop 248} 249 250} // namespace py