Previous Up Next

Chapter 13  The Moby compilation environment

The Moby compiler is a batch compiler that processes one file at a time. At the same time, it implements a language that requires intermodule typechecking. To support intermodule typechecking, as well as the propagation of other kinds of information between compilation units, the Moby compiler relies on a persistant compilation environment. In the current implementation, the compilation environment is stored in MBI files and the persistence is provided by the host file system.

13.1  Groups and the filemap

Moby programs are organized into groups of modules and signatures (sometimes these groups are called libraries). For each group, there is a filemap that maps the signature and module names of the group to its source file. Effectively, the filemap serves as the top-level index for the group.

A filemap is a text file with the following simple syntax:
FileMap
::= (UnitSpec FileName ;)*
UnitSpec
::= module Identifier
| signature Identifier
While it is possible to create and edit a filemap using a text editor, they are usually generated by the moby-depend tool.

13.2  MBI files

MBI files are binary files that contain information about previously compiled Moby code and Moby libraries. Information contained in an MBI file includes: An MBI file is structured as an indexed collection of varying-length records. At the beginning of the file is a header that provides summary information about the MBI file (e.g., target architecture, is multi-threading supported, etc.). Following the header is a dictionary that maps stamps to the records that make up the content of the MBI file. Each dictionary entry contains three pieces of information: the name of the entry, the kind of the entry, and its byte offset in the file.
ASDL
give a list of different entry kinds
For example, consider the following small Moby module:
module M { datatype T { C of Int } val x : T = C(5) }
It can be represented by the following MBI file:
Stamp Name Kind Contents
0 M DK_MODULE decls: [1, 5, 6]
1 T DK_TYPE
TD_DATA:
 owner: 0
 cons: [(C, [T_CON(3, [])])]
2 Int DK_XTYPE owner: 3
3 Int DK_XMODULE owner: 4
4 moby-basis DK_LIBRARY guid: "..."
5 C DK_CON
DC_DATA:
 stamp: 1
 id: 0
