blob: dcfb189325ecfd3b5026660a537325a93a50d41d [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* \file src/ffi/object.cc
* \brief Registry to record dynamic types
*/
#include <tvm/ffi/any.h>
#include <tvm/ffi/c_api.h>
#include <tvm/ffi/container/array.h>
#include <tvm/ffi/container/dict.h>
#include <tvm/ffi/container/list.h>
#include <tvm/ffi/container/map.h>
#include <tvm/ffi/container/tensor.h>
#include <tvm/ffi/enum.h>
#include <tvm/ffi/error.h>
#include <tvm/ffi/function.h>
#include <tvm/ffi/memory.h>
#include <tvm/ffi/object.h>
#include <tvm/ffi/reflection/accessor.h>
#include <tvm/ffi/reflection/creator.h>
#include <tvm/ffi/reflection/registry.h>
#include <tvm/ffi/string.h>
#include <string_view>
#include <utility>
#include <vector>
#include "object_internal.h"
namespace tvm {
namespace ffi {
/*!
* \brief Global registry that manages
*
* \note We do not use mutex to guard updating of TypeTable
*
* The assumption is that updating of TypeTable will be done
* in the main thread during initialization or loading, or
* explicitly locked from the caller.
*
* Then the followup code will leverage the information
*/
class TypeTable {
public:
/*! \brief Type information */
struct Entry : public TypeInfo {
/*! \brief stored type key */
String type_key_data;
/*! \brief acenstor information */
std::vector<const TVMFFITypeInfo*> type_ancestors_data;
/*! \brief type fields informaton */
std::vector<TVMFFIFieldInfo> type_fields_data;
/*! \brief type methods informaton */
std::vector<TVMFFIMethodInfo> type_methods_data;
/*! \brief extra information */
TVMFFITypeMetadata metadata_data;
// NOTE: the indices in [index, index + num_reserved_slots) are
// reserved for the child-class of this type.
/*! \brief Total number of slots reserved for the type and its children. */
int32_t num_slots;
/*! \brief number of allocated child slots. */
int32_t allocated_slots;
/*! \brief Whether child can overflow. */
bool child_slots_can_overflow{true};
Entry(int32_t type_index, int32_t type_depth, String type_key, int32_t num_slots,
bool child_slots_can_overflow, const Entry* parent) {
// setup fields in the class
this->type_key_data = std::move(type_key);
this->num_slots = num_slots;
this->allocated_slots = 1;
this->child_slots_can_overflow = child_slots_can_overflow;
// set up type acenstors information
if (type_depth != 0) {
TVM_FFI_ICHECK_NOTNULL(parent);
TVM_FFI_ICHECK_EQ(type_depth, parent->type_depth + 1);
type_ancestors_data.resize(type_depth);
// copy over parent's type information
for (int32_t i = 0; i < parent->type_depth; ++i) {
type_ancestors_data[i] = parent->type_ancestors[i];
}
// set last type information to be parent
type_ancestors_data[parent->type_depth] = parent;
}
// initialize type info: no change to type_key and type_ancestors fields
// after this line
this->type_index = type_index;
this->type_depth = type_depth;
this->type_key = TVMFFIByteArray{this->type_key_data.data(), this->type_key_data.length()};
this->type_key_hash = std::hash<String>()(this->type_key_data);
this->type_ancestors = type_ancestors_data.data();
// initialize the reflection information
this->num_fields = 0;
this->num_methods = 0;
this->fields = nullptr;
this->methods = nullptr;
this->metadata = nullptr;
}
};
struct TypeAttrColumnData : public TVMFFITypeAttrColumn {
std::vector<Any> data_;
};
int32_t GetOrAllocTypeIndex(String type_key, int32_t static_type_index, int32_t type_depth,
int32_t num_child_slots, bool child_slots_can_overflow,
int32_t parent_type_index) {
auto it = type_key2index_.find(type_key);
if (it != type_key2index_.end()) {
return type_table_[(*it).second]->type_index;
}
// get parent's entry
Entry* parent = [&]() -> Entry* {
if (parent_type_index < 0) return nullptr;
// try to allocate from parent's type table.
TVM_FFI_ICHECK_LT(parent_type_index, type_table_.size())
<< " type_key=" << type_key << ", static_index=" << static_type_index;
return type_table_[parent_type_index].get();
}();
// get allocated index
int32_t allocated_tindex = [&]() {
// Step 0: static allocation
if (static_type_index >= 0) {
TVM_FFI_ICHECK_LT(static_type_index, type_table_.size());
TVM_FFI_ICHECK(type_table_[static_type_index] == nullptr)
<< "Conflicting static index " << static_type_index << " between "
<< ToStringView(type_table_[static_type_index]->type_key) << " and " << type_key;
return static_type_index;
}
TVM_FFI_ICHECK_NOTNULL(parent);
int num_slots = num_child_slots + 1;
if (parent->allocated_slots + num_slots <= parent->num_slots) {
// allocate the slot from parent's reserved pool
int32_t allocated_tindex = parent->type_index + parent->allocated_slots;
// update parent's state
parent->allocated_slots += num_slots;
return allocated_tindex;
}
// Step 2: allocate from overflow
TVM_FFI_ICHECK(parent->child_slots_can_overflow)
<< "Reach maximum number of sub-classes for " << ToStringView(parent->type_key);
// allocate new entries.
int32_t allocated_tindex = static_cast<int32_t>(type_counter_);
type_counter_ += num_slots;
TVM_FFI_ICHECK_LE(type_table_.size(), type_counter_);
type_table_.reserve(type_counter_);
// resize type table
while (static_cast<int32_t>(type_table_.size()) < type_counter_) {
type_table_.emplace_back(nullptr);
}
return allocated_tindex;
}();
// if parent cannot overflow, then this class cannot.
if (parent != nullptr && !(parent->child_slots_can_overflow)) {
child_slots_can_overflow = false;
}
// total number of slots include the type itself.
if (parent != nullptr) {
TVM_FFI_ICHECK_GT(allocated_tindex, parent->type_index);
}
type_table_[allocated_tindex] =
std::make_unique<Entry>(allocated_tindex, type_depth, type_key, num_child_slots + 1,
child_slots_can_overflow, parent);
// update the key2index mapping.
type_key2index_.Set(type_key, allocated_tindex);
return allocated_tindex;
}
int32_t TypeKeyToIndex(const TVMFFIByteArray* type_key) {
String type_key_str(type_key->data, type_key->size);
auto it = type_key2index_.find(type_key_str);
TVM_FFI_ICHECK(it != type_key2index_.end()) << "Cannot find type `" << type_key_str << "`";
return static_cast<int32_t>((*it).second);
}
Entry* GetTypeEntry(int32_t type_index) {
Entry* entry = nullptr;
if (type_index >= 0 && static_cast<size_t>(type_index) < type_table_.size()) {
entry = type_table_[type_index].get();
}
TVM_FFI_ICHECK(entry != nullptr) << "Cannot find type info for type_index=" << type_index;
return entry;
}
Array<String> GetRegisteredTypeKeys() const {
Array<String> ret;
for (const auto& entry : type_table_) {
if (entry) {
ret.push_back(entry->type_key_data);
}
}
return ret;
}
void RegisterTypeField(int32_t type_index, const TVMFFIFieldInfo* info) {
Entry* entry = GetTypeEntry(type_index);
std::string_view new_name(info->name.data, info->name.size);
std::string_view type_key(entry->type_key.data, entry->type_key.size);
// Check: no duplicate field name within this type's own fields.
for (const auto& existing : entry->type_fields_data) {
TVM_FFI_ICHECK(std::string_view(existing.name.data, existing.name.size) != new_name)
<< "Duplicate field name \"" << new_name << "\" in type \"" << type_key << "\"";
}
// Warn: field name should not shadow any ancestor field.
for (int32_t d = 0; d < entry->type_depth; ++d) {
const TVMFFITypeInfo* ancestor = entry->type_ancestors[d];
for (int32_t i = 0; i < ancestor->num_fields; ++i) {
if (std::string_view(ancestor->fields[i].name.data, ancestor->fields[i].name.size) ==
new_name) {
std::cerr << "[WARNING] Field \"" << new_name << "\" in type \"" << type_key
<< "\" duplicates an ancestor field in \""
<< std::string_view(ancestor->type_key.data, ancestor->type_key.size)
<< "\". Child types should not re-register inherited fields." << std::endl;
}
}
}
TVMFFIFieldInfo field_data = *info;
// Retain FunctionObj setter via any_pool_ so it outlives the Entry.
if ((field_data.flags & kTVMFFIFieldFlagBitSetterIsFunctionObj) &&
field_data.setter != nullptr) {
TVMFFIAny setter_ref;
setter_ref.type_index = kTVMFFIFunction;
setter_ref.zero_padding = 0;
setter_ref.v_obj = static_cast<TVMFFIObject*>(field_data.setter);
any_pool_.emplace_back(AnyView::CopyFromTVMFFIAny(setter_ref));
}
field_data.name = this->CopyString(info->name);
field_data.doc = this->CopyString(info->doc);
field_data.metadata = this->CopyString(info->metadata);
if (info->flags & kTVMFFIFieldFlagBitMaskHasDefault) {
field_data.default_value_or_factory =
this->CopyAny(AnyView::CopyFromTVMFFIAny(info->default_value_or_factory))
.CopyToTVMFFIAny();
} else {
field_data.default_value_or_factory = AnyView(nullptr).CopyToTVMFFIAny();
}
entry->type_fields_data.push_back(field_data);
// refresh ptr as the data can change
entry->fields = entry->type_fields_data.data();
entry->num_fields = static_cast<int32_t>(entry->type_fields_data.size());
}
void RegisterTypeMethod(int32_t type_index, const TVMFFIMethodInfo* info) {
Entry* entry = GetTypeEntry(type_index);
TVMFFIMethodInfo method_data = *info;
method_data.name = this->CopyString(info->name);
method_data.doc = this->CopyString(info->doc);
method_data.metadata = this->CopyString(info->metadata);
method_data.method = this->CopyAny(AnyView::CopyFromTVMFFIAny(info->method)).CopyToTVMFFIAny();
entry->type_methods_data.push_back(method_data);
entry->methods = entry->type_methods_data.data();
entry->num_methods = static_cast<int32_t>(entry->type_methods_data.size());
}
void RegisterTypeMetadata(int32_t type_index, const TVMFFITypeMetadata* metadata) {
Entry* entry = GetTypeEntry(type_index);
if (entry->metadata != nullptr) {
TVM_FFI_LOG_AND_THROW(RuntimeError)
<< "Overriding " << ToStringView(entry->type_key) << ", possible causes:\n"
<< "- two ObjectDef<T>() calls for the same T \n"
<< "- when we forget to assign _type_key to ObjectRef<Y> that inherits from T\n"
<< "- another type with the same key is already registered\n"
<< "Cross check the reflection registration.";
}
entry->metadata_data = *metadata;
entry->metadata_data.doc = this->CopyString(metadata->doc);
entry->metadata = &(entry->metadata_data);
}
void RegisterTypeAttr(int32_t type_index, const TVMFFIByteArray* name, const TVMFFIAny* value) {
AnyView value_view = AnyView::CopyFromTVMFFIAny(*value);
String name_str(*name);
size_t column_index = 0;
auto it = type_attr_name_to_column_index_.find(name_str);
if (it == type_attr_name_to_column_index_.end()) {
column_index = type_attr_columns_.size();
type_attr_columns_.emplace_back(std::make_unique<TypeAttrColumnData>());
type_attr_name_to_column_index_.Set(name_str, static_cast<int64_t>(column_index));
} else {
column_index = (*it).second;
}
TypeAttrColumnData* column = type_attr_columns_[column_index].get();
if (type_index == kTVMFFINone) {
// Sentinel: just ensure the column exists without registering a value.
if (column->data_.empty()) {
column->data = reinterpret_cast<const TVMFFIAny*>(column->data_.data());
column->size = 0;
column->begin_index = 0;
}
return;
}
// TODO(1.0): set begin_index to first registered type_index for sparse column storage
// For now, begin_index is always 0 (resize from index 0).
if (static_cast<size_t>(type_index) >= column->data_.size()) {
// Extend back from index 0.
column->data_.resize(static_cast<size_t>(type_index) + 1, Any(nullptr));
}
column->data = reinterpret_cast<const TVMFFIAny*>(column->data_.data());
column->size = static_cast<int32_t>(column->data_.size());
column->begin_index = 0;
Any& slot = column->data_[type_index - column->begin_index];
if (slot.type_index() != kTVMFFINone) {
TVM_FFI_THROW(RuntimeError)
<< "TypeAttr `" << name_str << "` is already registered for type index " << type_index
<< ". To update the stored value, register a mutable container (e.g., Dict/List) "
<< "once and mutate it in place on subsequent calls.";
}
slot = value_view;
}
const TVMFFITypeAttrColumn* GetTypeAttrColumn(const TVMFFIByteArray* name) {
String name_str(*name);
auto it = type_attr_name_to_column_index_.find(name_str);
if (it == type_attr_name_to_column_index_.end()) return nullptr;
return type_attr_columns_[(*it).second].get();
}
void Dump(int min_children_count) {
std::vector<int> num_children(type_table_.size(), 0);
// expected child slots compute the expected slots
// based on the current child slot setting
std::vector<int> expected_child_slots(type_table_.size(), 0);
// reverse accumulation so we can get total counts in a bottom-up manner.
for (auto it = type_table_.rbegin(); it != type_table_.rend(); ++it) {
const Entry* ptr = it->get();
if (ptr != nullptr && ptr->type_depth != 0) {
int parent_index = ptr->type_ancestors[ptr->type_depth - 1]->type_index;
num_children[parent_index] += num_children[ptr->type_index] + 1;
if (expected_child_slots[ptr->type_index] + 1 < ptr->num_slots) {
expected_child_slots[ptr->type_index] = ptr->num_slots - 1;
}
expected_child_slots[parent_index] += expected_child_slots[ptr->type_index] + 1;
}
}
for (const auto& ptr : type_table_) {
if (ptr != nullptr && num_children[ptr->type_index] >= min_children_count) {
std::cerr << '[' << ptr->type_index << "]\t" << ToStringView(ptr->type_key);
if (ptr->type_depth != 0) {
int32_t parent_index = ptr->type_ancestors[ptr->type_depth - 1]->type_index;
std::cerr << "\tparent=" << ToStringView(type_table_[parent_index]->type_key);
} else {
std::cerr << "\tparent=root";
}
std::cerr << "\tnum_child_slots=" << ptr->num_slots - 1
<< "\tnum_children=" << num_children[ptr->type_index]
<< "\texpected_child_slots=" << expected_child_slots[ptr->type_index]
<< std::endl;
}
}
}
static TypeTable* Global() {
// deliberately create a new instance via raw new
// to ensure table lives longer in case unloading
// still need the table info
// memory will be recycled by the OS at program exit
static TypeTable* inst = new TypeTable();
return inst;
}
private:
TypeTable() : type_attr_columns_{}, type_attr_name_to_column_index_{} {
type_table_.reserve(TypeIndex::kTVMFFIDynObjectBegin);
for (int32_t i = 0; i < TypeIndex::kTVMFFIDynObjectBegin; ++i) {
type_table_.emplace_back(nullptr);
}
// initialize the entry for object
this->GetOrAllocTypeIndex(String(Object::_type_key), Object::_type_index, Object::_type_depth,
Object::_type_child_slots, Object::_type_child_slots_can_overflow,
-1);
TVMFFITypeMetadata info;
info.total_size = sizeof(Object);
info.structural_eq_hash_kind = kTVMFFISEqHashKindUnsupported;
info.creator = nullptr;
info.doc = TVMFFIByteArray{nullptr, 0};
RegisterTypeMetadata(Object::_type_index, &info);
// reserve the static types
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFINone, TypeIndex::kTVMFFINone);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIInt, TypeIndex::kTVMFFIInt);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIBool, TypeIndex::kTVMFFIBool);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIFloat, TypeIndex::kTVMFFIFloat);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIOpaquePtr, TypeIndex::kTVMFFIOpaquePtr);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIDataType, TypeIndex::kTVMFFIDataType);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIDevice, TypeIndex::kTVMFFIDevice);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIDLTensorPtr, TypeIndex::kTVMFFIDLTensorPtr);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIRawStr, TypeIndex::kTVMFFIRawStr);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIByteArrayPtr, TypeIndex::kTVMFFIByteArrayPtr);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFIObjectRValueRef,
TypeIndex::kTVMFFIObjectRValueRef);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFISmallStr, TypeIndex::kTVMFFISmallStr);
ReserveBuiltinTypeIndex(StaticTypeKey::kTVMFFISmallBytes, TypeIndex::kTVMFFISmallBytes);
// reserved static type indices for depth 1 object types
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIStr, TypeIndex::kTVMFFIStr);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIBytes, TypeIndex::kTVMFFIBytes);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIError, TypeIndex::kTVMFFIError);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIFunction, TypeIndex::kTVMFFIFunction);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIShape, TypeIndex::kTVMFFIShape);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFITensor, TypeIndex::kTVMFFITensor);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIArray, TypeIndex::kTVMFFIArray);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIList, TypeIndex::kTVMFFIList);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIMap, TypeIndex::kTVMFFIMap);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIDict, TypeIndex::kTVMFFIDict);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIModule, TypeIndex::kTVMFFIModule);
ReserveDepthOneObjectTypeIndex(StaticTypeKey::kTVMFFIOpaquePyObject,
TypeIndex::kTVMFFIOpaquePyObject);
}
void ReserveBuiltinTypeIndex(const char* type_key, int32_t static_type_index) {
this->GetOrAllocTypeIndex(String(type_key), static_type_index, 0, 0, false, -1);
}
void ReserveDepthOneObjectTypeIndex(const char* type_key, int32_t static_type_index) {
this->GetOrAllocTypeIndex(String(type_key), static_type_index, 1, 0, false,
TypeIndex::kTVMFFIObject);
}
static ObjectPtr<details::StringObj> MakeInplaceString(const char* data, size_t length) {
ObjectPtr<details::StringObj> p =
make_inplace_array_object<details::StringObj, char>(length + 1);
static_assert(alignof(details::StringObj) % alignof(char) == 0);
static_assert(sizeof(details::StringObj) % alignof(char) == 0);
char* dest_data = reinterpret_cast<char*>(p.get()) + sizeof(details::StringObj);
p->data = dest_data;
p->size = length;
std::memcpy(dest_data, data, length);
dest_data[length] = '\0';
return p;
}
TVMFFIByteArray CopyString(TVMFFIByteArray str) {
if (str.size == 0) {
return TVMFFIByteArray{nullptr, 0};
}
// use explicit object creation to ensure the space pointer to not move
auto str_obj = MakeInplaceString(str.data, str.size);
TVMFFIByteArray c_val{str_obj->data, str_obj->size};
any_pool_.emplace_back(ObjectRef(std::move(str_obj)));
return c_val;
}
AnyView CopyAny(Any val) {
AnyView view = AnyView(val);
any_pool_.emplace_back(std::move(val));
return view;
}
int64_t type_counter_{TypeIndex::kTVMFFIDynObjectBegin};
std::vector<std::unique_ptr<Entry>> type_table_;
Map<String, int64_t> type_key2index_;
std::vector<Any> any_pool_;
// type attribute columns
std::vector<std::unique_ptr<TypeAttrColumnData>> type_attr_columns_;
Map<String, int64_t> type_attr_name_to_column_index_;
};
/**
* \brief Opaque implementation
*/
class OpaqueObjectImpl : public Object, public TVMFFIOpaqueObjectCell {
public:
OpaqueObjectImpl(void* handle, void (*deleter)(void* handle)) : deleter_(deleter) {
this->handle = handle;
}
void SetTypeIndex(int32_t type_index) {
details::ObjectUnsafe::GetHeader(this)->type_index = type_index;
}
~OpaqueObjectImpl() {
if (deleter_ != nullptr) {
deleter_(handle);
}
}
private:
void (*deleter_)(void* handle);
};
ObjectRef GetMissingObject() {
static ObjectRef missing_obj(make_object<Object>());
return missing_obj;
}
ObjectRef GetKwargsObject() {
static ObjectRef kwargs_obj(make_object<Object>());
return kwargs_obj;
}
} // namespace ffi
} // namespace tvm
void TVMFFIGetVersion(TVMFFIVersion* out_version) {
out_version->major = TVM_FFI_VERSION_MAJOR;
out_version->minor = TVM_FFI_VERSION_MINOR;
out_version->patch = TVM_FFI_VERSION_PATCH;
}
int TVMFFIObjectDecRef(TVMFFIObjectHandle handle) {
TVM_FFI_SAFE_CALL_BEGIN();
tvm::ffi::details::ObjectUnsafe::DecRefObjectHandle(handle);
TVM_FFI_SAFE_CALL_END();
}
int TVMFFIObjectIncRef(TVMFFIObjectHandle handle) {
TVM_FFI_SAFE_CALL_BEGIN();
tvm::ffi::details::ObjectUnsafe::IncRefObjectHandle(handle);
TVM_FFI_SAFE_CALL_END();
}
int TVMFFIObjectCreateOpaque(void* handle, int32_t type_index, void (*deleter)(void* handle),
TVMFFIObjectHandle* out) {
TVM_FFI_SAFE_CALL_BEGIN();
if (type_index != kTVMFFIOpaquePyObject) {
TVM_FFI_THROW(RuntimeError) << "Only kTVMFFIOpaquePyObject is supported for now";
}
// create initial opaque object
tvm::ffi::ObjectPtr<tvm::ffi::OpaqueObjectImpl> p =
tvm::ffi::make_object<tvm::ffi::OpaqueObjectImpl>(handle, deleter);
// need to set the type index after creation, because the set to RuntimeTypeIndex()
// happens after the constructor is called
p->SetTypeIndex(type_index);
*out = tvm::ffi::details::ObjectUnsafe::MoveObjectPtrToTVMFFIObjectPtr(std::move(p));
TVM_FFI_SAFE_CALL_END();
}
int TVMFFITypeKeyToIndex(const TVMFFIByteArray* type_key, int32_t* out_tindex) {
TVM_FFI_SAFE_CALL_BEGIN();
out_tindex[0] = tvm::ffi::TypeTable::Global()->TypeKeyToIndex(type_key);
TVM_FFI_SAFE_CALL_END();
}
int TVMFFITypeRegisterField(int32_t type_index, const TVMFFIFieldInfo* info) {
TVM_FFI_SAFE_CALL_BEGIN();
tvm::ffi::TypeTable::Global()->RegisterTypeField(type_index, info);
TVM_FFI_SAFE_CALL_END();
}
int TVMFFITypeRegisterMethod(int32_t type_index, const TVMFFIMethodInfo* info) {
TVM_FFI_SAFE_CALL_BEGIN();
tvm::ffi::TypeTable::Global()->RegisterTypeMethod(type_index, info);
TVM_FFI_SAFE_CALL_END();
}
int TVMFFITypeRegisterMetadata(int32_t type_index, const TVMFFITypeMetadata* metadata) {
TVM_FFI_SAFE_CALL_BEGIN();
tvm::ffi::TypeTable::Global()->RegisterTypeMetadata(type_index, metadata);
TVM_FFI_SAFE_CALL_END();
}
int TVMFFITypeRegisterAttr(int32_t type_index, const TVMFFIByteArray* name,
const TVMFFIAny* value) {
TVM_FFI_SAFE_CALL_BEGIN();
tvm::ffi::TypeTable::Global()->RegisterTypeAttr(type_index, name, value);
TVM_FFI_SAFE_CALL_END();
}
const TVMFFITypeAttrColumn* TVMFFIGetTypeAttrColumn(const TVMFFIByteArray* name) {
TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
return tvm::ffi::TypeTable::Global()->GetTypeAttrColumn(name);
TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIGetTypeAttrColumn);
}
int32_t TVMFFITypeGetOrAllocIndex(const TVMFFIByteArray* type_key, int32_t static_type_index,
int32_t type_depth, int32_t num_child_slots,
int32_t child_slots_can_overflow, int32_t parent_type_index) {
TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
tvm::ffi::String s_type_key(type_key->data, type_key->size);
return tvm::ffi::TypeTable::Global()->GetOrAllocTypeIndex(
s_type_key, static_type_index, type_depth, num_child_slots, child_slots_can_overflow,
parent_type_index);
TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFITypeGetOrAllocIndex);
}
const TVMFFITypeInfo* TVMFFIGetTypeInfo(int32_t type_index) {
TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
return tvm::ffi::TypeTable::Global()->GetTypeEntry(type_index);
TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIGetTypeInfo);
}
// string APIs, we blend into object.cc to keep things simple
int TVMFFIStringFromByteArray(const TVMFFIByteArray* input, TVMFFIAny* out) {
TVM_FFI_SAFE_CALL_BEGIN();
// must set to none first
out->type_index = kTVMFFINone;
tvm::ffi::TypeTraits<tvm::ffi::String>::MoveToAny(tvm::ffi::String(input->data, input->size),
out);
TVM_FFI_SAFE_CALL_END();
}
int TVMFFIBytesFromByteArray(const TVMFFIByteArray* input, TVMFFIAny* out) {
TVM_FFI_SAFE_CALL_BEGIN();
// must set to none first
out->type_index = kTVMFFINone;
tvm::ffi::TypeTraits<tvm::ffi::Bytes>::MoveToAny(tvm::ffi::Bytes(input->data, input->size), out);
TVM_FFI_SAFE_CALL_END();
}
namespace {
TVM_FFI_STATIC_INIT_BLOCK() {
namespace ffi = ::tvm::ffi;
namespace refl = ::tvm::ffi::reflection;
refl::TypeAttrDef<ffi::Object>().def(
refl::type_attr::kConvert, &refl::details::FFIConvertFromAnyViewToObjectRef<ffi::ObjectRef>);
refl::TypeAttrDef<ffi::details::StringObj>().def(
refl::type_attr::kConvert, &refl::details::FFIConvertFromAnyViewToObjectRef<ffi::String>);
refl::TypeAttrDef<ffi::details::BytesObj>().def(
refl::type_attr::kConvert, &refl::details::FFIConvertFromAnyViewToObjectRef<ffi::Bytes>);
refl::TypeAttrDef<ffi::ErrorObj>().def(
refl::type_attr::kConvert, &refl::details::FFIConvertFromAnyViewToObjectRef<ffi::Error>);
refl::TypeAttrDef<ffi::FunctionObj>().def(
refl::type_attr::kConvert, &refl::details::FFIConvertFromAnyViewToObjectRef<ffi::Function>);
refl::TypeAttrDef<ffi::ShapeObj>().def(
refl::type_attr::kConvert, &refl::details::FFIConvertFromAnyViewToObjectRef<ffi::Shape>);
refl::TypeAttrDef<ffi::TensorObj>().def(
refl::type_attr::kConvert, &refl::details::FFIConvertFromAnyViewToObjectRef<ffi::Tensor>);
refl::TypeAttrDef<ffi::ArrayObj>().def(
refl::type_attr::kConvert,
&refl::details::FFIConvertFromAnyViewToObjectRef<ffi::Array<ffi::Any>>);
refl::TypeAttrDef<ffi::MapObj>().def(
refl::type_attr::kConvert,
&refl::details::FFIConvertFromAnyViewToObjectRef<ffi::Map<ffi::Any, ffi::Any>>);
// Skipped: TypeIndex::kTVMFFIModule
// Skipped: TypeIndex::kTVMFFIOpaquePyObject
refl::TypeAttrDef<ffi::ListObj>().def(
refl::type_attr::kConvert,
&refl::details::FFIConvertFromAnyViewToObjectRef<ffi::List<ffi::Any>>);
refl::TypeAttrDef<ffi::DictObj>().def(
refl::type_attr::kConvert,
&refl::details::FFIConvertFromAnyViewToObjectRef<ffi::Dict<ffi::Any, ffi::Any>>);
refl::ObjectDef<ffi::EnumObj>(refl::init(false))
.def_ro("_value", &ffi::EnumObj::_value, "Ordinal assigned at registration.",
refl::AttachFieldFlag::SEqHashIgnore())
.def_ro("_name", &ffi::EnumObj::_name, "Instance name.");
refl::EnsureTypeAttrColumn(refl::type_attr::kEnumEntries);
refl::EnsureTypeAttrColumn(refl::type_attr::kEnumAttrs);
refl::EnsureTypeAttrColumn(refl::type_attr::kEnumValueEntries);
refl::GlobalDef()
.def_method("ffi.GetRegisteredTypeKeys",
[]() -> ffi::Array<ffi::String> {
return ffi::TypeTable::Global()->GetRegisteredTypeKeys();
})
.def("ffi.GetInvalidObject", ffi::GetMissingObject)
.def("ffi.GetKwargsObject", ffi::GetKwargsObject);
}
} // namespace