Hi,
If you read the squeak vm mailing they talk about read only objects.
But wait, we've read only why should we change it?? In GST it's done by
testing at "each" access if the object is RO or not. But we can do it
lazily by using the hardware and operating system. Objects can be putted
in a separate space with read-only access, thus we get a page fault when
you try to change an object.
I've implemented the first step a separate space for the *old* read-only
objects. I've first fixed a bug with the oldspace_nomemory each space
should have its own function. Thus there are for each space a
*space_nomemory, gst_init_mem_default initialize the new ro_oldspace.
The macro MAKE_OOP_READONLY calls the _gst_make_oop_readonly function:
* first I check if the oop ro state is the same as the new state; if
yes I leave.
* If the object is fixed or young I only change the state BUT if the
object is old it is moved inside a ro_oldspace if it becomes RO or it's
moved from the ro_oldspace to the oldspace it is writeable
* gst_make_oop_fixed check if is old and remove the object from the
right space (oldspace or ro_old_space)
* the oldspace_nomemory, fixedspace_nomemory, ro_oldspace_nomemory returns
the correct heap ;-)
* _gst_compact: i'll compact the memory of both oldspace and
ro_oldspace, I don't use the new heap size to grow the ro_oldspace heap
size.
* _gst_sweep_oop is changed to free the memory from the right space ;-)
* the image loading is updated to take care of the ro_oldspace
I think it's all ;-)
Right now the ro mapping is not done but as Paolo said on IRC the patch
will give less false positive on grey page scanning.
Cheers,
Gwen
diff --git a/libgst/gstpriv.h b/libgst/gstpriv.h
index 68c34b9..2c6c49f 100644
--- a/libgst/gstpriv.h
+++ b/libgst/gstpriv.h
@@ -373,8 +373,7 @@ enum {
/* Set whether an object, OOP, is readonly or readwrite. */
#define MAKE_OOP_READONLY(oop, ro) \
- (((oop)->flags &= ~F_READONLY), \
- ((oop)->flags |= (ro) ? F_READONLY : 0))
+ _gst_make_oop_readonly (oop, ro)
#ifdef ENABLE_SECURITY
diff --git a/libgst/oop.c b/libgst/oop.c
index ad264d9..1dbb475 100644
--- a/libgst/oop.c
+++ b/libgst/oop.c
@@ -145,9 +145,18 @@ static OOP *queue_put (surv_space *q, OOP *src, int n);
/* Move an object from survivor space to oldspace. */
static void tenure_one_object ();
+/* Initialize an allocation heap with a hooks set. */
+static heap_data *init_space (void *function, size_t size);
+
/* Initialize an allocation heap with the oldspace hooks set. */
static heap_data *init_old_space (size_t size);
+/* Initialize an allocation heap with the read-only oldspace hooks set. */
+static heap_data *init_ro_old_space (size_t size);
+
+/* Initialize an allocation heap with the fixedspace hooks set. */
+static heap_data *init_fixed_space (size_t size);
+
/* Initialize a surv_space structure. */
static void init_survivor_space (struct surv_space *space, size_t size);
@@ -208,6 +217,15 @@ static int oldspace_sigsegv_handler (void* fault_address, int serious);
#endif
/* Hook that triggers garbage collection. */
+static heap_data *grow_nomemory (heap_data *h, size_t sz);
+
+/* Hook that triggers garbage collection. */
+static heap_data *ro_oldspace_nomemory (heap_data *h, size_t sz);
+
+/* Hook that triggers garbage collection. */
+static heap_data *fixedspace_nomemory (heap_data *h, size_t sz);
+
+/* Hook that triggers garbage collection. */
static heap_data *oldspace_nomemory (heap_data *h, size_t sz);
/* Answer the number of fields to be scanned in the object starting
@@ -247,16 +265,34 @@ init_survivor_space (struct surv_space *space, size_t size)
}
heap_data *
-init_old_space (size_t size)
+init_space (void *function, size_t size)
{
heap_data *h = _gst_mem_new_heap (0, size);
h->after_prim_allocating = oldspace_after_allocating;
h->before_prim_freeing = oldspace_before_freeing;
- h->nomemory = oldspace_nomemory;
+ h->nomemory = function;
return h;
}
+heap_data *
+init_fixed_space (size_t size)
+{
+ return init_space (fixedspace_nomemory, size);
+}
+
+heap_data *
+init_ro_old_space (size_t size)
+{
+ return init_space (ro_oldspace_nomemory, size);
+}
+
+heap_data *
+init_old_space (size_t size)
+{
+ return init_space (oldspace_nomemory, size);
+}
+
void
_gst_init_mem_default ()
{
@@ -331,8 +367,9 @@ _gst_init_mem (size_t eden, size_t survivor, size_t old,
{
if (old)
{
+ _gst_mem.ro_old = init_ro_old_space (old);
_gst_mem.old = init_old_space (old);
- _gst_mem.fixed = init_old_space (old);
+ _gst_mem.fixed = init_fixed_space (old);
}
_gst_mem.active_half = &_gst_mem.surv[0];
@@ -695,6 +732,49 @@ _gst_swap_objects (OOP oop1,
_gst_make_oop_weak (oop1);
}
+mst_Boolean
+_gst_make_oop_readonly (OOP oop, mst_Boolean ro)
+{
+ gst_object newObj;
+ int size;
+
+ /* they are the same so I can return */
+ if (((oop->flags & F_READONLY) > 1) == ro)
+ return ro;
+
+ /* If the object is young or if it is fixed. It isn't moved to the ro oldspace */
+ if (!(oop->flags & F_OLD) || (oop->flags & F_FIXED))
+ return (((oop)->flags &= ~F_READONLY), ((oop)->flags |= (ro) ? F_READONLY : 0));
+
+ size = SIZE_TO_BYTES (TO_INT(oop->object->objSize));
+ if (ro)
+ {
+ /* become read only */
+ newObj = (gst_object) _gst_mem_alloc (_gst_mem.ro_old, size);
+ if (!newObj)
+ abort ();
+
+ memcpy (newObj, oop->object, size);
+ _gst_mem_free (_gst_mem.old, oop->object);
+
+ oop->flags |= F_READONLY;
+ }
+ else
+ {
+ /* become writeable */
+ newObj = (gst_object) _gst_mem_alloc (_gst_mem.old, size);
+ if (!newObj)
+ abort ();
+
+ memcpy (newObj, oop->object, size);
+ _gst_mem_free (_gst_mem.ro_old, oop->object);
+
+ oop->flags &= ~F_READONLY;
+ }
+
+ oop->object = newObj;
+ return ro;
+}
void
_gst_make_oop_fixed (OOP oop)
@@ -715,7 +795,12 @@ _gst_make_oop_fixed (OOP oop)
if ((oop->flags & F_OLD) == 0)
_gst_mem.numOldOOPs++;
else
- _gst_mem_free (_gst_mem.old, oop->object);
+ {
+ if (IS_OOP_READONLY (oop))
+ _gst_mem_free (_gst_mem.ro_old, oop->object);
+ else
+ _gst_mem_free (_gst_mem.old, oop->object);
+ }
oop->object = newObj;
}
@@ -734,12 +819,18 @@ _gst_tenure_oop (OOP oop)
if (!(oop->flags & F_FIXED))
{
int size = SIZE_TO_BYTES (TO_INT(oop->object->objSize));
- newObj = (gst_object) _gst_mem_alloc (_gst_mem.old, size);
+
+ if (IS_OOP_READONLY (oop))
+ newObj = (gst_object) _gst_mem_alloc (_gst_mem.ro_old, size);
+ else
+ newObj = (gst_object) _gst_mem_alloc (_gst_mem.old, size);
+
+ _gst_mem.numOldOOPs++;
+
if (!newObj)
abort ();
memcpy (newObj, oop->object, size);
- _gst_mem.numOldOOPs++;
oop->object = newObj;
}
@@ -889,25 +980,43 @@ oldspace_before_freeing (heap_data *h, heap_block *blk, size_t sz)
}
heap_data *
-oldspace_nomemory (heap_data *h, size_t sz)
+grow_nomemory (heap_data *h, size_t sz)
{
if (!_gst_gc_running)
_gst_global_gc (sz);
else
{
/* Already garbage collecting, emergency growth just to satisfy
- tenuring necessities. */
- int grow_amount_to_satisfy_rate = _gst_mem.old->heap_limit
+ tenuring necessities. */
+ int grow_amount_to_satisfy_rate = h->heap_limit
* (100.0 + _gst_mem.space_grow_rate) / 100;
- int grow_amount_to_satisfy_threshold =
- (sz + _gst_mem.old->heap_total)
- * 100.0 /_gst_mem.grow_threshold_percent;
+ int grow_amount_to_satisfy_threshold =
+ (sz + h->heap_total)
+ * 100.0 /_gst_mem.grow_threshold_percent;
- _gst_mem.old->heap_limit = MAX (grow_amount_to_satisfy_rate,
- grow_amount_to_satisfy_threshold);
+ h->heap_limit = MAX (grow_amount_to_satisfy_rate,
+ grow_amount_to_satisfy_threshold);
}
- return _gst_mem.old;
+ return h;
+}
+
+heap_data *
+ro_oldspace_nomemory (heap_data *h, size_t sz)
+{
+ return grow_nomemory (_gst_mem.ro_old, sz);
+}
+
+heap_data *
+fixedspace_nomemory (heap_data *h, size_t sz)
+{
+ return grow_nomemory (_gst_mem.fixed, sz);
+}
+
+heap_data *
+oldspace_nomemory (heap_data *h, size_t sz)
+{
+ return grow_nomemory (_gst_mem.old, sz);
}
#ifndef NO_SIGSEGV_HANDLING
@@ -992,6 +1101,7 @@ _gst_compact (size_t new_heap_limit)
grey_area_node *node, **next, *last;
heap_data *new_heap = init_old_space (
new_heap_limit ? new_heap_limit : _gst_mem.old->heap_limit);
+ heap_data *new_ro_heap = init_ro_old_space (_gst_mem.ro_old->heap_limit);
if (new_heap_limit)
{
@@ -1037,7 +1147,7 @@ _gst_compact (size_t new_heap_limit)
oop < &_gst_mem.ot[_gst_mem.ot_size]; oop++)
{
PREFETCH_LOOP (oop, PREF_READ | PREF_NTA);
- if ((oop->flags & (F_OLD | F_FIXED | F_LOADED)) == F_OLD)
+ if ((oop->flags & (F_OLD | F_FIXED | F_LOADED | F_READONLY)) == F_OLD)
{
gst_object new;
size_t size = SIZE_TO_BYTES (TO_INT (oop->object->objSize));
@@ -1046,12 +1156,26 @@ _gst_compact (size_t new_heap_limit)
_gst_mem_free (_gst_mem.old, oop->object);
oop->object = new;
}
+ else if ((oop->flags & (F_OLD | F_FIXED | F_LOADED | F_READONLY)) == (F_OLD | F_READONLY))
+ {
+ gst_object new;
+ size_t size = SIZE_TO_BYTES (TO_INT (oop->object->objSize));
+ new = _gst_mem_alloc (new_ro_heap, size);
+ memcpy (new, oop->object, size);
+ _gst_mem_free (_gst_mem.ro_old, oop->object);
+ oop->object = new;
+ }
}
xfree (_gst_mem.old);
+ xfree (_gst_mem.ro_old);
+
_gst_mem.old = new_heap;
new_heap->nomemory = oldspace_nomemory;
+ _gst_mem.ro_old = new_ro_heap;
+ new_ro_heap->nomemory = ro_oldspace_nomemory;
+
_gst_restore_object_pointers ();
update_stats (&stats.timeOfLastCompaction, NULL, &_gst_mem.timeToCompact);
@@ -1462,11 +1586,17 @@ _gst_sweep_oop (OOP oop)
}
else if UNCOMMON (oop->flags & F_OLD)
{
+
_gst_mem.numOldOOPs--;
stats.reclaimedOldSpaceBytesSinceLastGlobalGC +=
SIZE_TO_BYTES (TO_INT (OOP_TO_OBJ (oop)->objSize));
if ((oop->flags & F_LOADED) == 0)
- _gst_mem_free (_gst_mem.old, oop->object);
+ {
+ if (IS_OOP_READONLY (oop))
+ _gst_mem_free (_gst_mem.ro_old, oop->object);
+ else
+ _gst_mem_free (_gst_mem.old, oop->object);
+ }
}
oop->flags = 0;
diff --git a/libgst/oop.h b/libgst/oop.h
index 6816b3f..8a1d63f 100644
--- a/libgst/oop.h
+++ b/libgst/oop.h
@@ -189,7 +189,7 @@ typedef struct cheney_scan_state {
struct memory_space
{
- heap_data *old, *fixed;
+ heap_data *ro_old, *old, *fixed;
struct new_space eden;
struct surv_space surv[2], tenuring_queue;
@@ -437,6 +437,10 @@ extern mst_Boolean _gst_realloc_oop_table (size_t newSize)
extern void _gst_tenure_oop (OOP oop)
ATTRIBUTE_HIDDEN;
+/* Set whether an object, OOP, is readonly or readwrite. */
+extern mst_Boolean _gst_make_oop_readonly (OOP oop, mst_Boolean ro)
+ ATTRIBUTE_HIDDEN;
+
/* Move OOP to fixedspace. */
extern void _gst_make_oop_fixed (OOP oop)
ATTRIBUTE_HIDDEN;
diff --git a/libgst/save.c b/libgst/save.c
index 77cc8b9..7ee690c 100644
--- a/libgst/save.c
+++ b/libgst/save.c
@@ -652,7 +652,12 @@ load_normal_oops (int imageFd)
object = (gst_object) _gst_mem_alloc (_gst_mem.fixed, size);
}
else
- object = (gst_object) _gst_mem_alloc (_gst_mem.old, size);
+ {
+ if (flags & F_READONLY)
+ object = (gst_object) _gst_mem_alloc (_gst_mem.ro_old, size);
+ else
+ object = (gst_object) _gst_mem_alloc (_gst_mem.old, size);
+ }
buffer_read (imageFd, object, size);
if UNCOMMON (wrong_endianness)
diff --git a/snprintfv/snprintfv/filament.h b/snprintfv/snprintfv/filament.h
index 4a91eb6..8a7ce6c 100644
--- a/snprintfv/snprintfv/filament.h
+++ b/snprintfv/snprintfv/filament.h
@@ -1,4 +1,4 @@
-#line 1 "../../../snprintfv/snprintfv/filament.in"
+#line 1 "./filament.in"
/* -*- Mode: C -*- */
/* filament.h --- a bit like a string but different =)O|
@@ -118,7 +118,7 @@ extern char * fildelete (Filament *fil);
extern void _fil_extend (Filament *fil, size_t len, boolean copy);
-#line 61 "../../../snprintfv/snprintfv/filament.in"
+#line 61 "./filament.in"
/* Save the overhead of a function call in the great majority of cases. */
#define fil_maybe_extend(fil, len, copy) \
diff --git a/snprintfv/snprintfv/printf.h b/snprintfv/snprintfv/printf.h
index 49a2e9f..1437dd5 100644
--- a/snprintfv/snprintfv/printf.h
+++ b/snprintfv/snprintfv/printf.h
@@ -1,4 +1,4 @@
-#line 1 "../../../snprintfv/snprintfv/printf.in"
+#line 1 "./printf.in"
/* -*- Mode: C -*- */
/* printf.in --- printf clone for argv arrays
@@ -266,7 +266,7 @@ enum
} \
} SNV_STMT_END
-#line 269 "../../../snprintfv/snprintfv/printf.in"
+#line 269 "./printf.in"
/**
* printf_generic_info:
* @pinfo: the current state information for the format
@@ -302,7 +302,7 @@ extern int printf_generic_info (struct printf_info *const pinfo, size_t n, int *
extern int printf_generic (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args);
-#line 270 "../../../snprintfv/snprintfv/printf.in"
+#line 270 "./printf.in"
/**
* register_printf_function:
* @spec: the character which will trigger @func, cast to an unsigned int.
@@ -789,7 +789,7 @@ extern int snv_vasprintf (char **result, const char *format, va_list ap);
extern int snv_asprintfv (char **result, const char *format, snv_constpointer const args[]);
-#line 271 "../../../snprintfv/snprintfv/printf.in"
+#line 271 "./printf.in"
/* If you don't want to use snprintfv functions for *all* of your string
formatting API, then define COMPILING_SNPRINTFV_C and use the snv_
diff --git a/snprintfv/snprintfv/stream.h b/snprintfv/snprintfv/stream.h
index 496bd33..0bebce1 100644
--- a/snprintfv/snprintfv/stream.h
+++ b/snprintfv/snprintfv/stream.h
@@ -1,4 +1,4 @@
-#line 1 "../../../snprintfv/snprintfv/stream.in"
+#line 1 "./stream.in"
/* -*- Mode: C -*- */
/* stream.h --- customizable stream routines
@@ -180,7 +180,7 @@ extern int stream_puts (char *s, STREAM *stream);
extern int stream_get (STREAM *stream);
-#line 88 "../../../snprintfv/snprintfv/stream.in"
+#line 88 "./stream.in"
#ifdef __cplusplus
#if 0
/* This brace is so that emacs can still indent properly: */
_______________________________________________
help-smalltalk mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/help-smalltalk