6 x DK_VAL
owner: 0
ty: T_CON(1, [])
The first entry in this MBI file is for the module M. It contains a list of the names declared in the module (this list includes the constructor C, which is part of T's declaration). The second entry is for the datatype T; this entry contains the type's owner (M) and a list of the constructors. For each constructor, we have the constructor name with its list of argument types. In this case, there is one constructor (C) with an argument type of Int, which is described by the third entry. The Int type is defined in another MBI file, so it's kind is DK_XTYPE and it's entry contains the stamp of its owner, which is the externally defined Int module. The fourth entry describes the Int module as being defined in the moby-basis library, which is described by the fifth entry. For the moby-basis library, the MBI file records is GUID (Globally Unique ID). The full name of the Int type is then the pair of its library's GUID and the path Int.Int. These full names are globally unique and are used to preserve sharing between modules that might reference the same external types. The sixth entry describes the constructor C; the entry's contents lists the stamp of the owning datatype and the index of the constructor in the datatype's list of constructors. The seventh, and last, entry describes the value identifier x. Its contents includes the owner (M) and the type of the identifier.
BOL
Overloading

13.3  MBX files

This section, describes the syntax of MBX files, which are an ASCII representation of MBI files, and which are used to implement ``native'' Moby modules. The gen-mbi tool translates MBX files to their binary MBI representation and the dump-mbi prints a textual representation of an MBI file.

13.3.1  Basic structure of an MBX file

An MBX file consists of one or more units. There are two kinds of units: a module, which defines the interface and possibly implementation of a Moby compilation unit; and a pervasive unit, which defines top-level bindings and overload schemas.
MBXFile
::= (MBXUnit)+
MBXUnit
::= %module ModuleId Guid { Decl* }
| %pervasive Guidopt { PervDecl* }
Decl
::= TypeDecl
PervDecl
::= OverloadDecl

13.3.2  Overloading specifications

OverloadDecl
::= %overload ValId : TyScheme
| %bind ValId : TyScheme = ValSpec

13.3.3  Specifying types

TypeDecl
::= %type TypeId TyParamsopt = %prim BOLType
| %type TypeId TyParamsopt = Type
| %enumtype TypeId { NullaryDataCons }
| %datatype TypeId TyParamsopt { DataCons }
| %objtype TypeId TyParamsopt { ObjMemberList }
| %tagtype TypeId TyParamsopt
| %tagtype TypeId TyParamsopt %of OneOrMoreTys
| %tagtype TypeId TyParamsopt %extends NamedTy
| %tagtype TypeId TyParamsopt %of OneOrMoreTys %extends NamedTy

13.3.4  Specifying BOL types

The BOL representation has a simple (and incomplete) type system that is described in Section 6.1. BOL types are the primitive types in the Moby compiler and are very close to machine representation. We use MBX files to establish a binding between abstract Moby types, such as Int, and their underlying machine representation as described by a BOL type. The syntax of BOL types in an MBX file is as follows:
BOLType
::= %any
| %unit
| %bool
| %int8
| %int16
| %int32
| %int64
| %integer
| %enum ( Num , Num )
| %float
| %double
| %extended
| %ptr BOLHeapType
| %seq BOLHeapType
BOLHeapType
::= %object
| %closure
| %struct Num ( BOLFieldType (, BOLFieldType)* )
BOLFieldType
::= Num : BOLType ([ Num ])opt

13.3.5  Value bindings

ValueDecl
::= %val ValId : TyScheme (= PrimValue)opt
| %val ValId : TyScheme = ValSpec
PrimValue
::= %prim PrimOp
| %prim BOLFunction
ValSpec
::= Pathopt ValId

The form ``%prim PrimOp'' is syntactic sugar for a function definition that applies PrimOp to its arguments. For example, the definitions
%val add : (Int, Int) -> Int = %prim I32Add %val div : (Int, Int) -> Int = %prim I32Div
are expanded into the following:
%val add : (Int, Int) -> Int = %prim add (a : %int32, b : %int32, ex) { %let c : %int32 = I32Add(a, b) %return (c) } %val div : (Int, Int) -> Int = %prim div (a : %int32, b : %int32, ex) { %let c : %int32 = I32Div(a, b, ex) %return (c) }
Note that in the case of the add function, the exception handler continuation is ignored, whereas it is passed as an argument to the I32Div operator in the case of the div function. This specialization is supported by comparing the arity of the Moby type on the lhs with the arity and signature of the operator on the rhs.

13.3.6  Specifying BOL code

BOLFunction
::= Var Params BOLBlock
BOLBlock
::= { BOLStmt }
BOLExpr
::= BOLBlock
| TailExpr
BOLStmt
::= TailExpr
| %let Binding BOLStmt
| %fun BOLFunction (%and BOLFunction)* BOLStmt
| %cont BOLFunction BOLStmt
| %stack Var ( Int , Int ) : BOLType BOLStmt
TailExpr
::= %if Var %then BOLExpr %else BOLExpr
| %switch Var Case+ (%default : BOLExpr)opt
| %call Var ( Var (, Var)* )
| %ccall CFun Convention ( Var (, Var)* )
| %throw Var ( Var (, Var)* )
| %return Terms
Case
::= %case Num : BOLExpr
Binding
::= Params = BOLExpr
| Param = # Num Var
| Param = %alloc ( BOLField (, BOLField)* )
| Param = BOLTerm
| Param = %meth Var . Label
| Param = %field Var . Label
| Param = %meth Var
| Param = %field Var
| Param = %meth Var @ Var
| Param = %field Var @ Var
| _ = %field Var @ Var := Var
BOLTerm
::= PrimOp BOLTerms
| Var
| Constant
BOLTerms
::= ( (BOLTerm (, BOLTerm)*)opt )
BOLField
::= Num : Var
Params
::= _
| ParamList
ParamList
::= Param
| ( Param (, Param)* )
Param
::= Var (: BOLType)opt

13.3.7  The comp-env library

The comp-env library (located in src/comp-env) provides low-level support for reading and writing MBI files.

13.3.8  The gen-mbi tool

13.3.9  Future directions

The current scheme does not allow generation of object files from MBX specifications; all code can only be accessed via inlining. This restriction may be too limiting for supporting the Moby foreign interface.
Previous Up Next