Swaroop, Scott (Smith) and I have just had a series of discussions, and
BitC is now once again polymorphic. Swaroop came up with the following
lovely example program explaining why overloading was a really bad idea
(adapted from a paper by Andrew Wright):

(define count (mutable 0))

(define f1
  (lambda (f)
    (local ((define x (mutable 0))
            (define f2 (lambda (y)
                         (set! x (+ x 1))
                         (set! count x)
                         (f y))))
       f2)))

(define f3 (f1 (lambda (x) x)))

(f3 1:int) ; count = 1
(f3 2:int) ; count = 2
(f3 3:int) ; count = 3
(f3 #t)    ; count = 0 !!!


Isn't that lovely.


So: BitC is once again polymorphic, and now adopts the ML value-type
polymorphism restriction. This puts us back into the well-understood ML
type system, but it has implications for calling convention.

Consider a procedure

  (define (g x:'a) ... body ...)

If the received parameter x does not have a single size, then we would
need to polyinstantiate the implementation of g, because the code would
need to embed (for example) different parameter offsets. The difficulty
with this is that polyinstantiation of this sort drives you back into
Swaroop's sample problem above.

The proposed resolution is as follows:

BitC is a "call by value" language.

When an actual parameter is passed in a position where the corresponding
formal parameter's type is parameterized (i.e. the type is a type
variable), the implementation shall proceed as follows:

1. The calling procedure shall allocate temporary space on its stack
   to hold the copies that are required to satisfy the call by value
   requirement, and shall make the necessary copies.

2. The calling procedure will then construct a parameter frame
   containing pointers to the copies, and pass these as arguments
   to the callee


Similarly, when a type is declared as having an unboxed member of
parameterized type, instances shall be constructed using the obvious
linearized extension of the above technique for parameter frame
construction 

   Note: Yes, I need to make this precise. I'm just trying to get
   the idea captured for the list.

   The critical thing is to capture the fact that given

The implementation is free to re-inline the field/parameter if it is
able to determine that all instantiations of the parameterized type have
the same representation size. The implementation is NOT REQUIRED to do
this.

Note that this does not create a representation size conflict for
globals, because in the following example:

     (defstruct (s 'a) ( field : (unboxed 'a) ))
     (define some-instance (mutable (unboxed (s 3:int))))

the 'some-instance' binding is not bound to an instance of a value type,
and is therefore assigned a dummy type. This type is immediately unified
with the type (s int), whereupon 'some-instance' is effectively made
monomorphic.


Interlingual Compatibility

Note that the above rule is only triggered by underspecified
(parameterized) types. Thus, in:

  (define (external-proc arg : struct-type-name)
    (declare (suppressed))
    ... dummy body ... )

the formal parameter 'arg' will be expanded directly in the call frame.
This allows structural compatibility to apply when calling, say, C.


shap

_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to