+ // This function could be made to do a binary search if we can
+ // manage to somehow sort the IFaceTables...
+ uintptr_t downcast(::System::_i_Object *obj, const GUID *new_guid)
+ {
+ if (!obj)
+ return 0;
+
+ void unsupported_long_size();
+
+ if (sizeof(long) != 4 && sizeof(long) != 8)
+ unsupported_long_size();
+
+ IFaceTable *tbl = obj->info->concrete_IFaceTable;
+ unsigned long new_guid_first = new_guid->l[0];
+
+ // This doesn't use guids_equal(), as that would eliminate the
+ // ability to cache the first word of new_guid. The compiler
+ // *might* do it anyway, but this code was written before
+ // guids_equal existed, and I don't want to risk removing an
+ // optimization by changing it now without testing how GCC
+ // behaves.
+
+ while (true) {
+ if (tbl->info->guid->l[0] == new_guid_first &&
+ tbl->info->guid->l[1] == new_guid->l[1] &&
+ (sizeof(long) == 8 ||
+ (tbl->info->guid->l[2] == new_guid->l[2] &&
+ tbl->info->guid->l[3] == new_guid->l[3])))
+ break;
+
+ tbl++;
+ if (__builtin_expect(!tbl->info->guid->l[0], 0))