NAME ^

src/packfile.c - Parrot PackFile API

DESCRIPTION ^

PackFile Manipulation Functions ^

This file contains all the functions required for the processing of the structure of a PackFile. It is not intended to understand the byte code stream itself, but merely to dissect and reconstruct data from the various segments. See docs/parrotbyte.pod for information about the structure of the frozen bytecode.

void PackFile_destroy(struct PackFile *pf)

Delete a PackFile.

static INTVAL PackFile_check_segment_size(opcode_t segment_size, const char *debug)

Internal function to check segment_size % sizeof(opcode_t).

static void make_code_pointers(struct PackFile_Segment *seg)

Make compat/shorthand pointers.

The first segments read are the default segments.

static int sub_pragma(Parrot_Interp interpreter, int action, PMC *sub_pmc)

Handle :load, :main ... pragmas for sub_pmc

static PMC *run_sub(Parrot_Interp interpreter, PMC *sub_pmc)

Run the sub_pmc due its :load, :immediate, ... pragma

<static PMC* do_1_sub_pragma(Parrot_Interp interpreter, struct PackFile *self, int action)>

Run autoloaded or immediate bytecode, mark MAIN subroutine entry

static void do_sub_pragmas(Interp *interpreter, struct PackFile_Bytecode *self, int action, PMC *eval_pmc)

action is one of PBC_PBC, PBC_LOADED, or PBC_MAIN. Also store the eval_pmc in the sub structure, so that the eval PMC is kept alive be living subs.

opcode_t PackFile_unpack(Interp *interpreter, struct PackFile *self, opcode_t *packed, size_t packed_size)

Unpack a PackFile from a block of memory. The format is:

  byte     wordsize
  byte     byteorder
  byte     major
  byte     minor
  byte     intvalsize
  byte     floattype
  byte     pad[10] = fingerprint

  opcode_t magic
  opcode_t language type

  opcode_t dir_format
  opcode_t padding

  directory segment
    * segment
    ...
All segments have this common header:

  - op_count    ... total segment size incl. this count
  - itype       ... internal type of data
  - id          ... id of data e.g. byte code nr.
  - size        ... size of data oparray
  - data[size]  ... data array e.g. bytecode
  segment specific data follows here ...
Checks to see if the magic matches the Parrot magic number for Parrot PackFiles.

Returns size of unpacked if everything is OK, else zero (0).

INTVAL PackFile_map_segments (Interp*, struct PackFile_Directory *dir, PackFile_map_segments_func_t callback, void *user_data)

For each segment in the directory dir the callback function callback is called. The pointer user_data is append to each call.

If a callback returns non-zero the processing of segments is stopped, and this value is returned.

INTVAL PackFile_add_segment (struct PackFile_Directory *dir, struct PackFile_Segment *seg)

Adds the Segment seg to the directory dir The PackFile becomes the owner of the segment; that means its getting destroyed, when the packfile gets destroyed.

struct PackFile_Segment *PackFile_find_segment (Interp *, struct PackFile_Directory *dir, const char *name, int sub_dir)

Finds the segment with the name name in the PackFile_Directory if sub_dir is true, directories are searched recursively The segment is returned, but its still owned by the PackFile.

struct PackFile_Segment *PackFile_remove_segment_by_name (Interp *, struct PackFile_Directory *dir, const char *name)

Finds and removes the segment with name name in the PackFile_Directory. The segment is returned and must be destroyed by the user.

PackFile Structure Functions ^

static void PackFile_set_header(struct PackFile *self)

Fill a PackFile header with system specific data.

struct PackFile *PackFile_new(Interp*, INTVAL is_mapped)

Allocate a new empty PackFile and setup the directory.

Directory segment:

  +----------+----------+----------+----------+
  |    Segment Header                         |
  |    ..............                         |
  +----------+----------+----------+----------+

  +----------+----------+----------+----------+
  |    number of directory items              |
  +----------+----------+----------+----------+
followed by a sequence of items

  +----------+----------+----------+----------+
  |    Segment type                           |
  +----------+----------+----------+----------+
  |    "name"                                 |
  |    ...     '\0'       padding bytes       |
  +----------+----------+----------+----------+
  |    Offset in the file                     |
  +----------+----------+----------+----------+
  |    Size of the segment                    |
  +----------+----------+----------+----------+
"name" is a NUL-terminated c-string encoded in plain ASCII.

Segment types are defined in include/parrot/packfile.h.

Offset and size are in opcode_t.

A Segment Header has these entries:

 - op_count     total ops of segment incl. this count
 - itype        internal type of segment
 - id           internal id e.g code seg nr
 - size         size of following op array, 0 if none
 * data         possibly empty data, or e.g. byte code
INTVAL PackFile_funcs_register(Interp*, struct PackFile *pf, UINTVAL type, struct PackFile_funcs funcs)

Register the pack/unpack/... functions for a packfile type.

static opcode_t *default_unpack (Interp *interpreter, struct PackFile_Segment *self, opcode_t *cursor)

The default unpack function.

void default_dump_header (Parrot_Interp interpreter, struct PackFile_Segment *self)

