Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -28,10 +28,11 @@ protocol.m \ selector.m \ sparsearray.m \ static-instances.m \ synchronized.m \ + tagged-pointer.m \ ${USE_SRCS_THREADS} SRCS_THREADS = threading.m \ ../mutex.m \ ../once.m \ ../tlskey.m Index: src/runtime/ObjFWRT.h ================================================================== --- src/runtime/ObjFWRT.h +++ src/runtime/ObjFWRT.h @@ -242,10 +242,15 @@ void *_Nullable bytes); extern void *_Nullable objc_destructInstance(id _Nullable object); extern void *_Null_unspecified objc_autoreleasePoolPush(void); extern void objc_autoreleasePoolPop(void *_Null_unspecified pool); extern id _Nullable _objc_rootAutorelease(id _Nullable object); +extern int_fast8_t objc_registerTaggedPointerClass(Class _Nonnull class); +extern Class _Nullable object_getTaggedPointerClass(id _Nonnull object); +extern uintptr_t object_getTaggedPointerValue(id _Nonnull object); +extern id _Nullable objc_createTaggedPointer(uint_fast8_t class, + uintptr_t value); /* * Used by the compiler, but can also be called manually. * * These declarations are also required to prevent Clang's implicit Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -797,5 +797,38 @@ { M68K_ARG(struct objc_hashtable *, table, a0) objc_hashtable_free(table); } + +int_fast8_t +glue_objc_registerTaggedPointerClass PPC_PARAMS(Class class) +{ + M68K_ARG(Class, class, a0) + + return objc_registerTaggedPointerClass(class); +} + +Class +glue_object_getTaggedPointerClass PPC_PARAMS(id object) +{ + M68K_ARG(id, object, a0) + + return object_getTaggedPointerClass(object); +} + +uintptr_t +glue_object_getTaggedPointerValue PPC_PARAMS(id object) +{ + M68K_ARG(id, object, a0) + + return object_getTaggedPointerValue(object); +} + +id +glue_objc_createTaggedPointer PPC_PARAMS(uint_fast8_t class, uintptr_t value) +{ + M68K_ARG(uint_fast8_t, class, d0) + M68K_ARG(uintptr_t, value, d1) + + return objc_createTaggedPointer(class, value); +} Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -145,10 +145,14 @@ extern struct objc_hashtable *glue_objc_hashtable_new(void); extern void glue_objc_hashtable_set(void); extern void *glue_objc_hashtable_get(void); extern void glue_objc_hashtable_delete(void); extern void glue_objc_hashtable_free(void); +extern int_fast8_t glue_objc_registerTaggedPointerClass(void); +extern Class _Nullable glue_object_getTaggedPointerClass(void); +extern uintptr_t glue_object_getTaggedPointerValue(void); +extern id _Nullable glue_objc_createTaggedPointer(void); #ifdef OF_MORPHOS const ULONG __abox__ = 1; #endif struct ExecBase *SysBase; @@ -671,10 +675,14 @@ (CONST_APTR)glue_objc_hashtable_new, (CONST_APTR)glue_objc_hashtable_set, (CONST_APTR)glue_objc_hashtable_get, (CONST_APTR)glue_objc_hashtable_delete, (CONST_APTR)glue_objc_hashtable_free, + (CONST_APTR)glue_objc_registerTaggedPointerClass, + (CONST_APTR)glue_object_getTaggedPointerClass, + (CONST_APTR)glue_object_getTaggedPointerValue, + (CONST_APTR)glue_objc_createTaggedPointer, (CONST_APTR)-1, #ifdef OF_MORPHOS (CONST_APTR)FUNCARRAY_END #endif }; Index: src/runtime/amigaos3.sfd ================================================================== --- src/runtime/amigaos3.sfd +++ src/runtime/amigaos3.sfd @@ -87,6 +87,11 @@ struct objc_hashtable *_Nonnull glue_objc_hashtable_new(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size)(a0,a1,d0) void glue_objc_hashtable_set(struct objc_hashtable *_Nonnull table, const void *_Nonnull key, const void *_Nonnull object)(a0,a1,a2) void *_Nullable glue_objc_hashtable_get(struct objc_hashtable *_Nonnull table, const void *_Nonnull key)(a0,a1) void glue_objc_hashtable_delete(struct objc_hashtable *_Nonnull table, const void *_Nonnull key)(a0,a1) void glue_objc_hashtable_free(struct objc_hashtable *_Nonnull table)(a0) +* Public functions again +int_fast8_t glue_objc_registerTaggedPointerClass(Class _Nonnull class_)(a0) +Class _Nullable glue_object_getTaggedPointerClass(id _Nonnull object)(a0) +uintptr_t glue_object_getTaggedPointerValue(id _Nonnull object)(a0) +id _Nullable glue_objc_createTaggedPointer(uint_fast8_t class_, uintptr_t value)(d0,d1) ==end Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -844,10 +844,13 @@ struct objc_object *object; if (object_ == nil) return Nil; + if (object_isTaggedPointer(object_)) + return object_getTaggedPointerClass(object_); + object = (struct objc_object *)object_; return object->isa; } Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -705,5 +705,11 @@ void objc_hashtable_free(struct objc_hashtable *table) { glue_objc_hashtable_free(table); } + +extern int_fast8_t objc_registerTaggedPointerClass(Class _Nonnull class); +extern Class _Nullable object_getTaggedPointerClass(id _Nonnull object); +extern uintptr_t object_getTaggedPointerValue(id _Nonnull object); +extern id _Nullable objc_createTaggedPointer(uint_fast8_t class, + uintptr_t value); Index: src/runtime/lookup-asm/lookup-asm-x86-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86-elf.S +++ src/runtime/lookup-asm/lookup-asm-x86-elf.S @@ -31,10 +31,13 @@ \name: mov edx, [esp+4] test edx, edx jz short ret_nil + bt edx, 0 + jc short .Ltagged_pointer_\name + mov edx, [edx] mov edx, [edx+32] .Lmain_\name: mov eax, [esp+8] @@ -56,10 +59,23 @@ 0: call get_eip add eax, offset _GLOBAL_OFFSET_TABLE_ lea eax, [eax+\not_found@GOTOFF] jmp eax + +.Ltagged_pointer_\name: + movzx edx, dl + shr edx, 1 + + call get_eip + add eax, offset _GLOBAL_OFFSET_TABLE_ + + lea eax, [eax+objc_tagged_pointer_classes@GOTOFF] + mov edx, [eax+edx*4] + mov edx, [edx+32] + + jmp short .Lmain_\name .type \name, %function .size \name, .-\name .endm .macro generate_lookup_super name lookup Index: src/runtime/lookup-asm/lookup-asm-x86-win32.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86-win32.S +++ src/runtime/lookup-asm/lookup-asm-x86-win32.S @@ -29,10 +29,13 @@ \name: mov edx, [esp+4] test edx, edx jz short ret_nil + bt edx, 0 + jc short .Ltagged_pointer_\name + mov edx, [edx] mov edx, [edx+32] .Lmain_\name: mov eax, [esp+8] @@ -45,16 +48,23 @@ mov edx, [edx+ecx*4] movzx ecx, byte ptr [eax] mov eax, [edx+ecx*4] test eax, eax - jz short 0f + jz \not_found ret -0: - jmp \not_found +.Ltagged_pointer_\name: + movzx edx, dl + shr edx, 1 + + mov eax, offset _objc_tagged_pointer_classes + mov edx, [eax+edx*4] + mov edx, [edx+32] + + jmp short .Lmain_\name .endm .macro generate_lookup_super name lookup \name: mov edx, [esp+4] Index: src/runtime/lookup-asm/lookup-asm-x86_64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-elf.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-elf.S @@ -30,10 +30,13 @@ .macro generate_lookup name not_found \name: test rdi, rdi jz short ret_nil + bt edi, 0 + jc short .Ltagged_pointer_\name + mov r8, [rdi] mov r8, [r8+64] .Lmain_\name: mov rax, [rsi] @@ -49,10 +52,20 @@ test rax, rax jz short \not_found@PLT ret + +.Ltagged_pointer_\name: + movzx r8, dil + shr r8, 1 + + mov rax, [rip+objc_tagged_pointer_classes@GOTPCREL] + mov r8, [rax+r8*8] + mov r8, [r8+64] + + jmp short .Lmain_\name .type \name, %function .size \name, .-\name .endm .macro generate_lookup_super name lookup Index: src/runtime/lookup-asm/lookup-asm-x86_64-win64.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-win64.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-win64.S @@ -25,13 +25,16 @@ .globl objc_msg_lookup_super_stret .section .text .macro generate_lookup name not_found \name: - test %rcx, %rcx + test rcx, rcx jz short ret_nil + bt ecx, 0 + jc short .Ltagged_pointer_\name + mov r8, [rcx] mov r8, [r8+56] .Lmain_\name: mov r10, rcx @@ -55,10 +58,20 @@ 0: mov rcx, r10 mov rdx, r11 jmp \not_found + +.Ltagged_pointer_\name: + movzx r8, cl + shr r8, 1 + + mov rax, offset objc_tagged_pointer_classes + mov r8, [rax+r8*8] + mov r8, [r8+56] + + jmp short .Lmain_\name .endm .macro generate_lookup_super name lookup \name: mov r8, rcx Index: src/runtime/morphos-clib.h ================================================================== --- src/runtime/morphos-clib.h +++ src/runtime/morphos-clib.h @@ -77,10 +77,15 @@ void *glue_objc_destructInstance(id); void *glue_objc_autoreleasePoolPush(void); void glue_objc_autoreleasePoolPop(void *); id glue__objc_rootAutorelease(id); /* The following functions are private! Don't use! */ -struct objc_hashtable *glue_objc_hashtable_new(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size); -void glue_objc_hashtable_set(struct objc_hashtable *table, const void *key, const void *object); -void *glue_objc_hashtable_get(struct objc_hashtable *table, const void *key); -void glue_objc_hashtable_delete(struct objc_hashtable *table, const void *key); -void glue_objc_hashtable_free(struct objc_hashtable *table); +struct objc_hashtable *glue_objc_hashtable_new(objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t); +void glue_objc_hashtable_set(struct objc_hashtable *, const void *, const void *); +void *glue_objc_hashtable_get(struct objc_hashtable *, const void *); +void glue_objc_hashtable_delete(struct objc_hashtable *, const void *); +void glue_objc_hashtable_free(struct objc_hashtable *); +/* Public functions again */ +int_fast8_t glue_objc_registerTaggedPointerClass(Class); +Class _Nullable glue_object_getTaggedPointerClass(id); +uintptr_t glue_object_getTaggedPointerValue(id); +id glue_objc_createTaggedPointer(uint_fast8_t, uintptr_t); Index: src/runtime/morphos.fd ================================================================== --- src/runtime/morphos.fd +++ src/runtime/morphos.fd @@ -85,6 +85,11 @@ glue_objc_hashtable_new(hash,equal,size)(sysv,r12base) glue_objc_hashtable_set(table,key,object)(sysv,r12base) glue_objc_hashtable_get(table,key)(sysv,r12base) glue_objc_hashtable_delete(table,key)(sysv,r12base) glue_objc_hashtable_free(table)(sysv,r12base) +* Public functions again +glue_objc_registerTaggedPointerClass(class_)(sysv,r12base) +glue_object_getTaggedPointerClass(object)(sysv,r12base) +glue_object_getTaggedPointerValue(object)(sysv,r12base) +glue_objc_createTaggedPointer(class_,value)(sysv,r12base) ##end Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -333,10 +333,18 @@ uint8_t j = idx; return dtable->buckets[i]->buckets[j]; #endif } + +static inline bool +object_isTaggedPointer(id _Nullable object) +{ + uintptr_t pointer = (uintptr_t)object; + + return pointer & 1; +} #if defined(OF_ELF) # if defined(OF_X86_64) || defined(OF_X86) || defined(OF_POWERPC) || \ defined(OF_ARM64) || defined(OF_ARM) || \ defined(OF_MIPS64_N64) || defined(OF_MIPS) || \ ADDED src/runtime/tagged-pointer.m Index: src/runtime/tagged-pointer.m ================================================================== --- /dev/null +++ src/runtime/tagged-pointer.m @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "ObjFWRT.h" + +#import "private.h" + +#define NUM_TAGGED_POINTER_CLASSES 0x7F + +Class objc_tagged_pointer_classes[NUM_TAGGED_POINTER_CLASSES]; +static uint_fast8_t taggedPointerClassesCount; + +int_fast8_t +objc_registerTaggedPointerClass(Class class) +{ + uint_fast8_t i; + + objc_global_mutex_lock(); + + if (taggedPointerClassesCount == NUM_TAGGED_POINTER_CLASSES) { + objc_global_mutex_unlock(); + return -1; + } + + i = taggedPointerClassesCount++; + objc_tagged_pointer_classes[i] = class; + + objc_global_mutex_unlock(); + + return i; +} + +Class +object_getTaggedPointerClass(id object) +{ + uintptr_t pointer = (uintptr_t)object; + + pointer &= 0x7E; + pointer >>= 1; + + if (pointer >= NUM_TAGGED_POINTER_CLASSES) + return Nil; + + return objc_tagged_pointer_classes[pointer]; +} + +uintptr_t +object_getTaggedPointerValue(id object) +{ + uintptr_t pointer = (uintptr_t)object; + + pointer &= ~(uintptr_t)0xFF; + pointer >>= 8; + + return pointer; +} + +id +objc_createTaggedPointer(uint_fast8_t class, uintptr_t value) +{ + uintptr_t pointer; + + if (class >= NUM_TAGGED_POINTER_CLASSES) + return nil; + + if (value > (UINTPTR_MAX >> 8)) + return nil; + + pointer = (class << 1) | 1; + pointer |= (value << 8); + + return (id)pointer; +}