Version française
Home     About     Download     Resources     Contact us    
Browse thread
va_arg values
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Bob Matcuk <Hamartiology@s...>
Subject: va_arg values
I've been wondering what is the best way to write a C function that
takes a variable number of value arguments. Lets say, for example,
that I was writing a function that took an object, a string
(specifying a method on the object), and a variable number of
arguments to pass to the method. The function would then construct an
array (with the object being the first element) from these arguments
and pass it along to caml_callbackN. This function, of course, would
only ever be called by other C functions.

The thing that I guess I'm caught up on is the fact that I cannot
directly apply CAMLparam to these variable arguments. Some calling
conventions place all arguments on the stack, in which case CAMLparamN
could be used (as long as you knew whether the stack was building up
or down). However, some do not do this (the AMD64 calling convention,
for example, puts the first 6 arguments in registers, the rest on the
stack).

I guess the real question is: is it even necessary to worry about this?
The function, as I said, will only ever be called from other C
functions (who have already designated these values as being
params/local to themselves, assuming they are written correctly). I
seem to recall reading somewhere that if you write a function that
will only ever be called from other C functions that have already
registered the values (via CAMLparam/CAMLlocal), then it's
unnecessary to do it again. The function doesn't allocate any new
values either, so it shouldn't trip the GC anyway, right? The function
should, therefore, be something like this:

value func(value obj, char *method, int n, ...)
{
  va_list ap;
  int i;
  value *args = calloc(n + 1, sizeof(value));
  value r;

  args[0] = obj;
  va_start(ap, n);
  for (i = 0; i < n; i++)
    args[i + 1] = va_arg(ap, value);
  va_end(ap);

  r = caml_callbackN(caml_get_public_method(obj, hash_variant(method)),
                     n + 1, args);
  free(args);
  return r;
}

Should probably check calloc for success and maybe throw an exception
if it failed... Which actually brings me to another quick question: if
I throw an exception, say caml_failwith("..."), is it necessary to
still call CAMLreturn after it? Or will the exception cause the
function to exit?

Is it an invalid assumption that it is unnecessary to bother with the
CAMLparam/CAMLlocal stuff since there's nothing to trip the GC? If so,
what is the best way to handle all the CAMLparam/CAMLlocal stuff? For
example, CAMLlocalN(args, n + 1) is invalid because C does not allow
you to declare dynamic arrays. Looping over the arguments with
va_start/for loop/va_arg and calling CAMLparam on them is also invalid
because it would be declaring the caml__root_##x variable within the for
loop. I have typed up some code that should work if it is necessary,
but it's messy and if CAMLparam is ever changed, it's likely I'll need
to change my code too. I want to avoid that.

One last quick question: is the line "args[i + 1] = va_arg(ap, value);"
above legal? args[] is an array of value and va_arg(ap, value) will
return a value. So, essentially, it's the same thing as the assignment
in the following example:

value func(value v1)
{
  value v2 = v1;
  ...
}

I know values are just pointers so it is syntactically correct, but
what I'm asking is: is it safe to do? Should I be using some function
instead to create a copy of the value?

Thanks in advance for any insight!

--
Bob Matcuk
http://www.Squeg.Net/

Explanation of My Return Address, GPG Key:
http://www.Squeg.Net/returnAddr.php

hamartiology - http://www.kokogiak.com/logolepsy/ow_h.html#hamartiology