-
Notifications
You must be signed in to change notification settings - Fork 49
[Feature] Support dynamic-style overload for FFI object types #286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Summary of ChangesHello @DarkSharpness, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the Foreign Function Interface (FFI) by implementing dynamic-style function overloading for object types. This feature allows developers to define multiple C++ methods or constructors with identical names but distinct parameter lists, which can then be seamlessly invoked from FFI bindings. The change improves the usability and expressiveness of FFI object definitions, making them more aligned with standard C++ programming patterns. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a powerful feature to support overloading of FFI object methods, including constructors, instance methods, and static methods. The implementation is well-designed, with good attention to performance by minimizing virtual function calls. The changes are well-structured, with the core logic encapsulated in the new include/tvm/ffi/extra/overload.h header, and necessary supporting changes made to function.h and registry.h. The addition of tests in tests/cpp/test_overload.cc is great and covers the primary use cases. I have a couple of minor suggestions for improvement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have sufficient evidence to form an opinion on the design below (copied from unittests), but indeed it's super interesting and creative.
struct TestOverloadObj : public Object {
explicit TestOverloadObj(int32_t x) : type(Type::INT) {}
explicit TestOverloadObj(float y) : type(Type::FLOAT) {}
static int add_one_int(int x) { return x + 1; }
static float add_one_float(float x) { return x + 1.0f; }
template <typename T>
auto holds(T) {
if constexpr (std::is_same_v<T, int32_t>) {
return type == Type::INT;
} else if constexpr (std::is_same_v<T, float>) {
return type == Type::FLOAT;
} else {
static_assert(sizeof(T) == 0, "Unsupported type");
}
}
enum class Type { INT, FLOAT } type;
TVM_FFI_DECLARE_OBJECT_INFO("test.TestOverloadObj", TestOverloadObj, Object);
};
TVM_FFI_STATIC_INIT_BLOCK() {
namespace refl = tvm::ffi::reflection;
refl::OverloadObjectDef<TestOverloadObj>()
.def(refl::init<int32_t>())
.def(refl::init<float>())
.def("hold_same_type", &TestOverloadObj::holds<int32_t>)
.def("hold_same_type", &TestOverloadObj::holds<float>)
.def_static("add_one_static", &TestOverloadObj::add_one_int)
.def_static("add_one_static", &TestOverloadObj::add_one_float);
}|
cc @junrushao . for mismatched arg number: |
93821a3 to
448fbde
Compare
0d9a0ef to
7532c25
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, the changes LGTM! Supporting function overloading is very helpful.
Based on our offline discussions regarding the design, this implementation looks solid. I especially like how we designed these features:
- The overloaded function is optional and independent of the Function class.
- The code path for the first overload is aligned to the non-overload version to minimize overhead
- Although we need to check arguments at runtime, the function signatures are known at compile time, and we are using templates to generate the checking code for certain function signatures. This reduces the runtime overhead.
One thing to note is that we are doing parameter type checking & conversion at the same time. If the conversion is slow (such as Array<Array<Type>>), we need to check and convert all array elements), this may introduce some overhead. But I think it's fine since these slow paths are currently relatively uncommon.
7532c25 to
ed91bc1
Compare
junrushao
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late response! I really like this PR
|
@junrushao Thanks so much for merging this PR! |
Introduced by #286, where `CaptureTuple`, i.e. `CaptureTupleAux<PackedArgs>::type`, is defined as: ``` std::tuple<std::optional<std::decay_t<Args>>...> ``` and star access to its `std::optional` is indeed unchecked but intended.
Related discussion here #265 .
Modification in short:
Function::FromPackedInplaceinfunction.hand generalize some methods inregistry.hextra/overload.h)