Changes between Initial Version and Version 1 of Pointers


Ignore:
Timestamp:
07/11/13 13:28:51 (13 years ago)
Author:
siegel
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Pointers

    v1 v1  
     1
     2= Pointers and Scopes =
     3
     4== Scoping goals ==
     5
     6* It should be possible to statically determine the scope of any expression.  That means the expression only references objects in that scope.
     7* It should be possible to specify/verify the "read scope" and "write scope" of any procedure.
     8* The goals above are complicated by pointers, which can potentially to point to any scope if not controlled. So there must be ways to specify/verify some restrictions on the scopes of pointers.
     9
     10== Scopes ==
     11
     12First, scopes are declared like variable declarations:
     13
     14{{{
     15{ ...
     16  $scope s;
     17  …
     18}
     19}}}
     20
     21gives a name to that scope.  In fact, every scope has a name automatically, this just gives the program a way to refer to it.
     22
     23Scopes cannot be used in expressions except as specified below.  In particular they cannot be assigned or passed as arguments to functions.
     24
     25== Pointer types ==
     26
     27* Given any object type T, there is a type "pointer-to-T".
     28* Given in addition a scope s, there is a type "pointer-to-T-in-s".
     29* The type "pointer-to-T-in-s" is a subtype of "pointer-to-T".
     30* The type "pointer-to-T" is identical to the type "pointer-to-T-in-CIVL_Root_scope", where `CIVL_Root_scope` is the root system (most global) scope.
     31* Furthermore, if s1 is contained in s2, "pointer-to-T-in-s1" is a subtype of "pointer-to-T-in-s2".
     32
     33Syntax: a variable is declared to have type "pointer-to-int-in-s", for example, as follows:
     34{{{
     35  int *<s> t;
     36}}}
     37In general, the scope modifier is always placed after the `*` and surrounded by angle brackets.
     38
     39=== Address-of ===
     40
     41The address-of operator `&` returns a pointer of the appropriate subtype using the innermost scope in which its lhs argument is declared.  For example:
     42{{{
     43{
     44  $scope s1;
     45  int x;
     46  double a[N];
     47  int *<s1> p = &x;
     48  double *<s1> q = &a[2];
     49}
     50}}}
     51is legal (it will type-check) because `&x` has type pointer-to-int-in-s1, since `s1` is the scope in which `x` is declared. Etc.
     52
     53=== Pointer addition and subtractions ===
     54
     55if p has type pointer-to-T-in-s, then p+i (for an integer i) has type pointer-to-T-in-s. I.e., pointer addition cannot leave the scope.  (in fact, it cannot leave the object).
     56
     57Pointer subtraction: pointer subtraction is defined on two pointers of the same type, where "same" includes the scope.  That is checked statically.    As in C, it is only defined if the two pointers point to the same object.  In CIVL-C, a runtime error will be thrown if they do not point to the same object.
     58
     59=== Pointer casts ===
     60
     61If scope s1 is contained in scope s2, an expression of type pointer-to-T-in-s1 can always be cast to pointer-to-T-in-s2, because the first is a subtype of the second.  This is checked statically.  The cast in the other direction is also OK, but will only be checked at runtime.  If neither s1 is contained in s2 nor s2 is contained in s1, a cast from one pointer type to the other is illegal and will be reported as a syntax error statically.
     62
     63A type pointer-to-T1-in-s can be cast to a type pointer-to-T2-in-s according to the usual rules of C (or whatever variation is used in CIVL-C). In other words, usual casting rules apply as long as you don't change the scope.
     64
     65== Parameterized typedefs ==
     66
     67typedefs can be parameterized by scopes, e.g.
     68
     69{{{
     70<s> typedef struct message_struct {
     71  int size;
     72  void *<s> data;
     73} Message;
     74}}}
     75
     76When the typedef is used, you specify the scope parameters:
     77
     78{{{
     79Message<s1> buffer[N];
     80}}}
     81
     82For each scope s, you get a different type `Message<s>`.  There is no (subtype or other) relationship between `Message<s1>` and `Message<s2>` and you cannot cast from one to the other.
     83
     84Multiple scopes can be used as parameters:
     85{{{
     86<s1,s2,s3> typedef struct ...
     87}}}
     88
     89== Parameterized procedures ==
     90
     91Procedures can be parameterized by scopes, for example, as follows:
     92{{{
     93<s> int *<s> f(int *<s> p);
     94}}}
     95This means: for any scope s, f takes a pointer-to-int-in-s and returns a pointer-to-int-in-s.  Multiple scopes can be used as parameters: `<s,t>` ....
     96
     97The procedure f is invoked by specifying the scope as follows: ` ... f<s1>(...) …`.  Eventually we can infer the s in most cases.
     98
     99== Procedure contracts ==
     100
     101Procedure contracts can be optionally associated to procedure declarations or definitions in CIVL-C.  There will be typical requires/ensures and other clauses in these contracts. In addition, the following two kinds of clauses can be used:
     102{{{
     103    $reads s1;
     104    $writes s2;
     105}}}
     106where s1 and s2 are scopes.  This means that any object read in any execution of f must lie in scope s1 and any object modified in any execution of f must lie is scope s2.  The scopes s1 and s2 can be parameters, as in:
     107{{{
     108<s1,s2> double *<s2> f(int *<s1> p)
     109  $reads s1;
     110  $writes s2;
     111  {
     112    ...
     113  }
     114 }}}
     115
     116== Heaps ==
     117
     118A heap is declared using the built-in type `$heap`:
     119{{{
     120{ ... $heap h1; …}
     121
     122}}}
     123However, a heap cannot be assigned or used in expressions, with one exception: it can be the argument of address-of (&).  Hence this is fine:
     124
     125{{{
     126{ ...
     127  $scope s1;
     128  $heap h1;
     129  $heap *<s1> p = &h1;
     130  ...
     131}
     132}}}
     133
     134=== Malloc and free ===
     135
     136These built-in functions have the following signatures:
     137{{{
     138<s> void *<s> $malloc($heap *<s> heap, int size)
     139  $reads s;
     140  $writes s;
     141 
     142<s> void $free($heap *<s> heap, void *<s> ptr)
     143  $reads s;
     144  $writes s;
     145}}}
     146
     147This means:
     148* for any scope s, `$malloc` takes a pointer-to-heap-in-s,  and an integer `size`, and returns a pointer-to-void-in-s.
     149* `$free` takes a pointer-to-heap-in-s and a pointer-to-void-in-s, and returns nothing.
     150* both procedures can only read and modify s.
     151
     152A runtime error will be generated if the second argument to `$free` is not really a pointer to the heap specified in the first argument.
     153
     154It may be that the first argument to `$free` is unnecessary. However, it helps keep track of what is modified by the procedure (namely, the heap that that argument points to).  At the very least, we need to keep track of the scope of the heap. Possibly, we could get by with:
     155{{{
     156<s> void $free(void *<s> ptr)
     157  $reads s;
     158  $writes s;
     159}}}
     160
     161== Memcpy ==
     162
     163This is another built-in function with signature:
     164{{{
     165  <s,t> void memcpy(void *<s> p, void *<t> q, size_t size)
     166    $reads t;
     167    $writes s;
     168}}}
     169This copies data from `q` to `p` as usual. 
     170
     171== Examples==
     172
     173
     174{{{
     175{
     176  $scope shared;
     177  $heap shared_heap;
     178  double *<shared> p = $malloc<shared>(&shared_heap, n*sizeof(double));
     179  double *<shared> q = $malloc<shared>(&shared_heap, n*sizeof(double));
     180
     181  for (int i=0; i<n; i++) p[i] = (double)i;
     182  $memcpy<shared,shared>(p, q, n*sizeof(double));
     183  $free<shared>(&shared_heap, p);
     184  $free<shared>(&shared_heap, q);
     185}
     186}}}
     187
     188Here is how an MPI program can be modeled with every process getting its own heap:
     189
     190{{{
     191void MPI_proc(int pid) {
     192  $scope proc_scope;
     193  $heap proc_heap;
     194  ...
     195  ... $malloc<proc_scope>(&proc_heap, size) ...
     196  ...
     197}
     198
     199void main(int nprocs) {
     200  $proc procs[nprocs];
     201 
     202  for (int i=0; i<nprocs; i++)
     203    procs[i] = $spawn MPI_proc(i);
     204  ...
     205}
     206}}}