summaryrefslogtreecommitdiffstats
path: root/byterun/memory.c
diff options
context:
space:
mode:
authorXavier Leroy <xavier.leroy@inria.fr>2013-06-01 07:43:45 +0000
committerXavier Leroy <xavier.leroy@inria.fr>2013-06-01 07:43:45 +0000
commit1b72ae5896ae5a9c4f5cd79f1d289e3de19c9954 (patch)
treeb725ba7fa1926d1646c1bed7c349d58fdfeb2006 /byterun/memory.c
parent87508f1d4b13203eddd8366e4ce26f39c1da07f3 (diff)
More efficient implementation of caml_modify().
Performance improvement in caml_initialize(). git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@13723 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
Diffstat (limited to 'byterun/memory.c')
-rw-r--r--byterun/memory.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/byterun/memory.c b/byterun/memory.c
index 6f86e3e9a..775146207 100644
--- a/byterun/memory.c
+++ b/byterun/memory.c
@@ -502,10 +502,11 @@ CAMLexport void caml_adjust_gc_speed (mlsize_t res, mlsize_t max)
*/
/* [caml_initialize] never calls the GC, so you may call it while a block is
unfinished (i.e. just after a call to [caml_alloc_shr].) */
-void caml_initialize (value *fp, value val)
+CAMLexport void caml_initialize (value *fp, value val)
{
+ CAMLassert(Is_in_heap(fp));
*fp = val;
- if (Is_block (val) && Is_young (val) && Is_in_heap (fp)){
+ if (Is_block (val) && Is_young (val)) {
if (caml_ref_table.ptr >= caml_ref_table.limit){
caml_realloc_ref_table (&caml_ref_table);
}
@@ -517,9 +518,54 @@ void caml_initialize (value *fp, value val)
unless you are sure the value being overwritten is not a shared block and
the value being written is not a young block. */
/* [caml_modify] never calls the GC. */
-void caml_modify (value *fp, value val)
+/* [caml_modify] can also be used to do assignment on data structures that are
+ in the minor heap instead of in the major heap. In this case, it
+ is a bit slower than simple assignment.
+ In particular, you can use [caml_modify] when you don't know whether the
+ block being changed is in the minor heap or the major heap.
+*/
+
+CAMLexport void caml_modify (value *fp, value val)
{
- Modify (fp, val);
+ /* The write barrier implemented by [caml_modify] checks for the
+ following two conditions and takes appropriate action:
+ 1- a pointer from the major heap to the minor heap is created
+ --> add [fp] to the remembered set
+ 2- a pointer from the major heap to the major heap is overwritten,
+ while the GC is in the marking phase
+ --> call [caml_darken] on the overwritten pointer so that the
+ major GC treats it as an additional root.
+ */
+ value old;
+
+ if (Is_young(fp)) {
+ /* The modified object resides in the minor heap.
+ Conditions 1 and 2 cannot occur. */
+ *fp = val;
+ } else {
+ /* The modified object resides in the major heap. */
+ CAMLassert(Is_in_heap(fp));
+ old = *fp;
+ *fp = val;
+ if (Is_block(old)) {
+ /* If [old] is a pointer within the minor heap, we already
+ have a major->minor pointer and [fp] is already in the
+ remembered set. Conditions 1 and 2 cannot occur. */
+ if (Is_young(old)) return;
+ /* Here, [old] can be a pointer within the major heap.
+ Check for condition 2. */
+ if (caml_gc_phase == Phase_mark) caml_darken(old, NULL);
+ }
+ /* Check for condition 1. */
+ if (Is_block(val) && Is_young(val)) {
+ /* Add [fp] to remembered set */
+ if (caml_ref_table.ptr >= caml_ref_table.limit){
+ CAMLassert (caml_ref_table.ptr == caml_ref_table.limit);
+ caml_realloc_ref_table (&caml_ref_table);
+ }
+ *caml_ref_table.ptr++ = fp;
+ }
+ }
}
CAMLexport void * caml_stat_alloc (asize_t sz)