The default dump header function.

static void default_dump (Parrot_Interp interpreter, struct PackFile_Segment *self)

The default dump function.

static INTVAL pf_register_standard_funcs(Interp*, struct PackFile *pf)

Called from within PackFile_new() register the standard functions.

struct PackFile_Segment *PackFile_Segment_new_seg(Interp*, struct PackFile_Directory *dir, UINTVAL type, const char *name, int add)

Create a new segment.

struct PackFile_ByteCode *PF_create_default_segs(Interp*, const char *file_name, int add)

Create bytecode, constant, and fixup segment for file_nam. If add is true, the current packfile becomes the owner of these segments by adding the segments to the directory.

void PackFile_Segment_destroy(Interp *, struct PackFile_Segment *self)

size_t PackFile_Segment_packed_size(Interp*, struct PackFile_Segment *self)

opcode_t *PackFile_Segment_pack(Interp*, struct PackFile_Segment *self, opcode_t *cursor)

opcode_t *PackFile_Segment_unpack(Interp *interpreter, struct PackFile_Segment *self, opcode_t *cursor)

All all these functions call the related default_* function.

If a special is defined this gets called after.

void PackFile_Segment_dump(Interp *interpreter, struct PackFile_Segment *self)

Dumps the segment self.

Standard Directory Functions ^

static struct PackFile_Segment *directory_new(Interp*, struct PackFile *pf, const char *name, int add)

Returns a new PackFile_Directory cast as a PackFile_Segment.

static void directory_dump(Interp *interpreter, struct PackFile_Segment *self)

Dumps the directory self.

static opcode_t *directory_unpack(Interp *interpreter, struct PackFile_Segment *segp, opcode_t *cursor)

Unpacks the directory.

static void directory_destroy(Interp*, struct PackFile_Segment *self)

Destroys the directory.

static void sort_segs(Interp*, struct PackFile_Directory *dir)

Sorts the segments in dir.

static size_t directory_packed_size(Interp*, struct PackFile_Segment *self)

Returns the size of the directory minus the value returned by default_packed_size().

static opcode_t *directory_pack(Interp*, struct PackFile_Segment *self, opcode_t *cursor)

Packs the directory self.

PackFile_Segment Functions ^

static void segment_init(Interp*, struct PackFile_Segment *self, struct PackFile *pf, const char *name)

Initializes the segment self.

struct PackFile_Segment *PackFile_Segment_new(Interp*, struct PackFile *pf, const char *name, int add)

Create a new default section.

Default Function Implementations ^

The default functions are called before the segment specific functions and can read a block of opcode_t data.

static void default_destroy(Interp*, struct PackFile_Segment *self)

The default destroy function.

static size_t default_packed_size(Interp*, struct PackFile_Segment *self)

Returns the default size of the segment self.

static opcode_t *default_pack(Interp*, struct PackFile_Segment *self, opcode_t *dest)

Performs the default pack.

ByteCode ^

static void byte_code_destroy(Interp*, struct PackFile_Segment *self)

Destroys the PackFile_ByteCode segment self.

static struct PackFile_Segment *byte_code_new(Interp*, struct PackFile *pf, const char *name, int add)

New PackFile_ByteCode segment.

add is ignored.

Debug Info ^

static void pf_debug_destroy (Interp*, struct PackFile_Segment *self)

Destroys the PackFile_Debug segment self.

static struct PackFile_Segment *pf_debug_new (Interp*, struct PackFile *pf, const char *name, int add)

Returns a new PackFile_Debug segment.

add is ignored.

static size_t pf_debug_packed_size (Interp*, struct PackFile_Segment *self)

Returns the size of the PackFile_Debug segment's filename in opcode_t units.

static opcode_t *pf_debug_pack(Interp*, struct PackFile_Segment *self, opcode_t *cursor)

Pack the debug segment.

static opcode_t *pf_debug_unpack(Interp *interpreter, struct PackFile_Segment *self, opcode_t *cursor)

Unpack a debug segment into a PackFile_Debug structure.

static void pf_debug_dump (Interp *interpreter, struct PackFile_Segment *self)

Dumps a debug segment to a human readable form.

struct PackFile_Debug *Parrot_new_debug_seg(Interp *interpreter, struct PackFile_ByteCode *cs, size_t size)

Create and append (or resize) a new debug seg for a code segment.

c<void Parrot_debug_add_mapping(Interp *interpreter, struct PackFile_Debug *debug, opcode_t offset, int mapping_type, const char *filename, int source_seg)>

Add a bytecode offset to filename/source segment mapping. mapping_type may be one of PF_DEBUGMAPPINGTYPE_NONE (in which case the last two parameters are ignored), PF_DEBUGMAPPINGTYPE_FILENAME (in which case filename must be given) or PF_DEBUGMAPPINGTYPE_SOURCESEG (in which case source_seg should contains the number of the source segment in question).

STRING *Parrot_debug_pc_to_filename(Interp *interpreter, struct PackFile_Debug *debug, opcode_t pc)

Take a position in the bytecode and return the filename of the source for that position.

