Viewing file: weak.h (7.64 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/**************************************************************************/ /* */ /* OCaml */ /* */ /* Damien Doligez, projet Para, INRIA Rocquencourt */ /* */ /* Copyright 1997 Institut National de Recherche en Informatique et */ /* en Automatique. */ /* */ /* All rights reserved. This file is distributed under the terms of */ /* the GNU Lesser General Public License version 2.1, with the */ /* special exception on linking described in the file LICENSE. */ /* */ /**************************************************************************/
/* Operations on weak arrays */
#ifndef CAML_WEAK_H #define CAML_WEAK_H
#include "mlvalues.h"
#ifdef __cplusplus extern "C" { #endif
/** The requirements of the functions must be satisfied, it is unspecified what happens if they are not. The debugging runtime could check some of them. */
CAMLextern value caml_ephemeron_create(mlsize_t len); /** Create an ephemeron with the given number of keys. This function allocates. */
CAMLextern mlsize_t caml_ephemeron_num_keys(value eph); /** Return the number of key in the ephemeron. The valid key offset goes from [0] to the predecessor of the returned value. */
CAMLextern int caml_ephemeron_key_is_set(value eph, mlsize_t offset); /** Return 1 if the key in the ephemeron at the given offset is set. Otherwise 0. The value [eph] must be an ephemeron and [offset] a valid key offset. */
CAMLextern void caml_ephemeron_set_key(value eph, mlsize_t offset, value k); /** Set the key of the given ephemeron [eph] at the given offset [offset] to the given value [k]. The value [eph] must be an ephemeron, [offset] a valid key offset and [k] a block. */
CAMLextern void caml_ephemeron_unset_key(value eph, mlsize_t offset); /** Unset the key of the given ephemeron at the given offset. The value [eph] must be an ephemeron and [offset] a valid key offset. */
CAMLextern int caml_ephemeron_get_key(value eph, mlsize_t offset, value *key); /** Return 1 if the key in the ephemeron at the given offset is set. Otherwise 0. When returning 1, set [*key] to the pointed value.
The value [eph] must be an ephemeron and [offset] a valid key offset. */
CAMLextern int caml_ephemeron_get_key_copy(value eph, mlsize_t offset, value *key); /** Return 1 if the key in the ephemeron at the given offset is set. Otherwise 0. When returning 1, set [*key] to a shallow copy of the key. This function allocates.
The value [eph] must be an ephemeron and [offset] a valid key offset. */
CAMLextern void caml_ephemeron_blit_key(value eph1, mlsize_t off1, value eph2, mlsize_t off2, mlsize_t len); /** Fill the given range of keys of [eph2] with the given range of keys of [eph1]. Contrary to using caml_ephemeron_get_key followed by caml_ephemeron_set_key or caml_ephemeron_unset_key, this function does not prevent the incremental GC from erasing the value in its current cycle. The value [eph1] (resp. [eph2]) must be an ephemeron and the offsets between [off1] and [off1+len] (resp. between [off2] and [off2+offset]) must be valid keys of [eph1] (resp. [eph2]). */
CAMLextern int caml_ephemeron_data_is_set(value eph); /** Return 1 if the data in the ephemeron is set. Otherwise 0. The value [eph] must be an ephemeron. */
CAMLextern void caml_ephemeron_set_data(value eph, value k); /** Set the data of the given ephemeron [eph] to the given value [k]. The value [eph] must be an ephemeron and [k] a block. */
CAMLextern void caml_ephemeron_unset_data(value eph); /** Unset the data of the given ephemeron. The value [eph] must be an ephemeron. */
CAMLextern int caml_ephemeron_get_data(value eph, value *data); /** Return 1 if the data in the ephemeron at the given offset is set. Otherwise 0. When returning 1, set [*data] to the pointed value.
The value [eph] must be an ephemeron and [offset] a valid key offset. */
CAMLextern int caml_ephemeron_get_data_copy(value eph, value *data); /** Return 1 if the data in the ephemeron at the given offset is set. Otherwise 0. When returning 1, set [*data] to a shallow copy of the data. This function allocates.
The value [eph] must be an ephemeron and [offset] a valid key offset. */
CAMLextern void caml_ephemeron_blit_data(value eph1, value eph2); /** Sets the data of [eph2] to be the same as the data of [eph1]. Contrary to using caml_ephemeron_get_data followed by caml_ephemeron_set_data or caml_ephemeron_unset_data, this function does not prevent the incremental GC from erasing the value in its current cycle. The values [eph1] and [eph2] must be ephemerons. */
#define caml_weak_array_length caml_ephemeron_num_keys #define caml_weak_array_create caml_ephemeron_create #define caml_weak_array_check caml_ephemeron_key_is_set #define caml_weak_array_unset caml_ephemeron_unset_key #define caml_weak_array_set caml_ephemeron_set_key #define caml_weak_array_get caml_ephemeron_get_key #define caml_weak_array_get_copy caml_ephemeron_get_key_copy #define caml_weak_array_blit caml_ephemeron_blit_key
#ifdef CAML_INTERNALS
extern value caml_ephe_list_head; extern value caml_ephe_none;
/** The first field 0: weak list; second field 1: data; others 2..: keys;
A weak pointer is an ephemeron with the data at caml_ephe_none If fields are added, don't forget to update weak.ml, [additional_values], and obj.ml, [Ephemeron.additional_values].
*/
#define CAML_EPHE_LINK_OFFSET 0 #define CAML_EPHE_DATA_OFFSET 1 #define CAML_EPHE_FIRST_KEY 2 #define CAML_EPHE_MAX_WOSIZE (Max_wosize - CAML_EPHE_FIRST_KEY)
/* In the header, in order to let major_gc.c and weak.c see the body of the function */ static inline void caml_ephe_clean (value v){ value child; int release_data = 0; mlsize_t size, i; header_t hd; CAMLassert(caml_gc_phase == Phase_clean);
hd = Hd_val (v); size = Wosize_hd (hd); for (i = 2; i < size; i++){ child = Field (v, i); ephemeron_again: if (child != caml_ephe_none && Is_block (child) && Is_in_heap_or_young (child)){ if (Tag_val (child) == Forward_tag){ value f = Forward_val (child); if (Is_block (f)) { if (!Is_in_value_area(f) || Tag_val (f) == Forward_tag || Tag_val (f) == Lazy_tag || Tag_val (f) == Double_tag){ /* Do not short-circuit the pointer. */ }else{ Field (v, i) = child = f; if (Is_block (f) && Is_young (f)) add_to_ephe_ref_table(&caml_ephe_ref_table, v, i); goto ephemeron_again; } } } if (Is_white_val (child) && !Is_young (child)){ release_data = 1; Field (v, i) = caml_ephe_none; } } }
child = Field (v, 1); if(child != caml_ephe_none){ if (release_data){ Field (v, 1) = caml_ephe_none; } else { /* The mark phase must have marked it */ CAMLassert( !(Is_block (child) && Is_in_heap (child) && Is_white_val (child)) ); } } }
#endif /* CAML_INTERNALS */
#ifdef __cplusplus } #endif
#endif /* CAML_WEAK_H */
|