PreviousUpNext

15.4.536  src/lib/compiler/execution/main/link-and-run-package.pkg

## 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.pkg
herein

    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.pkg
herein

    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;



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext