10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric  * Block_private.h
30b57cec5SDimitry Andric  *
40b57cec5SDimitry Andric  * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
50b57cec5SDimitry Andric  * to any person obtaining a copy of this software and associated documentation
60b57cec5SDimitry Andric  * files (the "Software"), to deal in the Software without restriction,
70b57cec5SDimitry Andric  * including without limitation the rights to use, copy, modify, merge, publish,
80b57cec5SDimitry Andric  * distribute, sublicense, and/or sell copies of the Software, and to permit
90b57cec5SDimitry Andric  * persons to whom the Software is furnished to do so, subject to the following
100b57cec5SDimitry Andric  * conditions:
110b57cec5SDimitry Andric  *
120b57cec5SDimitry Andric  * The above copyright notice and this permission notice shall be included in
130b57cec5SDimitry Andric  * all copies or substantial portions of the Software.
140b57cec5SDimitry Andric  *
150b57cec5SDimitry Andric  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
160b57cec5SDimitry Andric  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
170b57cec5SDimitry Andric  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
180b57cec5SDimitry Andric  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
190b57cec5SDimitry Andric  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
200b57cec5SDimitry Andric  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
210b57cec5SDimitry Andric  * SOFTWARE.
220b57cec5SDimitry Andric  *
230b57cec5SDimitry Andric  */
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric #ifndef _BLOCK_PRIVATE_H_
260b57cec5SDimitry Andric #define _BLOCK_PRIVATE_H_
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #if !defined(BLOCK_EXPORT)
290b57cec5SDimitry Andric #   if defined(__cplusplus)
300b57cec5SDimitry Andric #       define BLOCK_EXPORT extern "C"
310b57cec5SDimitry Andric #   else
320b57cec5SDimitry Andric #       define BLOCK_EXPORT extern
330b57cec5SDimitry Andric #   endif
340b57cec5SDimitry Andric #endif
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric #ifndef _MSC_VER
370b57cec5SDimitry Andric #include <stdbool.h>
380b57cec5SDimitry Andric #else
390b57cec5SDimitry Andric /* MSVC doesn't have <stdbool.h>. Compensate. */
400b57cec5SDimitry Andric typedef char bool;
410b57cec5SDimitry Andric #define true (bool)1
420b57cec5SDimitry Andric #define false (bool)0
430b57cec5SDimitry Andric #endif
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric #if defined(__cplusplus)
460b57cec5SDimitry Andric extern "C" {
470b57cec5SDimitry Andric #endif
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric enum {
510b57cec5SDimitry Andric     BLOCK_REFCOUNT_MASK =     (0xffff),
520b57cec5SDimitry Andric     BLOCK_NEEDS_FREE =        (1 << 24),
530b57cec5SDimitry Andric     BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
540b57cec5SDimitry Andric     BLOCK_HAS_CTOR =          (1 << 26), /* Helpers have C++ code. */
550b57cec5SDimitry Andric     BLOCK_IS_GC =             (1 << 27),
560b57cec5SDimitry Andric     BLOCK_IS_GLOBAL =         (1 << 28),
570b57cec5SDimitry Andric     BLOCK_HAS_DESCRIPTOR =    (1 << 29)
580b57cec5SDimitry Andric };
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric /* Revised new layout. */
620b57cec5SDimitry Andric struct Block_descriptor {
630b57cec5SDimitry Andric     unsigned long int reserved;
640b57cec5SDimitry Andric     unsigned long int size;
650b57cec5SDimitry Andric     void (*copy)(void *dst, void *src);
660b57cec5SDimitry Andric     void (*dispose)(void *);
670b57cec5SDimitry Andric };
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric struct Block_layout {
710b57cec5SDimitry Andric     void *isa;
720b57cec5SDimitry Andric     int flags;
730b57cec5SDimitry Andric     int reserved;
740b57cec5SDimitry Andric     void (*invoke)(void *, ...);
750b57cec5SDimitry Andric     struct Block_descriptor *descriptor;
760b57cec5SDimitry Andric     /* Imported variables. */
770b57cec5SDimitry Andric };
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric struct Block_byref {
810b57cec5SDimitry Andric     void *isa;
820b57cec5SDimitry Andric     struct Block_byref *forwarding;
830b57cec5SDimitry Andric     int flags; /* refcount; */
840b57cec5SDimitry Andric     int size;
850b57cec5SDimitry Andric     void (*byref_keep)(struct Block_byref *dst, struct Block_byref *src);
860b57cec5SDimitry Andric     void (*byref_destroy)(struct Block_byref *);
870b57cec5SDimitry Andric     /* long shared[0]; */
880b57cec5SDimitry Andric };
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric struct Block_byref_header {
920b57cec5SDimitry Andric     void *isa;
930b57cec5SDimitry Andric     struct Block_byref *forwarding;
940b57cec5SDimitry Andric     int flags;
950b57cec5SDimitry Andric     int size;
960b57cec5SDimitry Andric };
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric /* Runtime support functions used by compiler when generating copy/dispose helpers. */
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric enum {
1020b57cec5SDimitry Andric     /* See function implementation for a more complete description of these fields and combinations */
1030b57cec5SDimitry Andric     BLOCK_FIELD_IS_OBJECT   =  3,  /* id, NSObject, __attribute__((NSObject)), block, ... */
1040b57cec5SDimitry Andric     BLOCK_FIELD_IS_BLOCK    =  7,  /* a block variable */
1050b57cec5SDimitry Andric     BLOCK_FIELD_IS_BYREF    =  8,  /* the on stack structure holding the __block variable */
1060b57cec5SDimitry Andric     BLOCK_FIELD_IS_WEAK     = 16,  /* declared __weak, only used in byref copy helpers */
1070b57cec5SDimitry Andric     BLOCK_BYREF_CALLER      = 128  /* called from __block (byref) copy/dispose support routines. */
1080b57cec5SDimitry Andric };
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric /* Runtime entry point called by compiler when assigning objects inside copy helper routines */
1110b57cec5SDimitry Andric BLOCK_EXPORT void _Block_object_assign(void *destAddr, const void *object, const int flags);
1120b57cec5SDimitry Andric     /* BLOCK_FIELD_IS_BYREF is only used from within block copy helpers */
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric /* runtime entry point called by the compiler when disposing of objects inside dispose helper routine */
1160b57cec5SDimitry Andric BLOCK_EXPORT void _Block_object_dispose(const void *object, const int flags);
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric /* Other support functions */
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric /* Runtime entry to get total size of a closure */
1230b57cec5SDimitry Andric BLOCK_EXPORT unsigned long int Block_size(void *block_basic);
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric /* the raw data space for runtime classes for blocks */
1280b57cec5SDimitry Andric /* class+meta used for stack, malloc, and collectable based blocks */
1290b57cec5SDimitry Andric BLOCK_EXPORT void * _NSConcreteStackBlock[32];
1300b57cec5SDimitry Andric BLOCK_EXPORT void * _NSConcreteMallocBlock[32];
1310b57cec5SDimitry Andric BLOCK_EXPORT void * _NSConcreteAutoBlock[32];
1320b57cec5SDimitry Andric BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32];
1330b57cec5SDimitry Andric BLOCK_EXPORT void * _NSConcreteGlobalBlock[32];
1340b57cec5SDimitry Andric BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32];
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric /* the intercept routines that must be used under GC */
1380b57cec5SDimitry Andric BLOCK_EXPORT void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
1390b57cec5SDimitry Andric                                   void (*setHasRefcount)(const void *, const bool),
1400b57cec5SDimitry Andric                                   void (*gc_assign_strong)(void *, void **),
1410b57cec5SDimitry Andric                                   void (*gc_assign_weak)(const void *, void *),
1420b57cec5SDimitry Andric                                   void (*gc_memmove)(void *, void *, unsigned long));
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric /* earlier version, now simply transitional */
1450b57cec5SDimitry Andric BLOCK_EXPORT void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
1460b57cec5SDimitry Andric                                   void (*setHasRefcount)(const void *, const bool),
1470b57cec5SDimitry Andric                                   void (*gc_assign_strong)(void *, void **),
1480b57cec5SDimitry Andric                                   void (*gc_assign_weak)(const void *, void *));
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric BLOCK_EXPORT void _Block_use_RR( void (*retain)(const void *),
1510b57cec5SDimitry Andric                                  void (*release)(const void *));
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric /* make a collectable GC heap based Block.  Not useful under non-GC. */
1540b57cec5SDimitry Andric BLOCK_EXPORT void *_Block_copy_collectable(const void *aBlock);
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric /* thread-unsafe diagnostic */
1570b57cec5SDimitry Andric BLOCK_EXPORT const char *_Block_dump(const void *block);
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric /* Obsolete */
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric /* first layout */
1630b57cec5SDimitry Andric struct Block_basic {
1640b57cec5SDimitry Andric     void *isa;
1650b57cec5SDimitry Andric     int Block_flags;  /* int32_t */
1660b57cec5SDimitry Andric     int Block_size;  /* XXX should be packed into Block_flags */
1670b57cec5SDimitry Andric     void (*Block_invoke)(void *);
1680b57cec5SDimitry Andric     void (*Block_copy)(void *dst, void *src);  /* iff BLOCK_HAS_COPY_DISPOSE */
1690b57cec5SDimitry Andric     void (*Block_dispose)(void *);             /* iff BLOCK_HAS_COPY_DISPOSE */
1700b57cec5SDimitry Andric     /* long params[0];  // where const imports, __block storage references, etc. get laid down */
1710b57cec5SDimitry Andric };
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric #if defined(__cplusplus)
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric #endif
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric #endif /* _BLOCK_PRIVATE_H_ */
180