Changes in / [3f8ab8f:0723a57]


Ignore:
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • doc/papers/general/Paper.tex

    r3f8ab8f r0723a57  
    12201220p2 = &y;  $\C{// p2 points to y}$
    12211221p3 = &p1;  $\C{// p3 points to p1}$
    1222 *p2 = ((*p1 + *p2) * (**p3 - *p1)) / (**p3 - 15);
    12231222\end{cfa}
    12241223
    12251224Unfortunately, the dereference and address-of operators introduce a great deal of syntactic noise when dealing with pointed-to values rather than pointers, as well as the potential for subtle bugs.
    1226 For both brevity and clarity, it would be desirable to have the compiler figure out how to elide the dereference operators in a complex expression such as the assignment to @*p2@ above.
     1225It would be desirable to have the compiler figure out how to elide the dereference operators in a complex expression such as @*p2 = ((*p1 + *p2) * (**p3 - *p1)) / (**p3 - 15);@, for both brevity and clarity.
    12271226However, since C defines a number of forms of \emph{pointer arithmetic}, two similar expressions involving pointers to arithmetic types (\eg @*p1 + x@ and @p1 + x@) may each have well-defined but distinct semantics, introducing the possibility that a user programmer may write one when they mean the other, and precluding any simple algorithm for elision of dereference operators.
    12281227To solve these problems, \CFA introduces reference types @T&@; a @T&@ has exactly the same value as a @T*@, but where the @T*@ takes the address interpretation by default, a @T&@ takes the value interpretation by default, as below:
     
    12491248
    12501249Secondly, unlike the references in \CC which always point to a fixed address, \CFA references are rebindable.
    1251 This allows \CFA references to be default-initialized (\eg to a null pointer), and also to point to different addresses throughout their lifetime.
     1250This allows \CFA references to be default-initialized (to a null pointer), and also to point to different addresses throughout their lifetime.
    12521251This rebinding is accomplished without adding any new syntax to \CFA, but simply by extending the existing semantics of the address-of operator in C.
    12531252In C, the address of a lvalue is always a rvalue, as in general that address is not stored anywhere in memory, and does not itself have an address.
     
    12751274The syntactic motivation for this is clearest when considering overloaded operator-assignment, \eg @int ?+=?(int &, int)@; given @int x, y@, the expected call syntax is @x += y@, not @&x += y@.
    12761275
    1277 More generally, this initialization of references from lvalues rather than pointers is an instance of a ``lvalue-to-reference'' conversion rather than an elision of the address-of operator; this conversion can actually be used in any context in \CFA an implicit conversion would be allowed.
    1278 Similarly, use of a the value pointed to by a reference in an rvalue context can be thought of as a ``reference-to-rvalue'' conversion, and \CFA also includes a qualifier-adding ``reference-to-reference'' conversion, analagous to the @T *@ to @const T *@ conversion in standard C.
    1279 The final reference conversion included in \CFA is ``rvalue-to-reference'' conversion, implemented by means of an implicit temporary.
     1276This initialization of references from lvalues rather than pointers can be considered a ``lvalue-to-reference'' conversion rather than an elision of the address-of operator; similarly, use of a the value pointed to by a reference in an rvalue context can be thought of as a ``reference-to-rvalue'' conversion.
     1277\CFA includes one more reference conversion, an ``rvalue-to-reference'' conversion, implemented by means of an implicit temporary.
    12801278When an rvalue is used to initialize a reference, it is instead used to initialize a hidden temporary value with the same lexical scope as the reference, and the reference is initialized to the address of this temporary.
    12811279This allows complex values to be succinctly and efficiently passed to functions, without the syntactic overhead of explicit definition of a temporary variable or the runtime cost of pass-by-value.
     
    12861284One of the strengths of C is the control over memory management it gives programmers, allowing resource release to be more consistent and precisely timed than is possible with garbage-collected memory management.
    12871285However, this manual approach to memory management is often verbose, and it is useful to manage resources other than memory (\eg file handles) using the same mechanism as memory.
    1288 \CC is well-known for an approach to manual memory management that addresses both these issues, Resource Aquisition Is Initialization (RAII), implemented by means of special \emph{constructor} and \emph{destructor} functions; we have implemented a similar feature in \CFA.
    1289 While RAII is a common feature of object-oriented programming languages, its inclusion in \CFA does not violate the design principle that \CFA retain the same procedural paradigm as C.
    1290 In particular, \CFA does not implement class-based encapsulation: neither the constructor nor any other function has privileged access to the implementation details of a type, except through the translation-unit-scope method of opaque structs provided by C.
    1291 
    1292 In \CFA, a constructor is a function named @?{}@, while a destructor is a function named @^?{}@; like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @S s = { ... };@ or @^(s){};@.
    1293 Every constructor and destructor must have a return type of @void@, and its first parameter must have a reference type whose base type is the type of the object the function constructs or destructs.
    1294 This first parameter is informally called the @this@ parameter, as in many object-oriented languages, though a programmer may give it an arbitrary name.
    1295 Destructors must have exactly one parameter, while constructors allow passing of zero or more additional arguments along with the @this@ parameter.
    1296 
    1297 \begin{cfa}
    1298 struct Array {
    1299         int * data;
    1300         int len;
    1301 };
    1302 
    1303 void ?{}( Array& arr ) {
    1304         arr.len = 10;
    1305         arr.data = calloc( arr.len, sizeof(int) );
    1306 }
    1307 
    1308 void ^?{}( Array& arr ) {
    1309         free( arr.data );
    1310 }
    1311 
    1312 {
    1313         Array x;
    1314         `?{}(x);`       $\C{// implicitly compiler-generated}$
    1315         // ... use x
    1316         `^?{}(x);`      $\C{// implicitly compiler-generated}$
    1317 }
    1318 \end{cfa}
    1319 
    1320 In the example above, a \emph{default constructor} (\ie one with no parameters besides the @this@ parameter) and destructor are defined for the @Array@ struct, a dynamic array of @int@.
    1321 @Array@ is an example of a \emph{managed type} in \CFA, a type with a non-trivial constructor or destructor, or with a field of a managed type.
    1322 As in the example, all instances of managed types are implicitly constructed upon allocation, and destructed upon deallocation; this ensures proper initialization and cleanup of resources contained in managed types, in this case the @data@ array on the heap.
    1323 The exact details of the placement of these implicit constructor and destructor calls are omitted here for brevity, the interested reader should consult \cite{Schluntz17}.
    1324 
    1325 Constructor calls are intended to seamlessly integrate with existing C initialization syntax, providing a simple and familiar syntax to veteran C programmers and allowing constructor calls to be inserted into legacy C code with minimal code changes.
    1326 As such, \CFA also provides syntax for \emph{copy initialization} and \emph{initialization parameters}:
    1327 
    1328 \begin{cfa}
    1329 void ?{}( Array& arr, Array other );
    1330 
    1331 void ?{}( Array& arr, int size, int fill );
    1332 
    1333 Array y = { 20, 0xDEADBEEF }, z = y;
    1334 \end{cfa}
    1335 
    1336 Copy constructors have exactly two parameters, the second of which has the same type as the base type of the @this@ parameter; appropriate care is taken in the implementation to avoid recursive calls to the copy constructor when initializing this second parameter.
    1337 Other constructor calls look just like C initializers, except rather than using field-by-field initialization (as in C), an initialization which matches a defined constructor will call the constructor instead.
    1338 
    1339 In addition to initialization syntax, \CFA provides two ways to explicitly call constructors and destructors.
    1340 Explicit calls to constructors double as a placement syntax, useful for construction of member fields in user-defined constructors and reuse of large storage allocations.
    1341 While the existing function-call syntax works for explicit calls to constructors and destructors, \CFA also provides a more concise \emph{operator syntax} for both:
    1342 
    1343 \begin{cfa}
    1344 Array a, b;
    1345 (a){};                                  $\C{// default construct}$
    1346 (b){ a };                               $\C{// copy construct}$
    1347 ^(a){};                                 $\C{// destruct}$
    1348 (a){ 5, 0xFFFFFFFF };   $\C{// explicit constructor call}$
    1349 \end{cfa}
    1350 
    1351 To provide a uniform type interface for @otype@ polymorphism, the \CFA compiler automatically generates a default constructor, copy constructor, assignment operator, and destructor for all types.
    1352 These default functions can be overridden by user-generated versions of them.
    1353 For compatibility with the standard behaviour of C, the default constructor and destructor for all basic, pointer, and reference types do nothing, while the copy constructor and assignment operator are bitwise copies; if default zero-initialization is desired, the default constructors can be overridden.
    1354 For user-generated types, the four functions are also automatically generated.
    1355 @enum@ types are handled the same as their underlying integral type, and unions are also bitwise copied and no-op initialized and destructed.
    1356 For compatibility with C, a copy constructor from the first union member type is also defined.
    1357 For @struct@ types, each of the four functions are implicitly defined to call their corresponding functions on each member of the struct.
    1358 To better simulate the behaviour of C initializers, a set of \emph{field constructors} is also generated for structures.
    1359 A constructor is generated for each non-empty prefix of a structure's member-list which copy-constructs the members passed as parameters and default-constructs the remaining members.
    1360 To allow users to limit the set of constructors available for a type, when a user declares any constructor or destructor, the corresponding generated function and all field constructors for that type are hidden from expression resolution; similarly, the generated default constructor is hidden upon declaration of any constructor.
    1361 These semantics closely mirror the rule for implicit declaration of constructors in \CC\cite[p.~186]{ANSI98:C++}.
    1362 
    1363 In rare situations user programmers may not wish to have constructors and destructors called; in these cases, \CFA provides an ``escape hatch'' to not call them.
    1364 If a variable is initialized using the syntax \lstinline|S x @= {}| it will be an \emph{unmanaged object}, and will not have constructors or destructors called.
    1365 Any C initializer can be the right-hand side of an \lstinline|@=| initializer, \eg  \lstinline|Array a @= { 0, 0x0 }|, with the usual C initialization semantics.
    1366 In addition to the expressive power, \lstinline|@=| provides a simple path for migrating legacy C code to \CFA, by providing a mechanism to incrementally convert initializers; the \CFA design team decided to introduce a new syntax for this escape hatch because we believe that our RAII implementation will handle the vast majority of code in a desirable way, and we wished to maintain familiar syntax for this common case.
     1286\CC is well-known for an approach to manual memory management that addresses both these issues, Resource Allocation Is Initialization (RAII), implemented by means of special \emph{constructor} and \emph{destructor} functions; we have implemented a similar feature in \CFA.
     1287
     1288\TODO{Fill out section. Mention field-constructors and at-equal escape hatch to C-style initialization. Probably pull some text from Rob's thesis for first draft.}
     1289
    13671290
    13681291\subsection{Default Parameters}
  • src/libcfa/bits/defs.h

    r3f8ab8f r0723a57  
    1 //
     1// 
    22// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 //
    7 // defs.h --
    8 //
     6// 
     7// defs.h -- 
     8// 
    99// Author           : Thierry Delisle
    1010// Created On       : Thu Nov  9 13:24:10 2017
     
    1212// Last Modified On : Tue Jan  2 09:17:06 2018
    1313// Update Count     : 2
    14 //
     14// 
    1515
    1616#pragma once
     
    3434
    3535#ifdef __cforall
    36 #ifndef __NO_ABORT_OVERLOAD
    37 void abort ( const char fmt[], ... ) __attribute__ ((__nothrow__, __leaf__, __noreturn__));
    38 #endif
    3936extern "C" {
    4037#endif
  • src/libcfa/interpose.c

    r3f8ab8f r0723a57  
    2828}
    2929
    30 #define __NO_ABORT_OVERLOAD // no abort overload avoid ambiguities
    3130#include "bits/debug.h"
    3231#include "bits/defs.h"
    3332#include "bits/signal.h"
    3433#include "startup.h"
    35 
    36 //=============================================================================================
    37 // Interposing helpers
    38 //=============================================================================================
    3934
    4035typedef void (*generic_fptr_t)(void);
     
    7469}
    7570
     71
     72__typeof__( exit ) libc_exit __attribute__(( noreturn ));
     73__typeof__( abort ) libc_abort __attribute__(( noreturn ));
     74
    7675forall(dtype T)
    77 static inline void ptr_from_symbol( T** symbol_ptr, const char * symbol_name, const char * version) {
     76static inline void assign_ptr( T** symbol_ptr, const char * symbol_name, const char * version) {
    7877        union {
    7978                generic_fptr_t gp;
     
    8685}
    8786
    88 #define INTERPOSE_LIBC( x, ver ) ptr_from_symbol( (void**)&__cabi_libc.x, #x, ver)
    89 
    90 //=============================================================================================
    91 // Terminating Signals logic
    92 //=============================================================================================
     87#define INIT_REALRTN( x, ver ) assign_ptr( (void**)&libc_##x, #x, ver)
    9388
    9489void sigHandler_segv ( __CFA_SIGPARMS__ );
     
    9792void sigHandler_abort( __CFA_SIGPARMS__ );
    9893
    99 struct {
    100         __typeof__( exit  ) exit  __attribute__(( noreturn ));
    101         __typeof__( abort ) abort __attribute__(( noreturn ));
    102 } __cabi_libc;
    103 
    10494extern "C" {
    10595        void __cfaabi_interpose_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_CORE ) ));
     
    10797                const char *version = NULL;
    10898
    109                 INTERPOSE_LIBC( abort, version );
    110                 INTERPOSE_LIBC( exit , version );
     99                INIT_REALRTN( abort, version );
     100                INIT_REALRTN( exit, version );
    111101
    112102                __cfaabi_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO ); // Failure handler
     
    122112//=============================================================================================
    123113
    124 // Forward declare abort after the __typeof__ call to avoid ambiguities
    125 void abort ( const char fmt[], ... ) __attribute__ ((__nothrow__, __leaf__, __noreturn__));
    126 
    127114extern "C" {
    128115        void abort( void ) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) {
     
    130117        }
    131118
    132         void abortf( const char fmt[], ... ) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) {
    133                 va_list argp;
    134                 va_start( argp, fmt );
    135                 abort( fmt, argp );
    136                 va_end( argp );
    137         }
    138 
    139119        void exit( int __status ) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) {
    140                 __cabi_libc.exit(__status);
    141         }
     120                libc_exit(__status);
     121        }
     122}
     123
     124void abort( const char fmt[], ... ) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) {
     125        va_list argp;
     126        va_start( argp, fmt );
     127        abortf( fmt, argp );
     128        va_end( argp );
    142129}
    143130
     
    150137static int abort_lastframe;
    151138
    152 void abort( const char fmt[], ... ) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) {
    153         void * kernel_data = kernel_abort();                    // must be done here to lock down kernel
    154         int len;
    155 
    156         abort_lastframe = kernel_abort_lastframe();
    157         len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
    158         __cfaabi_dbg_bits_write( abort_text, len );
    159 
    160         if ( fmt ) {
    161                 va_list args;
    162                 va_start( args, fmt );
    163 
    164                 len = vsnprintf( abort_text, abort_text_size, fmt, args );
    165                 va_end( args );
     139extern "C" {
     140        void abortf( const char fmt[], ... ) __attribute__ ((__nothrow__, __leaf__, __noreturn__)) {
     141                void * kernel_data = kernel_abort();                    // must be done here to lock down kernel
     142                int len;
     143
     144                abort_lastframe = kernel_abort_lastframe();
     145                len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
    166146                __cfaabi_dbg_bits_write( abort_text, len );
    167147
    168                 if ( fmt[strlen( fmt ) - 1] != '\n' ) {         // add optional newline if missing at the end of the format text
    169                         __cfaabi_dbg_bits_write( "\n", 1 );
    170                 }
    171         }
    172 
    173         kernel_abort_msg( kernel_data, abort_text, abort_text_size );
    174         __cabi_libc.abort();
     148                if ( fmt ) {
     149                        va_list args;
     150                        va_start( args, fmt );
     151
     152                        len = vsnprintf( abort_text, abort_text_size, fmt, args );
     153                        va_end( args );
     154                        __cfaabi_dbg_bits_write( abort_text, len );
     155
     156                        if ( fmt[strlen( fmt ) - 1] != '\n' ) {         // add optional newline if missing at the end of the format text
     157                                __cfaabi_dbg_bits_write( "\n", 1 );
     158                        }
     159                }
     160
     161                kernel_abort_msg( kernel_data, abort_text, abort_text_size );
     162                libc_abort();
     163        }
    175164}
    176165
Note: See TracChangeset for help on using the changeset viewer.