## freezefile-g.pkg -- Loading, saving and managing freezefiles.
# Compiled by:
#
src/app/makelib/makelib.sublib# See overview comments in
#
#
src/app/makelib/freezefile/freezefile.api#
src/lib/compiler/src/library/unpickler.pkg#
#
# FILE FORMAT
#
# The format of a foo.lib.frozen file ("freezefile") is as follows:
#
# - s: The size s of the pickled dependency graph.
# This size is itself written as a four-byte string.
#
# - t: The size of the pickled dictionary for the entire
# library (using the pickleEnvN interface of the pickler)
# in the same format as s.
#
# - The pickled dependency graph. This graph contains
# integer offsets of the .compiled files for the individual
# sourcefile members. These offsets need to be adjusted
# by adding s + t + 8. The pickled dependency graph also
# contains integer offsets relative to other freezefiles.
# These offsets need no further adjustment.
#
# - Individual .compiled file contents (concatenated) but without
# their symbol tables. The format of .compiled files is described in:
#
#
src/lib/compiler/execution/compiledfile/compiledfile.pkg#
#
#
# GENERIC INVOCATION CONTEXT
#
# Our freezefile_g generic is invoked once each
# by the standard and bootstrap compilers:
#
#
src/app/makelib/main/makelib-g.pkg#
src/app/makelib/mythryl-compiler-compiler/mythryl-compiler-compiler-g.pkg#
#
#
# RUNTIME INVOCATION CONTEXT
#
#
# Our most typical call is from the local freeze() in
#
#
src/app/makelib/parse/libfile-parser-g.pkg### "If you have a garden and a library,
### you have everything you need."
###
### -- Marcus Tullius Cicero
stipulate
package ad = anchor_dictionary; # anchor_dictionary is from
src/app/makelib/paths/anchor-dictionary.pkg package bio = data_file__premicrothread; # data_file__premicrothread is from
src/lib/std/src/posix/data-file--premicrothread.pkg package cf = compiledfile; # compiledfile is from
src/lib/compiler/execution/compiledfile/compiledfile.pkg package err = error_message; # error_message is from
src/lib/compiler/front/basics/errormsg/error-message.pkg package fil = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.pkg package fp = filename_policy; # filename_policy is from
src/app/makelib/main/filename-policy.pkg package flt = frozenlib_tome; # frozenlib_tome is from
src/app/makelib/freezefile/frozenlib-tome.pkg package ftm = frozenlib_tome_map; # frozenlib_tome_map is from
src/app/makelib/freezefile/frozenlib-tome-map.pkg package lg = inter_library_dependency_graph; # inter_library_dependency_graph is from
src/app/makelib/depend/inter-library-dependency-graph.pkg package lms = list_mergesort; # list_mergesort is from
src/lib/src/list-mergesort.pkg package lgr = logger; # logger is from
src/lib/src/lib/thread-kit/src/lib/logger.pkg package mcv = mythryl_compiler_version; # mythryl_compiler_version is from
src/lib/core/internal/mythryl-compiler-version.pkg package ms = makelib_state; # makelib_state is from
src/app/makelib/main/makelib-state.pkg package mvi = makelib_version_intlist; # makelib_version_intlist is from
src/app/makelib/stuff/makelib-version-intlist.pkg package ph = picklehash; # picklehash is from
src/lib/compiler/front/basics/map/picklehash.pkg package pkj = pickler_junk; # pickler_junk is from
src/lib/compiler/front/semantic/pickle/pickler-junk.pkg package pp = standard_prettyprinter; # standard_prettyprinter is from
src/lib/prettyprint/big/src/standard-prettyprinter.pkg package psp = symbol_and_picklehash_pickling; # symbol_and_picklehash_pickling is from
src/lib/compiler/front/semantic/pickle/symbol-and-picklehash-pickling.pkg package pkr = pickler; # pickler is from
src/lib/compiler/src/library/pickler.pkg package s2m = collect_all_modtrees_in_symbolmapstack; # collect_all_modtrees_in_symbolmapstack is from
src/lib/compiler/front/typer-stuff/symbolmapstack/collect-all-modtrees-in-symbolmapstack.pkg package sa = supported_architectures; # supported_architectures is from
src/lib/compiler/front/basics/main/supported-architectures.pkg package sg = intra_library_dependency_graph; # intra_library_dependency_graph is from
src/app/makelib/depend/intra-library-dependency-graph.pkg package shm = sharing_mode; # sharing_mode is from
src/app/makelib/stuff/sharing-mode.pkg package sm = line_number_db; # line_number_db is from
src/lib/compiler/front/basics/source/line-number-db.pkg package sts = string_set; # string_set is from
src/lib/src/string-set.pkg package stx = stampmapstack; # stampmapstack is from
src/lib/compiler/front/typer-stuff/modules/stampmapstack.pkg package sy = symbol; # symbol is from
src/lib/compiler/front/basics/map/symbol.pkg package sym = symbol_map; # symbol_map is from
src/app/makelib/stuff/symbol-map.pkg package sys = symbol_set; # symbol_set is from
src/app/makelib/stuff/symbol-set.pkg package syx = symbolmapstack; # symbolmapstack is from
src/lib/compiler/front/typer-stuff/symbolmapstack/symbolmapstack.pkg package tag = pickler_sumtype_tags; # pickler_sumtype_tags is from
src/lib/compiler/src/library/pickler-sumtype-tags.pkg package tlt = thawedlib_tome; # thawedlib_tome is from
src/app/makelib/compilable/thawedlib-tome.pkg package tst = tome_symbolmapstack; # tome_symbolmapstack is from
src/app/makelib/depend/tome-symbolmapstack.pkg package ttm = thawedlib_tome_map; # thawedlib_tome_map is from
src/app/makelib/compilable/thawedlib-tome-map.pkg package tts = thawedlib_tome_set; # thawedlib_tome_set is from
src/app/makelib/compilable/thawedlib-tome-set.pkg package upj = unpickler_junk; # unpickler_junk is from
src/lib/compiler/front/semantic/pickle/unpickler-junk.pkg package upr = unpickler; # unpickler is from
src/lib/compiler/src/library/unpickler.pkg package ssm # "ssm" ==e "symbol set map"
=
map_g (
package {
Key = sys::Set;
compare = sys::compare;
}
);
Pp = pp::Pp;
# Logging support. To log messages from this file scatter
#
# to_log {. sprintf "Whatever"; }; # Do not add trailing newline to message string.
#
# calls through the code as appropriate and then either
# uncomment the below
#
# my _ = lgr::enable freezefile_logging;
#
# line or do
#
# logger::enable (the (logger::find_logtree_node_by_name "freezelog::logging"));
#
# from the Mythryl interactive prompt.
#
freezefile_logging
=
lgr::make_logtree_leaf
{ parent => fil::all_logging,
name => "freezelog::logging",
default => FALSE # Change to true or call (lgr::enable freezefile_logging) to enable logging in this file.
};
#
to_log = lgr::log_if freezefile_logging 0;
herein
# This generic is invoked from:
#
#
src/app/makelib/main/makelib-g.pkg #
src/app/makelib/mythryl-compiler-compiler/mythryl-compiler-compiler-g.pkg #
generic package freezefile_g (
#
architecture: sa::Supported_Architectures; # PWRPC32/SPARC32/INTEL32. Used (only) as arg to cf::write_compiledfile, where it ultimately prevents mixing code for different architectures during linking.
#
package ffr: Freezefile_Roster; # Freezefile_Roster is from
src/app/makelib/freezefile/freezefile-roster-g.pkg # freezefile_roster_g is from
src/app/makelib/freezefile/freezefile-roster-g.pkg # # "ffr" == "freezefile_roster".
#
compile_library # fun recompile from either
src/app/makelib/main/makelib-g.pkg : # or else
src/app/makelib/mythryl-compiler-compiler/mythryl-compiler-compiler-g.pkg ms::Makelib_State
->
lg::Inter_Library_Dependency_Graph
->
Null_Or (
tlt::Thawedlib_Tome
->
{ compiledfile: cf::Compiledfile,
component_bytesizes: cf::Component_Bytesizes
}
);
get_symbol_and_inlining_mapstacks
:
tlt::Thawedlib_Tome -> sg::Tome_Compile_Result;
)
:
Freezefile # Freezefile is from
src/app/makelib/freezefile/freezefile.api {
Library_Fetcher
=
( ms::Makelib_State,
ad::File,
Null_Or( mvi::Makelib_Version_Intlist )
, ad::Renamings # MUSTDIE
)
->
Null_Or( lg::Inter_Library_Dependency_Graph );
library_picklehash_bytesize # presumably this is saying that picklehashes are 16 bytes.
= # If so, this should be 'ph::pickle_hash_size' instead of '16', no?
16; # XXX BUGGO FIXME.
Map = { symbol_set_map: ssm::Map( pkr::Id ),
thawedlib_tome_map: ttm::Map( pkr::Id ),
pickle_map: pkj::Map
};
my empty_map: Map
=
{ symbol_set_map => ssm::empty,
thawedlib_tome_map => ttm::empty,
pickle_map => pkj::empty_map
};
lifter
=
{ extract => \\ (m: Map) = m.pickle_map,
#
patchback => \\ (m: Map, pickle_map) = { symbol_set_map => m.symbol_set_map,
thawedlib_tome_map => m.thawedlib_tome_map,
pickle_map
}
};
symbol_sets
=
{ find => \\ (m: Map, k)
=
ssm::get (m.symbol_set_map, k),
insert => \\ ( { symbol_set_map, thawedlib_tome_map, pickle_map }, k, v)
=
{ thawedlib_tome_map,
symbol_set_map => ssm::set (symbol_set_map, k, v),
pickle_map
}
};
thawedlib_tome_tin_sets
=
{ find => \\ (map: Map, sg::THAWEDLIB_TOME_TIN tome_tin)
=
ttm::get (map.thawedlib_tome_map, tome_tin.thawedlib_tome),
insert => \\ ( { symbol_set_map, thawedlib_tome_map, pickle_map }, sg::THAWEDLIB_TOME_TIN tin, v)
=
{ symbol_set_map,
thawedlib_tome_map => ttm::set (thawedlib_tome_map, tin.thawedlib_tome, v),
pickle_map
}
};
#
fun fetch_pickle (input_stream: bio::Input_Stream)
=
{ library_picklehash_bytestring = read_n_bytes library_picklehash_bytesize; # Read and ignore 16-byte library picklehash.
#
dependency_graph_bytesize = large_unt::to_int_x (pack_big_endian_unt1::get_vec (read_n_bytes 4, 0)); # Read four-byte length-in-bytes of following graph pickle.
#
dependency_graph_pickle = byte::bytes_to_string (read_n_bytes dependency_graph_bytesize); # Read graph pickle itself.
#
{ pickle => dependency_graph_pickle,
bytesize => dependency_graph_bytesize
};
}
where
fun read_n_bytes n # A simple wrapper around bio::read_n
=
{ byte_vector = bio::read_n (input_stream, n);
# Sanity check -- make sure we read requested number of bytes:
#
if (n != vector_of_one_byte_unts::length byte_vector)
#
fil::say {. " freezefile-g.pkg: fetch_pickle: format error"; };
raise exception upr::FORMAT;
fi;
byte_vector;
};
end;
#
fun make_pickle_fetcher make_freezefile_name ()
=
safely::do
{
open_it => bio::open_for_read o make_freezefile_name,
close_it => bio::close_input,
cleanup => \\ _ = ()
}
(.pickle o fetch_pickle);
# Build a mapping
#
# flt::Frozenlib_Tome -> (Int, sy::Symbol)
#
# that maps each Frozenlib_Tome in a lg::Library to the
# 0..N index of its exporting sub-library in the
# lg::LIBRARY.sublibraries
# list, plus a representative symbol (naming a package or
# api defined in that tome) that can be used to find the
# Frozenlib_Tome within the exports of that sub-library.
#
# (We will need this mapping when pickling.)
#
fun make_tome_to_sublib_map (sublibraries: List( lg::Library_Thunk )): flt::Frozenlib_Tome -> (Int, sy::Symbol)
=
get
where
# Handle one catalog entry (api or package definition
# within a .api or .pkg file) for sub-library:
#
fun do_one_fat_tome
#
(sublib_index: Int) # The index, 0->N-1, of the current sublibrary within the lg::LIBRARY.sublibraries list of its owning library.
#
( symbol: sy::Symbol, # A symbol naming a package or api within current sublibrary.
fat_tome: lg::Fat_Tome, # The package or api named by preceding symbol.
tome_to_sublib_map # The result map we're constructing.
)
=
case (fat_tome.masked_tome_thunk ())
#
{ exports_mask, tome_tin => sg::TOME_IN_FROZENLIB { frozenlib_tome_tin => sg::FROZENLIB_TOME_TIN tin, ... } }
=>
# A given tome (.api or .pkg file) may contain multiple actual
# api and/or package definitions. If so, we will be called
# once for each such def and we will here blindly overwrite any
# pre-existing tome_to_sublib_map entry for this tome with one for
# the new symbol, meaning that the last symbol registered wins:
#
ftm::set (tome_to_sublib_map, tin.frozenlib_tome, (sublib_index, symbol));
_ => tome_to_sublib_map;
esac;
# ... but we want the first guy to win,
# so we do fold_backward and count from the top:
#
fun do_one_sublib' (g as lg::LIBRARY { catalog, ... }, (tome_to_sublib_map, sublib_index))
=>
( sym::keyed_fold_forward # symbol_map is from
src/app/makelib/stuff/symbol-map.pkg (do_one_fat_tome sublib_index)
tome_to_sublib_map
catalog,
#
sublib_index - 1
);
do_one_sublib' (_, (tome_to_sublib_map, sublib_index))
=>
( tome_to_sublib_map,
sublib_index - 1
);
end;
#
fun do_one_sublib (lt: lg::Library_Thunk, inversemap_and_sublibindex)
=
do_one_sublib' (lt.library_thunk (), inversemap_and_sublibindex);
my (tome_to_sublib_map, _)
=
fold_backward
do_one_sublib
(ftm::empty, length sublibraries - 1)
sublibraries;
# frozenlib_tome_map is from
src/app/makelib/freezefile/frozenlib-tome-map.pkg #
fun get (frozenlib_tome: flt::Frozenlib_Tome)
=
case (ftm::get (tome_to_sublib_map, frozenlib_tome))
#
THE p => p;
NULL => err::impossible "save_freezefile: bad inverse map";
esac;
end; # fun make_tome_to_sublib_map
# A library picklehash is created by "pickling" the dependency graph
# of the library in a cursory fashion, thereby recording the
# interface picklehashes of external references.
#
# The so-created pickle string is never used for unpickling.
# Instead, it is hashed and the picklehash stored at in the
# header of its .lib.frozen file to support later
# corruption/staleness checks -- for example via
#
#
src/app/makelib/freezefile/verify-freezefile-g.pkg #
# In paranoia mode makelib checks if the recorded
# hash is identical to the one that _would_ be created if
# one were to re-freeze the library now.
#
fun compute_library_picklehash
(
libfile: ad::File,
catalog_tomes: List( sg::Tome_Tin ), # All the tomes in the library catalog.
sublibraries: List( lg::Library_Thunk )
)
=
pkj::hash_pickle
(byte::string_to_bytes
(pkr::funtree_to_pickle empty_map (wrap_catalog_tomes ()))
)
where
fun tome_compare
( sg::TOME_IN_FROZENLIB { frozenlib_tome_tin => sg::FROZENLIB_TOME_TIN tin1, ... },
sg::TOME_IN_FROZENLIB { frozenlib_tome_tin => sg::FROZENLIB_TOME_TIN tin2, ... }
)
=>
flt::compare
( tin1.frozenlib_tome,
tin2.frozenlib_tome
);
tome_compare (sg::TOME_IN_FROZENLIB _, sg::TOME_IN_THAWEDLIB _) => GREATER;
tome_compare (sg::TOME_IN_THAWEDLIB _, sg::TOME_IN_FROZENLIB _) => LESS;
tome_compare ( sg::TOME_IN_THAWEDLIB (sg::THAWEDLIB_TOME_TIN tin1),
sg::TOME_IN_THAWEDLIB (sg::THAWEDLIB_TOME_TIN tin2)
)
=>
tlt::compare # thawedlib_tome is from
src/app/makelib/compilable/thawedlib-tome.pkg ( tin1.thawedlib_tome,
tin2.thawedlib_tome
);
end;
# To deal with the primordial library (where export nodes come in
# in an ad-hoc order not derived from the export map),
# we first sort the list of export nodes, thereby getting rid
# of duplicates. This should normally canonicalize the list.
# The resulting order is unfortunately not persistent.
# Most of the time this should not matter, though. ("most"?! XXX BUGGO FIXME)
#
catalog_tomes
=
lms::sort_list_and_drop_duplicates
tome_compare
catalog_tomes;
tome_to_sublib_map
=
make_tome_to_sublib_map sublibraries;
# symbol_and_picklehash_pickling is from
src/lib/compiler/front/semantic/pickle/symbol-and-picklehash-pickling.pkg wrap_picklehash = psp::wrap_picklehash;
share = pkr::adhoc_share;
# wrap_symbol = psp::wrap_symbol;
# wrap_string = pkr::wrap_string;
wrap_list = pkr::wrap_list;
wrap_int = pkr::wrap_int;
#
fun wrap_thawedlib_tome_tin (tome_tin: sg::Thawedlib_Tome_Tin) # Compare to wrap_sourcefile_node(tome_tin: sg::Thawedlib_Tome_Tin)
=
share thawedlib_tome_tin_sets wrap_raw_thawedlib_tome_tin tome_tin
where
mknod = pkr::make_funtree_node tag::thawedlib_tome;
#
fun wrap_raw_thawedlib_tome_tin (sg::THAWEDLIB_TOME_TIN t)
=
mknod "a" [ wrap_list wrap_thawedlib_tome_tin t.near_imports,
wrap_list wrap_far_tome t.far_imports
];
end
also
fun wrap_far_tome { exports_mask, tome_tin }
=
{ mknod = pkr::make_funtree_node tag::far_tome;
#
mknod "f" [ wrap_tome tome_tin ];
}
also
fun wrap_tome (tome: sg::Tome_Tin)
=
{ mknod = pkr::make_funtree_node tag::tome;
#
case tome
#
sg::TOME_IN_FROZENLIB { frozenlib_tome_tin => sg::FROZENLIB_TOME_TIN { frozenlib_tome, ... }, symbol_and_inlining_mapstacks, ... }
=>
{ (tome_to_sublib_map frozenlib_tome)
->
(sublib_index, symbol); # 'symbol' names an api or package exported by the tome. Unused here.
symbol_and_inlining_mapstacks
->
{ symbolmapstack_picklehash,
inlining_mapstack_picklehash,
...
};
mknod "2" [ wrap_int sublib_index, # Offset of sublib within lg::LIBRARY.sublibraries list.
wrap_picklehash symbolmapstack_picklehash,
wrap_picklehash inlining_mapstack_picklehash
];
};
#
sg::TOME_IN_THAWEDLIB thawedlib_tome_tin
=>
mknod "3" [wrap_thawedlib_tome_tin thawedlib_tome_tin];
esac;
};
#
fun wrap_catalog_tomes ()
=
{ mknod = pkr::make_funtree_node tag::sublibraries;
#
mknod "g" [wrap_list wrap_tome catalog_tomes];
};
end; # fun compute_library_picklehash
# Comparison of on-disk picklehash with in-memory image.
# We are called (only) from:
#
#
src/app/makelib/freezefile/verify-freezefile-g.pkg
#
fun on_disk_library_picklehash_matches_in_memory_library_image (makelib_state: ms::Makelib_State) (arg as (libfile, _, _))
=
{ new_picklehash = byte::bytes_to_string (ph::to_bytes (compute_library_picklehash arg));
filename_policy = makelib_state.makelib_session.filename_policy;
freezefile_name = fp::make_freezefile_name filename_policy libfile; # "foo.lib.frozen"
safely::do
{
open_it => {. bio::open_for_read freezefile_name; },
close_it => bio::close_input, # data_file__premicrothread is from
src/lib/std/src/posix/data-file--premicrothread.pkg cleanup => \\ _ = ()
}
{. old_picklehash
=
byte::bytes_to_string (bio::read_n (#stream, library_picklehash_bytesize));
old_picklehash == new_picklehash;
}
except _
=
FALSE;
};
########################################################################################################
#
fun load_freezefile
#
{ get_library, saw_errors }
#
( makelib_state: makelib_state::Makelib_State,
libfile: ad::File,
makelib_version_intlist: Null_Or( mvi::Makelib_Version_Intlist ) # XXX BUGGO FIXME 'version' here can die, I think.
, anchor_rebinds # MUSTDIE
)
=
{
THE (safely::do
{ open_it => bio::open_for_read o make_freezefile_name,
close_it => bio::close_input,
cleanup => \\ _ = ()
}
read_freezefile_contents
)
except
upr::FORMAT
=>
{ report_error ["file is corrupted (old version?)"];
NULL;
};
io_exceptions::IO _
=>
NULL;
end;
}
where
error_info
=
( makelib_state.plaint_sink,
saw_errors
);
library_description
=
ad::describe libfile;
# makelib_state is from
src/app/makelib/main/makelib-state.pkg #
fun report_error (error_message: List(String))
=
err::error_no_file
#
error_info
sm::null_region
err::ERROR (cat ("(built) " ! library_description ! ": " ! error_message))
err::null_error_body;
anchor_dictionary = makelib_state.makelib_session.anchor_dictionary;
filename_policy = makelib_state.makelib_session.filename_policy;
#
fun make_freezefile_name ()
=
fp::make_freezefile_name
filename_policy
libfile;
#
fun read_freezefile_contents (input_stream: bio::Input_Stream)
=
read_sharable_value library_sharemap read_library
where
fun get_library' (makelib_state, p, vo
, rb # MUSTDIE
)
=
case (get_library (makelib_state, p, vo
, rb # MUSTDIE
))
#
THE lib => lib;
#
NULL =>
{
report_error [
" .../freezefile/freezefile-g.pkg: Unable to find ",
ad::describe p,
" (",
ad::abbreviate (ad::os_string p),
")"
];
raise exception upr::FORMAT;
};
esac;
(fetch_pickle input_stream)
->
{ bytesize => dependency_graph_bytesize,
pickle => dependency_graph_pickle
};
offset_adjustment
=
dependency_graph_bytesize + 4 + library_picklehash_bytesize; # 64-bit issue XXX BUGGO FIXME
my { charstream, clear_pickle_cache }
=
upr::make_enhanced_charstream_for_string
( THE dependency_graph_pickle,
make_pickle_fetcher make_freezefile_name
);
unpickler = upr::make_unpickler charstream;
###################################################
#
# Allocate Per-Type Backref Maps
#
# A vanilla recursive dagwalk can read and write
# simple tree structures, but we must implement special
# handling for pickled datastructures with shared
# nodes -- nodes with multiple parents.
#
# If we didn't, shared nodes would be duplicated
# by a pickle + unpickle sequence, resulting in some
# datastructures potentially coming back exponentially
# larger than they started out. Not good.
#
# To maintain sharing through the pickle + unpickle
# sequence we store special backreferences in the
# pickles, which upon unpickling (i.e., here) we convert
# back into pointers to shared values. (Pickle backrefs are
# a teeny bit like \1 or $1 backrefs in regular expressions,
# which serve a vaguely similar purpose. Hence the name.)
#
# To make this work, we need a table of already-unpickled
# graph nodes with which to resolve the backreferences as
# we encounter them.
#
# In fact, to keep the type checker happy, we need a
# separate backref table for each type of shared node.
#
# We call such a table a "Sharemap" because it maps
# small ints to shared values of a given type.
#
# These all incorporate a toplevel refcell so that we can
# update them as we read -- they are all MUTABLE STATE.
#
# Here we create these mutable per-type sharemaps,
# each initially empty.
#
# Note that we can't really have shared values for
# some types such as immediate integers, so we don't
# waste time or space creating sharemaps for them.
#
#
my far_frozenlib_tome_sharemap: upr::Sharemap( sg::Far_Frozenlib_Tome ) = upr::make_sharemap ();
my flt_frozenlib_tome_sharemap: upr::Sharemap( flt::Frozenlib_Tome ) = upr::make_sharemap ();
my library_thunk_sharemap: upr::Sharemap( lg::Library_Thunk ) = upr::make_sharemap ();
my list_of_frozenlib_tome_tin_sharemap: upr::Sharemap( List( sg::Frozenlib_Tome_Tin ) ) = upr::make_sharemap ();
my list_of_list_of_string_sharemap: upr::Sharemap( List(List(String)) ) = upr::make_sharemap ();
my list_of_string_sharemap: upr::Sharemap( List( String ) ) = upr::make_sharemap ();
my list_of_void_to_far_frozenlib_tome_sharemap: upr::Sharemap( List(Void -> sg::Far_Frozenlib_Tome) ) = upr::make_sharemap ();
my makelib_version_intlist_sharemap: upr::Sharemap( mvi::Makelib_Version_Intlist ) = upr::make_sharemap ();
my nullor__makelib_version_intlist__sharemap: upr::Sharemap( Null_Or( mvi::Makelib_Version_Intlist ) ) = upr::make_sharemap ();
my nullor_picklehash_sharemap: upr::Sharemap( Null_Or( ph::Picklehash ) ) = upr::make_sharemap ();
my nullor_symbolset_sharemap: upr::Sharemap( Null_Or( sys::Set ) ) = upr::make_sharemap ();
my pair__frozenlib_tome_tin__nullor_int__sharemap: upr::Sharemap( (sg::Frozenlib_Tome_Tin, Null_Or(Int)) ) = upr::make_sharemap ();
my pair__symbol__fat_tome__sharemap: upr::Sharemap( (sy::Symbol, lg::Fat_Tome) ) = upr::make_sharemap ();
my frozenlib_tome_tin_sharemap: upr::Sharemap( sg::Frozenlib_Tome_Tin ) = upr::make_sharemap ();
my symbolmap__fat_tome__sharemap: upr::Sharemap( sym::Map( lg::Fat_Tome ) ) = upr::make_sharemap ();
my symbolset_sharemap: upr::Sharemap( sys::Set ) = upr::make_sharemap ();
# MUSTDIE these are probably both about rb=rebindings
my renaming_sharemap: upr::Sharemap( ad::Renaming ) = upr::make_sharemap ();
my list_of_renaming_sharemap: upr::Sharemap( List( ad::Renaming )) = upr::make_sharemap ();
# These four appear to be typeagnostic -- I cannot
# assign them a fixed type. I haven't figured that out
# yet. -- 2011-01-18 CrT
#
#
my sh_list_sharemap /* : upr::Sharemap( List( Void -> inter_library_dependency_graph::Library_Thunk ) ) */ = upr::make_sharemap ();
my fat_tome_list_sharemap /* : upr::Sharemap( List( Void -> (sy::Symbol, lg::Fat_Tome)) ) dinnae work */ = upr::make_sharemap ();
my library_sharemap /* : upr::Sharemap( Int ) */ = upr::make_sharemap ();
my absolute_path_sharemap /* : upr::Sharemap( lg::Library ) */ = upr::make_sharemap ();
#
#
fun read_list sharemap read_element = upr::read_list unpickler sharemap read_element;
read_string = upr::read_string unpickler;
fun read_null_or sharemap read_value = upr::read_null_or unpickler sharemap read_value;
read_int = upr::read_int unpickler;
# read_bool = upr::read_bool unpickler;
fun read_sharable_value sharemap read_value = upr::read_sharable_value unpickler sharemap read_value;
fun read_unsharable_value read_value = upr::read_unsharable_value unpickler read_value;
read_picklehash = symbol_and_picklehash_unpickling::read_picklehash (unpickler, read_string);
# symbol_and_picklehash_unpickling is from
src/lib/compiler/front/semantic/pickle/symbol-and-picklehash-unpickling.pkg read_list_of_strings = read_list list_of_string_sharemap read_string;
read_list_of_lists_of_strings = read_list list_of_list_of_string_sharemap read_list_of_strings;
#
fun list2path c sl
=
c (ad::unpickle # anchor_dictionary is from
src/app/makelib/paths/anchor-dictionary.pkg anchor_dictionary
{ pickled => sl,
relative_to => libfile
}
)
except
ad::FORMAT
=
{ report_error ["freezefile-g.pkg: list2path: format error"];
raise exception upr::FORMAT;
};
#
fun read_absolute_path ()
=
read_sharable_value absolute_path_sharemap absolute_path
where
fun absolute_path 'p'
=>
list2path ad::file (read_list_of_lists_of_strings ());
absolute_path _
=>
{ report_error ["freezefile-g.pkg: absolute_path: format error"];
raise exception upr::FORMAT;
};
end;
end;
#
fun read_version () # version intlist (e.g. "12.3.9" -> [12,3,9]) as in
src/app/makelib/stuff/makelib-version-intlist.pkg =
read_sharable_value makelib_version_intlist_sharemap v
where
fun v 'v'
=>
case (mvi::from_string (read_string ()))
#
THE v => v;
#
NULL =>
{ report_error ["freezefile-g.pkg: version: format error"];
raise exception upr::FORMAT;
};
esac;
v _ =>
{ report_error ["freezefile-g.pkg: version/2: format error"];
raise exception upr::FORMAT;
};
end;
end;
# MUSTDIE (?) -- this is probably all "rb"=="rebinding" shit
fun read_renaming () # "rb" == "recursive binding"? (Almost certainly 'rebinding')
=
read_sharable_value renaming_sharemap r
where
fun r 'b'
=>
{ anchor => read_string (),
value => list2path (\\ x = x) (read_list_of_lists_of_strings ())
};
r _ =>
{ report_error ["freezefile-g.pkg: rb: format error"];
raise exception upr::FORMAT;
};
end;
end;
#
fun read_library_thunk ()
=
read_sharable_value library_thunk_sharemap xsg
where
# MUSTDIE
# fun read_it ()
fun read_it get_rbl # rbl == "recursive binding list"? (or rebinding list?)
=
{
p = read_absolute_path ();
vo = read_null_or nullor__makelib_version_intlist__sharemap read_version ();
rbl = get_rbl (); # MUSTDIE
#
fun lib_thunk ()
=
get_library' (makelib_state, p, vo
, rbl # MUSTDIE
);
{ libfile => p,
library_thunk => memoize::memoize lib_thunk
, renamings => rbl # MUSTDIE
};
};
# fun xsg 's' => read_it (); # MUSTDIE (\\ () = []); # Backward-compatible
# xsg 'S' => read_it (); # MUSTDIE (list list_of_renaming_sharemap rb);
fun xsg 's' => read_it (\\ () = []); # Backward-compatible
xsg 'S' => read_it (read_list list_of_renaming_sharemap read_renaming);
xsg _ => { report_error ["freezefile-g.pkg: xsg: format error"];
raise exception upr::FORMAT;
};
end;
end;
#
fun read_library 'g'
=>
{ makelib_version_intlist
=
read_null_or nullor__makelib_version_intlist__sharemap read_version ();
sublibraries
=
read_list sh_list_sharemap read_library_thunk ();
#
fun get_sublib sublib_index
=
case (.library_thunk (list::nth (sublibraries, sublib_index)) ())
#
lg::LIBRARY x => x;
lg::BAD_LIBRARY => err::impossible "load_freezefile: BAD_LIBRARY";
esac
except
exceptions::INDEX_OUT_OF_BOUNDS # exceptions is from
src/lib/std/exceptions.pkg =
{ report_error ["freezefile-g.pkg: gr: format error"];
raise exception upr::FORMAT;
};
#
fun context NULL
=>
{ report_error ["freezefile-g.pkg: context/NULL: format error"];
raise exception upr::FORMAT;
};
context (THE (sublib_index, symbol))
=>
{ ( get_sublib sublib_index )
->
{ catalog, ... };
# symbol_map is from
src/app/makelib/stuff/symbol-map.pkg case (sym::get (catalog, symbol))
#
THE (fat_tome: lg::Fat_Tome)
=>
case (fat_tome.masked_tome_thunk ())
#
{ exports_mask, tome_tin => sg::TOME_IN_FROZENLIB { symbol_and_inlining_mapstacks, ... } }
=>
ffr::add_symbolmapstack (symbol_and_inlining_mapstacks.symbolmapstack_thunk ()); # Add to global roster.
#
_ =>
{ report_error ["freezefile-g.pkg: context/THE: format error"];
raise exception upr::FORMAT;
};
esac;
#
NULL =>
{ report_error ["freezefile-g.pkg: context/THE/NULL: format error"];
raise exception upr::FORMAT;
};
esac;
};
end; # fun context
( upj::make_unpicklers { unpickler, read_list_of_strings } context)
->
{ read_inlining_mapstack, read_symbolmapstack, read_symbol, read_list_of_symbols };
lazy_symbol_dictionary = upr::read_lazy unpickler read_inlining_mapstack;
lazy_symbolmapstack = upr::read_lazy unpickler read_symbolmapstack;
#
fun read_symbol_set ()
=
read_sharable_value symbolset_sharemap s
where
fun s 's' => sys::add_list (sys::empty, read_list_of_symbols ());
s _ => { report_error ["freezefile-g.pkg: read_symbol_set: format error"];
raise exception upr::FORMAT;
};
end;
end;
exports_mask
=
read_null_or nullor_symbolset_sharemap read_symbol_set;
#
fun read_sharing_mode ()
=
read_unsharable_value s
where
fun s 'a' => shm::SHARE TRUE; # sharing_mode is from
src/app/makelib/stuff/sharing-mode.pkg s 'b' => shm::SHARE FALSE;
s 'c' => shm::DO_NOT_SHARE;
s _ => { report_error ["freezefile-g.pkg: shm: format error"];
raise exception upr::FORMAT;
};
end;
end;
read_null_or_picklehash
=
read_null_or nullor_picklehash_sharemap read_picklehash;
#
fun read_frozenlib_tome ()
=
read_sharable_value flt_frozenlib_tome_sharemap s
where
fun s 's'
=>
{ api_or_pkg_file_path = read_string (); # E.g. "foo.api" or "../emit/asm-emit.pkg".
locs = read_string (); # E.g. "$ROOT/src/lib/std/standard.lib:822.2-822.33"
byte_offset_in_freezefile = read_int () + offset_adjustment;
runtime_package_picklehash = read_null_or_picklehash ();
sharing_mode = read_sharing_mode ();
plaint_sink = err::error_no_source error_info locs;
freezefile_name = make_freezefile_name ();
{ libfile,
freezefile_name,
#
plaint_sink,
api_or_pkg_file_path,
byte_offset_in_freezefile,
#
runtime_package_picklehash,
sharing_mode
}: flt::Frozenlib_Tome;
};
s _ =>
{ report_error ["freezefile-g.pkg: si: format error"];
raise exception upr::FORMAT;
};
end;
end;
# This is the place where what used to be
# a THAWEDLIB_TOME changes to a FROZENLIB_TOME:
#
fun read_frozenlib_tome_tin ()
=
read_sharable_value frozenlib_tome_tin_sharemap sn'
where
fun sn' 'a'
=>
sg::FROZENLIB_TOME_TIN
{
frozenlib_tome => read_frozenlib_tome (),
near_imports => read_frozenlib_tome_tin_list (),
far_import_thunks => read_far_frozenlib_tome_thunk_list ()
};
sn' _
=>
{ report_error ["freezefile-g.pkg: sn: format error"];
raise exception upr::FORMAT;
};
end;
end
also
fun read_frozenlib_tome_tin_list ()
=
read_list list_of_frozenlib_tome_tin_sharemap read_frozenlib_tome_tin ()
# This one changes from far_compiledfile
# to a far_compiledfile_in_lib:
also
fun read_tome ()
=
read_sharable_value pair__frozenlib_tome_tin__nullor_int__sharemap tome'
where
fun tome' '2'
=>
{ sublib_index = read_int ();
symbol = read_symbol ();
my { catalog => slexp, ... }
=
get_sublib sublib_index;
# symbol_map is from
src/app/makelib/stuff/symbol-map.pkg case (sym::get (slexp, symbol))
#
THE (fat_tome: lg::Fat_Tome)
=>
case (fat_tome.masked_tome_thunk ())
#
{ exports_mask, tome_tin => sg::TOME_IN_FROZENLIB { frozenlib_tome_tin, ... } }
=>
(frozenlib_tome_tin, THE sublib_index);
_ =>
{ report_error ["freezefile-g.pkg: tome/THE: format error"];
raise exception upr::FORMAT;
};
esac;
#
NULL =>
{ report_error ["freezefile-g.pkg: tome/I: format error"];
raise exception upr::FORMAT;
};
esac;
};
tome' '3' => (read_frozenlib_tome_tin (), NULL);
tome' _ => { report_error ["freezefile-g.pkg: tome/III: format error"];
raise exception upr::FORMAT;
};
end;
end
also
fun read_far_frozenlib_tome ()
=
read_sharable_value far_frozenlib_tome_sharemap f
where
fun f 'f'
=>
{ (exports_mask ()) -> exports_mask;
(read_tome ()) -> (frozenlib_tome_tin, sublibs_index);
#
{ exports_mask, frozenlib_tome_tin, sublibs_index };
};
f x =>
{ report_error ["freezefile-g.pkg: far_tome: format error, expected 'f' but got '", (char::to_string x), "' instead"];
raise exception upr::FORMAT;
};
end;
end
also
fun read_far_frozenlib_tome_thunk_list ()
=
read_list list_of_void_to_far_frozenlib_tome_sharemap read_far_frozenlib_tome_thunk ()
also
fun read_far_frozenlib_tome_thunk ()
=
upr::read_lazy unpickler read_far_frozenlib_tome ();
#
fun import_export ()
=
read_sharable_value pair__symbol__fat_tome__sharemap ie
where
fun ie 'i'
=>
{ symbol = read_symbol ();
my far_frozenlib_tome_thunk: Void -> sg::Far_Frozenlib_Tome
=
read_far_frozenlib_tome_thunk (); # Really reads far_bin_nodes!
symbolmapstack_thunk = lazy_symbolmapstack ();
inlining_mapstack_thunk = lazy_symbol_dictionary ();
symbolmapstack_picklehash = read_picklehash ();
inlining_mapstack_picklehash = read_picklehash ();
compiledfile_version = read_string ();
allsyms = read_symbol_set ();
#
fun fat_tome_thunk ()
=
{ (far_frozenlib_tome_thunk ()) -> { exports_mask, frozenlib_tome_tin, sublibs_index };
symbol_and_inlining_mapstacks
=
{ symbolmapstack_thunk,
inlining_mapstack_thunk,
#
symbolmapstack_picklehash,
inlining_mapstack_picklehash,
#
compiledfile_version
};
{ exports_mask,
tome_tin => sg::TOME_IN_FROZENLIB { frozenlib_tome_tin, symbol_and_inlining_mapstacks, sublibs_index }
};
};
# symbolmapstack__to__tome_symbolmapstack is from
src/app/makelib/depend/symbolmapstack--to--tome-symbolmapstack.pkg e = symbolmapstack__to__tome_symbolmapstack::convert_memo symbolmapstack_thunk;
# Put a filter in front to avoid needlessly
# querying the FCTENV -- this
# avoids spurious module loadings:
e' = tst::FILTER (sys::singleton symbol, e);
( symbol,
{ masked_tome_thunk => memoize::memoize fat_tome_thunk,
tome_symbolmapstack => e',
exports_mask => allsyms
} # : lg::Fat_Tome
);
};
ie 'j'
=>
{ symbol = read_symbol ();
node_thunk = read_far_frozenlib_tome_thunk ();
allsyms = read_symbol_set ();
# "This seems (is?) a bit clumsy... "
fun xth ()
=
{
(node_thunk ())
->
{ exports_mask => f,
frozenlib_tome_tin => n,
sublibs_index => pos
};
my fat_tome: lg::Fat_Tome
=
the (sym::get
( .catalog (get_sublib (the pos)),
symbol
) )
except
_ = { report_error ["freezefile-g.pkg: xth: format error"];
raise exception upr::FORMAT;
};
(f, n, pos, fat_tome.masked_tome_thunk, fat_tome.tome_symbolmapstack);
};
xth = memoize::memoize xth;
#
fun eth ()
=
#5 (xth ());
e' = tst::FILTER
(
sys::singleton symbol,
tst::SUSPEND eth
);
# symbol_set is from
src/app/makelib/stuff/symbol-set.pkg #
fun fat_tome_thunk ()
=
{ (xth ())
->
( exports_mask: sg::Exports_Mask,
frozenlib_tome_tin: sg::Frozenlib_Tome_Tin,
sublibs_index: Null_Or( Int ),
masked_tome_thunk: Void -> sg::Masked_Tome,
_: tst::Tome_Symbolmapstack
);
symbol_and_inlining_mapstacks
=
case ((masked_tome_thunk()).tome_tin: sg::Tome_Tin)
#
sg::TOME_IN_FROZENLIB r
=>
r.symbol_and_inlining_mapstacks;
#
_ =>
{ report_error ["freezefile-g.pkg: fat_tome_thunk: format error"];
raise exception upr::FORMAT;
};
esac;
{ exports_mask,
tome_tin => sg::TOME_IN_FROZENLIB { frozenlib_tome_tin, symbol_and_inlining_mapstacks, sublibs_index }
};
};
( symbol,
#
{ masked_tome_thunk => memoize::memoize fat_tome_thunk,
tome_symbolmapstack => e',
exports_mask => allsyms
}
);
};
ie _ =>
{ report_error ["freezefile-g.pkg: import_export: format error"];
raise exception upr::FORMAT;
};
end;
end; # fun import_export
fat_tome_list
=
read_list fat_tome_list_sharemap import_export;
#
fun r_exports ()
=
read_sharable_value symbolmap__fat_tome__sharemap e
where
fun e 'e'
=>
fold_forward
sym::set'
sym::empty
(fat_tome_list ());
e _ =>
{ report_error ["freezefile-g.pkg: r_exports: format error"];
#
raise exception upr::FORMAT;
};
end;
end;
#
catalog = r_exports ();
lg::LIBRARY
{
catalog,
sublibraries,
#
libfile,
sources => source_path_map::empty,
#
more => lg::MAIN_LIBRARY
{
makelib_version_intlist,
frozen_vs_thawed_stuff => lg::FROZENLIB_STUFF { clear_pickle_cache }
}
};
};
read_library _
=>
{ report_error ["freezefile-g.pkg: work: format error"];
raise exception upr::FORMAT;
};
end; # fun do_library
end; # fun read_freezefile_contents
end; # load_freezefile
# Create the actual on-disk freezefile
# for LIBRARY, then change its status
# from THAWED to FROZEN.
#
# We get called from compile_primordial_library() in
#
#
src/app/makelib/mythryl-compiler-compiler/mythryl-compiler-compiler-g.pkg #
# and twice from
#
#
src/app/makelib/parse/libfile-parser-g.pkg #
fun save_freezefile
#
makelib_state
#
{
library => library_to_freeze as lg::LIBRARY lib_to_freeze,
saw_errors
, renamings # MUSTDIE
}
=>
case lib_to_freeze.more
#
lg::MAIN_LIBRARY { frozen_vs_thawed_stuff => lg::THAWEDLIB_STUFF _, makelib_version_intlist }
=>
case (compile_library makelib_state library_to_freeze) # Compile library code proper.
#
THE (get_compiledfile: tlt::Thawedlib_Tome -> { compiledfile: cf::Compiledfile,
component_bytesizes: cf::Component_Bytesizes
}
)
=>
case (list::filter library_thunk_is_not_frozen lib_to_freeze.sublibraries) # Check that all referenced external libraries are frozen.
#
[] => save_freezefile' { get_compiledfile, makelib_version_intlist }; # All referenced external libraries are frozen, go ahead and write the foo.lib.frozen file.
#
unfrozen_sublibraries => report_save_freezefile_failure unfrozen_sublibraries; # At least one referenced external library is not frozen, so abort.
esac;
NULL =>
{ saw_errors := TRUE;
NULL;
};
esac;
#
lg::MAIN_LIBRARY { frozen_vs_thawed_stuff => lg::FROZENLIB_STUFF _, ... }
=>
THE library_to_freeze; # Library to be frozen is already frozen; nothing to do, so just return it.
#
lg::SUBLIBRARY _
=>
err::impossible "save_freezefile: no library";
esac
where
filename_policy = makelib_state.makelib_session.filename_policy;
#
fun save_freezefile'
{
makelib_version_intlist: Null_Or( mvi::Makelib_Version_Intlist ), # Used only in wrap_sublibraries()
#
get_compiledfile: tlt::Thawedlib_Tome -> { compiledfile: cf::Compiledfile,
component_bytesizes: cf::Component_Bytesizes
}
}
=
{
{ safely::do
{ open_it,
close_it,
cleanup
}
{. bio::write (#output_stream, library_picklehash_bytestring);
write_int1 (#output_stream, dependency_graph_bytesize );
bio::write (#output_stream, dependency_graph_pickle );
my { code_bytesize,
data_bytesize,
symbolmapstack_bytesize,
inlinables_bytesize
}
=
fold_forward (write_compiledfile_for_thawedlib_tome #output_stream)
{
symbolmapstack_bytesize => 0,
inlinables_bytesize => 0,
code_bytesize => 0,
data_bytesize => 0
}
thawedlib_tomes_in_lib;
# 2006-09-11 CrT: This is just noise at present:
#
# fil::say ["[code: ", int::to_string code_bytesize,
# ", data: ", int::to_string data_bytesize,
# ", inlinable: ", int::to_string inlinables_bytesize,
# ", symbolmapstack: ", int::to_string symbolmapstack_bytesize,
# " bytes]\n"
# ];
();
};
reload_freezefile ();
}
except
any_exception
=
{
err::error_no_file (makelib_state.plaint_sink, saw_errors) sm::null_region
err::ERROR
( cat [ "Exception raised while library building ",
ad::describe libfile
]
)
err::null_error_body;
NULL;
};
}
where
lib_to_freeze -> { libfile, sublibraries, catalog, ... };
#
fun force f
=
f ();
library_picklehash
=
compute_library_picklehash
(
libfile,
#
map (.tome_tin o force o .masked_tome_thunk)
(sym::vals_list catalog),
#
sublibraries
);
#
fun write_compiledfile_for_thawedlib_tome
#
stream
#
( thawedlib_tome: tlt::Thawedlib_Tome,
#
{ symbolmapstack_bytesize,
inlinables_bytesize,
code_bytesize,
data_bytesize
}
)
=
{
(get_compiledfile thawedlib_tome)
->
{ compiledfile, component_bytesizes };
component_bytesizes
->
{ symbolmapstack_bytesize => e,
inlinables_bytesize => inlining_data,
code_bytesize => c,
data_bytesize => d
};
compiler_version_id = mcv::mythryl_compiler_version.compiler_version_id; # Something like: [110, 58, 3, 0, 2].
ignore
(cf::write_compiledfile
{
architecture, # PWRPC32/SPARC32/INTEL32.
compiler_version_id, # Something like: [110, 58, 3, 0, 2]. First two go into file 'magic'.
stream,
drop_symbol_and_inlining_mapstacks => TRUE, # We strip symbol table info from foo.lib.frozen files. We keep it in foo.pkg.compiled
# files -- see
src/app/makelib/compile/compile-in-dependency-order-g.pkg compiledfile
}
);
code_bytesize += c;
data_bytesize += d;
symbolmapstack_bytesize += e;
inlinables_bytesize += inlining_data;
{ symbolmapstack_bytesize,
inlinables_bytesize,
code_bytesize,
data_bytesize
};
}; # fun write_compiledfile_for_thawedlib_tome
#
fun compiledfile_bytesize_on_disk (thawedlib_tome: tlt::Thawedlib_Tome)
=
cf::compiledfile_bytesize_on_disk
{
compiledfile => (get_compiledfile thawedlib_tome).compiledfile,
drop_symbol_and_inlining_mapstacks => TRUE # Needs to match above call to cf::write_compiledfile
};
#
fun get_symbolmapstack_picklehash_for_thawedlib_tome (thawedlib_tome: tlt::Thawedlib_Tome)
=
cf::hash_of_symbolmapstack_pickle (get_compiledfile thawedlib_tome).compiledfile;
fun abbreviate_filepath (full_pathname: String)
=
# Drop rootdir of the Mythryl sourcetree from filename, thus reducing (say)
#
# /mythryl7/mythryl7.110.58/mythryl7.110.58/src/app/makelib/freezefile/freezefile-g.pkg
#
# to just
#
#
src/app/makelib/freezefile/freezefile-g.pkg #
{ root = winix__premicrothread::file::current_directory (); # "/pub/home/cynbe/src/mythryl/mythryl7/mythryl7.110.58/mythryl7.110.58";
if (string::is_prefix root full_pathname)
#
string::extract (full_pathname, string::length_in_bytes root + 1, NULL);
else
full_pathname;
fi;
};
final_freezefile_name # "foo.lib" -> "foo.lib.frozen"
=
fp::make_freezefile_name filename_policy libfile;
temporary_freezefile_name
=
make_temporary_freezefile_name final_freezefile_name
where
#
fun make_temporary_freezefile_name filename # "foo.lib.frozen" -> "foo.lib.frozen.12345.tmp"
=
{ pid = winix__premicrothread::process::get_process_id ();
include package sfprintf;
pid = sprintf' "%d" [ INT pid ];
filename + "." + pid + ".tmp";
};
end;
fil::say {.
cat
[
"\n freezefile-g.pkg: Creating freeze file ",
abbreviate_filepath final_freezefile_name
];
};
# my _ =
# 2006-09-11 CrT: This is just noise for now:
# if (not (sts::is_empty wrapped_privileges))
# #
# fil::say {. cat
# ("freezefile: wrapping the following privileges:\n"
# ! map (\\ s = (" " + s + "\n"))
# (sts::vals_list wrapped_privileges));
# };
# fi;
error_info
=
(makelib_state.plaint_sink, saw_errors); # Is this ever used? XXX BUGGO FIXME
tome_to_sublib_map
=
make_tome_to_sublib_map sublibraries;
thawedlib_tomes_in_lib' = REF ([]: List( tlt::Thawedlib_Tome ));
stipulate
tome_offset_map = REF ttm::empty;
total_tome_bytes = REF 0;
herein
fun compute_tome_offset_in_library
(
thawedlib_tome: tlt::Thawedlib_Tome,
compiledfile_size_on_disk: Int
)
=
case (ttm::get (*tome_offset_map, thawedlib_tome))
#
# This test is necessary because of a tiny chance
# that a portion of a pickle needs to be re-done
# by the pickler because it underestimated its
# size during lazy pickling. Ideally, the pickler
# should run without side-effects, but in the
# present case all we need is idempotence.
#
THE tome_offset =>
{
tome_offset;
};
#
NULL =>
{
tome_offset = *total_tome_bytes;
#
total_tome_bytes := tome_offset + compiledfile_size_on_disk;
tome_offset_map := ttm::set (*tome_offset_map, thawedlib_tome, tome_offset);
#
thawedlib_tomes_in_lib' := thawedlib_tome ! *thawedlib_tomes_in_lib';
#
tome_offset;
};
esac;
end;
#
fun prepath2list what p
=
{ fun warn_relabs (abs, descr)
=
{ relative_or_absolute
=
abs ?? "absolute"
:: "relative";
library_description
=
ad::describe libfile;
#
fun ppb pp
=
{ fun blank ()
=
pp::break pp { blanks=>1, indent_on_wrap=>0 };
#
fun string s
=
pp.lit s;
#
fun ss s
=
{ string s;
blank ();
};
#
fun nl ()
=
pp.newline();
nl ();
pp.box {. pp.rulename "fz1";
apply ss ["The", "path", "specifying"];
apply ss [what, descr, "is"];
string relative_or_absolute; string "."; nl ();
apply ss ["(This", "means", "that", "in", "order",
"to", "be", "able", "to", "use", "the",
"built", "library"];
string library_description; ss ", ";
apply ss ["it", "will", "be", "necessary", "to",
"keep", "all", "imported", "libraries",
"with", "names", "derived", "from", "or",
"equal", "to"];
ss descr;
apply ss ["in", "the", "same"];
ss relative_or_absolute;
apply ss ["location", "as", "they", "are"];
string "now.)";
};
}; # ppb
err::error_no_file
(makelib_state.plaint_sink, saw_errors) sm::null_region err::WARNING
(library_description + ": uses non-anchored path") ppb;
};
ad::pickle
{ warn => warn_relabs }
{ file => p,
relative_to => libfile
};
};
# Collect all fat_tomes in our lg::LIBRARY.catalog and build
# a context suitable for pkj::symbolmapstack_pickler:
#
my pickling_context: List( (Null_Or( (Int, sy::Symbol) ), stx::Stampmapstack))
=
{ fun wrap_list f [] k s => k s;
wrap_list f (h ! t) k s => f h (wrap_list f t k) s;
end;
#
fun wrap_tome
#
(tome: sg::Tome_Tin)
#
k
#
(s as ( frozenlib_tomes: ftm::Map( ((Int, sy::Symbol), Void -> syx::Symbolmapstack) ),
thawedlib_tomes: tts::Set
) )
=
case tome
#
sg::TOME_IN_FROZENLIB { frozenlib_tome_tin => sg::FROZENLIB_TOME_TIN { frozenlib_tome, ... }, symbol_and_inlining_mapstacks, ... }
=>
{ (tome_to_sublib_map frozenlib_tome)
->
( sublib_index, # Position of sublibrary within lg::LIBRARY.sublibraries list.
symbol # 'symbol' names an api or package exported by the tome.
);
frozenlib_tomes'
=
ftm::set (frozenlib_tomes, frozenlib_tome, ((sublib_index, symbol), symbol_and_inlining_mapstacks.symbolmapstack_thunk));
k (frozenlib_tomes', thawedlib_tomes);
};
sg::TOME_IN_THAWEDLIB tome
=>
wrap_thawedlib_tome_tin tome k s;
esac
also
fun wrap_thawedlib_tome_tin
#
(sg::THAWEDLIB_TOME_TIN tin)
k
( frozenlib_tomes: ftm::Map( ((Int, sy::Symbol), Void -> syx::Symbolmapstack) ),
thawedlib_tomes: tts::Set
)
=
if (tts::member (thawedlib_tomes, tin.thawedlib_tome))
#
k (frozenlib_tomes, thawedlib_tomes);
else
thawedlib_tomes' = tts::add (thawedlib_tomes, tin.thawedlib_tome);
#
wrap_list wrap_thawedlib_tome_tin tin.near_imports (wrap_list wrap_far_tome tin.far_imports k) (frozenlib_tomes, thawedlib_tomes');
fi
also
fun wrap_far_tome { exports_mask, tome_tin } k s
=
wrap_tome tome_tin k s;
#
fun wrap_fat_tome (fat_tome: lg::Fat_Tome) k s
=
wrap_far_tome (fat_tome.masked_tome_thunk ()) k s;
my fat_tome_catalog: List( ((Int, sy::Symbol), Void -> syx::Symbolmapstack) )
=
# Construct an index of our lg::LIBRARY.catalog
# contents in the form of a sorted list of values
#
# ( ( sublib_index: Int, # Int 0..N-1 offset of fat_tome within lg::LIBRARY.sublibrary list.
# api_or_tome_name: sy::Symbol # Symbol naming the package or api in fat_tome. (Technically, name of first export -- a fat_tome can have multiple exports.)
# ),
# symbolmapstack_thunk: Void -> syx::Symbolmapstack # Thunk constructing symbolmapstack for fat_tome.
# )
#
# where the sort is on sublib_index. We also
# suppress duplicate entries, so that each
# sublib_index should occur exactly once:
#
lms::sort_list
#
(\\ (x, y) = (#1 (#1 x) > #1 (#1 y)))
#
(ftm::vals_list fat_tome_catalog')
where
my fat_tome_catalog': ftm::Map( ((Int, sy::Symbol), Void -> syx::Symbolmapstack) )
=
# Construct an index of our lg::LIBRARY.catalog
# contents in the form of a map from fat-tome keys
# to values as described above:
#
wrap_list wrap_fat_tome (sym::vals_list catalog)
#1
(ftm::empty, tts::empty);
end;
lib_arg (fat_tome_catalog, stx::empty_stampmapstack)
where
#
fun lib_arg ([], _)
=>
[];
lib_arg ((lsm, ge) ! t, m)
=>
{ m' = s2m::collect_all_modtrees_in_symbolmapstack' (ge (), m);
#
(THE lsm, m') ! lib_arg (t, m');
};
end;
end;
}; # pickling_context: List( (Null_Or( (Int, sy::Symbol) ), stx::Stampmapstack))
stipulate
make_symbolmapstack_funtree = pkj::make_symbolmapstack_funtree (\\ _ = ()) (pkj::FREEZEFILE_PICKLING pickling_context);
#
wrap_symbolmapstack' = pkr::lift_funtree_maker lifter make_symbolmapstack_funtree;
wrap_inlining_mapstack' = pkr::lift_funtree_maker lifter pkj::make_inlining_mapstack_funtree;
herein
wrap_symbolmapstack_thunk = pkr::wrap_thunk wrap_symbolmapstack';
wrap_inlining_mapstack_thunk = pkr::wrap_thunk wrap_inlining_mapstack';
end;
wrap_symbol = psp::wrap_symbol;
wrap_picklehash = psp::wrap_picklehash;
adhoc_share = pkr::adhoc_share;
wrap_null_or = pkr::wrap_null_or;
wrap_list = pkr::wrap_list;
wrap_string = pkr::wrap_string;
# wrap_bool = pkr::wrap_bool;
wrap_int = pkr::wrap_int;
#
fun wrap_symbol_set (symbolset: sys::Set)
=
adhoc_share symbol_sets raw_symbol_set symbolset
where
mknod = pkr::make_funtree_node tag::symbolset;
#
fun raw_symbol_set symbolset
=
mknod "s" [wrap_list wrap_symbol (sys::vals_list symbolset)];
end;
wrap_exports_mask = wrap_null_or wrap_symbol_set;
stipulate
mknod = pkr::make_funtree_node tag::sharing_mode;
herein
#
fun wrap_sharing_mode (shm::SHARE TRUE ) => mknod "a" [];
wrap_sharing_mode (shm::SHARE FALSE) => mknod "b" [];
wrap_sharing_mode (shm::DO_NOT_SHARE) => mknod "c" [];
end;
end;
#
fun wrap_thawedlib_tome (tt: tlt::Thawedlib_Tome)
=
{ # FIXME: this is not a technical flaw, but perhaps one
# that deserves fixing anyway: If we only look at
# api_or_pkg_file_path, then we are losing information
# about sub-libraries within freezefiles. However, the
# api_or_pkg_file_path in flt::Frozenlib_Tome is only used for
# diagnostics and has no impact on the operation of makelib itself.
api_or_pkg_file_path = ad::os_string_relative (tlt::sourcepath_of tt); # Sourcefile pathname verbatim from .lib-file, e.g. "foo.api" or "../emit/asm-emit.pkg".
locs = tlt::error_location makelib_state tt; # E.g. "$ROOT/src/lib/std/standard.lib:822.2-822.33"
tome_offset_in_library = compute_tome_offset_in_library (tt, compiledfile_bytesize_on_disk tt); # Is this byte_offset_in_freezefile...?
my { is_runtime_package, ... }
=
tlt::attributes_of tt;
sharing_mode
=
tlt::get_sharing_mode tt;
mknod = pkr::make_funtree_node tag::thawed_tome;
runtime_package_picklehash
=
if is_runtime_package THE (get_symbolmapstack_picklehash_for_thawedlib_tome tt);
else NULL;
fi;
mknod "s" [ wrap_string api_or_pkg_file_path,
wrap_string locs,
wrap_int tome_offset_in_library,
wrap_null_or wrap_picklehash runtime_package_picklehash,
wrap_sharing_mode sharing_mode
];
};
#
fun wrap_absolute_path (p: ad::File)
=
{ mknod = pkr::make_funtree_node tag::absolute_path;
#
mknod "p" [wrap_list (wrap_list wrap_string) (prepath2list "library"
(ad::file_to_basename p))];
};
# anchor_dictionary is from
src/app/makelib/paths/anchor-dictionary.pkg #
fun wrap_sourcefile_node (tome_tin: sg::Thawedlib_Tome_Tin) # Compare to wrap_thawedlib_tome_tin (tome_tin: sg::Thawedlib_Tome_Tin)
=
adhoc_share thawedlib_tome_tin_sets raw_thawedlib_tome_tin tome_tin
where
mknod = pkr::make_funtree_node tag::thawedlib_tome;
#
fun raw_thawedlib_tome_tin (sg::THAWEDLIB_TOME_TIN tin)
=
mknod "a" [ wrap_thawedlib_tome tin.thawedlib_tome,
wrap_list wrap_sourcefile_node tin.near_imports,
wrap_list lazy_far_tome' tin.far_imports
];
end
# Here we ignore the interface info
# because we will not need it when
# we unpickle:
#
also
fun wrap_tome (tome: sg::Tome_Tin)
=
{ mknod = pkr::make_funtree_node tag::tome;
case tome
#
sg::TOME_IN_FROZENLIB { frozenlib_tome_tin => sg::FROZENLIB_TOME_TIN { frozenlib_tome, ... }, ... }
=>
{ (tome_to_sublib_map frozenlib_tome)
->
(sublib_index, symbol);
#
mknod "2" [ wrap_int sublib_index, # Position within lg::LIBRARY.sublibraries list.
wrap_symbol symbol # Symbol naming api or package exported by tome.
];
};
#
sg::TOME_IN_THAWEDLIB tome
=>
mknod "3" [wrap_sourcefile_node tome];
esac;
}
also
fun wrap_masked_tome ({ exports_mask, tome_tin }: sg::Masked_Tome)
=
{ mknod = pkr::make_funtree_node tag::far_tome;
#
mknod "f" [ wrap_exports_mask exports_mask,
wrap_tome tome_tin
];
}
also
fun wrap_masked_tome_thunk (masked_tome_thunk: Void -> sg::Masked_Tome)
=
pkr::wrap_thunk wrap_masked_tome masked_tome_thunk # Only use of wrap_masked_tome.
also
fun lazy_far_tome' arg
=
wrap_masked_tome_thunk {. arg; };
# Here is the place where we
# need to write interface info:
#
fun wrap_catalog_entry # Handle one key-val entry pair from lg::LIBRARY.catalog
( symbol: sy::Symbol,
fat_tome: lg::Fat_Tome
)
=
{ mknod = pkr::make_funtree_node tag::catalog_entry;
case (fat_tome.masked_tome_thunk ())
#
{ exports_mask, tome_tin => sg::TOME_IN_THAWEDLIB (sg::THAWEDLIB_TOME_TIN { thawedlib_tome, ... } ) }
=>
{ # This is the case of an actual internal node:
#
(get_symbol_and_inlining_mapstacks thawedlib_tome)
->
{ symbolmapstack_thunk,
inlining_mapstack_thunk,
symbolmapstack_picklehash,
inlining_mapstack_picklehash,
compiledfile_version
};
mknod "i" [ wrap_symbol symbol,
wrap_masked_tome_thunk fat_tome.masked_tome_thunk,
wrap_symbolmapstack_thunk symbolmapstack_thunk,
wrap_inlining_mapstack_thunk inlining_mapstack_thunk,
wrap_picklehash symbolmapstack_picklehash,
wrap_picklehash inlining_mapstack_picklehash,
wrap_string compiledfile_version,
wrap_symbol_set fat_tome.exports_mask
];
};
{ exports_mask => _, tome_tin => sg::TOME_IN_FROZENLIB _ }
=>
# This is the case of a simple re-export;
# we avoid pickling any dictionaries here because
# they can be re-fetched from the farlib directly
# when unpickling:
#
mknod "j" [ wrap_symbol symbol,
wrap_masked_tome_thunk fat_tome.masked_tome_thunk,
wrap_symbol_set fat_tome.exports_mask
];
esac;
};
#
fun wrap_catalog (catlog: sym::Map( lg::Fat_Tome )) # lg::LIBRARY.catalog has type sym::Map(lg::Fat_Tome)
=
{ mknod = pkr::make_funtree_node tag::catalog;
#
mknod "e" [wrap_list wrap_catalog_entry (sym::keyvals_list catalog)];
};
#
fun wrap_makelib_version_intlist (makelib_version_intlist: mvi::Makelib_Version_Intlist)
=
{ mknod = pkr::make_funtree_node tag::makelib_version_intlist;
#
mknod "v" [wrap_string (mvi::to_string makelib_version_intlist)];
};
# MUSTDIE (?) this is probably all rb==rebindings stuff
fun wrap_rebinding { anchor, value }
=
{ mknod = pkr::make_funtree_node tag::rebinding;
#
mknod "b" [ wrap_string anchor,
wrap_list (wrap_list wrap_string)
(prepath2list "anchor naming" value)
];
};
#
fun wrap_library_thunk (lt: lg::Library_Thunk)
=
{ mknod = pkr::make_funtree_node tag::library_thunk;
#
null_or_version_intlist
=
case (lt.library_thunk ())
#
lg::LIBRARY { more => lg::MAIN_LIBRARY x, ... }
=>
x.makelib_version_intlist;
#
_ => NULL;
esac;
mknod "S" [ wrap_absolute_path lt.libfile,
wrap_null_or wrap_makelib_version_intlist null_or_version_intlist
, wrap_list wrap_rebinding lt.renamings # MUSTDIE
];
};
#
fun wrap_sublibraries ()
=
{ mknod = pkr::make_funtree_node tag::sublibraries;
# Pickle the sublibraries first because
# we need to already have them back
# when we unpickle frozen_compilables:
#
mknod "g" [ wrap_null_or wrap_makelib_version_intlist makelib_version_intlist,
wrap_list wrap_library_thunk sublibraries,
wrap_catalog catalog
];
};
dependency_graph_pickle = byte::string_to_bytes (pkr::funtree_to_pickle empty_map (wrap_sublibraries ()));
dependency_graph_bytesize = vector_of_one_byte_unts::length dependency_graph_pickle;
offset_adjustment
=
dependency_graph_bytesize + 4 + library_picklehash_bytesize; # 64-bit issue XXX BUGGO FIXME
# We could generate the graph for a freezefile here
# directly by transcribing the original graph.
#
# However, it is cumbersome and is likely to result
# in a larger memory footprint because we don't get
# the benefit of lazy unpickling of dictionaries.
#
# It seems easier to simply rely on "load_freezefile"
# to re-fetch the stable graph.
#
fun reload_freezefile ()
=
{ fun get_library (_, p, _
, _ # MUSTDIE
)
=
{ fun the_sublib (lt: lg::Library_Thunk)
=
ad::compare (p, lt.libfile) == EQUAL;
#
fun force f = f ();
null_or::map
(force o .library_thunk)
(list::find the_sublib sublibraries);
};
load_freezefile
{ get_library, saw_errors }
( makelib_state,
libfile
, NULL # version info -- XXX SUCKO DELETEME
, renamings # MUSTDIE
);
};
#
fun write_int1 (outstream: bio::Output_Stream, i: Int)
=
{ a = rw_vector_of_one_byte_unts::make_rw_vector (4, 0u0);
pack_big_endian_unt1::set (a, 0, large_unt::from_int i); # pack_big_endian_unt1 is from
src/lib/std/src/pack-big-endian-unt1.pkg bio::write (outstream, rw_vector_of_one_byte_unts::to_vector a);
};
thawedlib_tomes_in_lib = reverse *thawedlib_tomes_in_lib';
library_picklehash_bytestring = ph::to_bytes library_picklehash;
if (vector_of_one_byte_unts::length library_picklehash_bytestring != library_picklehash_bytesize)
#
err::impossible "save_freezefile: library picklehash size wrong";
fi;
#
fun open_it ()
=
autodir::open_binary_output temporary_freezefile_name; # XXX BUGGO FIXME don't really need autodir:: here.
#
fun close_it stream
=
{ bio::close_output stream;
# We make writing the freezefile effectively atomic
# by writing it to a temporary name and then renaming
# it to its final name only when done.
#
# Time to do the rename:
#
winix__premicrothread::file::rename_file
{
from => temporary_freezefile_name,
to => final_freezefile_name
};
};
#
fun cleanup _
=
{ winix__premicrothread::file::remove_file temporary_freezefile_name
except
_ = ();
};
end; # fun save_freezefile' in fun save_freezefile
#
fun library_thunk_is_not_frozen (lt: lg::Library_Thunk)
=
case (lt.library_thunk ())
#
lg::LIBRARY { more => lg::MAIN_LIBRARY { frozen_vs_thawed_stuff => lg::FROZENLIB_STUFF _, ... }, ... }
=>
FALSE;
_ => TRUE;
esac;
# Report "foo.lib cannot be frozen because the following sub-libraries are not frozen: ..."
#
fun report_save_freezefile_failure unfrozen_sublibraries
=
{ be_verb = case unfrozen_sublibraries
#
[_] => "y is";
_ => "ies are";
esac;
#
fun ppb (pp:Pp)
=
loop unfrozen_sublibraries
where
fun loop [] => ();
#
loop ((lt: lg::Library_Thunk) ! t)
=>
{ pp.lit (ad::describe lt.libfile);
pp.newline();
loop t;
};
end;
pp.newline();
pp.lit (cat [ "because the following sub-librar",
be_verb,
" not frozen:"]
);
pp.newline();
end;
plaint_sink
=
makelib_state.plaint_sink;
library_description
=
ad::describe lib_to_freeze.libfile;
err::error_no_file (plaint_sink, saw_errors)
sm::null_region
err::ERROR
("src/app/makelib/freezefile/freezefile-g.pkg: " + library_description + " cannot be frozen")
ppb;
NULL;
};
end; # where
save_freezefile _ { library => lg::BAD_LIBRARY, ... }
=>
NULL;
end; # end of fun save_freezefile
}; # generic package freezefile_g
end; # stipulate
## (C) 1999 Lucent Technologies, Bell Laboratories
## Author: Matthias Blume (blume@kurims.kyoto-u.ac.jp)
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.