guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

VM module design


From: Keisuke Nishida
Subject: VM module design
Date: Wed, 21 Feb 2001 05:02:48 -0500
User-agent: Wanderlust/2.4.0 (Rio) SEMI/1.13.7 (Awazu) FLIM/1.13.2 (Kasanui) Emacs/21.0.96 (i686-pc-linux-gnu) MULE/5.0 (SAKAKI)

Hello,

Just some design notes for my VM module system.

Modules and Packages
--------------------

Modules have bindings from identifiers to objects.
Packages have bindings from identifiers to modules or other packages.

There is a root package named `~'.  Suppose the following module
hierarchy (P - package  M - module):

  ~ [P]
    foo [M]
    lib [P]
      bar [M]
      baz [M]

The module `bar' can be represented by notation "~:lib:bar"

Bindings in modules are defined by syntax `define' (in case of Scheme).
Bindings in packages are defined by file or directory names.


Module Creation
---------------

  ---- root/foo.scm ------------
  (define-module foo)
  ...
  ------------------------------

`define-module' creates a new module `foo' in the current package `~'.
The module name is visible in the module itself, referring to itself:

  ------------------------------
  address@hidden> (define-module foo)
  ~:foo
  address@hidden> foo
  $1 = #<module ~:foo>
  ------------------------------

A module has local variables and public interface.  Variables
in the public interface are visible from other modules.

Local variables are defined as usual.  Public variables are
defined with a prefix of the module name:

  ---- root/foo.scm ------------
  (define-module foo)

  (define x 1)      ;; local variable
  (define foo:y 2)  ;; public variable
  ------------------------------

Public variables are accessible without the prefix in the module.
Local variables are accessible with the prefix if one wants.


External modules
----------------

  ---- root/lib/bar.scm --------
  (define-module bar)

  (define bar:x 1)
  ------------------------------

  ---- root/lib/baz.scm --------
  (define-module baz)

  (define baz:y 2)
  ------------------------------

These modules are accessible in `foo' in the following two ways:

  ---- root/foo.scm ------------
  (define-module foo
    :use ~:lib:bar
    :import lib:baz)
  ...
  ------------------------------

Modules can be specified by either absolute or relative names.
Keyword `:use' does not import any variables except the module
itself.  Keyword `:import' imports all public variables defined
in the module specified.

  ------------------------------
  address@hidden> (define-module foo
                 :use lib:bar
                 :import lib:baz)
  ~:foo
  address@hidden> bar
  $1 = #<module ~:lib:bar>
  address@hidden> baz
  ERROR: Unbound variable: baz
  address@hidden> x
  ERROR: Unbound variable: x
  address@hidden> y
  $2 = 2
  ------------------------------

Variables defined in `bar' are accessible as follows:

  ------------------------------
  address@hidden> bar:x
  $3 = 1
  ------------------------------

The use of `:use' is more reliable in the sense that all importing
variables are accessed through the module prefix.  On the other hand,
the use of `:import' is more convenient if you are familiar with
the variables defined in that module.


Compilation
-----------

At the beginning of compilation, top level variables are globally
identified in the module hierarchy and transformed as follows:

  (define-module foo)

  bar  ->  ~:foo:bar

The notation "~:foo:bar" is expanded as follows:

  ~:foo:bar  ->  (lookup (lookup ~ 'foo) 'bar)

`lookup' is a function that resolves bindings in a given module
or a package.  If the compiler finds that a binding can be
statically solved, it optimizes it and eliminates runtime
`lookup's.

There is a case, however, the compiler cannot eliminate a
`lookup', as shown in the following example:

  (let ((module (lookup-module some-name)))
    module:foo)     ;; -> (lookup module 'foo)


Autoloading
-----------

There is no special syntax for autoloading; all modules are
automatically loaded on demand, at the cost of one branch in
every top-level variable access.

Global variables are stored in bytecode by symbolic names
like "foo:bar".  These names are linked with variables at run
time, not loading time.  The VM checks if a variable is already
loaded, and if not, it loads a module, find the variable, and
stores it in the bytecode.

I think this is okay because 1) it costs only one `if' in C
2) top-level variable access is relatively rare among the
overall VM activity 3) improvement of loading speed is more
preferable than that of execution speed 4) we can simply
forget about autoloadings.


I'm going to implement these stuff from now on.

Kei



reply via email to

[Prev in Thread] Current Thread [Next in Thread]