| 164 | } |
| 165 | |
| 166 | ScriptingObject* ScriptingObject::FromInterface(void* interfaceObj, const ScriptingTypeHandle& interfaceType) |
| 167 | { |
| 168 | if (!interfaceObj || !interfaceType) |
| 169 | return nullptr; |
| 170 | PROFILE_CPU(); |
| 171 | |
| 172 | // Find the type which implements this interface and has the same vtable as interface object |
| 173 | // TODO: implement vtableInterface->type hashmap caching in Scripting service to optimize sequential interface casts |
| 174 | auto& modules = BinaryModule::GetModules(); |
| 175 | for (auto module : modules) |
| 176 | { |
| 177 | for (auto& type : module->Types) |
| 178 | { |
| 179 | if (type.Type != ScriptingTypes::Script) |
| 180 | continue; |
| 181 | auto interfaceImpl = type.GetInterface(interfaceType); |
| 182 | if (!interfaceImpl || !interfaceImpl->IsNative) |
| 183 | continue; |
| 184 | |
| 185 | // Get vtable for this type |
| 186 | void* vtable = type.Script.VTable; |
| 187 | if (!vtable && type.GetDefaultInstance()) |
| 188 | { |
| 189 | // Use vtable from default instance of this type |
| 190 | vtable = *(void***)type.GetDefaultInstance(); |
| 191 | } |
| 192 | |
| 193 | // Check if object interface vtable matches the type interface vtable value |
| 194 | ScriptingObject* predictedObj = (ScriptingObject*)((byte*)interfaceObj - interfaceImpl->VTableOffset); |
| 195 | void* predictedVTable = *(void***)predictedObj; |
| 196 | if (vtable == predictedVTable) |
| 197 | { |
| 198 | ASSERT(predictedObj->GetType().GetInterface(interfaceType)); |
| 199 | return predictedObj; |
| 200 | } |
| 201 | |
| 202 | // Check for case of passing object directly |
| 203 | predictedObj = (ScriptingObject*)interfaceObj; |
| 204 | predictedVTable = *(void***)predictedObj; |
| 205 | if (vtable == predictedVTable) |
| 206 | { |
| 207 | ASSERT(predictedObj->GetType().GetInterface(interfaceType)); |
| 208 | return predictedObj; |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | // Special case for interface wrapper object |
| 214 | for (const auto& e : ScriptingObjectsInterfaceWrappers) |
| 215 | { |
| 216 | if (e.Value == interfaceObj) |
| 217 | return e.Key.First; |
| 218 | } |
| 219 | |
| 220 | return nullptr; |
| 221 | } |
| 222 | |
| 223 | void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHandle& interfaceType) |
nothing calls this directly
no test coverage detected