- // insert tagged isa table
-#if defined(__x86_64__)
- {
- // `movq $0x1122334455667788, %r10` 49 ba 88 77 66 55 44 33 22 11
- if (vtable_prototype_tagtable_size != 10) {
- _objc_fatal("vtable_prototype busted");
- }
- uint8_t *p = (uint8_t *)(dst + vtable_prototype_tagtable_offset);
- if (*p++ != 0x49) _objc_fatal("vtable_prototype busted");
- if (*p++ != 0xba) _objc_fatal("vtable_prototype busted");
- if (*(uintptr_t *)p != 0x1122334455667788) {
- _objc_fatal("vtable_prototype busted");
- }
- uintptr_t addr = (uintptr_t)_objc_tagged_isa_table;
- memcpy(p, &addr, sizeof(addr));
- }
-#else
-# warning unknown architecture
-#endif
-
- return vtable_prototype_size;
-}
-
-
-static void initVtables(void)
-{
- if (DisableVtables) {
- if (PrintVtables) {
- _objc_inform("VTABLES: vtable dispatch disabled by OBJC_DISABLE_VTABLES");
- }
- vtableCount = 0;
- vtableSelectors = NULL;
- vtableTrampolines = NULL;
- return;
- }
-
- const char * const *names;
- size_t i;
-
- if (UseGC) {
- names = defaultVtableGC;
- vtableCount = sizeof(defaultVtableGC) / sizeof(defaultVtableGC[0]);
- } else {
- names = defaultVtable;
- vtableCount = sizeof(defaultVtable) / sizeof(defaultVtable[0]);
- }
- if (vtableCount > vtableMax) vtableCount = vtableMax;
-
- vtableSelectors = (SEL*)_malloc_internal(vtableCount * sizeof(SEL));
- vtableTrampolines = (IMP*)_malloc_internal(vtableCount * sizeof(IMP));
-
- // Built-in trampolines and their descriptors
-
- size_t defaultVtableTrampolineCount =
- sizeof(defaultVtableTrampolines) / sizeof(defaultVtableTrampolines[0]);
-#ifndef NDEBUG
- // debug: use generated code for 3/4 of the table
- // Disabled even in Debug builds to avoid breaking backtrace symbol names.
- // defaultVtableTrampolineCount /= 4;
-#endif
-
- for (i = 0; i < defaultVtableTrampolineCount && i < vtableCount; i++) {
- vtableSelectors[i] = sel_registerName(names[i]);
- vtableTrampolines[i] = defaultVtableTrampolines[i];
- }
- appendTrampolines(&defaultVtableTrampolineDescriptors);
-
-
- // Generated trampolines and their descriptors
-
- if (vtableCount > defaultVtableTrampolineCount) {
- // Memory for trampoline code
- size_t generatedCount =
- vtableCount - defaultVtableTrampolineCount;
-
- const int align = 16;
- size_t codeSize =
- round_page(sizeof(objc_trampoline_header) + align +
- generatedCount * (sizeof(objc_trampoline_descriptor)
- + vtable_prototype_size + align));
- void *codeAddr = mmap(0, codeSize, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANON,
- VM_MAKE_TAG(VM_MEMORY_OBJC_DISPATCHERS), 0);
- uint8_t *t = (uint8_t *)codeAddr;
-
- // Trampoline header
- objc_trampoline_header *thdr = (objc_trampoline_header *)t;
- thdr->headerSize = sizeof(objc_trampoline_header);
- thdr->descSize = sizeof(objc_trampoline_descriptor);
- thdr->descCount = (uint32_t)generatedCount;
- thdr->next = NULL;
-
- // Trampoline descriptors
- objc_trampoline_descriptor *tdesc = (objc_trampoline_descriptor *)(thdr+1);
- t = (uint8_t *)&tdesc[generatedCount];
- t += align - ((uintptr_t)t % align);
-
- // Dispatch code
- size_t tdi;
- for (i = defaultVtableTrampolineCount, tdi = 0;
- i < vtableCount;
- i++, tdi++)
- {
- vtableSelectors[i] = sel_registerName(names[i]);
- if (ignoreSelector(vtableSelectors[i])) {
- vtableTrampolines[i] = (IMP)&vtable_ignored;
- tdesc[tdi].offset = 0;
- tdesc[tdi].flags = 0;
- } else {
- vtableTrampolines[i] = (IMP)t;
- tdesc[tdi].offset =
- (uint32_t)((uintptr_t)t - (uintptr_t)&tdesc[tdi]);
- tdesc[tdi].flags =
- OBJC_TRAMPOLINE_MESSAGE|OBJC_TRAMPOLINE_VTABLE;
-
- t += makeVtableTrampoline(t, i);
- t += align - ((uintptr_t)t % align);
- }
- }
-
- appendTrampolines(thdr);
- sys_icache_invalidate(codeAddr, codeSize);
- mprotect(codeAddr, codeSize, PROT_READ|PROT_EXEC);
- }
-
-
- if (PrintVtables) {
- for (i = 0; i < vtableCount; i++) {
- _objc_inform("VTABLES: vtable[%zu] %p %s",
- i, vtableTrampolines[i],
- sel_getName(vtableSelectors[i]));
- }
- }
-
- if (PrintVtableImages) {
- _objc_inform("VTABLE IMAGES: '#' implemented by class");
- _objc_inform("VTABLE IMAGES: '-' inherited from superclass");
- _objc_inform("VTABLE IMAGES: ' ' not implemented");
- for (i = 0; i <= vtableCount; i++) {
- char spaces[vtableCount+1+1];
- size_t j;
- for (j = 0; j < i; j++) {
- spaces[j] = '|';
- }
- spaces[j] = '\0';
- _objc_inform("VTABLE IMAGES: %s%s", spaces,
- i<vtableCount ? sel_getName(vtableSelectors[i]) : "");
- }
- }
-
- if (PrintVtables || PrintVtableImages) {
- vtableStrlen = 0;
- for (i = 0; i < vtableCount; i++) {
- vtableStrlen += strlen(sel_getName(vtableSelectors[i]));
- }
- }
-}
-
-
-static int vtable_getIndex(SEL sel)
-{
- unsigned int i;
- for (i = 0; i < vtableCount; i++) {
- if (vtableSelectors[i] == sel) return i;
- }
- return -1;
-}
-
-static BOOL vtable_containsSelector(SEL sel)
-{
- return (vtable_getIndex(sel) < 0) ? NO : YES;
-}
-
-static void printVtableOverrides(class_t *cls, class_t *supercls)
-{
- char overrideMap[vtableCount+1];
- unsigned int i;
-
- if (supercls) {
- size_t overridesBufferSize = vtableStrlen + 2*vtableCount + 1;
- char *overrides =
- (char *)_calloc_internal(overridesBufferSize, 1);
- for (i = 0; i < vtableCount; i++) {
- if (ignoreSelector(vtableSelectors[i])) {
- overrideMap[i] = '-';
- continue;
- }
- if (getMethodNoSuper_nolock(cls, vtableSelectors[i])) {
- strlcat(overrides, sel_getName(vtableSelectors[i]), overridesBufferSize);
- strlcat(overrides, ", ", overridesBufferSize);
- overrideMap[i] = '#';
- } else if (getMethod_nolock(cls, vtableSelectors[i])) {
- overrideMap[i] = '-';
- } else {
- overrideMap[i] = ' ';
- }
- }
- if (PrintVtables) {
- _objc_inform("VTABLES: %s%s implements %s",
- getName(cls), isMetaClass(cls) ? "(meta)" : "",
- overrides);
- }
- _free_internal(overrides);
- }
- else {
- for (i = 0; i < vtableCount; i++) {
- overrideMap[i] = '#';
- }
- }
-
- if (PrintVtableImages) {
- overrideMap[vtableCount] = '\0';
- _objc_inform("VTABLE IMAGES: %s %s%s", overrideMap,
- getName(cls), isMetaClass(cls) ? "(meta)" : "");
- }
-}
-
-/***********************************************************************
-* updateVtable
-* Rebuilds vtable for cls, using superclass's vtable if appropriate.
-* Assumes superclass's vtable is up to date.
-* Does nothing to subclass vtables.
-* Locking: runtimeLock must be held by the caller.
-**********************************************************************/
-static void updateVtable(class_t *cls, BOOL force)
-{
- rwlock_assert_writing(&runtimeLock);
-
- // Keep default vtable until +initialize is complete.
- // Default vtable redirects to objc_msgSend, which
- // enforces +initialize locking.
- if (!force && !_class_isInitialized((Class)cls)) {
- /*
- if (PrintVtables) {
- _objc_inform("VTABLES: KEEPING DEFAULT vtable for "
- "uninitialized class %s%s",
- getName(cls), isMetaClass(cls) ? "(meta)" : "");
- }
- */
- return;
- }
-
- // Decide whether this class can share its superclass's vtable.
-
- class_t *supercls = getSuperclass(cls);
- BOOL needVtable = NO;
- unsigned int i;
- if (!supercls) {
- // Root classes always need a vtable
- needVtable = YES;
- }
- else if (cls->data()->flags & RW_SPECIALIZED_VTABLE) {
- // Once you have your own vtable, you never go back
- needVtable = YES;
- }
- else {
- for (i = 0; i < vtableCount; i++) {
- if (ignoreSelector(vtableSelectors[i])) continue;
- method_t *m = getMethodNoSuper_nolock(cls, vtableSelectors[i]);
- // assume any local implementation differs from super's
- if (m) {
- needVtable = YES;
- break;
- }
- }
- }
-
- // Build a vtable for this class, or not.
-
- if (!needVtable) {
- if (PrintVtables) {
- _objc_inform("VTABLES: USING SUPERCLASS vtable for class %s%s",
- getName(cls), isMetaClass(cls) ? "(meta)" : "");
- }
- cls->vtable = supercls->vtable;
- }
- else {
- if (PrintVtables) {
- _objc_inform("VTABLES: %s vtable for class %s%s",
- (cls->data()->flags & RW_SPECIALIZED_VTABLE) ?
- "UPDATING SPECIALIZED" : "CREATING SPECIALIZED",
- getName(cls), isMetaClass(cls) ? "(meta)" : "");
- }
- if (PrintVtables || PrintVtableImages) {
- printVtableOverrides(cls, supercls);
- }
-
- IMP *new_vtable;
- IMP *super_vtable = supercls ? supercls->vtable : &_objc_empty_vtable;
- // fixme use msgForward (instead of msgSend from empty vtable) ?
-
- if (cls->data()->flags & RW_SPECIALIZED_VTABLE) {
- // update cls->vtable in place
- new_vtable = cls->vtable;
- assert(new_vtable != &_objc_empty_vtable);
- } else {
- // make new vtable
- new_vtable = (IMP*)malloc(vtableCount * sizeof(IMP));
- changeInfo(cls, RW_SPECIALIZED_VTABLE, 0);
- }
-
- for (i = 0; i < vtableCount; i++) {
- if (ignoreSelector(vtableSelectors[i])) {
- new_vtable[i] = (IMP)&vtable_ignored;
- } else {
- method_t *m = getMethodNoSuper_nolock(cls, vtableSelectors[i]);
- if (m) new_vtable[i] = _method_getImplementation(m);
- else new_vtable[i] = super_vtable[i];
- }
- }
-
- if (cls->vtable != new_vtable) {
- // don't let other threads see uninitialized parts of new_vtable
- OSMemoryBarrier();
- cls->vtable = new_vtable;
- }
- }
-}
-
-// SUPPORT_VTABLE
-#else
-// !SUPPORT_VTABLE
-
-static void initVtables(void)
-{
- if (PrintVtables) {
- _objc_inform("VTABLES: no vtables on this architecture");
- }
-}
-
-static BOOL vtable_containsSelector(SEL sel)
-{
- return NO;
-}
-
-static void updateVtable(class_t *cls, BOOL force)
-{
-}
-
-// !SUPPORT_VTABLE
-#endif