cvsuser 03/11/19 07:43:35
Modified: . MANIFEST vtable.tbl
classes array.pmc default.pmc perlint.pmc
config/gen/makefiles root.in
include/parrot parrot.h
ops ops.num pmc.ops
Added: src pmc_freeze.c
Log:
First draft of freeze -- Leo's base code
Revision Changes Path
1.504 +3 -0 parrot/MANIFEST
Index: MANIFEST
===================================================================
RCS file: /cvs/public/parrot/MANIFEST,v
retrieving revision 1.503
retrieving revision 1.504
diff -u -w -r1.503 -r1.504
--- MANIFEST 17 Nov 2003 02:28:02 -0000 1.503
+++ MANIFEST 19 Nov 2003 15:43:17 -0000 1.504
@@ -1610,6 +1610,7 @@
include/parrot/parrot.h [devel]include
include/parrot/perltypes.h [devel]include
include/parrot/pmc.h [devel]include
+include/parrot/pmc_freeze.h [devel]include
include/parrot/pobj.h [devel]include
include/parrot/regfuncs.h [devel]include
include/parrot/register.h [devel]include
@@ -2170,6 +2171,7 @@
src/pdb.c []
src/pdump.c []
src/pmc.c []
+src/pmc_freeze.c []
src/register.c []
src/res_lea.c []
src/resources.c []
@@ -2226,6 +2228,7 @@
t/pmc/eval.t []
t/pmc/exception.t []
t/pmc/float.t []
+t/pmc/freeze.t []
t/pmc/intlist.t []
t/pmc/io.t []
t/pmc/iter.t []
1.49 +4 -1 parrot/vtable.tbl
Index: vtable.tbl
===================================================================
RCS file: /cvs/public/parrot/vtable.tbl,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -w -r1.48 -r1.49
--- vtable.tbl 1 Nov 2003 15:00:32 -0000 1.48
+++ vtable.tbl 19 Nov 2003 15:43:17 -0000 1.49
@@ -1,4 +1,4 @@
-# $Id: vtable.tbl,v 1.48 2003/11/01 15:00:32 leo Exp $
+# $Id: vtable.tbl,v 1.49 2003/11/19 15:43:17 dan Exp $
# [MAIN] #default section name
void init()
@@ -284,3 +284,6 @@
INTVAL isa_keyed(PMC* key, STRING* method)
INTVAL isa_keyed_int(INTVAL key, STRING* method)
+void freeze(visit_info* info)
+void thaw (visit_info* info)
+void visit (visit_info* info)
1.70 +34 -1 parrot/classes/array.pmc
Index: array.pmc
===================================================================
RCS file: /cvs/public/parrot/classes/array.pmc,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -w -r1.69 -r1.70
--- array.pmc 20 Oct 2003 17:18:59 -0000 1.69
+++ array.pmc 19 Nov 2003 15:43:20 -0000 1.70
@@ -1,7 +1,7 @@
/* array.pmc
* Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
* CVS Info
- * $Id: array.pmc,v 1.69 2003/10/20 17:18:59 dan Exp $
+ * $Id: array.pmc,v 1.70 2003/11/19 15:43:20 dan Exp $
* Overview:
* These are the vtable functions for the Array base class
* Data Structure and Algorithms:
@@ -534,6 +534,39 @@
break;
}
return ret;
+ }
+
+ void visit(visit_info *info) {
+ INTVAL i;
+
+ SUPER(info);
+ /* doesn't handle sparse arrays - test only */
+ for (i = 0; i < VTABLE_elements(INTERP, SELF); ++i) {
+ PMC *child;
+ void *ret = list_get(INTERP, (List *) PMC_data(pmc), i,
+ enum_type_PMC);
+ if (!ret || ret == (void *) -1) {
+ ret = NULL;
+ child = NULL;
+ }
+ else
+ child = *(PMC**)ret;
+ info->thaw_ptr = ret;
+ (info->visit_child_function)(INTERP, child, info);
+ }
+ }
+
+ void freeze(visit_info *info) {
+ IMAGE_IO *io = info->image_io;
+ io->vtable->push_integer(INTERP, io,
+ VTABLE_elements(INTERP, SELF));
+ }
+
+ void thaw(visit_info *info) {
+ IMAGE_IO *io = info->image_io;
+ SUPER(info);
+ DYNSELF.set_integer_native(
+ io->vtable->shift_integer(INTERP, io));
}
}
1.73 +10 -1 parrot/classes/default.pmc
Index: default.pmc
===================================================================
RCS file: /cvs/public/parrot/classes/default.pmc,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -w -r1.72 -r1.73
--- default.pmc 20 Oct 2003 17:44:40 -0000 1.72
+++ default.pmc 19 Nov 2003 15:43:20 -0000 1.73
@@ -1,6 +1,6 @@
/* default.pmc
* Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
- * CVS Info $Id: default.pmc,v 1.72 2003/10/20 17:44:40 dan Exp $
+ * CVS Info $Id: default.pmc,v 1.73 2003/11/19 15:43:20 dan Exp $
* Overview:
* These are the vtable functions for the default PMC class
* Data Structure and Algorithms:
@@ -315,6 +315,15 @@
INTVAL isa (STRING* method) {
return does_isa(INTERP, method, SELF->vtable->isa_str);
+ }
+
+ void visit(visit_info *info) {
+ }
+ void freeze(visit_info *info) {
+ }
+
+ void thaw(visit_info *info) {
+ DYNSELF.init();
}
}
1.51 +12 -1 parrot/classes/perlint.pmc
Index: perlint.pmc
===================================================================
RCS file: /cvs/public/parrot/classes/perlint.pmc,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -w -r1.50 -r1.51
--- perlint.pmc 23 Oct 2003 08:08:15 -0000 1.50
+++ perlint.pmc 19 Nov 2003 15:43:20 -0000 1.51
@@ -1,7 +1,7 @@
/* perlint.pmc
* Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
* CVS Info
- * $Id: perlint.pmc,v 1.50 2003/10/23 08:08:15 leo Exp $
+ * $Id: perlint.pmc,v 1.51 2003/11/19 15:43:20 dan Exp $
* Overview:
* These are the vtable functions for the PerlInt base class
* Data Structure and Algorithms:
@@ -12,6 +12,7 @@
#include "parrot/parrot.h"
#include "parrot/perltypes.h"
+#include <assert.h>
pmclass PerlInt extends perlscalar {
@@ -467,4 +468,14 @@
SELF->cache.int_val --;
}
+ void freeze(visit_info *info) {
+ IMAGE_IO *io = info->image_io;
+ io->vtable->push_integer(INTERP, io, SELF->cache.int_val);
+ }
+
+ void thaw(visit_info *info) {
+ IMAGE_IO *io = info->image_io;
+ SUPER(info);
+ SELF->cache.int_val = io->vtable->shift_integer(INTERP, io);
+ }
}
1.171 +6 -1 parrot/config/gen/makefiles/root.in
Index: root.in
===================================================================
RCS file: /cvs/public/parrot/config/gen/makefiles/root.in,v
retrieving revision 1.170
retrieving revision 1.171
diff -u -w -r1.170 -r1.171
--- root.in 19 Nov 2003 14:52:07 -0000 1.170
+++ root.in 19 Nov 2003 15:43:23 -0000 1.171
@@ -45,6 +45,8 @@
INC=./${inc}
+# generated by config/init/headers.pl
+
NONGEN_HEADERS = ${nongen_headers}
###############################################################################
@@ -174,7 +176,8 @@
$(SRC)/register$(O) $(SRC)/core_ops$(O) $(SRC)/core_ops_prederef$(O)
$(SRC)/core_ops_switch$(O) \
$(SRC)/memory$(O) $(SRC)/objects$(O) ${exec_o} \
$(SRC)/packfile$(O) $(SRC)/stacks$(O) $(SRC)/string$(O) $(SRC)/sub$(O)
$(SRC)/encoding$(O) \
- $(SRC)/chartype$(O) $(SRC)/runops_cores$(O) $(SRC)/trace$(O) $(SRC)/pmc$(O)
$(SRC)/key$(O) $(SRC)/hash$(O) \
+ $(SRC)/chartype$(O) $(SRC)/runops_cores$(O) $(SRC)/trace$(O) \
+ $(SRC)/pmc$(O) $(SRC)/pmc_freeze$(O) $(SRC)/key$(O) $(SRC)/hash$(O) \
$(SRC)/core_pmcs$(O) $(SRC)/platform$(O) ${jit_o} \
${gc_o} $(SRC)/rx$(O) $(SRC)/rxstacks$(O) $(SRC)/intlist$(O) $(SRC)/list$(O) \
$(SRC)/embed$(O) $(SRC)/warnings$(O) ${cg_o} \
@@ -439,6 +442,8 @@
$(SRC)/global_setup$(O) : $(GENERAL_H_FILES)
$(SRC)/pmc$(O) : $(GENERAL_H_FILES)
+
+$(SRC)/pmc_freeze$(O) : $(GENERAL_H_FILES)
$(SRC)/hash$(O) : $(GENERAL_H_FILES)
1.82 +3 -2 parrot/include/parrot/parrot.h
Index: parrot.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/parrot.h,v
retrieving revision 1.81
retrieving revision 1.82
diff -u -w -r1.81 -r1.82
--- parrot.h 30 Oct 2003 06:42:48 -0000 1.81
+++ parrot.h 19 Nov 2003 15:43:26 -0000 1.82
@@ -1,7 +1,7 @@
/* parrot.h
* Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
* CVS Info
- * $Id: parrot.h,v 1.81 2003/10/30 06:42:48 mrjoltcola Exp $
+ * $Id: parrot.h,v 1.82 2003/11/19 15:43:26 dan Exp $
* Overview:
* General header file includes for the parrot interpreter
* Data Structure and Algorithms:
@@ -225,6 +225,8 @@
#include "parrot/chartype.h"
#include "parrot/string.h"
#include "parrot/hash.h"
+#include "parrot/list.h"
+#include "parrot/pmc_freeze.h"
#include "parrot/vtable.h"
#include "parrot/register.h"
#include "parrot/stacks.h"
@@ -237,7 +239,6 @@
#include "parrot/op.h"
#include "parrot/pmc.h"
#include "parrot/events.h"
-#include "parrot/list.h"
#include "parrot/intlist.h"
#include "parrot/smallobject.h"
#include "parrot/headers.h"
1.12 +3 -0 parrot/ops/ops.num
Index: ops.num
===================================================================
RCS file: /cvs/public/parrot/ops/ops.num,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -w -r1.11 -r1.12
--- ops.num 1 Nov 2003 16:33:26 -0000 1.11
+++ ops.num 19 Nov 2003 15:43:32 -0000 1.12
@@ -1275,3 +1275,6 @@
seti_ind_i_ic 1248
seti_ind_ic_ic 1249
get_addr_i_p 1250
+freeze_s_p 1251
+thaw_p_s 1252
+thaw_p_sc 1253
1.15 +34 -0 parrot/ops/pmc.ops
Index: pmc.ops
===================================================================
RCS file: /cvs/public/parrot/ops/pmc.ops,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -w -r1.14 -r1.15
--- pmc.ops 3 Nov 2003 02:46:43 -0000 1.14
+++ pmc.ops 19 Nov 2003 15:43:33 -0000 1.15
@@ -500,6 +500,40 @@
###############################################################################
+=head2 Freeze, thaw and friends
+
+Ops to PMC freeze, thaw
+
+=over 4
+
+=cut
+
+########################################
+
+=item B<freeze>(out STR, in PMC)
+
+Set $1 to the frozen image of $2.
+
+=item B<thaw>(out PMC, in STR)
+
+Set $1 to a newly created PMC from the inage $2.
+
+=cut
+
+op freeze(out STR, in PMC) {
+ $1 = Parrot_freeze(interpreter, $2);
+ goto NEXT();
+}
+
+op thaw(out PMC, in STR) {
+ $1 = Parrot_thaw(interpreter, $2);
+ goto NEXT();
+}
+
+=back
+
+=cut
+
=head1 COPYRIGHT
Copyright (C) 2001-2003 The Perl Foundation. All rights reserved.
1.1 parrot/src/pmc_freeze.c
Index: pmc_freeze.c
===================================================================
/* pmc_freeze.c
* Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
* CVS Info
* $Id: pmc_freeze.c,v 1.1 2003/11/19 15:43:35 dan Exp $
* Overview:
* Freeze and thaw functionality
* Data Structure and Algorithms:
* Freeze uses the next_for_GC pointer to remeber seen PMCs.
* PMCs are written as IDs (or tags), which are calculated
* from their arena address. This PMC number is multiplied
* by four. The 2 lo bits indicate a seen PMC or a PMC of the
* same type as the previous one respectively.
*
* Thawing PMCs uses a list with (maximum) size of the
* amount of PMCs to keep track of retrieved PMCs.
*
* The individual information of PMCs is frozen/thawed by their
* vtables.
*
* To avoid recursion, the whole functionality is driven by
* pmc->vtable->visit, which is called for the first PMC initially.
* Container PMCs call a "todo-callback" for all contained PMCs.
* The individual action vtable (freeze/thaw) is then called for
* all todo-PMCs.
*
* History:
* Initial version by leo 2003.11.03 - 2003.11.07
* Notes:
* The seen-hash version for freezing might go away sometimes.
* References:
* Lot of discussion on p6i
*/
#include "parrot/parrot.h"
#include <assert.h>
/*
* define this to 1 for testing
*/
#define FREEZE_ASCII 0
/*
* normal freeze can use next_for_GC ptrs or a seen hash
*/
#define FREEZE_USE_NEXT_FOR_GC 1
/*
* when thawing a string longer then this size, we first do a
* DOD run and then block DOD/GC - the system can't give us more headers
*/
#define THAW_BLOCK_DOD_SIZE 100000
/*
* preallocate freeze image for aggregates with this estimation
*/
#if FREEZE_ASCII
# define FREEZE_BYTES_PER_ITEM 17
#else
# define FREEZE_BYTES_PER_ITEM 9
#endif
/*
* image stream functions
*/
/*
* plain ascii - for testing only:
* for speed reasons we mess around with the string buffers directly
* no encoding of strings, no transcoding
*/
static void
str_append(Parrot_Interp interpreter, STRING *s, const void *b, size_t len)
{
size_t used = s->bufused;
size_t need_free = s->buflen - used - len;
/*
* grow by factor 1.5 or such
*/
if (need_free <= 16) {
size_t new_size = s->buflen * 1.5;
if (new_size < s->buflen - need_free + 512)
new_size = s->buflen - need_free + 512;
Parrot_reallocate_string(interpreter, s, new_size);
assert(s->buflen - used - len >= 15);
}
mem_sys_memcopy((void *)((ptrcast_t)s->strstart + used), b, len);
s->bufused += len;
s->strlen += len;
}
static void
push_ascii_integer(Parrot_Interp interpreter, IMAGE_IO *io, INTVAL v)
{
char buffer[128];
sprintf(buffer, "%d ", (int) v);
str_append(interpreter, io->image, buffer, strlen(buffer));
}
static void
push_ascii_pmc(Parrot_Interp interpreter, IMAGE_IO *io, PMC* v)
{
char buffer[128];
sprintf(buffer, "%p ", v);
str_append(interpreter, io->image, buffer, strlen(buffer));
}
static INTVAL
shift_ascii_integer(Parrot_Interp interpreter, IMAGE_IO *io)
{
char *start, *p;
INTVAL i;
p = start = (char*)io->image->strstart;
i = strtoul(p, &p, 10);
++p;
assert(p <= start + io->image->bufused);
io->image->strstart = p;
io->image->bufused -= (p - start);
assert((int)io->image->bufused >= 0);
return i;
}
static PMC*
shift_ascii_pmc(Parrot_Interp interpreter, IMAGE_IO *io)
{
char *start, *p;
int i;
p = start = (char*)io->image->strstart;
i = strtoul(p, &p, 16);
++p;
assert(p <= start + io->image->bufused);
io->image->strstart = p;
io->image->bufused -= (p - start);
assert((int)io->image->bufused >= 0);
return (PMC*) i;
}
/*
* opcode_t io functions
*/
static void
op_append(Parrot_Interp interpreter, STRING *s, opcode_t b, size_t len)
{
size_t used = s->bufused;
size_t need_free = s->buflen - used - len;
/*
* grow by factor 1.5 or such
*/
if (need_free <= 16) {
size_t new_size = s->buflen * 1.5;
if (new_size < s->buflen - need_free + 512)
new_size = s->buflen - need_free + 512;
Parrot_reallocate_string(interpreter, s, new_size);
assert(s->buflen - used - len >= 15);
}
*((opcode_t *)((ptrcast_t)s->strstart + used)) = b;
s->bufused += len;
s->strlen += len;
}
static void
push_opcode_integer(Parrot_Interp interpreter, IMAGE_IO *io, INTVAL v)
{
op_append(interpreter, io->image, (opcode_t)v, sizeof(opcode_t));
}
static void
push_opcode_pmc(Parrot_Interp interpreter, IMAGE_IO *io, PMC* v)
{
op_append(interpreter, io->image, (opcode_t)v, sizeof(opcode_t));
}
static INTVAL
shift_opcode_integer(Parrot_Interp interpreter, IMAGE_IO *io)
{
char *start, *p;
INTVAL i;
p = start = (char*)io->image->strstart;
i = *((opcode_t*) p)++;
assert(p <= start + io->image->bufused);
io->image->strstart = p;
io->image->bufused -= (p - start);
assert((int)io->image->bufused >= 0);
return i;
}
static PMC*
shift_opcode_pmc(Parrot_Interp interpreter, IMAGE_IO *io)
{
return (PMC*) shift_opcode_integer(interpreter, io);
}
/*
* helper functions
*/
/*
* custom key_hash and compare functions
*/
static size_t
key_hash_int(Interp *interpreter, void *value)
{
return (size_t) value;
}
static int
int_compare(Parrot_Interp interp, void *a, void *b)
{
UNUSED(interp);
return a != b;
}
static void
pmc_add_ext(Parrot_Interp interpreter, PMC *pmc)
{
if (pmc->vtable->flags & VTABLE_PMC_NEEDS_EXT)
add_pmc_ext(interpreter, pmc);
}
/*
* set all next_for_GC pointers to NULL
*/
static void
cleanup_next_for_GC_pool(Parrot_Interp interpreter,
struct Small_Object_Pool *pool)
{
struct Small_Object_Arena *arena;
for (arena = pool->last_Arena; arena; arena = arena->prev) {
PMC *p = arena->start_objects;
UINTVAL i;
for (i = 0; i < arena->used; i++) {
if (p->pmc_ext)
p->next_for_GC = NULL;
p = (PMC *)((char *)p + sizeof(PMC));
}
}
}
static void
cleanup_next_for_GC(Parrot_Interp interpreter)
{
cleanup_next_for_GC_pool(interpreter,
interpreter->arena_base->pmc_pool);
cleanup_next_for_GC_pool(interpreter,
interpreter->arena_base->constant_pmc_pool);
}
/*
* this function setup stuff may be replaced by a real PMC
* in the future
* TODO add read/write header functions, e.g. vtable->init_pmc
*/
static image_funcs ascii_funcs = {
push_ascii_integer,
push_ascii_pmc,
shift_ascii_integer,
shift_ascii_pmc
};
static image_funcs opcode_funcs = {
push_opcode_integer,
push_opcode_pmc,
shift_opcode_integer,
shift_opcode_pmc
};
static IMAGE_IO io_init;
static void
ft_init(Parrot_Interp interpreter, visit_info *info)
{
info->image_io = &io_init;
info->image_io->image = info->image;
#if FREEZE_ASCII
info->image_io->vtable = &ascii_funcs;
#else
info->image_io->vtable = &opcode_funcs;
#endif
info->last_type = -1;
info->id_list = pmc_new(interpreter, enum_class_Array);
info->id = 0;
}
static void visit_todo_list(Parrot_Interp, PMC*, visit_info* info);
static void
todo_list_init(Parrot_Interp interpreter, visit_info *info)
{
Hash *hash;
info->visit_child_function = visit_todo_list;
/* we must use PMCs here, so that they get marked properly */
info->todo = pmc_new(interpreter, enum_class_Array);
info->seen = pmc_new_noinit(interpreter, enum_class_PerlHash);
hash = new_hash_x(interpreter, int_compare, key_hash_int,
(hash_mark_key_fn) NULL);
hash->entry_type = enum_type_int;
PObj_custom_mark_SET(info->seen);
PMC_ptr1v(info->seen) = hash;
ft_init(interpreter, info);
}
/*
* freeze, thaw a PMC (id)
*
* the ASCII representation of the PerlArray
* P0 = [P1=666, P2=777, P0]
* may look like this:
* 0xdf4 30 3 0xdf8 33 666 0xdf2 777 0xdf5
* (30 = class_enum_PerlArray, 33 = class_enum_PerlInt, the type of
* the second PerlInt is suppressed, the repeated P0 has bit 0 set)
*/
PARROT_INLINE static void
freeze_pmc(Parrot_Interp interpreter, PMC *pmc, visit_info *info,
int seen, UINTVAL id)
{
IMAGE_IO *io = info->image_io;
INTVAL type = pmc->vtable->base_type;
if (seen) {
id |= 1; /* mark bit 0 if this PMC is known */
}
else if (type == info->last_type) {
id |= 2; /* mark bit 1 and don't write type */
}
io->vtable->push_pmc(interpreter, io, (PMC*)id);
if (! (id & 3)) { /* else write type */
io->vtable->push_integer(interpreter, io, type);
info->last_type = type;
}
}
PARROT_INLINE static int
thaw_pmc(Parrot_Interp interpreter, visit_info *info,
UINTVAL *id, INTVAL *type)
{
PMC *n;
IMAGE_IO *io = info->image_io;
int seen = 0;
n = io->vtable->shift_pmc(interpreter, io);
if ( (UINTVAL) n & 1) { /* seen PMCs have bit 0 set */
seen = 1;
}
else if ( (UINTVAL) n & 2) { /* prev PMC was same type */
*type = info->last_type;
}
else { /* type follows */
info->last_type = *type = io->vtable->shift_integer(interpreter, io);
if (*type <= 0 || *type >= enum_class_max)
internal_exception(1, "Unknown PMC to thaw %d", (int) *type);
}
*id = (UINTVAL) n & ~3;
return seen;
}
/*
* visit/thaw common action functions:
* - freeze PMC
* -
*/
PARROT_INLINE static void
do_action(Parrot_Interp interpreter, PMC *pmc, visit_info *info,
int seen, UINTVAL id)
{
switch (info->what) {
case VISIT_FREEZE_AT_DESTRUCT:
case VISIT_FREEZE_NORMAL:
freeze_pmc(interpreter, pmc, info, seen, id);
info->visit_function = pmc->vtable->freeze;
break;
default:
internal_exception(1, "Illegal action %d", info->what);
break;
}
}
PARROT_INLINE static PMC*
thaw_create_pmc(Parrot_Interp interpreter, PMC *pmc, visit_info *info,
INTVAL type)
{
if (pmc) { /* first thawed PMC - just attach vtable */
pmc->vtable = Parrot_base_vtables[type];
pmc_add_ext(interpreter, pmc);
}
else { /* create a new header */
switch (info->what) {
case VISIT_THAW_NORMAL:
pmc = pmc_new_noinit(interpreter, type);
break;
case VISIT_THAW_CONSTANTS:
pmc = constant_pmc_new_noinit(interpreter, type);
break;
default:
internal_exception(1, "Illegal visit_next type");
break;
}
assert(info->thaw_ptr);
*info->thaw_ptr = pmc;
}
return pmc;
}
PARROT_INLINE static PMC*
do_thaw(Parrot_Interp interpreter, PMC* pmc, visit_info *info, int *seen)
{
UINTVAL id;
INTVAL type;
PMC ** b;
int must_have_seen = thaw_pmc(interpreter, info, &id, &type);
b = list_get(interpreter, PMC_data(info->id_list), id >> 2,
enum_type_PMC);
if (b == (void*)-1)
b = NULL;
else if (b) {
pmc = *(PMC**)b;
if (!pmc)
b = NULL;
}
if (b) {
*seen = 1;
#if FREEZE_USE_NEXT_FOR_GC
/*
* the next_for_GC method doesn't keep track of repeated scalars
* and such, as these are lacking the next_for_GC pointer, so
* these are just duplicated with their data.
* But we track these when thawing, so that we don't create dups
*/
if (!must_have_seen) {
/* so we must consume the bytecode */
VTABLE_thaw(interpreter, pmc, info);
}
#else
assert(must_have_seen);
#endif
*info->thaw_ptr = pmc;
return pmc;
}
assert(!must_have_seen);
*seen = 0;
pmc = thaw_create_pmc(interpreter, pmc, info, type);
info->visit_function = pmc->vtable->thaw;
list_assign(interpreter, PMC_data(info->id_list), id >> 2, pmc,
enum_type_PMC);
/* remember nested aggregates depth first */
if (pmc->pmc_ext)
list_push(interpreter, PMC_data(info->todo), pmc, enum_type_PMC);
return pmc;
}
#if ARENA_DOD_FLAGS
static UINTVAL
id_from_pmc(Parrot_Interp interpreter, PMC* pmc)
{
UINTVAL id = 1; /* first PMC in first arena */
struct Small_Object_Arena *arena, *pmc_arena;
struct Small_Object_Pool *pool;
pool = interpreter->arena_base->pmc_pool;
pmc_arena = GET_ARENA( (PObj*) pmc);
for (arena = pool->last_Arena; arena; arena = arena->prev) {
if (arena == pmc_arena) {
id += GET_OBJ_N(arena, (PObj*) pmc);
return id << 2; /* lo bits are flags */
}
id += arena->total_objects;
}
pool = interpreter->arena_base->constant_pmc_pool;
for (arena = pool->last_Arena; arena; arena = arena->prev) {
if (arena == pmc_arena) {
id += GET_OBJ_N(arena, (PObj*) pmc);
return id << 2;
}
id += arena->total_objects;
}
internal_exception(1, "Couldn't find PMC in arenas");
return -1;
}
#else
static UINTVAL
id_from_pmc(Parrot_Interp interpreter, PMC* pmc)
{
UINTVAL id = 1; /* first PMC in first arena */
struct Small_Object_Arena *arena;
struct Small_Object_Pool *pool;
ptrdiff_t ptr_diff;
pool = interpreter->arena_base->pmc_pool;
for (arena = pool->last_Arena; arena; arena = arena->prev) {
ptr_diff = (ptrdiff_t)pmc - (ptrdiff_t)arena->start_objects;
if (ptr_diff >= 0 && ptr_diff <
(ptrdiff_t)(arena->used * pool->object_size)) {
assert(ptr_diff % pool->object_size == 0);
id += ptr_diff / pool->object_size;
return id << 2;
}
id += arena->total_objects;
}
pool = interpreter->arena_base->constant_pmc_pool;
for (arena = pool->last_Arena; arena; arena = arena->prev) {
ptr_diff = (ptrdiff_t)pmc - (ptrdiff_t)arena->start_objects;
if (ptr_diff >= 0 && ptr_diff <
(ptrdiff_t)(arena->used * pool->object_size)) {
assert(ptr_diff % pool->object_size == 0);
id += ptr_diff / pool->object_size;
return id << 2;
}
id += arena->total_objects;
}
internal_exception(1, "Couldn't find PMC in arenas");
return -1;
}
#endif
/*
* remember next child to visit via the next_for_GC pointer
* generate a unique ID per PMC and freeze the ID not the PMC addr
* so thaw the hash-lookup can be replaced by an array lookup then
* which is a lot faster
*/
PARROT_INLINE static int
next_for_GC_seen(Parrot_Interp interpreter, PMC *pmc, visit_info *info,
UINTVAL *id)
{
int seen = 0;
/*
* we can only remember PMCs with a next_for_GC pointer
* which is located in pmc_ext
*/
if (pmc->pmc_ext) {
/* already seen? */
if (pmc->next_for_GC) {
seen = 1;
goto skip;
}
/* put pmc at the end of the list */
info->mark_ptr->next_for_GC = pmc;
/* make end self-referential */
info->mark_ptr = pmc->next_for_GC = pmc;
}
skip:
*id = id_from_pmc(interpreter, pmc);
return seen;
}
/*
* return true if PMC was seen, else put in on the todo list
* generate ID (tag) for PMC, offset by 4 as are addresses, lo bits
* are flags
*/
PARROT_INLINE static int
todo_list_seen(Parrot_Interp interpreter, PMC *pmc, visit_info *info,
UINTVAL *id)
{
HashBucket *b = hash_get_bucket(interpreter, PMC_ptr1v(info->seen), pmc);
if (b) {
*id = (UINTVAL) b->value;
return 1;
}
info->id += 4; /* next id to freeze */
*id = info->id;
hash_put(interpreter, PMC_ptr1v(info->seen), pmc, (void*)*id);
/* remember containers */
if (pmc->pmc_ext)
list_push(interpreter, PMC_data(info->todo), pmc, enum_type_PMC);
return 0;
}
/*
* visit_child callbacks:
* check if PMC was seen, generate ID for it
* then do the appropriate action
*/
static void
visit_next_for_GC(Parrot_Interp interpreter, PMC* pmc, visit_info* info)
{
UINTVAL id;
int seen = next_for_GC_seen(interpreter, pmc, info, &id);
do_action(interpreter, pmc, info, seen, id);
/*
* TODO probe for class methods that override the default.
* To avoid overhead, we could have an array[class_enums]
* which (after first find_method) has a bit, if a user
* callback is there.
*/
if (!seen)
(info->visit_function)(interpreter, pmc, info);
}
/*
* check seen via the todo list
*/
static void
visit_todo_list(Parrot_Interp interpreter, PMC* pmc, visit_info* info)
{
UINTVAL id;
int seen = todo_list_seen(interpreter, pmc, info, &id);
do_action(interpreter, pmc, info, seen, id);
if (!seen)
(info->visit_function)(interpreter, pmc, info);
}
/*
* callback for thaw - action first, todo-list and seen handling
* is all in do_thaw
*/
static void
visit_todo_list_thaw(Parrot_Interp interpreter, PMC* old, visit_info* info)
{
int seen;
PMC* pmc = do_thaw(interpreter, old, info, &seen);
if (!seen)
(info->visit_function)(interpreter, pmc, info);
}
/*
* work loops:
* put first item on todo list
* run as long as there are itens to be done
*/
static void
visit_loop_next_for_GC(Parrot_Interp interpreter, PMC *current,
visit_info *info)
{
PMC *prev = NULL;
visit_next_for_GC(interpreter, current, info);
if (current->pmc_ext) {
for ( ; current != prev; current = current->next_for_GC) {
VTABLE_visit(interpreter, current, info);
prev = current;
}
}
}
static void
visit_loop_todo_list(Parrot_Interp interpreter, PMC *current,
visit_info *info)
{
List *todo = PMC_data(info->todo);
(info->visit_child_function)(interpreter, current, info);
while (list_length(interpreter, todo)) {
current = *(PMC**)list_shift(interpreter, todo, enum_type_PMC);
VTABLE_visit(interpreter, current, info);
}
}
/*
* allocate image to some estimated size
*/
static void
create_image(Parrot_Interp interpreter, PMC *pmc, visit_info *info)
{
INTVAL len = FREEZE_BYTES_PER_ITEM;
if (VTABLE_does(interpreter, pmc,
string_from_cstring(interpreter, "array", 0)) ||
VTABLE_does(interpreter, pmc,
string_from_cstring(interpreter, "hash", 0))) {
INTVAL items = VTABLE_elements(interpreter, pmc);
/*
* TODO check e.g. first item of aggregate and estimate size
*/
len = items * FREEZE_BYTES_PER_ITEM;
}
info->image = string_make(interpreter, NULL, len, NULL, 0, NULL);
}
/*
* public interface
*/
/*
* freeze_at_destruct must not consume any resources
* (except the image itself)
* It uses the next_for_GC pointer, so its not reentrant and must
* not be interrupted by a DOD run
*/
STRING*
Parrot_freeze_at_destruct(Parrot_Interp interpreter, PMC* pmc)
{
visit_info info;
Parrot_block_DOD(interpreter);
cleanup_next_for_GC(interpreter);
info.what = VISIT_FREEZE_AT_DESTRUCT;
info.mark_ptr = pmc;
info.visit_child_function = visit_next_for_GC;
create_image(interpreter, pmc, &info);
ft_init(interpreter, &info);
visit_loop_next_for_GC(interpreter, pmc, &info);
cleanup_next_for_GC(interpreter);
Parrot_unblock_DOD(interpreter);
return info.image;
}
/*
* freeze using either method
*/
STRING*
Parrot_freeze(Parrot_Interp interpreter, PMC* pmc)
{
#if FREEZE_USE_NEXT_FOR_GC
/*
* we could do a DOD run here before, to free resources
*/
return Parrot_freeze_at_destruct(interpreter, pmc);
#else
/*
* freeze using a todo list and seen hash
* Please note that both have to be PMCs, so that trace_system_stack
* can call mark on the PMCs
*/
visit_info info;
info.what = VISIT_FREEZE_NORMAL;
create_image(interpreter, pmc, &info);
todo_list_init(interpreter, &info);
visit_loop_todo_list(interpreter, pmc, &info);
return info.image;
#endif
}
/*
* thaw could use the next_for_GC pointers as todo-list too,
* but this would need 2 runs through the arenas to clean the
* next_for_GC pointers.
* For now it seems cheaper to use a list for remembering contained
* aggregates. We could of course decide dynamically, which strategy
* to use, e.g.: given a big image, the first thawed item is a small
* aggregate. This implies, it probably contains[1] more nested containers,
* for which the next_for_GC approach could be a win.
* [1] or some big strings :)
*/
PMC*
Parrot_thaw(Parrot_Interp interpreter, STRING* image)
{
visit_info info;
PMC *n = NULL;
int dod_block = 0;
info.image = image;
if (string_length(image) > THAW_BLOCK_DOD_SIZE) {
Parrot_do_dod_run(interpreter, 1);
Parrot_block_DOD(interpreter);
Parrot_block_GC(interpreter);
dod_block = 1;
}
info.what = VISIT_THAW_NORMAL;
todo_list_init(interpreter, &info);
info.visit_child_function = visit_todo_list_thaw;
n = new_pmc_header(interpreter);
visit_loop_todo_list(interpreter, n, &info);
if (dod_block) {
Parrot_unblock_DOD(interpreter);
Parrot_unblock_GC(interpreter);
}
return n;
}
/*
* there are for sure shortcuts to clone faster, e.g. allways
* thaw the image immediately or use a special callback
*
* for now we just do:
*/
PMC*
Parrot_clone(Parrot_Interp interpreter, PMC* pmc)
{
return Parrot_thaw(interpreter, Parrot_freeze(interpreter, pmc));
}
/*
* Local variables:
* c-indentation-style: bsd
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/