NAME
src/packfile.c - Parrot PackFile API
DESCRIPTION
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/pdds/pdd13_bytecode.pod for information about the structure of the frozen bytecode.
PackFile Manipulation Functions
void Parrot_trace_eprintf(const char *s, ...)
Print out an error message.
Passes arguments directly to void PackFile_destroy(PARROT_INTERP, PackFile *pf)
Deletes a static void make_code_pointers(PackFile_Segment *seg)
Makes compact/shorthand pointers.The first segments read are the default segments.
static int sub_pragma(PARROT_INTERP, pbc_action_enum_t action, const PMC *sub_pmc)
Checks sub_pmc's pragmas (e.g.
flags like static PMC* run_sub(PARROT_INTERP, PMC *sub_pmc)
Runs the sub_pmc due to its :load,
:immediate,
...
pragma
static PMC* do_1_sub_pragma(PARROT_INTERP, PMC *sub_pmc, pbc_action_enum_t action)
Runs autoloaded or immediate bytecode,
marking the MAIN subroutine entry.
static void mark_1_seg(PARROT_INTERP, PackFile_ConstTable *ct)
While the PMCs should be constant,
their possible contents such as properties aren't constructed const,
so we have to mark them.
static INTVAL find_const_iter(PARROT_INTERP, PackFile_Segment *seg, void *user_data)
Iterates over a PackFile_Directory,
marking any constant segments.
Internal use only.
void mark_const_subs(PARROT_INTERP)
Iterates over all directories and PackFile_Segments,
finding and marking any constant Subs.
void do_sub_pragmas(PARROT_INTERP, PackFile_ByteCode *self, pbc_action_enum_t action, PMC *eval_pmc)
opcode_t PackFile_unpack(PARROT_INTERP, PackFile *self, const opcode_t *packed, size_t packed_size)
Unpacks a INTVAL PackFile_map_segments(PARROT_INTERP, const PackFile_Directory *dir, PackFile_map_segments_func_t callback, void *user_data)
Calls the callback function void PackFile_add_segment(PARROT_INTERP, PackFile_Directory *dir, PackFile_Segment *seg)
Adds the Segment PackFile_Segment * PackFile_find_segment(PARROT_INTERP, PackFile_Directory *dir, const STRING *name, int sub_dir)
Finds the segment with the name PackFile_Segment * PackFile_remove_segment_by_name(PARROT_INTERP, PackFile_Directory *dir, STRING *name)
Finds, removes, and returns the segment with name
vfprintf
.
PackFile
.
:load
,
:main
,
etc.) returning 1 if the sub should be run for action
,
a pbc_action_enum_t
.
action
is one of PBC_PBC
,
PBC_LOADED
,
PBC_INIT
,
or PBC_MAIN
.
These determine which subs get executed at this point.
Some rules:
:immediate subs always execute immediately :postcomp subs always execute immediately :main subs execute when we have the PBC_MAIN or PBC_PBC actions :init subs execute when :main does :load subs execute on PBC_LOADAlso store the
eval_pmc
in the sub structure, so that the eval PMC is kept alive by living subs.
PackFile
from a block of memory, ensuring that the magic number is valid and that Parrot can read this bytecode version, Parrot, and performing any required endian and word size transforms.Returns size of unpacked opcodes if everything is okay, else zero (0).
callback
for each segment in the directory dir
called. The pointer user_data
is included in each call.If a callback returns non-zero, segment processing stops, returning this value.
seg
to the directory dir
. The PackFile becomes the owner of the segment; it gets destroyed when the PackFile does.
name
in the PackFile_Directory
if sub_dir
is true, searches directories recursively. The returned segment is still owned by the PackFile
.
name
in the PackFile_Directory
. The caller is responsible for destroying the segment.PackFile Structure Functions
static void PackFile_set_header(PackFile_Header *header)
Fills a PackFile * PackFile_new(PARROT_INTERP, INTVAL is_mapped)
Allocates a new empty PackFile * PackFile_new_dummy(PARROT_INTERP, STRING *name)
Creates a new (initial) dummy PackFile. This is necessary if the interpreter doesn't load any bytecode but instead uses void PackFile_funcs_register(PARROT_INTERP, PackFile *pf, UINTVAL type, const PackFile_funcs funcs)
Registers the static const opcode_t * default_unpack(PARROT_INTERP, PackFile_Segment *self, const opcode_t *cursor)
Unpacks a PackFile given a cursor into PBC. This is the default unpack.
void default_dump_header(PARROT_INTERP, const PackFile_Segment *self)
Dumps the header of a given PackFile_Segment.
static void default_dump(PARROT_INTERP, const PackFile_Segment *self)
Dumps a PackFile_Segment.
static void pf_register_standard_funcs(PARROT_INTERP, PackFile *pf)
Registers a PackFile's functions; called from within PackFile_Segment * PackFile_Segment_new_seg(PARROT_INTERP, PackFile_Directory *dir, UINTVAL type, STRING *name, int add)
Creates a new segment in the given PackFile_Directory of the given static PackFile_Segment * create_seg(PARROT_INTERP, PackFile_Directory *dir, pack_file_types t, STRING *name, STRING *file_name, int add)
Creates a new PackFile_Segment for the given PackFile_ByteCode * PF_create_default_segs(PARROT_INTERP, STRING *file_name, int add)
Creates the bytecode, constant, and fixup segments for void PackFile_Segment_destroy(PARROT_INTERP, PackFile_Segment *self)
Destroys the given PackFile_Segment.
size_t PackFile_Segment_packed_size(PARROT_INTERP, PackFile_Segment *self)
Returns the size of the given segment, when packed, taking into account padding and alignment.
opcode_t * PackFile_Segment_pack(PARROT_INTERP, PackFile_Segment *self, opcode_t *cursor)
Packs a PackFile_Segment, returning a cursor to the start of the results.
const opcode_t * PackFile_Segment_unpack(PARROT_INTERP, PackFile_Segment *self, const opcode_t *cursor)
Unpacks a PackFile_Segment, returning a cursor to the results on success and NULL otherwise.All all these functions call the related void PackFile_Segment_dump(PARROT_INTERP, PackFile_Segment *self)
Dumps the segment
PackFile
header with system specific data.
PackFile
and sets up 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
Parrot_compile_string
.
pack
/unpack
/... functions for a packfile type.
PackFile_new()
.
type
with the given name
. If add
is true, adds the segment to the directory.
file_name
. See PackFile_Segment_new_seg()
for the other arguments.
file_name
. If add
is true, the current packfile becomes the owner of these segments by adding the segments to the directory.
default_*
function.If a special is defined this gets called after.
self
.Standard Directory Functions
static PackFile_Segment * directory_new(PARROT_INTERP, PackFile *pf, STRING *name, int add)
Returns a new static void directory_dump(PARROT_INTERP, const PackFile_Segment *self)
Dumps the directory static const opcode_t * directory_unpack(PARROT_INTERP, PackFile_Segment *segp, const opcode_t *cursor)
Unpacks the directory from the provided cursor.
static void directory_destroy(PARROT_INTERP, PackFile_Segment *self)
Destroys the directory.
static void sort_segs(PackFile_Directory *dir)
Sorts the segments in static size_t directory_packed_size(PARROT_INTERP, PackFile_Segment *self)
Returns the size of the directory minus the value returned by static opcode_t * directory_pack(PARROT_INTERP, PackFile_Segment *self, opcode_t *cursor)
Packs the directory
PackFile_Directory
cast as a PackFile_Segment
.
self
.
dir
.
default_packed_size()
.
self
, using the given cursor.PackFile_Segment
Functions
static void segment_init(PARROT_INTERP, PackFile_Segment *self, PackFile *pf, STRING *name)
Initializes the segment PackFile_Segment * PackFile_Segment_new(PARROT_INTERP, PackFile *pf, STRING *name, int add)
Creates a new default section.
self
with the provided PackFile and the given name. Note that this duplicates the given name.
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(PARROT_INTERP, PackFile_Segment *self)
The default destroy function. Destroys a PackFile_Segment.
static size_t default_packed_size(const PackFile_Segment *self)
Returns the default size of the segment static opcode_t * default_pack(const PackFile_Segment *self, opcode_t *dest)
Performs the default pack.
self
.
ByteCode
static void byte_code_destroy(PARROT_INTERP, PackFile_Segment *self)
Destroys the static PackFile_Segment * byte_code_new(PARROT_INTERP, PackFile *pf, STRING *name, int add)
Creates a new
PackFile_ByteCode
segment self
.
PackFile_ByteCode
segment. Ignores pf
, name
, and add
.Debug Info
static void pf_debug_destroy(PARROT_INTERP, PackFile_Segment *self)
Destroys the static PackFile_Segment * pf_debug_new(PARROT_INTERP, PackFile *pf, STRING *name, int add)
Creates and returns a new static size_t pf_debug_packed_size(PARROT_INTERP, PackFile_Segment *self)
Returns the size of the static opcode_t * pf_debug_pack(PARROT_INTERP, PackFile_Segment *self, opcode_t *cursor)
Packs the debug segment, using the given cursor.
static const opcode_t * pf_debug_unpack(PARROT_INTERP, PackFile_Segment *self, const opcode_t *cursor)
Unpacks a debug segment into a PackFile_Debug structure, given the cursor.
static void pf_debug_dump(PARROT_INTERP, const PackFile_Segment *self)
Dumps a debug segment to a human readable form.
PackFile_Debug * Parrot_new_debug_seg(PARROT_INTERP, PackFile_ByteCode *cs, size_t size)
Creates and appends (or resizes) a new debug seg for a code segment. Uses the given size as its size.
void Parrot_debug_add_mapping(PARROT_INTERP, PackFile_Debug *debug, opcode_t offset, const char *filename)
Adds a bytecode offset to a filename mapping for a PackFile_Debug.
STRING * Parrot_debug_pc_to_filename(PARROT_INTERP, const PackFile_Debug *debug, opcode_t pc)
Returns the filename of the source for the given position in the bytecode.
void Parrot_switch_to_cs_by_nr(PARROT_INTERP, opcode_t seg)
Switches the current bytecode segment to the segment keyed by number PackFile_ByteCode * Parrot_switch_to_cs(PARROT_INTERP, PackFile_ByteCode *new_cs, int really)
Switches to a bytecode segment static PackFile_Constant * clone_constant(PARROT_INTERP, PackFile_Constant *old_const)
Clones a constant (at least, if it's a Sub PMC), returning the clone.
static PackFile_Constant ** find_constants(PARROT_INTERP, PackFile_ConstTable *ct)
Finds the constant table associated with a thread. For now, we need to copy constant tables because some entries aren't really constant; e.g. subroutines need to refer to namespace pointers.
void Parrot_destroy_constants(PARROT_INTERP)
Destroys the constants for an interpreter.
PackFile_Debug
segment self
.
PackFile_Debug
segment. Ignores pf
, name
, and add
ignored.
PackFile_Debug
segment's filename in opcode_t
units.
seg
.
new_cs
, returning the old segment.
PackFile FixupTable Structure Functions
void PackFile_FixupTable_clear(PARROT_INTERP, PackFile_FixupTable *self)
Clears a PackFile FixupTable.
static void fixup_destroy(PARROT_INTERP, PackFile_Segment *self)
Calls static size_t fixup_packed_size(PARROT_INTERP, PackFile_Segment *self)
What does this do?
static opcode_t * fixup_pack(PARROT_INTERP, PackFile_Segment *self, opcode_t *cursor)
Packs the fixup table for a given packfile.
static PackFile_Segment * fixup_new(PARROT_INTERP, PackFile *pf, STRING *name, int add)
Returns a new static const opcode_t * fixup_unpack(PARROT_INTERP, PackFile_Segment *seg, const opcode_t *cursor)
Unpacks a PackFile FixupTable from a block of memory, given a cursor.Returns one (1) if everything is okay, else zero (0).
void PackFile_FixupTable_new_entry(PARROT_INTERP, const char *label, INTVAL type, opcode_t offs)
Adds a new fix-up entry with label and type. Creates a new PackFile FixupTable if none is present.
static PackFile_FixupEntry * find_fixup(PackFile_FixupTable *ft, INTVAL type, const char *name)
Finds the fix-up entry in a given FixupTable static INTVAL find_fixup_iter(PARROT_INTERP, PackFile_Segment *seg, void *user_data)
Internal iterator for PackFile_FixupEntry * PackFile_find_fixup_entry(PARROT_INTERP, INTVAL type, char *name)
Searches the whole PackFile recursively for a fix-up entry with the given
PackFile_FixupTable_clear()
with self
.
PackFile_FixupTable
segment.
ft
for type
and name
and returns it.This ignores directories. For a recursive version see PackFile_find_fixup_entry()
.
PackFile_find_fixup_entry
; recurses into directories.
type
and name
, and returns the found entry or NULL.This also recurses into directories, compared to the simplier find_fixup
which just searches one PackFile_FixupTable.PackFile ConstTable Structure Functions
void PackFile_ConstTable_clear(PARROT_INTERP, PackFile_ConstTable *self)
Clear the const opcode_t * PackFile_ConstTable_unpack(PARROT_INTERP, PackFile_Segment *seg, const opcode_t *cursor)
Unpacks a PackFile ConstTable from a block of memory. The format is:
static PackFile_Segment * const_new(PARROT_INTERP, PackFile *pf, STRING *name, int add)
Returns a new static void const_destroy(PARROT_INTERP, PackFile_Segment *self)
Destroys the
PackFile_ConstTable
self
.
opcode_t const_count * constantsReturns cursor if everything is OK, else zero (0).
PackFile_ConstTable
segment.
PackFile_ConstTable
self
.PackFile Constant Structure Functions
PackFile_Constant * PackFile_Constant_new(PARROT_INTERP)
Allocates 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(PARROT_INTERP, PackFile_Constant *self)
Deletes the size_t PackFile_Constant_pack_size(PARROT_INTERP, const PackFile_Constant *self, const PackFile_ConstTable *ct)
Determines the size of the buffer needed in order to pack the PackFile Constant into a contiguous region of memory.
const opcode_t * PackFile_Constant_unpack(PARROT_INTERP, PackFile_ConstTable *constt, PackFile_Constant *self, const opcode_t *cursor)
Unpacks a PackFile Constant from a block of memory. The format is:
const opcode_t * PackFile_Constant_unpack_pmc(PARROT_INTERP, PackFile_ConstTable *constt, PackFile_Constant *self, const opcode_t *cursor)
Unpacks a constant PMC.
const opcode_t * PackFile_Constant_unpack_key(PARROT_INTERP, PackFile_ConstTable *constt, PackFile_Constant *self, const opcode_t *cursor)
Unpacks a PackFile Constant from a block of memory. The format consists of a sequence of key atoms, each with the following format:
PackFile_Segment * PackFile_Annotations_new(PARROT_INTERP, struct PackFile *pf, STRING *name, int add)
Creates a new annotations segment structure. Ignores the parameters void PackFile_Annotations_destroy(PARROT_INTERP, PackFile_Segment *seg)
Frees all memory associated with an annotations segment.
size_t PackFile_Annotations_packed_size(PARROT_INTERP, PackFile_Segment *seg)
Computes the number of opcode_ts needed to store the passed annotations segment.
opcode_t * PackFile_Annotations_pack(PARROT_INTERP, PackFile_Segment *seg, opcode_t *cursor)
Packs this segment into bytecode.
const opcode_t * PackFile_Annotations_unpack(PARROT_INTERP, PackFile_Segment *seg, const opcode_t *cursor)
Unpacks this segment from the bytecode.
void PackFile_Annotations_dump(PARROT_INTERP, const PackFile_Segment *seg)
Produces a dump of the annotations segment.
void PackFile_Annotations_add_group(PARROT_INTERP, PackFile_Annotations *self, opcode_t offset)
Starts a new bytecode annotation group. Takes the offset in the bytecode where the new annotations group starts.
void PackFile_Annotations_add_entry(PARROT_INTERP, PackFile_Annotations *self, opcode_t offset, opcode_t key, opcode_t type, opcode_t value)
Adds a new bytecode annotation entry. Takes the annotations segment to add the entry to, the current bytecode offset (assumed to be the greatest one so far in the currently active group), the annotation key (as an index into the constats table), the annotation value type (one of PF_ANNOTATION_KEY_TYPE_INT, PF_ANNOTATION_KEY_TYPE_STR or PF_ANNOTATION_KEY_TYPE_NUM) and the value. The value will be an integer literal in the case of type being PF_ANNOTATION_KEY_TYPE_INT, or an index into the constants table otherwise.
static PMC * make_annotation_value_pmc(PARROT_INTERP, PackFile_Annotations *self, INTVAL type, opcode_t value)
Makes a PMC of the right type holding the value. Helper for PMC * PackFile_Annotations_lookup(PARROT_INTERP, PackFile_Annotations *self, opcode_t offset, STRING *key)
Looks up the annotation(s) in force at the given bytecode offset. If just one particular annotation is required, it can be passed as key, and the value will be returned (or a NULL PMC if no annotation of that name is in force). Otherwise, a Hash will be returned of the all annotations. If there are none in force, an empty hash will be returned.
static void compile_or_load_file(PARROT_INTERP, STRING *path, enum_runtime_ft file_type)
Either load a bytecode file and append it to the current packfile directory, or compile a PIR or PASM file from source.
void Parrot_load_language(PARROT_INTERP, STRING *lang_name)
Load the compiler libraries for a given high-level language into the interpreter.
static PackFile * PackFile_append_pbc(PARROT_INTERP, const char *filename)
Reads and appends a PBC it to the current directory. Fixes up sub addresses in newly loaded bytecode and runs void Parrot_load_bytecode(PARROT_INTERP, Parrot_String file_str)
Load a bytecode, PIR, or PASM file into the interpreter.
void PackFile_fixup_subs(PARROT_INTERP, pbc_action_enum_t what, PMC *eval)
Calls
PackFile_Constant
self
.Don't delete PMC
s or STRING
s. The GC will claim them.
opcode_t type * dataReturns cursor if everything is okay, else NULL.
opcode_t type opcode_t valueReturns cursor if everything is OK, else NULL.
name
and add
.
PackFile_Annotations_lookup()
.
:load
subs.
:load
, :init
, :main
, :immediate
and/or :postcomp
subroutines in the current packfile, depending on the value of action
. See do_sub_pragmas
for more details.HISTORY
Parrot_readbc and Parrot_loadbc renamed. Trace macros, long double and 64-bit conversion work by Reini Urban 2009.
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