Skip to content
This repository
Browse code

A little sloppy programming saw every attribute get/bind in P6opaque …

…accidentally cause the creation of two GC-ables. This brings that down to zero, as it was intended to be.
  • Loading branch information...
commit 6a1bb2a2292977e5204c874d2566626c00e426c1 1 parent 910fcac
Jonathan Worthington authored January 23, 2011
101  src/metamodel/reprs/P6opaque.c
@@ -72,13 +72,17 @@ static PMC * accessor_call(PARROT_INTERP, PMC *obj, STRING *name) {
72 72
  * everything will be looked up in spill. Otherwise returns a
73 73
  * populated name to index mapping. Note index is not related to the
74 74
  * storage position. */
75  
-static PMC * index_mapping_and_flat_list(PARROT_INTERP, PMC *WHAT, PMC *flat_list) {
76  
-    PMC    *result         = pmc_new(interp, enum_class_Hash);
  75
+static P6opaqueNameMap* index_mapping_and_flat_list(PARROT_INTERP, PMC *WHAT, PMC *flat_list) {
  76
+    PMC    *class_list     = pmc_new(interp, enum_class_ResizablePMCArray);
  77
+    PMC    *attr_map_list  = pmc_new(interp, enum_class_ResizablePMCArray);
77 78
     PMC    *current_class  = WHAT;
78 79
     INTVAL  current_slot   = 0;
79 80
     STRING *attributes_str = Parrot_str_new_constant(interp, "attributes");
80 81
     STRING *parents_str    = Parrot_str_new_constant(interp, "parents");
81 82
     STRING *name_str       = Parrot_str_new_constant(interp, "name");
  83
+    INTVAL i, num_classes;
  84
+
  85
+    P6opaqueNameMap *result = NULL;
82 86
 
83 87
     /* Walk through the parents list. */
84 88
     while (!PMC_IS_NULL(current_class))
@@ -89,6 +93,7 @@ static PMC * index_mapping_and_flat_list(PARROT_INTERP, PMC *WHAT, PMC *flat_lis
89 93
         /* Get attributes and iterate over them. */
90 94
         PMC *HOW        = STABLE(current_class)->HOW;
91 95
         PMC *attributes = introspection_call(interp, current_class, HOW, attributes_str);
  96
+        PMC *attr_map   = PMCNULL;
92 97
         PMC *attr_iter  = VTABLE_get_iter(interp, attributes);
93 98
         while (VTABLE_get_bool(interp, attr_iter)) {
94 99
             /* Get attribute. */
@@ -99,19 +104,20 @@ static PMC * index_mapping_and_flat_list(PARROT_INTERP, PMC *WHAT, PMC *flat_lis
99 104
             STRING *name     = VTABLE_get_string(interp, name_pmc);
100 105
 
101 106
             /* Allocate a slot. */
102  
-            INTVAL key = CLASS_KEY(current_class);
103  
-            if (!VTABLE_exists_keyed_int(interp, result, key))
104  
-                VTABLE_set_pmc_keyed_int(interp, result, key,
105  
-                        pmc_new(interp, enum_class_Hash));
106  
-            VTABLE_set_integer_keyed_str(interp,
107  
-                VTABLE_get_pmc_keyed_int(interp, result, key),
108  
-                name, current_slot);
  107
+            if (PMC_IS_NULL(attr_map))
  108
+                attr_map = pmc_new(interp, enum_class_Hash);
  109
+            VTABLE_set_pmc_keyed_str(interp, attr_map, name,
  110
+                Parrot_pmc_new_init_int(interp, enum_class_Integer, current_slot));
109 111
             current_slot++;
110 112
 
111  
-            /* Push it onto the flat list. */
  113
+            /* Push attr onto the flat list. */
112 114
             VTABLE_push_pmc(interp, flat_list, attr);
113 115
         }
114 116
 
  117
+        /* Add to class list and map list. */
  118
+        VTABLE_push_pmc(interp, class_list, current_class);
  119
+        VTABLE_push_pmc(interp, attr_map_list, attr_map);
  120
+
115 121
         /* Find the next parent(s). */
116 122
         parents = introspection_call(interp, current_class, HOW, parents_str);
117 123
 
@@ -125,7 +131,7 @@ static PMC * index_mapping_and_flat_list(PARROT_INTERP, PMC *WHAT, PMC *flat_lis
125 131
         else if (num_parents > 1)
126 132
         {
127 133
             /* Multiple inheritnace, so we can't compute this hierarchy. */
128  
-            return pmc_new(interp, enum_class_Hash);
  134
+            return mem_sys_allocate_zeroed(sizeof(P6opaqueNameMap));
129 135
         }
130 136
         else
131 137
         {
@@ -134,6 +140,14 @@ static PMC * index_mapping_and_flat_list(PARROT_INTERP, PMC *WHAT, PMC *flat_lis
134 140
         }
135 141
     }
136 142
 
  143
+    /* We can now form the name map. */
  144
+    num_classes = VTABLE_elements(interp, class_list);
  145
+    result = mem_sys_allocate_zeroed(sizeof(P6opaqueNameMap) * (1 + num_classes));
  146
+    for (i = 0; i < num_classes; i++) {
  147
+        result[i].class_key = VTABLE_get_pmc_keyed_int(interp, class_list, i);
  148
+        result[i].name_map  = VTABLE_get_pmc_keyed_int(interp, attr_map_list, i);
  149
+    }
  150
+
137 151
     return result;
138 152
 }
139 153
 
@@ -156,7 +170,7 @@ static void compute_allocation_strategy(PARROT_INTERP, PMC *WHAT, REPRP6opaque *
156 170
     /* If we have no attributes in the index mapping, then our allocation stratergy
157 171
      * is that everything goes into the spill hash. The size to allocate is just
158 172
      * two pointers - a shared table pointer and one for the spill hash. */
159  
-    if (VTABLE_elements(interp, repr->name_to_index_mapping) == 0) {
  173
+    if (repr->name_to_index_mapping[0].class_key == NULL) {
160 174
         repr->allocation_size = sizeof(RakudoObjectCommonalities) + sizeof(PMC *);
161 175
     }
162 176
 
@@ -290,6 +304,24 @@ static void set_pmc_at_offset(void *data, INTVAL offset, PMC *value) {
290 304
     *((PMC **)location) = value;
291 305
 }
292 306
 
  307
+/* Helper for finding a slot number. */
  308
+static INTVAL try_get_slot(PARROT_INTERP, REPRP6opaque *repr, PMC *class_key, STRING *name) {
  309
+    INTVAL slot = -1;
  310
+    if (repr->name_to_index_mapping) {
  311
+        P6opaqueNameMap *cur_map_entry = repr->name_to_index_mapping;
  312
+        while (cur_map_entry->class_key != NULL) {
  313
+            if (cur_map_entry->class_key == class_key) {
  314
+                PMC *slot_pmc = VTABLE_get_pmc_keyed_str(interp, cur_map_entry->name_map, name);
  315
+                if (!PMC_IS_NULL(slot_pmc))
  316
+                    slot = VTABLE_get_integer(interp, slot_pmc);
  317
+                break;
  318
+            }
  319
+            cur_map_entry++;
  320
+        }
  321
+    }
  322
+    return slot;
  323
+}
  324
+
293 325
 /* Creates a new type object of this representation, and associates it with
294 326
  * the given HOW. */
295 327
 static PMC * type_object_for(PARROT_INTERP, PMC *self, PMC *HOW) {
@@ -344,6 +376,7 @@ static INTVAL defined(PARROT_INTERP, PMC *self, PMC *obj) {
344 376
 static PMC * get_attribute(PARROT_INTERP, PMC *self, PMC *obj, PMC *class_handle, STRING *name) {
345 377
     P6opaqueInstance *instance = (P6opaqueInstance *)PMC_data(obj);
346 378
     REPRP6opaque     *repr     = P6O_REPR_STRUCT(self);
  379
+    INTVAL            slot;
347 380
 
348 381
     /* Ensure it is a defined object. */
349 382
     if (!instance->spill)
@@ -351,17 +384,10 @@ static PMC * get_attribute(PARROT_INTERP, PMC *self, PMC *obj, PMC *class_handle
351 384
                 "Cannot access attributes in a type object");
352 385
 
353 386
     /* Try the slot allocation first. */
354  
-    if (repr->name_to_index_mapping) {
355  
-        PMC *class_mapping = VTABLE_get_pmc_keyed_int(interp,
356  
-                repr->name_to_index_mapping, CLASS_KEY(class_handle));
357  
-        if (!PMC_IS_NULL(class_mapping)) {
358  
-            if (VTABLE_exists_keyed_str(interp, class_mapping, name))
359  
-            {
360  
-                INTVAL  position = VTABLE_get_integer_keyed_str(interp, class_mapping, name);
361  
-                PMC    *result   = get_pmc_at_offset(instance, repr->attribute_offsets[position]);
362  
-                return result ? result : PMCNULL;
363  
-            }
364  
-        }
  387
+    slot = try_get_slot(interp, repr, class_handle, name);
  388
+    if (slot >= 0) {
  389
+        PMC    *result   = get_pmc_at_offset(instance, repr->attribute_offsets[slot]);
  390
+        return result ? result : PMCNULL;
365 391
     }
366 392
     
367 393
     /* Fall back to the spill storage. */
@@ -379,6 +405,7 @@ static PMC * get_attribute_with_hint(PARROT_INTERP, PMC *self, PMC *obj, PMC *cl
379 405
 static void bind_attribute(PARROT_INTERP, PMC *self, PMC *obj, PMC *class_handle, STRING *name, PMC *value) {
380 406
     P6opaqueInstance *instance = (P6opaqueInstance *)PMC_data(obj);
381 407
     REPRP6opaque     *repr     = P6O_REPR_STRUCT(self);
  408
+    INTVAL            slot;
382 409
 
383 410
     /* Ensure it is a defined object. */
384 411
     if (!instance->spill)
@@ -386,17 +413,10 @@ static void bind_attribute(PARROT_INTERP, PMC *self, PMC *obj, PMC *class_handle
386 413
                 "Cannot access attributes in a type object");
387 414
 
388 415
     /* Try the slot allocation first. */
389  
-    if (repr->name_to_index_mapping) {
390  
-        PMC *class_mapping = VTABLE_get_pmc_keyed_int(interp,
391  
-                repr->name_to_index_mapping, CLASS_KEY(class_handle));
392  
-        if (!PMC_IS_NULL(class_mapping)) {
393  
-            if (VTABLE_exists_keyed_str(interp, class_mapping, name))
394  
-            {
395  
-                INTVAL position = VTABLE_get_integer_keyed_str(interp, class_mapping, name);
396  
-                set_pmc_at_offset(instance, repr->attribute_offsets[position], value);
397  
-                return;
398  
-            }
399  
-        }
  416
+    slot = try_get_slot(interp, repr, class_handle, name);
  417
+    if (slot >= 0) {
  418
+        set_pmc_at_offset(instance, repr->attribute_offsets[slot], value);
  419
+        return;
400 420
     }
401 421
 
402 422
     /* Fall back to the spill storage. */
@@ -501,7 +521,6 @@ static void gc_mark(PARROT_INTERP, PMC *self, PMC *obj) {
501 521
             }
502 522
         }
503 523
     }
504  
-
505 524
 }
506 525
 
507 526
 /* This Parrot-specific addition to the API is used to free an object. */
@@ -513,12 +532,20 @@ static void gc_free(PARROT_INTERP, PMC *self, PMC *obj) {
513 532
 /* This Parrot-specific addition to the API is used to mark a repr instance. */
514 533
 static void gc_mark_repr(PARROT_INTERP, PMC *self) {
515 534
     REPRP6opaque *repr = P6O_REPR_STRUCT(self);
516  
-    if (!PMC_IS_NULL(repr->name_to_index_mapping))
517  
-        Parrot_gc_mark_PMC_alive(interp, repr->name_to_index_mapping);
  535
+    if (repr->name_to_index_mapping) {
  536
+        P6opaqueNameMap *cur_map_entry = repr->name_to_index_mapping;
  537
+        while (cur_map_entry->class_key != NULL) {
  538
+            Parrot_gc_mark_PMC_alive(interp, cur_map_entry->name_map);
  539
+            cur_map_entry++;
  540
+        }
  541
+    }
518 542
 }
519 543
 
520 544
 /* This Parrot-specific addition to the API is used to free a repr instance. */
521 545
 static void gc_free_repr(PARROT_INTERP, PMC *self) {
  546
+    REPRP6opaque *repr = P6O_REPR_STRUCT(self);
  547
+    if (repr->name_to_index_mapping)
  548
+        mem_sys_free(repr->name_to_index_mapping);
522 549
     mem_sys_free(PMC_data(self));
523 550
     PMC_data(self) = NULL;
524 551
 }
10  src/metamodel/reprs/P6opaque.h
@@ -15,6 +15,12 @@ typedef struct {
15 15
     PMC *spill;
16 16
 } P6opaqueInstance;
17 17
 
  18
+/* This is used in the name to class mapping. */
  19
+typedef struct {
  20
+    PMC *class_key;
  21
+    PMC *name_map;
  22
+} P6opaqueNameMap;
  23
+
18 24
 /* A P6opaque REPR instance carries around both a slot mapping with it.
19 25
  * We waste some memory here in that we're storing the REPR pointer
20 26
  * table per "instantiation" of the REPR. It's per type rather than per
@@ -47,8 +53,8 @@ typedef struct {
47 53
     INTVAL unbox_str_offset;
48 54
 
49 55
     /* A table mapping attribute names to indexes (which can then be looked
50  
-     * up in the offset table). */
51  
-    PMC *name_to_index_mapping;
  56
+     * up in the offset table). Uses a final null entry as a sentinel. */
  57
+    P6opaqueNameMap *name_to_index_mapping;
52 58
 
53 59
     /* Offsets into the object that are elligible for PMC GC marking. */
54 60
     INTVAL *gc_pmc_mark_offsets;

0 notes on commit 6a1bb2a

Please sign in to comment.
Something went wrong with that request. Please try again.