ext/Internal/function-utils.cpp (108 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) #include "function-utils.h" #include "capi-trampolines.h" #include "handles.h" #include "runtime.h" namespace py { RawObject getExtensionFunction(RawObject object) { if (!object.isBoundMethod()) return Error::notFound(); RawObject function_obj = BoundMethod::cast(object).function(); if (!function_obj.isFunction()) return Error::notFound(); RawFunction function = Function::cast(function_obj); if (!function.isExtension()) return Error::notFound(); return function; } RawObject newCFunction(Thread* thread, PyMethodDef* method, const Object& name, const Object& self, const Object& module_name) { HandleScope scope(thread); Runtime* runtime = thread->runtime(); Function function( &scope, newExtensionFunction(thread, name, reinterpret_cast<void*>(method->ml_meth), method->ml_flags)); if (method->ml_doc != nullptr) { function.setDoc(runtime->newStrFromCStr(method->ml_doc)); } if (runtime->isInstanceOfStr(*module_name)) { function.setModuleName(*module_name); } return runtime->newBoundMethod(function, self); } RawObject newClassMethod(Thread* thread, PyMethodDef* method, const Object& name, const Object& type) { HandleScope scope(thread); Runtime* runtime = thread->runtime(); Function function(&scope, newExtensionFunction( thread, name, bit_cast<void*>(method->ml_meth), method->ml_flags)); if (method->ml_doc != nullptr) { function.setDoc(runtime->newStrFromCStr(method->ml_doc)); } Object result( &scope, thread->invokeFunction2(ID(builtins), ID(_descrclassmethod), type, function)); DCHECK(!result.isError(), "failed to create classmethod descriptor"); return *result; } RawObject newExtensionFunction(Thread* thread, const Object& name, void* function, int flags) { HandleScope scope(thread); Runtime* runtime = thread->runtime(); Function::Entry entry; Function::Entry entry_kw; Function::Entry entry_ex; flags &= ~METH_CLASS & ~METH_STATIC & ~METH_COEXIST; switch (flags) { case METH_NOARGS: entry = methodTrampolineNoArgs; entry_kw = methodTrampolineNoArgsKw; entry_ex = methodTrampolineNoArgsEx; break; case METH_O: entry = methodTrampolineOneArg; entry_kw = methodTrampolineOneArgKw; entry_ex = methodTrampolineOneArgEx; break; case METH_VARARGS: entry = methodTrampolineVarArgs; entry_kw = methodTrampolineVarArgsKw; entry_ex = methodTrampolineVarArgsEx; break; case METH_VARARGS | METH_KEYWORDS: entry = methodTrampolineKeywords; entry_kw = methodTrampolineKeywordsKw; entry_ex = methodTrampolineKeywordsEx; break; case METH_FASTCALL: entry = methodTrampolineFast; entry_kw = methodTrampolineFastKw; entry_ex = methodTrampolineFastEx; break; case METH_FASTCALL | METH_KEYWORDS: entry = methodTrampolineFastWithKeywords; entry_kw = methodTrampolineFastWithKeywordsKw; entry_ex = methodTrampolineFastWithKeywordsEx; break; default: UNIMPLEMENTED("Unsupported MethodDef type"); } Object code(&scope, runtime->newIntFromCPtr(function)); Object none(&scope, NoneType::object()); return thread->runtime()->newFunction( thread, name, code, /*flags=*/Function::Flags::kExtension, /*argcount=*/-1, /*total_args=*/-1, /*total_vars=*/-1, /*stacksize_or_builtin=*/none, entry, entry_kw, entry_ex); } RawObject newMethod(Thread* thread, PyMethodDef* method, const Object& name, const Object& /*type*/) { HandleScope scope(thread); Runtime* runtime = thread->runtime(); Function function(&scope, newExtensionFunction( thread, name, bit_cast<void*>(method->ml_meth), method->ml_flags)); if (method->ml_doc != nullptr) { function.setDoc(runtime->newStrFromCStr(method->ml_doc)); } // TODO(T62932301): We currently return the plain function here which means // we do not check the `self` parameter to be a proper subtype of `type`. // Should we wrap this with a new descriptor type? return *function; } } // namespace py