## link-and-run-package.pkg
#
# Link a Package_Closure into the running memory image by
# invoking it with the imported values it needs from other
# packages; the return value is a tuple of the values it
# exports to other packages.
#
# For most packages this call is quick, but a package may
# execute arbitrary code at this point; in particular if
# it is the toplevel package for an application, corresponding
# to a C main.c file, the entire application may execute
# during this call.
# Compiled by:
#
src/lib/compiler/execution/execute.sublib### "Walking on water and developing
### software from a specification
### are both easy if they are frozen."
###
### -- Edward V Berard
/*****************************************************************************
* EXECUTING THE EXECUTABLE *
*****************************************************************************/
stipulate
package cs = code_segment; # code_segment is from
src/lib/compiler/execution/code-segments/code-segment.pkg package it = import_tree; # import_tree is from
src/lib/compiler/execution/main/import-tree.pkg package lt = linking_mapstack; # linking_mapstack is from
src/lib/compiler/execution/linking-mapstack/linking-mapstack.pkg package ph = picklehash; # picklehash is from
src/lib/compiler/front/basics/map/picklehash.pkgherein
api Link_And_Run_Package {
#
exception LINK; # For makelib to
# signal to interactive loop that
# error messages have been issued
# already. The interactive loop
# should simply discard this
# exception (keep quiet) and
# go to the next input prompt.
make_package_closure
:
{ code_and_data_segments: cs::Code_And_Data_Segments,
#
exception_wrapper: Exception -> Exception
}
->
cs::Package_Closure;
link_and_run_package_closure
:
{ package_closure: cs::Package_Closure,
import_trees: List( it::Import_Tree ),
export_picklehash: Null_Or( ph::Picklehash ),
linking_mapstack: lt::Picklehash_To_Heapchunk_Mapstack
}
->
lt::Picklehash_To_Heapchunk_Mapstack;
};
end;
stipulate
package cos = compile_statistics; # compile_statistics is from
src/lib/compiler/front/basics/stats/compile-statistics.pkg package cs = code_segment; # code_segment is from
src/lib/compiler/execution/code-segments/code-segment.pkg package cx = compilation_exception; # compilation_exception is from
src/lib/compiler/front/basics/map/compilation-exception.pkg package imt = import_tree; # import_tree is from
src/lib/compiler/execution/main/import-tree.pkg package it = import_tree; # import_tree is from
src/lib/compiler/execution/main/import-tree.pkg package lt = linking_mapstack; # linking_mapstack is from
src/lib/compiler/execution/linking-mapstack/linking-mapstack.pkg package ph = picklehash; # picklehash is from
src/lib/compiler/front/basics/map/picklehash.pkg package uc = unsafe::unsafe_chunk;
package un = unsafe; # unsafe is from
src/lib/std/src/unsafe/unsafe.pkg package vu1 = vector_of_one_byte_unts; # vector_of_one_byte_unts is from
src/lib/std/src/vector-of-one-byte-unts.pkgherein
package link_and_run_package
: (weak) Link_And_Run_Package
{
exception LINK;
# control_print is from
src/lib/compiler/front/basics/print/control-print.pkg # error_message is from
src/lib/compiler/front/basics/errormsg/error-message.pkg Chunk = uc::Chunk;
say = control_print::say;
fun bug s
=
error_message::impossible ("Execute: " + s);
# This fun is called (only) from:
#
#
src/lib/compiler/execution/compiledfile/compiledfile.pkg #
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg #
fun make_package_closure # Turn the byte-vector-like code segments into an executable closure
{
code_and_data_segments => segs: cs::Code_And_Data_Segments,
exception_wrapper
}
=
{ package_closure
=
cs::make_package_closure segs.code_segment;
package_closure
=
if (vu1::length segs.bytecodes_to_regenerate_literals_vector > 0)
#
(\\ ivec = package_closure (uc::make_tuple (uc::to_tuple ivec @ [cs::make_package_literals_via_bytecode_interpreter segs.bytecodes_to_regenerate_literals_vector ])));
else (\\ ivec = package_closure ivec);
fi;
# Wrap it in given exception_wrapper and we're done:
#
\\ args # Args will include importtree and linkermapstack for this package;
=
package_closure args # Executing this call will link the package into the memory image by providing it with all external values it needs;
except # return value is the tuple of values this package exports for use by later packages -- see run_package_closure below.
e = raise exception exception_wrapper e;
};
# Link the package closure into our memory image by invoking
# it with an argument including its importtree and the linking_mapstack
# tracking previously-linked packages. The return value is the
# tuple of values exports by this package for use by other packages;
# upon return this package is initialized and ready to be called.
#
# For most packages this linking call is quick and simple, but
# if this package is a main program, the complete execution of
# the application will take place before this call returns (if it does):
#
# This fun is called (only) from:
#
#
src/lib/compiler/execution/compiledfile/compiledfile.pkg #
src/lib/compiler/toplevel/interact/read-eval-print-loop-g.pkg #
fun link_and_run_package_closure
{
package_closure: cs::Package_Closure, # Returned from above call.
import_trees: List( it::Import_Tree ), # List of stuff we need to get from other packages.
linking_mapstack: lt::Picklehash_To_Heapchunk_Mapstack, # Stuff we can get from other packages.
export_picklehash: Null_Or( ph::Picklehash ) # Our package 'name', under which our exports can be published for use by other packages.
}
=
{ # Construct a tuple containing all environmental values
# needed by this package. This will include all external
# functions it calls, all external values it uses etc:
#
my imports: Chunk
=
uc::make_tuple
(fold_backward
get_chunk
[]
import_trees
)
where
fun get_ith (pkg, i)
=
uc::nth (pkg, i)
except
_ = bug "unexpected linkage interface in execute";
fun get_chunk ((picklehash, importtree), resultlist)
=
{ # picklehash specifies some external package from which we need to export stuff;
# importtree specifies essentially a list of paths for extracting stuff from p,
# expressed as a tree for efficiency. These paths correspond to
# foo::bar::zot package::(subpackage::)*value paths; at this point
# the sub/package identifiers have all been reduced to simple integer offsets.
# Start by finding the toplevel exports tuple for the given package:
#
pkg = case (lt::get linking_mapstack picklehash)
#
THE pkg => pkg;
#
NULL =>
{ say ("lookup " + (ph::to_hex picklehash) + "\n");
#
raise exception cx::COMPILE "imported values not found or inconsistent";
};
esac;
# Now fetch all needed values from that package
# by traversing that package's exports tree per
# our imports tree:
#
get (pkg, importtree, resultlist);
}
where
fun get (pkg, imt::IMPORT_TREE_NODE [], resultlist)
=>
pkg ! resultlist;
get (pkg, imt::IMPORT_TREE_NODE xl, resultlist)
=>
fold_backward get' resultlist xl
where
fun get' ((i, importtree), resultlist)
=
get (get_ith (pkg, i), importtree, resultlist);
end;
end;
end;
end;
# Let our package initialize itself by memorizing
# all its imports; it will return to us the tree
# of its exports:
#
(package_closure imports) # If this is a main.c sort of package, the entire app execution takes place at this point!
->
(exports: Chunk);
case export_picklehash
#
THE picklehash => lt::singleton (picklehash, exports); # Publish this package's exports under its picklehash.
NULL => lt::empty; # This package exports nothing; presumably it functions entirely by side-effects.
esac;
};
# compile_statistics is from
src/lib/compiler/front/basics/stats/compile-statistics.pkg link_and_run_package_closure
=
cos::do_compiler_phase
(cos::make_compiler_phase "Execute")
link_and_run_package_closure;
};
end;