| 134 | } |
| 135 | |
| 136 | bool CompareObject(const ObjectRef& lhs, const ObjectRef& rhs) { |
| 137 | // NOTE: invariant: lhs and rhs are already the same type |
| 138 | const TVMFFITypeInfo* type_info = TVMFFIGetTypeInfo(lhs->type_index()); |
| 139 | if (type_info->metadata == nullptr) { |
| 140 | TVM_FFI_THROW(TypeError) << "Type metadata is not set for type `" |
| 141 | << String(type_info->type_key) |
| 142 | << "`, so StructuralHash is not supported for this type"; |
| 143 | } |
| 144 | if (type_info->metadata->structural_eq_hash_kind == kTVMFFISEqHashKindUnsupported) { |
| 145 | TVM_FFI_THROW(TypeError) << "_type_s_eq_hash_kind is not set for type `" |
| 146 | << String(type_info->type_key) |
| 147 | << "`, so StructuralHash is not supported for this type"; |
| 148 | } |
| 149 | |
| 150 | auto structural_eq_hash_kind = type_info->metadata->structural_eq_hash_kind; |
| 151 | if (structural_eq_hash_kind == kTVMFFISEqHashKindUniqueInstance) { |
| 152 | // use pointer comparison |
| 153 | return lhs.same_as(rhs); |
| 154 | } |
| 155 | if (structural_eq_hash_kind == kTVMFFISEqHashKindConstTreeNode) { |
| 156 | // fast path: constant tree node, pointer equality indicate equality and avoid content |
| 157 | // comparison if false, we should still run content comparison |
| 158 | if (lhs.same_as(rhs)) return true; |
| 159 | } |
| 160 | // check recorded mapping for DAG and fre var |
| 161 | if (structural_eq_hash_kind == kTVMFFISEqHashKindDAGNode || |
| 162 | structural_eq_hash_kind == kTVMFFISEqHashKindFreeVar) { |
| 163 | // if there is pre-recorded mapping, need to cross check the pointer equality after mapping |
| 164 | auto it = equal_map_lhs_.find(lhs); |
| 165 | if (it != equal_map_lhs_.end()) { |
| 166 | return it->second.same_as(rhs); |
| 167 | } |
| 168 | // if rhs is mapped but lhs is not, it means lhs is a free var, return false |
| 169 | if (equal_map_rhs_.count(rhs)) { |
| 170 | return false; |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | if (structural_eq_hash_kind != kTVMFFISEqHashKindFreeVar) { |
| 175 | bool success = CompareFields(lhs, rhs, type_info); |
| 176 | if (success && structural_eq_hash_kind == kTVMFFISEqHashKindDAGNode) { |
| 177 | // record the equality mapping for DAG nodes |
| 178 | equal_map_lhs_[lhs] = rhs; |
| 179 | equal_map_rhs_[rhs] = lhs; |
| 180 | } |
| 181 | return success; |
| 182 | } |
| 183 | // FreeVar path. In a non-recursive def region the FreeVar's own |
| 184 | // sub-fields are walked outside the def region (nested free vars |
| 185 | // there must resolve against an outer binding, not rebind), so we |
| 186 | // clamp ``def_region_kind_`` to ``kNone`` around the CompareFields |
| 187 | // call and restore before the binding decision below. |
| 188 | TVMFFIDefRegionKind saved_def_region_kind = def_region_kind_; |
| 189 | if (def_region_kind_ == kTVMFFIDefRegionKindNonRecursive) { |
| 190 | def_region_kind_ = kTVMFFIDefRegionKindNone; |
| 191 | } |
| 192 | bool success = CompareFields(lhs, rhs, type_info); |
| 193 | def_region_kind_ = saved_def_region_kind; |
nothing calls this directly
no test coverage detected