void Parrot_switch_to_cs_by_nr(Interp *interpreter, opcode_t seg)

Switch to byte code segment number seg.

struct PackFile_ByteCode *Parrot_switch_to_cs(Interp *interpreter, struct PackFile_ByteCode *new_cs, int really)

Switch to a byte code segment new_cs, returning the old segment.

void Parrot_pop_cs(Interp *interpreter)

Remove current byte code segment from directory and switch to previous.

PackFile FixupTable Structure Functions ^

void PackFile_FixupTable_clear(Interp *, struct PackFile_FixupTable *self)

Clear a PackFile FixupTable.

static void fixup_destroy (Interp*, struct PackFile_Segment *self)

Just calls PackFile_FixupTable_clear() with self.

static size_t fixup_packed_size(Interp*, struct PackFile_Segment *self)

What does this do?

static opcode_t *fixup_pack (Interp*, struct PackFile_Segment *self, opcode_t *cursor)

What does this do?

static struct PackFile_Segment *fixup_new(Interp*, struct PackFile *pf, const char *name, int add)

Returns a new PackFile_FixupTable segment.

static opcode_t *fixup_unpack(Interp *interpreter, struct PackFile_Segment *seg, opcode_t *cursor)

Unpack a PackFile FixupTable from a block of memory.

Returns one (1) if everything is OK, else zero (0).

void PackFile_FixupTable_new_entry(Interp *interpreter, char *label, enum_fixup_t type, opcode_t offs)

What does this do?

static struct PackFile_FixupEntry *find_fixup(struct PackFile_FixupTable *ft, enum_fixup_t type, const char *name)

Finds the fix-up entry for name and returns it.

static INTVAL find_fixup_iter(Interp*, struct PackFile_Segment *seg, void *user_data)

What does this do?

struct PackFile_FixupEntry *PackFile_find_fixup_entry(Interp *interpreter, enum_fixup_t type, char *name)

What does this do?

PackFile ConstTable Structure Functions ^

void PackFile_ConstTable_clear(Interp*, struct PackFile_ConstTable *self)

Clear the PackFile_ConstTable self.

opcode_t *PackFile_ConstTable_unpack(Interp *interpreter, struct PackFile_Segment *seg, opcode_t *cursor)

Unpack a PackFile ConstTable from a block of memory. The format is:

  opcode_t const_count
  *  constants
Returns cursor if everything is OK, else zero (0).

static struct PackFile_Segment *const_new(Interp*, struct PackFile *pf, const char *name, int add)

Returns a new PackFile_ConstTable segment.

static void const_destroy(Interp*, struct PackFile_Segment *self)

Destroys the PackFile_ConstTable self.

PackFile Constant Structure Functions ^

struct PackFile_Constant *PackFile_Constant_new(Interp*)

Allocate a new empty PackFile Constant.

This is only here so we can make a new one and then do an unpack.

void PackFile_Constant_destroy(Interp*, struct PackFile_Constant *self)

Delete the PackFile_Constant self.

Don't delete PMCs or STRINGs, they are destroyed via DOD/GC.

size_t PackFile_Constant_pack_size(Interp*, struct PackFile_Constant *self)

Determine the size of the buffer needed in order to pack the PackFile Constant into a contiguous region of memory.

opcode_t *PackFile_Constant_unpack(Interp *interpreter, struct PackFile_ConstTable *constt, struct PackFile_Constant *self, opcode_t *cursor)

Unpack a PackFile Constant from a block of memory. The format is:

  opcode_t type
  *  data
Returns cursor if everything is OK, else zero (0).

opcode_t *PackFile_Constant_unpack_pmc(Interp *interpreter, struct PackFile_ConstTable *constt, struct PackFile_Constant *self, opcode_t *cursor)

Unpack a constant PMC.

opcode_t *PackFile_Constant_unpack_key(Interp *interpreter, struct PackFile_ConstTable *constt, struct PackFile_Constant *self, opcode_t *cursor)

Unpack a PackFile Constant from a block of memory. The format consists of a sequence of key atoms, each with the following format:

  opcode_t type
  opcode_t value
Returns cursor if everything is OK, else zero (0).

static struct PackFile *PackFile_append_pbc(Interp *interpreter, const char *filename)

Read a PBC and append it to the current directory Fixup sub addresses in newly loaded bytecode and run :load subs.

void Parrot_load_bytecode(Interp *interpreter, STRING *filename)

Load and append a bytecode, IMC or PASM file into interpreter.

Load some bytecode (PASM, PIR, PBC ...) and append it to the current directory.

void PackFile_fixup_subs(Interp *interpreter, pbc_action_enum_t, PMC *eval)

Run :load or :immediate subroutines for the current code segment. If eval is given, set this is the owner of the subroutines.

HISTORY ^

Rework by Melvin; new bytecode format, make bytecode portable. (Do endian conversion and wordsize transforms on the fly.)

leo applied and modified Juergen Boemmels packfile patch giving an extensible packfile format with directory reworked again, with common chunks (default_*).

2003.11.21 leo: moved low level item fetch routines to new pf/pf_items.c


parrot