Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

579 lines (424 sloc) 15.615 kb
/*
Copyright (C) 2011-2014, Parrot Foundation.
=head1 NAME
src/pmc/packfileview.pmc - PackfileView PMC
=head1 DESCRIPTION
This class implements a user-accessible, read-only wrapper for the PackFile*
structure used internally by Parrot. It is essentially an interface for the user
to call Packfile subsystem API calls, and work with the PackFile* structures
output from utilities which generate them.
NOTICE: This PMC should contain very little logic. It should be a thin wrapper
around the public functions in src/packfile/api.c. This PMC should contain
absolutely NO functionality for modifying the packfile. To create a new
packfile or modify an existing one, use the PackFile PMC instead.
=head2 VTABLES
=over 4
=cut
*/
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
static void add_called_tag(PARROT_INTERP,
ARGMOD(PMC * self),
ARGIN(STRING * tag))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(3)
FUNC_MODIFIES(* self);
static INTVAL find_called_tag(PARROT_INTERP,
ARGIN(PMC * self),
ARGIN(STRING * tag))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(3);
PARROT_CAN_RETURN_NULL
static PackFile_ConstTable * get_const_table(PARROT_INTERP,
ARGIN(PMC * self))
__attribute__nonnull__(2);
PARROT_CANNOT_RETURN_NULL
static PMC * get_first_sub(PARROT_INTERP, ARGIN(PMC *pfpmc))
__attribute__nonnull__(1)
__attribute__nonnull__(2);
#define ASSERT_ARGS_add_called_tag __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(self) \
, PARROT_ASSERT_ARG(tag))
#define ASSERT_ARGS_find_called_tag __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(self) \
, PARROT_ASSERT_ARG(tag))
#define ASSERT_ARGS_get_const_table __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(self))
#define ASSERT_ARGS_get_first_sub __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(pfpmc))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/*
=item C<static PackFile_ConstTable * get_const_table(PARROT_INTERP, PMC * self)>
Get the constant table for the PackFile*. Return NULL if there's a problem.
=cut
*/
PARROT_CAN_RETURN_NULL
static PackFile_ConstTable *
get_const_table(SHIM_INTERP, ARGIN(PMC * self))
{
ASSERT_ARGS(get_const_table)
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(self);
PackFile * const pf = attrs->pf;
PackFile_ByteCode * bt;
if (!pf)
return NULL;
bt = pf->cur_cs;
if (!bt)
return NULL;
return bt->const_table;
}
/*
=item C<static INTVAL find_called_tag(PARROT_INTERP, PMC * self, STRING * tag)>
Find a called tag in the cache. Return 1 if it exists, 0 otherwise.
=item C<static void add_called_tag(PARROT_INTERP, PMC * self, STRING * tag)>
Add a called tag to the cache, if it doesn't exist already. Do nothing
otherwise.
=cut
*/
static INTVAL
find_called_tag(PARROT_INTERP, ARGIN(PMC * self), ARGIN(STRING * tag))
{
ASSERT_ARGS(find_called_tag)
Parrot_PackfileView_attributes * const attrs = PARROT_PACKFILEVIEW(self);
PMC * const called_tags = attrs->called_tags;
if (!PMC_IS_NULL(called_tags)) {
const INTVAL count = VTABLE_elements(interp, called_tags);
INTVAL i;
for (i = 0; i < count; i++) {
STRING * const str = VTABLE_get_string_keyed_int(interp, called_tags, i);
if (STRING_equal(interp, str, tag))
return 1;
}
}
return 0;
}
static void
add_called_tag(PARROT_INTERP, ARGMOD(PMC * self), ARGIN(STRING * tag))
{
ASSERT_ARGS(add_called_tag)
const int has_it = find_called_tag(interp, self, tag);
if (!has_it) {
Parrot_PackfileView_attributes * const attrs = PARROT_PACKFILEVIEW(self);
PMC * called_tags = attrs->called_tags;
if (PMC_IS_NULL(called_tags)) {
called_tags = Parrot_pmc_new(interp, enum_class_ResizableStringArray);
attrs->called_tags = called_tags;
}
VTABLE_push_string(interp, called_tags, tag);
}
}
pmclass PackfileView auto_attrs {
ATTR PackFile * pf;
ATTR STRING * path;
ATTR PMC * called_tags;
/*
=item C<VTABLE void init()>
Create the new PMC and set flags
=item C<VTABLE void destroy()>
Destroy the PMC *AND* the underlying PackFile*
=item C<VTABLE void mark()>
Mark the PMC and the PackFile* contents
=cut
*/
VTABLE void mark() :no_wb {
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(SELF);
if (attrs->pf != NULL)
Parrot_pf_mark_packfile(INTERP, attrs->pf);
if (!STRING_IS_NULL(attrs->path))
Parrot_gc_mark_STRING_alive(INTERP, attrs->path);
if (!PMC_IS_NULL(attrs->called_tags))
Parrot_gc_mark_PMC_alive(INTERP, attrs->called_tags);
}
VTABLE void init() {
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(SELF);
attrs->pf = NULL;
PObj_custom_mark_destroy_SETALL(SELF);
}
VTABLE void destroy() :no_wb {
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(SELF);
if (attrs->pf != NULL)
Parrot_pf_destroy(INTERP, attrs->pf);
}
/*
=item C<VTABLE void set_pointer(void *ptr)>
Set a pointer to a PackFile* structure. This can only be done once. Attempting
to set a new pointer will throw an exception. This rule is in place because
the lifetime of the PackFile* is tied to the lifetime of the PMC wrapping it,
and the PMC provides access to the PackFile* by the GC. Overwriting a pointer
to an old PackFile* structure will cause memory leaks, prematurely collected
Subs, and other creepy behaviors.
=item C<VTABLE void *get_pointer()>
Get a pointer to the underlying PackFile* structure
=item C<VTABLE INTVAL get_bool()>
Return 1 (true) if this PMC is currently pointing to a PackFile*. 0 (false)
otherwise.
=cut
*/
VTABLE void set_pointer(void * ptr) :manual_wb {
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(SELF);
if (attrs->pf != NULL)
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION,
"Cannot overwrite existing pointer in PackfileView");
attrs->pf = (PackFile*)ptr;
/* Do not free an empty pf? See above */
if (ptr != NULL)
PARROT_GC_WRITE_BARRIER(INTERP, SELF);
}
VTABLE void *get_pointer() :no_wb {
UNUSED(INTERP)
return PARROT_PACKFILEVIEW(SELF)->pf;
}
VTABLE INTVAL get_bool() :no_wb {
UNUSED(INTERP)
return (PARROT_PACKFILEVIEW(SELF)->pf != NULL);
}
/*
=item C<VTABLE void set_string_native(STRING *path)>
=item C<VTABLE STRING *get_string_native(STRING *path)>
=cut
*/
VTABLE void set_string_native(STRING * path) {
PARROT_PACKFILEVIEW(SELF)->path = path;
}
VTABLE STRING * get_string() :no_wb {
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(SELF);
UNUSED(INTERP);
return attrs->path ? attrs->path : STRINGNULL;
}
/*
=item C<VTABLE PMC *get_pmc_keyed_int(INTVAL idx)>
Get a PMC from the constants table, by index
=item C<VTABLE STRING *get_string_keyed_int(INTVAL idx)>
Get a STRING from the constants table, by index
=item C<VTABLE FLOATVAL get_number_keyed_int(INTVAL idx)>
Get a FLOATVAL from the constants table, by index
=cut
*/
VTABLE PMC * get_pmc_keyed_int(INTVAL idx) :no_wb {
PackFile_ConstTable * const ct = get_const_table(INTERP, SELF);
if (!ct)
return PMCNULL;
if (idx < 0 || idx >= ct->pmc.const_count) {
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
"index out of bounds");
}
return ct->pmc.constants[idx];
}
VTABLE STRING * get_string_keyed_int(INTVAL idx) :no_wb {
PackFile_ConstTable * const ct = get_const_table(INTERP, SELF);
if (!ct)
return STRINGNULL;
if (idx < 0 || idx >= ct->str.const_count) {
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
"index out of bounds");
}
return ct->str.constants[idx];
}
VTABLE FLOATVAL get_number_keyed_int(INTVAL idx) :no_wb {
PackFile_ConstTable * const ct = get_const_table(INTERP, SELF);
if (!ct)
return 0.0;
if (idx < 0 || idx >= ct->num.const_count) {
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS,
"index out of bounds");
}
return ct->num.constants[idx];
}
/*
=back
=head2 METHODS
=over 4
=item C<METHOD constant_counts()>
Return a 3-element FixedIntegerArray with the total number of FLOATVAL, STRING
and PMC constants in the respective constant tables.
=cut
*/
METHOD constant_counts() :no_wb {
PackFile_ConstTable * const ct = get_const_table(INTERP, SELF);
if (!ct)
Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_UNEXPECTED_NULL,
"NULL or Malformed Packfile");
else {
PMC * const counts = Parrot_pmc_new(INTERP, enum_class_FixedIntegerArray);
VTABLE_set_integer_native(INTERP, counts, 3);
VTABLE_set_integer_keyed_int(INTERP, counts, 0, ct->num.const_count);
VTABLE_set_integer_keyed_int(INTERP, counts, 1, ct->str.const_count);
VTABLE_set_integer_keyed_int(INTERP, counts, 2, ct->pmc.const_count);
RETURN(PMC *counts);
}
}
/*
=item C<METHOD main_sub()>
Get the :main sub from the packfile, if any.
=item C<METHOD subs_by_tag(STRING *tag)>
Get an array of all Subs with the given tag.
=item C<METHOD single_sub_by_tag(STRING *tag)>
Get a single Sub with the given tag. If there are more than one Subs with this
flag, it is unspecified which one is returned.
=item C<METHOD trigger(STRING *flag)>
Trigger subs with the given flag. Currently supported values are "load" and
"init".
=item C<METHOD all_tags()>
Return an array of all tags.
=item C<METHOD all_tagged_pmcs()>
Return a hash map of all tags, and the lists of pmcs with those tags.
=item C<METHOD all_subs()>
Return a ResizablePMCArray with all Sub constants from the constant table.
=item C<METHOD first_sub_in_const_table()>
Returns the first Sub constant from the constant table.
=item C<METHOD mark_initialized(STRING *tag)>
Mark a given tag as being initialized
=item C<METHOD is_initialized(STRING *tag)>
Determine if the given tag has been marked initialized
=cut
*/
METHOD main_sub() :no_wb {
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(SELF);
if (attrs->pf == NULL)
RETURN(PMC *PMCNULL);
else {
PMC * const main_sub = Parrot_pf_get_packfile_main_sub(INTERP, SELF);
RETURN(PMC *main_sub);
}
}
METHOD subs_by_tag(STRING *flag) :no_wb {
PMC * const subs = Parrot_pf_subs_by_tag(INTERP, SELF, flag);
RETURN(PMC *subs);
}
METHOD single_sub_by_tag(STRING *flag) :no_wb {
PMC * const sub = Parrot_pf_single_sub_by_tag(INTERP, SELF, flag);
RETURN(PMC *sub);
}
METHOD all_subs() :no_wb {
PMC * const array = Parrot_pf_all_subs(INTERP, SELF);
RETURN(PMC *array);
}
METHOD first_sub_in_const_table() {
PMC * const sub = get_first_sub(INTERP, SELF);
RETURN(PMC *sub);
}
METHOD all_tags() :no_wb {
PMC * const array = Parrot_pf_all_tags_list(INTERP, SELF);
RETURN(PMC *array);
}
METHOD all_tagged_pmcs() :no_wb {
PMC * const hash = Parrot_pf_all_tagged_pmcs(INTERP, SELF);
RETURN(PMC *hash);
}
METHOD mark_initialized(STRING *tag) {
add_called_tag(INTERP, SELF, tag);
}
METHOD is_initialized(STRING *tag) :no_wb {
const INTVAL has_it = find_called_tag(INTERP, SELF, tag);
RETURN(INTVAL has_it);
}
/*
=item C<METHOD serialized_size()>
Return the size, in bytes, for how large this packfile will be if serialized.
=item C<METHOD serialize()>
Serialize the packfile into a STRING buffer
=item C<METHOD deserialize(STRING *pbc)>
Read a PackFile* in from a STRING buffer and set it as the current PackFile*
ptr in this PMC. Subject to the normal set_pointer restrictions.
=cut
*/
METHOD serialized_size() :no_wb {
INTVAL size;
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(SELF);
if (attrs->pf == NULL)
RETURN(INTVAL 0);
size = Parrot_pf_serialized_size(INTERP, attrs->pf);
RETURN(INTVAL size);
}
METHOD serialize() :no_wb {
STRING *str;
Parrot_PackfileView_attributes * const attrs =
PARROT_PACKFILEVIEW(SELF);
if (attrs->pf == NULL)
RETURN(STRING *STRINGNULL);
str = Parrot_pf_serialize(INTERP, attrs->pf);
RETURN(STRING *str);
}
METHOD deserialize(STRING *pbc) {
PackFile * const pf = Parrot_pf_deserialize(INTERP, pbc);
VTABLE_set_pointer(INTERP, SELF, pf);
}
/*
=item C<METHOD read_from_file(STRING *filename)>
Read a PackFile* from the given .pbc file and set it as the current PackFile*
pointer in this PMC. Subject to the same restrictions as set_pointer.
=item C<METHOD write_to_file(STRING *filename)>
Serialize the contents of the PackFile in this PMC and write them out to the
given .pbc bytecode file.
=cut
*/
METHOD read_from_file(STRING * filename) {
PackFile * const pf = Parrot_pf_read_pbc_file(INTERP, filename);
VTABLE_set_pointer(INTERP, SELF, pf);
pf->view = SELF;
VTABLE_set_string_native(INTERP, SELF, filename);
}
METHOD write_to_file(STRING *filename) :no_wb {
Parrot_pf_write_pbc_file(INTERP, SELF, filename);
}
/*
=item C<METHOD get_version()>
Return a stringified version number of the packfile
=cut
*/
METHOD get_version() :no_wb {
STRING * const version = Parrot_pf_get_version_string(INTERP, SELF);
RETURN(STRING * version);
}
}
/*
=item C<static PMC * get_first_sub(PARROT_INTERP, PMC *pfpmc)>
Returns the first Sub constant from the constant table.
=cut
*/
PARROT_CANNOT_RETURN_NULL
static PMC *
get_first_sub(PARROT_INTERP, ARGIN(PMC *pfpmc))
{
ASSERT_ARGS(get_first_sub)
PackFile * const pf = (PackFile*)VTABLE_get_pointer(interp, pfpmc);
if (!pf || !pf->cur_cs || !pf->cur_cs->const_table)
Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_UNEXPECTED_NULL,
"NULL or invalid packfile");
{
PackFile_ConstTable * const ct = pf->cur_cs->const_table;
INTVAL i;
STRING * const SUB = CONST_STRING(interp, "Sub");
for (i = 0; i < ct->pmc.const_count; ++i) {
PMC * const x = ct->pmc.constants[i];
if (VTABLE_isa(interp, x, SUB))
return x;
}
return PMCNULL;
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/
Jump to Line
Something went wrong with that request. Please try again.