How are shrouded files saved?
There are two things saved when binding or shrouding (binding is just adding the shrouded
code to the end of the executable): the symbol table, and the list of line numbers. The
symbol table (global sequence SymTab) holds all of the data and IL code. The line numbers
(global sequence slist) give information for error dumps. Normally, slist also holds the
actual text of each line, but this is currently not saved, unless the '-c' option is
used, and 'with trace' is turned on.
These are stored in a simple binary format to save space and time. The compress() and
decompress() routines from database.e have been adapted to save Euphoria objects. When the
required size of a data element is known in advance, only that many bytes are used. If the
size may grow (i.e., symbol table entries) beyond a fixed amount, then the compression
routines are used. Following is the structure of a shrouded .oe file (see sequencef.e
for the details on reading/writing):
- 4 bytes: magic number
- 1 byte: Shroud version
- 1 byte: full_debug
- 1 byte: eval in use (so need to rebuild the hash table, and need variable names)
- Compressed number of entries
- Each entry:
- 1 byte length of final sequence (corresponds to SIZEOF_XXX_ENTRY constants in global.e)
- If length > 0:
- Length = 5 (constant): compressed euphoria object
- Length > 5 (routine or variable)
- S_OBJ != NOVALUE: 1 & compressed euphoria object
- 1 byte: 0
- Compressed symtab_index of S_NEXT
- 1 byte: S_MODE
- 1 byte: S_SCOPE
- If length > SIZEOF_CONSTANT:
- 1 byte: S_FILE_NO
- If full_debug or use_eval: Compressed S_NAME
- Compressed S_TOKEN
- Compressed S_VTYPE
- If length > S_VTYPE
- Compressed S_CODE
- Compressed S_LINETAB
- Compressed S_FIRSTLINE
- Compressed S_TEMPS
- 1 byte: S_NUM_ARGS
- Compressed S_GOTO
- Compressed S_BYREF
- Compressed list of file names
- Compressed length of global sequence slist
- If full_debug = 1:
- For each element of slist)
- Compressed source line
- Compressed local line number
- Compressed file number
- If full_debug = 0:
- Compressed number of entries
- Each entry:
- Compressed {file number, until line}. This is used for trace backs so that
the correct line and file are identified. Can save up to 20% on the size of
the shrouded file size.
When bound, this code is tacked onto the end of the executable that was run. After this,
the absolute offset of the start of the bound code is written as a 4-byte integer, followed
by the text "oe bound executable". Upon startup, the executable is checked to look for this
string, and if found, the shrouded code is loaded.
Shrouded files are saved with an oe extension. The interpreter checks the extension upon
startup, and loads the shrouded code rather than trying to parse the file.
Before the shrouded code is saved, the interpreter attempts to remove as many unused constants,
routines and variables as possible. Since the symbol table contains 'pointers' to different
entries, these deleted symbols have to be maintained. The symbols are represented in the
shrouded symbol table as entries with a length of 0.