Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
381 lines (274 sloc) 11.1 KB
/*
Copyright (C) 2001-2014, Parrot Foundation.
=head1 NAME
src/pmc/packfileannotations.pmc - PackfileAnnotations PMC
=head1 DESCRIPTION
This class implements a PackfileAnnotations object, a segment of the .pbc data
file used for listing annotations. It is a container for PackfileAnnotation
objects.
See packfile.pmc for the toplevel Packfile interface, see packfilesegment.pmc
for the list of common methods every packfile segment pmc must implement; see
PDD13 for the design spec.
To works properly PackfileAnnotations has to be added to PackfileDirectory with
PackfileConstantTable. Otherwise PackfileAnnotationKey can't be created.
=head2 Methods
=over 4
=cut
*/
#include "pmc/pmc_packfileannotation.h"
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */
pmclass PackfileAnnotations auto_attrs extends PackfileSegment {
/* ConstantTable used for names lookup */
ATTR PMC *const_table;
/* RPA of Annotation */
ATTR PMC *annotations;
/*
=item C<void init()>
Initialize PackfileAnnotations.
=cut
*/
VTABLE void init() {
Parrot_PackfileAnnotations_attributes * const attrs =
PMC_data_typed(SELF, Parrot_PackfileAnnotations_attributes*);
SUPER();
attrs->annotations = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
/*
Don't initialize C<const_table>. It will be set to NULL bu auto_attrs
handling. And should be set to proper PMC in set_directory.
*/
PObj_custom_mark_SET(SELF);
}
/*
=item C<void mark()>
Marks the object as live.
=cut
*/
VTABLE void mark() :no_wb {
Parrot_PackfileAnnotations_attributes * const attrs =
PARROT_PACKFILEANNOTATIONS(SELF);
Parrot_gc_mark_PMC_alive(INTERP, attrs->const_table);
Parrot_gc_mark_PMC_alive(INTERP, attrs->annotations);
SUPER();
}
/*
=item C<INTVAL elements()>
Get the number of elements in the array.
=cut
*/
VTABLE INTVAL elements() :no_wb {
return VTABLE_elements(INTERP,
PARROT_PACKFILEANNOTATIONS(SELF)->annotations);
}
/*
=item C<PMC *get_pmc_keyed_int(INTVAL index)>
Fetch an annotation PMC from the array.
=cut
*/
VTABLE PMC *get_pmc_keyed_int(INTVAL index) :no_wb {
return VTABLE_get_pmc_keyed_int(INTERP,
PARROT_PACKFILEANNOTATIONS(SELF)->annotations, index);
}
/*
=item C<void set_pmc_keyed_int(INTVAL index, PMC *annotation)>
Add an annotation to the array at the given offset. An exception will be
thrown unless all of the following criteria are met:
=over 4
=item - The type of the PMC passed is PackfileAnnotation
=item - The entry at the previous index is defined
=item - The offset of the previous entry is less than this entry
=item - The offset of the next entry, if it exists, is greater than this entry
=item - The key ID references a valid annotation key
=back
=cut
*/
VTABLE void set_pmc_keyed_int(INTVAL index, PMC *annotation) {
const Parrot_PackfileAnnotations_attributes * const attrs =
PARROT_PACKFILEANNOTATIONS(SELF);
const Parrot_PackfileAnnotation_attributes * const entity_attrs =
PARROT_PACKFILEANNOTATION(annotation);
INTVAL dummy;
/* TODO: add checks described above */
VTABLE_set_pmc_keyed_int(INTERP, attrs->annotations, index, annotation);
/* Add required constants */
Parrot_mmd_multi_dispatch_from_c_args(INTERP,
"get_or_create_constant", "PS->I", attrs->const_table,
entity_attrs->name, &dummy);
switch (entity_attrs->value_type) {
case PF_ANNOTATION_KEY_TYPE_STR:
Parrot_mmd_multi_dispatch_from_c_args(INTERP,
"get_or_create_constant", "PS->I", attrs->const_table,
entity_attrs->str_value, &dummy);
break;
default:
/* Do nothing. If value_type if INT it will be stored directly */
break;
}
}
/*
=item C<void set_directory()>
Handle setting of ownership.
Find PackfileConstantTable in PackfileDirectory and pass it to
PackfileAnnotationKeys.
=cut
*/
METHOD set_directory(PMC *directory) {
Parrot_PackfileAnnotations_attributes * const attrs =
PARROT_PACKFILEANNOTATIONS(SELF);
PMC * const iter = VTABLE_get_iter(INTERP, directory);
/* This should be SUPER(directory), but that doesn't work. */
attrs->directory = directory;
while (VTABLE_get_bool(INTERP, iter)) {
STRING * const name = VTABLE_shift_string(INTERP, iter);
PMC * const segment = VTABLE_get_pmc_keyed_str(INTERP, directory, name);
if (VTABLE_isa(INTERP, segment,
Parrot_str_new_constant(INTERP, "PackfileConstantTable"))) {
attrs->const_table = segment;
break;
}
}
}
/*
=item C<void set_pointer(void *ptr)>
Initialize PackfileAnnotations from PackFile_Annotations*.
=cut
*/
VTABLE void set_pointer(void *pointer) {
PackFile_Annotations * const a = (PackFile_Annotations*)pointer;
Parrot_PackfileAnnotations_attributes * const attrs =
PARROT_PACKFILEANNOTATIONS(SELF);
Parrot_PackfileAnnotation_attributes *annotation_attrs;
opcode_t i;
if (!attrs->const_table)
Parrot_ex_throw_from_c_noargs(INTERP,
EXCEPTION_MALFORMED_PACKFILE, "No constant table");
/* Copy annotations to own array */
VTABLE_set_integer_native(INTERP, attrs->annotations, 0); /* truncate */
for (i = 0; i < a->num_keys; ++i) {
PackFile_Annotations_Key * const key = &a->keys[i];
opcode_t j;
for (j = 0; j < (opcode_t)key->len; j++) {
PMC * const annotation = Parrot_pmc_new(INTERP, enum_class_PackfileAnnotation);
const opcode_t offs = a->base.data[(key->start + j) * 2 + ANN_ENTRY_OFF];
const opcode_t val = a->base.data[(key->start + j) * 2 + ANN_ENTRY_VAL];
/* Poke directly to annotation attributes. */
annotation_attrs = PARROT_PACKFILEANNOTATION(annotation);
annotation_attrs->offset = offs;
annotation_attrs->name = VTABLE_get_string_keyed_int(INTERP,
attrs->const_table, key->name);
switch (key->type) {
case PF_ANNOTATION_KEY_TYPE_INT:
VTABLE_set_integer_native(INTERP, annotation, val);
break;
case PF_ANNOTATION_KEY_TYPE_STR:
VTABLE_set_string_native(INTERP, annotation,
VTABLE_get_string_keyed_int(INTERP, attrs->const_table, val));
break;
case PF_ANNOTATION_KEY_TYPE_PMC:
VTABLE_set_pmc(INTERP, annotation,
VTABLE_get_pmc_keyed_int(INTERP, attrs->const_table, val));
break;
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_MALFORMED_PACKFILE,
"Unknown value type %d in PackfileAnnotations", key->type);
}
VTABLE_push_pmc(INTERP, attrs->annotations, annotation);
}
}
}
/*
=item C<void *get_pointer()>
Create PackFile_Annotations* from self.
=cut
*/
VTABLE void *get_pointer() :no_wb {
Parrot_PackfileAnnotations_attributes * const attrs =
PARROT_PACKFILEANNOTATIONS(SELF);
PackFile_Annotations * const res =
mem_gc_allocate_zeroed_typed(INTERP, PackFile_Annotations);
INTVAL i, num;
PMC *keys; /* Temporary representation of Keys */
INTVAL name_id;
INTVAL value_id;
res->base.type = PF_ANNOTATIONS_SEG;
/*
Create keys. Hash will be created in next structure:
keys => {
name => [
$int_key_id,
$str_key_id,
$num_key_id,
]
}
Each key has name from ConstantTable. We store them in names Array.
names => [
$constant_id_1,
$contsant_id_2,
...
]
*/
keys = Parrot_pmc_new(INTERP, enum_class_Hash);
/* Iterate over stored annotations and create Key if required. */
num = VTABLE_elements(INTERP, attrs->annotations);
for (i = 0; i < num; ++i) {
PMC * const entity = VTABLE_get_pmc_keyed_int(INTERP, attrs->annotations, i);
const Parrot_PackfileAnnotation_attributes * const entity_attrs =
PARROT_PACKFILEANNOTATION(entity);
/* Handle creating of Key */
PMC * key_array = VTABLE_get_pmc_keyed_str(INTERP, keys, entity_attrs->name);
if (PMC_IS_NULL(key_array)) {
/* Never see this name before. Create new FIA and add to keys. */
key_array = Parrot_pmc_new_init_int(INTERP, enum_class_FixedIntegerArray, 3);
VTABLE_set_integer_keyed_int(INTERP, key_array, 0, -1);
VTABLE_set_integer_keyed_int(INTERP, key_array, 1, -1);
VTABLE_set_integer_keyed_int(INTERP, key_array, 2, -1);
VTABLE_set_pmc_keyed_str(INTERP, keys, entity_attrs->name, key_array);
}
/* lookup constant for name. */
Parrot_mmd_multi_dispatch_from_c_args(INTERP, "get_or_create_constant",
"PS->I", attrs->const_table, entity_attrs->name, &name_id);
/* lookup value */
switch (entity_attrs->value_type) {
case PF_ANNOTATION_KEY_TYPE_INT:
value_id = entity_attrs->int_value;
break;
case PF_ANNOTATION_KEY_TYPE_STR:
Parrot_mmd_multi_dispatch_from_c_args(INTERP, "get_or_create_constant",
"PS->I", attrs->const_table, entity_attrs->str_value,
&value_id);
break;
case PF_ANNOTATION_KEY_TYPE_PMC:
Parrot_mmd_multi_dispatch_from_c_args(INTERP, "get_or_create_constant",
"PP->I", attrs->const_table, entity_attrs->pmc_value,
&value_id);
break;
default:
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_MALFORMED_PACKFILE,
"Unknown value type in PackfileAnnotation");
}
/* store entity */
Parrot_pf_annotations_add_entry(interp, res, entity_attrs->offset, name_id,
entity_attrs->value_type, value_id);
}
return res;
}
/*
=item C<METHOD type()>
Get segment type.
=cut
*/
METHOD type() :no_wb {
RETURN(INTVAL PF_ANNOTATIONS_SEG);
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/