this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "function-utils.h"
3
4#include "capi-trampolines.h"
5#include "handles.h"
6#include "runtime.h"
7
8namespace py {
9
10RawObject getExtensionFunction(RawObject object) {
11 if (!object.isBoundMethod()) return Error::notFound();
12 RawObject function_obj = BoundMethod::cast(object).function();
13 if (!function_obj.isFunction()) return Error::notFound();
14 RawFunction function = Function::cast(function_obj);
15 if (!function.isExtension()) return Error::notFound();
16 return function;
17}
18
19RawObject newCFunction(Thread* thread, PyMethodDef* method, const Object& name,
20 const Object& self, const Object& module_name) {
21 HandleScope scope(thread);
22 Runtime* runtime = thread->runtime();
23 Function function(
24 &scope, newExtensionFunction(thread, name,
25 reinterpret_cast<void*>(method->ml_meth),
26 method->ml_flags));
27 if (method->ml_doc != nullptr) {
28 function.setDoc(runtime->newStrFromCStr(method->ml_doc));
29 }
30 if (runtime->isInstanceOfStr(*module_name)) {
31 function.setModuleName(*module_name);
32 }
33 return runtime->newBoundMethod(function, self);
34}
35
36RawObject newClassMethod(Thread* thread, PyMethodDef* method,
37 const Object& name, const Object& type) {
38 HandleScope scope(thread);
39 Runtime* runtime = thread->runtime();
40 Function function(&scope, newExtensionFunction(
41 thread, name, bit_cast<void*>(method->ml_meth),
42 method->ml_flags));
43 if (method->ml_doc != nullptr) {
44 function.setDoc(runtime->newStrFromCStr(method->ml_doc));
45 }
46 Object result(
47 &scope, thread->invokeFunction2(ID(builtins), ID(_descrclassmethod), type,
48 function));
49 DCHECK(!result.isError(), "failed to create classmethod descriptor");
50 return *result;
51}
52
53RawObject newExtensionFunction(Thread* thread, const Object& name,
54 void* function, int flags) {
55 HandleScope scope(thread);
56 Runtime* runtime = thread->runtime();
57 Function::Entry entry;
58 Function::Entry entry_kw;
59 Function::Entry entry_ex;
60 flags &= ~METH_CLASS & ~METH_STATIC & ~METH_COEXIST;
61 switch (flags) {
62 case METH_NOARGS:
63 entry = methodTrampolineNoArgs;
64 entry_kw = methodTrampolineNoArgsKw;
65 entry_ex = methodTrampolineNoArgsEx;
66 break;
67 case METH_O:
68 entry = methodTrampolineOneArg;
69 entry_kw = methodTrampolineOneArgKw;
70 entry_ex = methodTrampolineOneArgEx;
71 break;
72 case METH_VARARGS:
73 entry = methodTrampolineVarArgs;
74 entry_kw = methodTrampolineVarArgsKw;
75 entry_ex = methodTrampolineVarArgsEx;
76 break;
77 case METH_VARARGS | METH_KEYWORDS:
78 entry = methodTrampolineKeywords;
79 entry_kw = methodTrampolineKeywordsKw;
80 entry_ex = methodTrampolineKeywordsEx;
81 break;
82 case METH_FASTCALL:
83 entry = methodTrampolineFast;
84 entry_kw = methodTrampolineFastKw;
85 entry_ex = methodTrampolineFastEx;
86 break;
87 case METH_FASTCALL | METH_KEYWORDS:
88 entry = methodTrampolineFastWithKeywords;
89 entry_kw = methodTrampolineFastWithKeywordsKw;
90 entry_ex = methodTrampolineFastWithKeywordsEx;
91 break;
92 default:
93 UNIMPLEMENTED("Unsupported MethodDef type");
94 }
95 Object code(&scope, runtime->newIntFromCPtr(function));
96 Object none(&scope, NoneType::object());
97 return thread->runtime()->newFunction(
98 thread, name, code, /*flags=*/Function::Flags::kExtension,
99 /*argcount=*/-1, /*total_args=*/-1,
100 /*total_vars=*/-1,
101 /*stacksize_or_builtin=*/none, entry, entry_kw, entry_ex);
102}
103
104RawObject newMethod(Thread* thread, PyMethodDef* method, const Object& name,
105 const Object& /*type*/) {
106 HandleScope scope(thread);
107 Runtime* runtime = thread->runtime();
108 Function function(&scope, newExtensionFunction(
109 thread, name, bit_cast<void*>(method->ml_meth),
110 method->ml_flags));
111 if (method->ml_doc != nullptr) {
112 function.setDoc(runtime->newStrFromCStr(method->ml_doc));
113 }
114 // TODO(T62932301): We currently return the plain function here which means
115 // we do not check the `self` parameter to be a proper subtype of `type`.
116 // Should we wrap this with a new descriptor type?
117 return *function;
118}
119
120} // namespace py