]> git.saurik.com Git - apple/objc4.git/blobdiff - runtime/objc-rtp.m
objc4-493.9.tar.gz
[apple/objc4.git] / runtime / objc-rtp.m
index c903eb5a3ee97e3d9757bed39fc939ee0f700606..2fa1b6c6e3056cf7967c436486fe5b5889d1a9dd 100644 (file)
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
-/*
-  Implementation of the "objc runtime pages", an fixed area 
-  in high memory that can be reached via an absolute branch.
-*/
 
 #import "objc-private.h"
 #import <objc/message.h>
 
 
-#if defined(__ppc__)
-
-static size_t rtp_copy_code(unsigned* dest, unsigned* source, size_t max_insns);
-static void rtp_set_up_objc_msgSend(uintptr_t address, size_t maxsize);
-static void rtp_set_up_other(uintptr_t address, size_t maxsize, const char *name, void *gc_code, void *non_gc_code);
-
-/**********************************************************************
-* rtp_init
-* Allocate and initialize the Objective-C runtime pages.
-* Kills the process if something goes wrong.
-**********************************************************************/
-__private_extern__ void rtp_init(void)
-{
-    kern_return_t ret;
-    vm_address_t objcRTPages = (vm_address_t)(kRTPagesHi - kRTPagesSize);
-
-    if (PrintRTP) {
-        _objc_inform("RTP: initializing rtp at [%p..%p)", 
-                     (void *)objcRTPages, (void *)kRTPagesHi);
-    }
-
-    // unprotect the ObjC runtime pages for writing
-    ret = vm_protect(mach_task_self(),
-                     objcRTPages, kRTPagesSize,
-                     FALSE, VM_PROT_READ | VM_PROT_WRITE);
-                     
-    if (ret != KERN_SUCCESS) {
-        if (PrintRTP) {
-            _objc_inform("RTP: warning: libSystem/kernel did not allocate Objective-C runtime pages; continuing anyway");
-        }
-        return;
-    }
-    
-    // initialize code in ObjC runtime pages
-    rtp_set_up_objc_msgSend(kRTAddress_objc_msgSend, kRTSize_objc_msgSend);
-#ifdef NO_GC
-    #define objc_assign_ivar_gc objc_assign_ivar_non_gc
-    #define objc_assign_global_gc objc_assign_global_non_gc
-    #define objc_assign_strongCast_gc objc_assign_strongCast_non_gc
-#endif
-    rtp_set_up_other(kRTAddress_objc_assign_ivar, kRTSize_objc_assign_ivar,
-                    "objc_assign_ivar", objc_assign_ivar_gc, objc_assign_ivar_non_gc);
-                    
-    rtp_set_up_other(kRTAddress_objc_assign_global, kRTSize_objc_assign_global,
-                    "objc_assign_global", objc_assign_global_gc, objc_assign_global_non_gc);
-                    
-    rtp_set_up_other(kRTAddress_objc_assign_strongCast, kRTSize_objc_assign_strongCast,
-                    "objc_assign_strongCast", objc_assign_strongCast_gc, objc_assign_strongCast_non_gc);
-
-    // initialize data in ObjC runtime pages
-    memset((char *)kRTAddress_zero, 0, 16);
-    strlcpy((char *)kIgnore, "<ignored selector>", OBJC_SIZE_T(19));
-
-    // re-protect the ObjC runtime pages for execution
-    ret = vm_protect(mach_task_self(),
-                     objcRTPages, kRTPagesSize,
-                     FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
-    if (ret != KERN_SUCCESS) {
-        _objc_inform("RTP: Could not re-protect Objective-C runtime pages!");
-    }
-}
-
-
-/**********************************************************************
-* rtp_set_up_objc_msgSend
-*
-* Construct the objc runtime page version of objc_msgSend
-* address is the entry point of the new implementation.
-* maxsize is the number of bytes available for the new implementation.
-**********************************************************************/
-static void rtp_set_up_objc_msgSend(uintptr_t address, size_t maxsize) 
-{
-    // Location in the runtime pages of the new function.
-    unsigned *buffer = (unsigned *)address;
-
-    // Location of the original implementation.
-    // objc_msgSend is simple enough to copy directly
-    unsigned *code = (unsigned *)objc_msgSend;
-    
-    // If building an instrumented or profiled runtime, simply branch 
-    // directly to the full implementation.
-#if defined(OBJC_INSTRUMENTED) || defined(PROFILE)
-    size_t written = objc_write_branch(buffer, code);
-    sys_icache_invalidate(buffer, written*4);
-    if (PrintRTP) {
-        _objc_inform("RTP: instrumented or profiled libobjc - objc_msgSend "
-                     "in RTP at %p is a %zu instruction branch", 
-                     buffer, written);
-    }
-    return;
-#endif
-
-    if (PrintRTP) {
-        _objc_inform("RTP: writing objc_msgSend at [%p..%p) ...", 
-                     (void *)address, (void *)(address+maxsize));
-    }
-
-    // Copy instructions from function to runtime pages
-    // i is the number of INSTRUCTIONS written so far
-    size_t max_insns = maxsize / sizeof(unsigned);
-    size_t i = rtp_copy_code(buffer, code, max_insns);
-    if (i + objc_branch_size(buffer + i, code + i) > max_insns) {
-        // objc_msgSend didn't fit in the alloted space.
-        // Branch to ordinary objc_msgSend instead so the program won't crash.
-        i = objc_write_branch(buffer, code);
-        sys_icache_invalidate(buffer, i*4);
-        _objc_inform("RTP: objc_msgSend is too large to fit in the "
-                     "runtime pages (%zu bytes available)", maxsize);
-        return;
-    }
-    
-    { 
-        // Replace load of _objc_nilReceiver into r11
-        // This assumes that the load of _objc_nilReceiver
-        // immediately follows the LAST `mflr r0` in objc_msgSend, 
-        // and that the original load sequence is six instructions long.
-
-        // instructions used to load _objc_nilReceiver
-        const unsigned op_mflr_r0    = 0x7c0802a6u;
-        const unsigned op_nop     = 0x60000000u;
-        
-        // get address of _objc_nilReceiver, and its lo and hi halves
-        uintptr_t address = (uintptr_t)&_objc_nilReceiver;
-        uint16_t lo = address & 0xffff;
-        uint16_t ha = ((address - (int16_t)lo) >> 16) & 0xffff;
-#if defined(__ppc64__)
-        uint16_t hi2 = (address >> 32) & 0xffff;
-        uint16_t hi3 = (address >> 48) & 0xffff;
-#endif
-
-        // search for mflr instruction
-        size_t j;
-        for (j = i; j-- != 0; ) {
-            if (buffer[j] == op_mflr_r0) {
-                const unsigned op_lis_r11 = 0x3d600000u;
-                const unsigned op_lwz_r11 = 0x816b0000u;
-#if defined(__ppc__)
-                // lis r11, ha
-                // lwz r11, lo(r11)
-                buffer[j + 0] = op_lis_r11 | ha;
-                buffer[j + 1] = op_nop;
-                buffer[j + 2] = op_nop;
-                buffer[j + 3] = op_lwz_r11 | lo;
-                buffer[j + 4] = op_nop;
-                buffer[j + 5] = op_nop;
-#elif defined(__ppc64__)
-                const unsigned op_ori_r11 = 0x616b0000u;
-                const unsigned op_oris_r11 = 0x656b0000u;
-                const unsigned op_sldi_r11 = 0x796b07c6u;
-                // lis  r11, hi3
-                // ori  r11, r11, hi2
-                // sldi r11, r11, 32
-                // oris r11, r11, ha
-                // lwz  r11, lo(r11)
-                buffer[j + 0] = op_lis_r11  | hi3;
-                buffer[j + 1] = op_ori_r11  | hi2;
-                buffer[j + 2] = op_sldi_r11;
-                buffer[j + 3] = op_oris_r11 | ha;
-                buffer[j + 4] = op_lwz_r11  | lo;
-                buffer[j + 5] = op_nop;
-#endif
-                break;
-            }
-        }
-    }
-    
-    // branch to the cache miss code
-    i += objc_write_branch(buffer + i, code + i);
-    
-    // flush the instruction cache
-    sys_icache_invalidate(buffer, i*4);
-
-    if (PrintRTP) {
-        _objc_inform("RTP: wrote   objc_msgSend at [%p..%p)", 
-                     (void *)address, (void *)(address + i*sizeof(unsigned)));
-    }
-}
-
-
-/**********************************************************************
-* rtp_set_up_other
-*
-* construct the objc runtime page version of the supplied code
-* address is the entry point of the new implementation.
-* maxsize is the number of bytes available for the new implementation.
-* name is the c string name of the routine being set up.
-* gc_code is the code to use if collecting is enabled (assumed to be large and requiring a branch.)
-* non_gc_code is the code to use if collecting is not enabled (assumed to be small enough to copy.)
-**********************************************************************/
-static void rtp_set_up_other(uintptr_t address, size_t maxsize, const char *name, void *gc_code, void *non_gc_code) {
-    // location in the runtime pages of this function
-    unsigned *buffer = (unsigned *)address;
-    
-    // Location of the original implementation.
-    unsigned *code = (unsigned *)(objc_collecting_enabled() ? gc_code : non_gc_code);
-    
-    if (objc_collecting_enabled()) {
-        size_t written = objc_write_branch(buffer, code);
-        sys_icache_invalidate(buffer, written*4);
-        if (PrintRTP) {
-            _objc_inform("RTP: %s in RTP at %p is a %zu instruction branch", 
-                         name, buffer, written);
-        }
-        return;
-    }
-
-    if (PrintRTP) {
-        _objc_inform("RTP: writing %s at [%p..%p) ...", 
-                     name, (void *)address, (void *)(address + maxsize));
-    }
-
-    // Copy instructions from function to runtime pages
-    // i is the number of INSTRUCTIONS written so far
-    size_t max_insns = maxsize / sizeof(unsigned);
-    size_t i = rtp_copy_code(buffer, code, max_insns);
-    if (i > max_insns) {
-        // code didn't fit in the alloted space.
-        // Branch to ordinary objc_assign_ivar instead so the program won't crash.
-        i = objc_write_branch(buffer, code);
-        sys_icache_invalidate(buffer, i*4);
-        _objc_inform("RTP: %s is too large to fit in the "
-                     "runtime pages (%zu bytes available)", name, maxsize);
-        return;
-    }
-    
-    // flush the instruction cache
-    sys_icache_invalidate(buffer, i*4);
-
-    if (PrintRTP) {
-        _objc_inform("RTP: wrote %s at [%p..%p)", 
-                     name, (void *)address, 
-                     (void *)(address + i * sizeof(unsigned)));
-    }
-}
-
-
-/**********************************************************************
-* rtp_copy_code
-*
-* Copy blr-terminated PPC instructions from source to dest.
-* If a blr is reached then that blr is copied, and the return value is 
-*   the number of instructions copied ( <= max_insns )
-* If no blr is reached then exactly max_insns instructions are copied, 
-*   and the return value is max_insns+1.
-**********************************************************************/
-static size_t rtp_copy_code(unsigned* dest, unsigned* source, size_t max_insns)
-{
-    const unsigned op_blr = 0x4e800020u;
-    size_t i;
-    
-    // copy instructions until blr is found
-    for (i = 0; i < max_insns; i++) {
-        dest[i] = source[i];
-        if (source[i] == op_blr) break;
-    }
-    
-    // return number of instructions copied
-    // OR max_insns+1 if no blr was found
-    return i + 1;
-}
-
-
-#elif defined(__i386__)
+#if defined(__i386__)
 
 
 /**********************************************************************
@@ -317,17 +51,19 @@ static void rtp_swap_imp(unsigned *address, void *code, const char *name)
 }
 
 
-__private_extern__ void rtp_init(void)
+PRIVATE_EXTERN void rtp_init(void)
 {
     // At load time, the page on which the objc_assign_* routines live is not
     // marked as executable. We fix that here, regardless of the GC choice.
-#ifndef NO_GC
+#if SUPPORT_GC
     if (UseGC)
     {
         rtp_swap_imp((unsigned*)objc_assign_ivar,
             objc_assign_ivar_gc, "objc_assign_ivar");
         rtp_swap_imp((unsigned*)objc_assign_global,
             objc_assign_global_gc, "objc_assign_global");
+        rtp_swap_imp((unsigned*)objc_assign_threadlocal,
+            objc_assign_threadlocal_gc, "objc_assign_threadlocal");
         rtp_swap_imp((unsigned*)objc_assign_strongCast,
             objc_assign_strongCast_gc, "objc_assign_strongCast");
     }
@@ -344,7 +80,7 @@ __private_extern__ void rtp_init(void)
 #else
 
 
-__private_extern__ void rtp_init(void)
+PRIVATE_EXTERN void rtp_init(void)
 {
     if (PrintRTP) {
         _objc_inform("RTP: no rtp implementation for this platform");