PreviousUpNext

15.4.530  src/lib/compiler/execution/code-segments/code-segment.pkg

## code-segment.pkg

# Compiled by:
#     src/lib/compiler/execution/execute.sublib



# An interface for manipulating code chunks.



###         "The Analytical Engine is not merely adapted
###          for tabulating the results of one particular
###          function and of no other, but for developing
###          and tabulating any function whatever."
###
###                           -- Ada Lovelace, 1842



stipulate
    package bio =  data_file__premicrothread;                                                           # data_file__premicrothread                             is from   src/lib/std/src/posix/data-file--premicrothread.pkg
    package bv  =  vector_of_one_byte_unts;     # "bv" == "bytevector"                  # vector_of_one_byte_unts               is from   src/lib/std/src/vector-of-one-byte-unts.pkg
    package wbv =  rw_vector_of_one_byte_unts;  # "wbv" == "writable bytevector"        # rw_vector_of_one_byte_unts            is from   src/lib/std/src/rw-vector-of-one-byte-unts.pkg
    package un  =  unsafe;                                                              # unsafe                                is from   src/lib/std/src/unsafe/unsafe.pkg
    package uc  =  unsafe::unsafe_chunk;                                                # unsafe_chunk                          is from   src/lib/std/src/unsafe/unsafe-chunk.pkg
    package ci  =  unsafe::mythryl_callable_c_library_interface;                        # mythryl_callable_c_library_interface  is from   src/lib/std/src/unsafe/mythryl-callable-c-library-interface.pkg

herein

    package   code_segment
    :         Code_Segment                                                              # Code_Segment                          is from   src/lib/compiler/execution/code-segments/code-segment.api
    {
        Chunk =   uc::Chunk;

        Code_Segment
            =
            CODE_SEGMENT  {
                entrypoint:     Ref( Int ),
                machinecode_bytevector: wbv::Rw_Vector
            };

        Code_And_Data_Segments
            =
            {   code_segment:                                   Code_Segment,           # The code segment for this compiled file.
                bytecodes_to_regenerate_literals_vector:        bv::Vector              # Re/generates our literals via         src/c/heapcleaner/make-package-literals-via-bytecode-interpreter.c
            };                                                                          # This gets done in                     src/lib/compiler/execution/main/link-and-run-package.pkg

        Package_Closure                                                                 # Package ready to link.
            =
            Chunk -> Chunk;                                                             # Input argument includes importtree and linkermapstack of loaded packages; return value is exports from now-ready-to-be-called package.

        exception FORMAT_ERROR;                                                         # Raised by input when there are insufficient bytes.

        my allot_code:  Int -> wbv::Rw_Vector
            =
            ci::find_c_function                                                         # This isn't a syscall, so there's no reason to use   ci::find_c_function'   instead.
              {
                lib_name => "heap",
                fun_name => "allocate_codechunk"                                        # "allocate_codechunk"                                          def in    src/c/lib/heap/allot-codechunk.c
              };        

        my make_package_literals_via_bytecode_interpreter:  bv::Vector -> Chunk
            =
            ci::find_c_function                                                         # This isn't a syscall and is usually used just at startup, so for now at least I don't think it needs to switch to   ci::find_c_function'
              {
                lib_name => "heap",
                fun_name => "make_package_literals_via_bytecode_interpreter"            # "make_package_literals_via_bytecode_interpreter"              def in    src/c/lib/heap/make-package-literals-via-bytecode-interpreter.c
              };                                                                        #  make_package_literals_via_bytecode_interpreter               def in    src/c/heapcleaner/make-package-literals-via-bytecode-interpreter.c

        my make_codechunk_executable:  (wbv::Rw_Vector, Int) -> Package_Closure         # Int is entrypoint.
            =
            ci::find_c_function                                                         # This *can* be a syscall (flush instruction cache) but it is a no-op on Intel, so for now I won't switch it to      ci::find_c_function'
              {
                lib_name => "heap",
                fun_name => "make_codechunk_executable"                                 # "make_codechunk_executable"                                   def in    src/c/lib/heap/make-codechunk-executable.c
              };



        fun  make_code_segment_of_bytesize  n                                           # Allocate an uninitialized code segment.
            =
            {   if (n <= 0)      raise exception SIZE;    fi;
                #
                CODE_SEGMENT {
                  entrypoint   =>  REF 0,
                  machinecode_bytevector =>  allot_code n
                };
            };

        # Allocate a code segment of the given size and initialize it
        # from the input stream.
        # NOTE: someday, we might read the data directly into the code
        # segment, but this will require hacking around with the reader.                # XXX SUCKO FIXME
        # This fun is called (only) from:
        #
        #     src/lib/compiler/execution/compiledfile/compiledfile.pkg
        # 
        fun read_machinecode_bytevector (instream, bytesize)
            =
            {   (make_code_segment_of_bytesize  bytesize)
                    ->
                    (co as CODE_SEGMENT { machinecode_bytevector, ... } );
                    

                data =  bio::read_n (instream, bytesize);

                if (bv::length data < bytesize)
                    #
                    control_print::say (cat [
                       ".compiled file format error: expected ", int::to_string bytesize,
                       " bytes, but only found ", int::to_string (bv::length data)
                     ]);

                    raise exception FORMAT_ERROR;
                fi;

                wbv::copy_vector  { from => data,  into => machinecode_bytevector,  at => 0 };

                co;
            };




        # This fun is called (only) from:
        #
        #     src/lib/compiler/execution/compiledfile/compiledfile.pkg
        # 
        fun write_machinecode_bytevector_and_flush (outstream, CODE_SEGMENT { machinecode_bytevector, ... } )                           # Write code segment to given output stream.
            =
            {   bio::write (outstream, un::cast machinecode_bytevector);
                #
                bio::flush  outstream;
            };



        
        # This fun is called (only) from:
        #
        #     src/lib/compiler/execution/code-segments/code-segment-buffer.pkg
        #     src/lib/compiler/execution/code-segments/unparse-code-and-data-segments.pkg
        #
        #
        fun get_machinecode_bytevector (CODE_SEGMENT { machinecode_bytevector, ... } )                                                  # View the code segment as an updatable rw_vector of bytes.
            =
            machinecode_bytevector;



        # Build a 1-slot Package_Closure record pointing to given machinecode bytevector.
        # This has the side-effect of flushing the instruction cache.                                                                   # Which is a no-op on Intel32.
        #
        # This function is called (only) from:
        #
        #     src/lib/compiler/execution/main/link-and-run-package.pkg
        #
        fun make_package_closure (CODE_SEGMENT { machinecode_bytevector, entrypoint => REF entrypoint } )
            =
            make_codechunk_executable                                                                                                   # "make_codechunk_executable"                                   def in    src/c/lib/heap/make-codechunk-executable.c
              (
                machinecode_bytevector,
                entrypoint                                                                                                              # This is currently always zero.
              );




        fun get_machinecode_bytevector_size_in_bytes   (CODE_SEGMENT { machinecode_bytevector, ... } )
            =
            wbv::length  machinecode_bytevector;


        fun get_entrypoint (CODE_SEGMENT c)
            =
            *(c.entrypoint);


        fun set_entrypoint (CODE_SEGMENT c,  entrypoint)
            =
            c.entrypoint :=  entrypoint;

    };
end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext