this repo has no description
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