Hi,
Currently, whenever we instantiate an object (e.g. from a Class PMC), we
get an Object PMC. This process also allocates a ResizablePMCArray to
hold the attributes. The first of the attached patches - which passes
all but one test file in Parrot - switches us to malloc'ing a C array to
store the attributes. The second needs to be applied to Rakudo to get it
to build with these changes (it has a dynop that plays with the object
guts).
There's one test failure in Parrot and some various ones in Rakudo (we
get through all of the sanity tests though), but I'm only really
inclined to spend time debugging these if there's a sense that this
patch is worthwhile and actually an improvement. I'm not really set up
to benchmark stuff so well and lack experience in this, so I'm posting
the patch here in hope that:
1) Someone will benchmark it and see if it actually helps and is
worthwhile spending more time on
2) Somebody might be able to spot, how I screwed up freeze/thaw.
3) I might get some other bits of review on it.
Thanks,
Jonathan
Index: src/pmc/class.pmc
===================================================================
--- src/pmc/class.pmc (revision 39081)
+++ src/pmc/class.pmc (working copy)
@@ -150,6 +150,7 @@
/* Store built attribute index and invalidate cache. */
_class->attrib_index = attrib_index;
_class->attrib_cache = cache;
+ _class->num_attrs = cur_index;
}
/* Takes a hash and initializes the class based on it. */
@@ -458,6 +459,7 @@
ATTR PMC *resolve_method; /* List of method names the class provides to
resolve
* conflicts with methods from roles. */
ATTR PMC *parent_overrides;
+ ATTR INTVAL num_attrs; /* The number of attributes this class has. */
/*
@@ -1169,6 +1171,7 @@
Parrot_Object_attributes *obj_guts;
PMC *object;
+ int i;
/* If we've not been instantiated before... */
if (!_class->instantiated) {
@@ -1178,7 +1181,6 @@
const INTVAL cur_hll = CONTEXT(interp)->current_HLL;
const INTVAL num_parents = VTABLE_elements(interp,
_class->parents);
INTVAL mro_length;
- int i;
/* don't use HLL mappings for internal-only data */
CONTEXT(interp)->current_HLL = 0;
@@ -1239,7 +1241,9 @@
obj_guts =
mem_allocate_zeroed_typed(Parrot_Object_attributes);
obj_guts->_class = SELF;
PMC_data(object) = obj_guts;
- obj_guts->attrib_store = pmc_new(interp, enum_class_ResizablePMCArray);
+ obj_guts->attrib_store = mem_allocate_n_typed(_class->num_attrs, PMC
*);
+ for (i = 0; i < _class->num_attrs; i++)
+ obj_guts->attrib_store[i] = PMCNULL;
if (!PMC_IS_NULL(init)) {
/* Initialize attributes with the supplied values. */
Index: src/pmc/object.pmc
===================================================================
--- src/pmc/object.pmc (revision 39081)
+++ src/pmc/object.pmc (working copy)
@@ -104,8 +104,8 @@
}
pmclass Object need_ext {
- ATTR PMC *_class; /* The class this is an instance of. */
- ATTR PMC *attrib_store; /* The attributes store - a resizable PMC array. */
+ ATTR PMC *_class; /* The class this is an instance of. */
+ ATTR PMC **attrib_store; /* The attributes store - an array of PMCs. */
/*
@@ -148,6 +148,9 @@
*/
VTABLE void destroy() {
+ Parrot_Object_attributes * const obj = PARROT_OBJECT(SELF);
+ if (obj->attrib_store)
+ mem_sys_free(obj->attrib_store);
mem_sys_free(PMC_data(SELF));
}
@@ -187,10 +190,15 @@
if (PARROT_OBJECT(SELF)) {
Parrot_Object_attributes * const obj = PARROT_OBJECT(SELF);
- if (obj->_class)
+ if (obj->_class) {
+ Parrot_Class_attributes * const _class =
PARROT_CLASS(obj->_class);
Parrot_gc_mark_PObj_alive(interp, (PObj*)obj->_class);
- if (obj->attrib_store)
- Parrot_gc_mark_PObj_alive(interp, (PObj*)obj->attrib_store);
+ if (obj->attrib_store) {
+ int i;
+ for (i = 0; i < _class->num_attrs; i++)
+ Parrot_gc_mark_PObj_alive(interp,
(PObj*)obj->attrib_store[i]);
+ }
+ }
}
}
@@ -225,7 +233,7 @@
Parrot_ex_throw_from_c_args(interp, NULL,
EXCEPTION_ATTRIB_NOT_FOUND,
"No such attribute '%S'", name);
- return VTABLE_get_pmc_keyed_int(interp, obj->attrib_store, index);
+ return obj->attrib_store[index];
}
/*
@@ -250,7 +258,7 @@
"No such attribute '%S' in class '%S'", name,
VTABLE_get_string(interp, key));
- return VTABLE_get_pmc_keyed_int(interp, obj->attrib_store, index);
+ return obj->attrib_store[index];
}
/*
@@ -285,7 +293,7 @@
Parrot_ex_throw_from_c_args(interp, NULL,
EXCEPTION_ATTRIB_NOT_FOUND,
"No such attribute '%S'", name);
- VTABLE_set_pmc_keyed_int(interp, obj->attrib_store, index, value);
+ obj->attrib_store[index] = value;
}
/*
@@ -308,7 +316,7 @@
"No such attribute '%S' in class '%S'", name,
VTABLE_get_string(interp, key));
- VTABLE_set_pmc_keyed_int(interp, obj->attrib_store, index, value);
+ obj->attrib_store[index] = value;
}
/*
@@ -647,7 +655,7 @@
/* See if we have a custom override of the method first. */
const int num_classes = VTABLE_elements(interp, _class->all_parents);
- int i, num_attrs;
+ int i;
for (i = 0; i < num_classes; i++) {
/* Get the class. */
PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp,
_class->all_parents, i);
@@ -672,15 +680,16 @@
/* Now create the underlying structure, and clone attributes
list.class. */
cloned_guts =
mem_allocate_zeroed_typed(Parrot_Object_attributes);
cloned_guts->_class = obj->_class;
- cloned_guts->attrib_store = VTABLE_clone(INTERP, obj->attrib_store);
+ cloned_guts->attrib_store = mem_allocate_n_typed(_class->num_attrs,
PMC *);
PMC_data(cloned) = cloned_guts;
- num_attrs = VTABLE_elements(INTERP,
cloned_guts->attrib_store);
- for (i = 0; i < num_attrs; i++) {
- PMC * const to_clone = VTABLE_get_pmc_keyed_int(INTERP,
cloned_guts->attrib_store, i);
+ for (i = 0; i < _class->num_attrs; i++) {
+ PMC * const to_clone = obj->attrib_store[i];
if (!PMC_IS_NULL(to_clone)) {
- VTABLE_set_pmc_keyed_int(INTERP, cloned_guts->attrib_store, i,
- VTABLE_clone(INTERP, to_clone));
+ cloned_guts->attrib_store[i] = VTABLE_clone(INTERP, to_clone);
}
+ else {
+ cloned_guts->attrib_store[i] = to_clone;
+ }
}
/* Some of the attributes may have been the PMCs providing storage for
any
@@ -718,16 +727,26 @@
VTABLE void visit(visit_info *info) {
Parrot_Object_attributes * const obj_data = PARROT_OBJECT(SELF);
PMC **pos;
+ INTVAL num_attrs, i;
/* 1) visit class */
pos = &obj_data->_class;
info->thaw_ptr = pos;
(info->visit_pmc_now)(INTERP, *pos, info);
+ /* Now we have the class, and if we're thawing, we can allocate the
+ * attributes storage array for visiting. */
+ num_attrs = PARROT_CLASS(obj_data->_class)->num_attrs;
+ if (!obj_data->attrib_store) {
+ obj_data->attrib_store = mem_allocate_n_typed(num_attrs, PMC *);
+ }
+
/* 2) visit the attributes */
- pos = &obj_data->attrib_store;
- info->thaw_ptr = pos;
- (info->visit_pmc_now)(INTERP, *pos, info);
+ for (i = 0; i < num_attrs; i++) {
+ pos = &obj_data->attrib_store[i];
+ info->thaw_ptr = pos;
+ (info->visit_pmc_now)(INTERP, *pos, info);
+ }
}
/*
diff --git a/src/ops/perl6.ops b/src/ops/perl6.ops
index b797c23..efbfb2d 100644
--- a/src/ops/perl6.ops
+++ b/src/ops/perl6.ops
@@ -5,6 +5,7 @@
#include "parrot/dynext.h"
#include "pmc_object.h"
+#include "pmc_class.h"
VERSION = PARROT_VERSION;
#if PARROT_HAS_ICU
@@ -94,8 +95,7 @@ inline op rebless_subclass(in PMC, in PMC) :base_core {
/* Now set any new attributes to be undef. */
for (i = 0; i < new_attribs; i++)
- VTABLE_set_pmc_keyed_int(interp,
PARROT_OBJECT(value)->attrib_store,
- i, pmc_new(interp, enum_class_Undef));
+ PARROT_OBJECT(value)->attrib_store[i] = pmc_new(interp,
enum_class_Undef);
}
else if (value->vtable->base_type != enum_class_Object
|| current_class->vtable->base_type != enum_class_Class) {
@@ -110,13 +110,20 @@ inline op rebless_subclass(in PMC, in PMC) :base_core {
* Shuffle up attributes to the point of the difference between the
number
* of attributes in the parent and the derived class. Yes, this is
evil -
* we're diddling the object's internals. */
+ INTVAL orig_attrs = PARROT_CLASS(current_class)->num_attrs;
+ PMC **new_attr_store = mem_allocate_n_typed(orig_attrs + new_attribs,
PMC *);
+ Parrot_block_GC_mark(interp);
+ memmove(new_attr_store + new_attribs,
PARROT_OBJECT(value)->attrib_store,
+ orig_attrs * sizeof(PMC *));
+ mem_sys_free(PARROT_OBJECT(value)->attrib_store);
+ PARROT_OBJECT(value)->attrib_store = new_attr_store;
for (i = 0; i < new_attribs; i++)
- VTABLE_unshift_pmc(interp, PARROT_OBJECT(value)->attrib_store,
- pmc_new(interp, enum_class_Undef));
+ new_attr_store[i] = pmc_new(interp, enum_class_Undef);
/* Now switch object's class pointer to point at the new class. This is
* also evil. */
PARROT_OBJECT(value)->_class = $2;
+ Parrot_unblock_GC_mark(interp);
}
goto NEXT();
_______________________________________________
http://lists.parrot.org/mailman/listinfo/parrot-dev