mframe.m
上传用户:shenzhenrh
上传日期:2013-05-12
资源大小:2904k
文件大小:52k
源码类别:

信息检索与抽取

开发平台:

Unix_Linux

  1. /* Implementation of functions for dissecting/making method calls 
  2.    Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
  3.    
  4.    Written by:  Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
  5.    Created: Oct 1994
  6.    
  7.    This file is part of the GNUstep Base Library.
  8.    This library is free software; you can redistribute it and/or
  9.    modify it under the terms of the GNU Library General Public
  10.    License as published by the Free Software Foundation; either
  11.    version 2 of the License, or (at your option) any later version.
  12.    
  13.    This library is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.    Library General Public License for more details.
  17.    
  18.    You should have received a copy of the GNU Library General Public
  19.    License along with this library; if not, write to the Free
  20.    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.    */ 
  22. /* These functions can be used for dissecting and making method calls
  23.    for many different situations.  They are used for distributed
  24.    objects; they could also be used to make interfaces between
  25.    Objective C and Scheme, Perl, Tcl, or other languages.
  26. */
  27. #include <objc/objc-api.h>
  28. #if defined(__hpux__) && defined(HAVE_SYS_SIGEVENT_H)
  29. #include <sys/sigevent.h>
  30. #endif
  31. BOOL sel_types_match (const char* t1, const char* t2);
  32. #include <objc/mframe.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. /* Deal with strrchr: */
  36. #if STDC_HEADERS || HAVE_STRING_H
  37. #include <string.h>
  38. /* An ANSI string.h and pre-ANSI memory.h might conflict.  */
  39. #if !STDC_HEADERS && HAVE_MEMORY_H
  40. #include <memory.h>
  41. #endif /* not STDC_HEADERS and HAVE_MEMORY_H */
  42. #define index strchr
  43. #define rindex strrchr
  44. #define bcopy(s, d, n) memcpy ((d), (s), (n))
  45. #define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
  46. #define bzero(s, n) memset ((s), 0, (n))
  47. #else /* not STDC_HEADERS and not HAVE_STRING_H */
  48. #include <strings.h>
  49. /* memory.h and strings.h conflict on some systems.  */
  50. #endif /* not STDC_HEADERS and not HAVE_STRING_H */
  51. void *alloca (size_t);
  52. #define inline
  53. /* For encoding and decoding the method arguments, we have to know where
  54.    to find things in the "argframe" as returned by __builtin_apply_args.
  55.    For some situations this is obvious just from the selector type 
  56.    encoding, but structures passed by value cause a problem because some
  57.    architectures actually pass these by reference, i.e. use the
  58.    structure-value-address mentioned in the gcc/config/_/_.h files.
  59.    These differences are not encoded in the selector types.
  60.    Below is my current guess for which architectures do this.
  61.    xxx I really should do this properly by looking at the gcc config values.
  62.    I've also been told that some architectures may pass structures with
  63.    sizef(structure) > sizeof(void*) by reference, but pass smaller ones by
  64.    value.  The code doesn't currently handle that case.
  65.    */
  66. char*
  67. mframe_build_signature(const char *typePtr, int *size, int *narg, char *buf)
  68. {
  69.   MFRAME_ARGS cum;
  70.   BOOL doMalloc = NO;
  71.   const char *types;
  72.   char *start;
  73.   char *dest;
  74.   int total = 0;
  75.   int count = 0;
  76.   /*
  77.    * If we have not been given a buffer - allocate space on the stack for
  78.    * the largest concievable type encoding.
  79.    */
  80.   if (buf == 0)
  81.     {
  82.       doMalloc = YES;
  83.       buf = alloca((strlen(typePtr)+1)*16);
  84.     }
  85.   /*
  86.    * Copy the return type info (including qualifiers) into the buffer.
  87.    */
  88.   types = objc_skip_typespec(typePtr);
  89.   strncpy (buf, typePtr, types - typePtr);
  90.   buf[types-typePtr] = ''; 
  91.   /*
  92.    * Point to the return type, initialise size of stack args, and skip
  93.    * to the first argument.
  94.    */
  95.   types = objc_skip_type_qualifiers(typePtr);
  96.   MFRAME_INIT_ARGS(cum, types);
  97.   types = objc_skip_typespec(types);
  98.   if (*types == '+')
  99.     {
  100.       types++;
  101.     }
  102.   while (isDigit (*types))
  103.     types++;
  104.   /*
  105.    * Where to start putting encoding information - leave enough room for
  106.    * the size of the stack args to be stored after the return type.
  107.    */
  108.   start = &buf[strlen(buf)+10];
  109.   dest = start;
  110.   /*
  111.    * Now step through all the arguments - copy any type qualifiers, but
  112.    * let the macro write all the other info into the buffer.
  113.    */
  114.   while (types && *types)
  115.     {
  116.       const char *qual = types;
  117.       /*
  118.        * If there are any type qualifiers - copy the through to the
  119.        * destination.
  120.        */
  121.       types = objc_skip_type_qualifiers(types);
  122.       while (qual < types)
  123. {
  124.   *dest++ = *qual++;
  125. }
  126.       MFRAME_ARG_ENCODING(cum, types, total, dest);
  127.       count++;
  128.     }
  129.   *dest = '';
  130.   /*
  131.    * Write the total size of the stack arguments after the return type,
  132.    * then copy the remaining type information to fill the gap.
  133.    */
  134.   sprintf(&buf[strlen(buf)], "%d", total);
  135.   dest = &buf[strlen(buf)];
  136.   while (*start)
  137.     {
  138.       *dest++ = *start++;
  139.     }
  140.   *dest = '';
  141.   /*
  142.    * If we have written into a local buffer - we need to allocate memory
  143.    * in which to return our result.
  144.    */
  145.   if (doMalloc)
  146.     {
  147.       char *tmp = objc_malloc(dest - buf + 1);
  148.       strcpy(tmp, buf);
  149.       buf = tmp;
  150.     }
  151.   /*
  152.    * If the caller wants to know the total size of the stack and/or the
  153.    * number of arguments, return them in the appropriate variables.
  154.    */
  155.   if (size)
  156.     {
  157.       *size = total;
  158.     }
  159.   if (narg)
  160.     {
  161.       *narg = count;
  162.     }
  163.   return buf;
  164. }
  165. /*
  166.  *      Step through method encoding information extracting details.
  167.  */
  168. const char *
  169. mframe_next_arg(const char *typePtr, NSArgumentInfo *info)
  170. {
  171.   NSArgumentInfo local;
  172.   BOOL flag;
  173.   if (info == 0)
  174.     {
  175.       info = &local;
  176.     }
  177.   /*
  178.    * Skip past any type qualifiers - if the caller wants them, return them.
  179.    */
  180.   flag = YES;
  181.   info->qual = 0;
  182.   while (flag)
  183.     {
  184.       switch (*typePtr)
  185. {
  186.   case _C_CONST:  info->qual |= _F_CONST; break;
  187.   case _C_IN:     info->qual |= _F_IN; break;
  188.   case _C_INOUT:  info->qual |= _F_INOUT; break;
  189.   case _C_OUT:    info->qual |= _F_OUT; break;
  190.   case _C_BYCOPY: info->qual |= _F_BYCOPY; break;
  191. #ifdef _C_BYREF
  192.   case _C_BYREF:  info->qual |= _F_BYREF; break;
  193. #endif
  194.   case _C_ONEWAY: info->qual |= _F_ONEWAY; break;
  195.   default: flag = NO;
  196. }
  197.       if (flag)
  198. {
  199.   typePtr++;
  200. }
  201.     }
  202.   info->type = typePtr;
  203.   /*
  204.    * Scan for size and alignment information.
  205.    */
  206.   switch (*typePtr++)
  207.     {
  208.       case _C_ID:
  209. info->size = sizeof(id);
  210. info->align = __alignof__(id);
  211. break;
  212.       case _C_CLASS:
  213. info->size = sizeof(Class);
  214. info->align = __alignof__(Class);
  215. break;
  216.       case _C_SEL:
  217. info->size = sizeof(SEL);
  218. info->align = __alignof__(SEL);
  219. break;
  220.       case _C_CHR:
  221. info->size = sizeof(char);
  222. info->align = __alignof__(char);
  223. break;
  224.       case _C_UCHR:
  225. info->size = sizeof(unsigned char);
  226. info->align = __alignof__(unsigned char);
  227. break;
  228.       case _C_SHT:
  229. info->size = sizeof(short);
  230. info->align = __alignof__(short);
  231. break;
  232.       case _C_USHT:
  233. info->size = sizeof(unsigned short);
  234. info->align = __alignof__(unsigned short);
  235. break;
  236.       case _C_INT:
  237. info->size = sizeof(int);
  238. info->align = __alignof__(int);
  239. break;
  240.       case _C_UINT:
  241. info->size = sizeof(unsigned int);
  242. info->align = __alignof__(unsigned int);
  243. break;
  244.       case _C_LNG:
  245. info->size = sizeof(long);
  246. info->align = __alignof__(long);
  247. break;
  248.       case _C_ULNG:
  249. info->size = sizeof(unsigned long);
  250. info->align = __alignof__(unsigned long);
  251. break;
  252. #ifdef _C_LNG_LNG
  253.       case _C_LNG_LNG:
  254. info->size = sizeof(long long);
  255. info->align = __alignof__(long long);
  256. break;
  257.       case _C_ULNG_LNG:
  258. info->size = sizeof(unsigned long long);
  259. info->align = __alignof__(unsigned long long);
  260. break;
  261. #endif
  262.       case _C_FLT:
  263. info->size = sizeof(float);
  264. info->align = __alignof__(float);
  265. break;
  266.       case _C_DBL:
  267. info->size = sizeof(double);
  268. info->align = __alignof__(double);
  269. break;
  270.       case _C_PTR:
  271. info->size = sizeof(char*);
  272. info->align = __alignof__(char*);
  273. if (*typePtr == '?')
  274.   {
  275.     typePtr++;
  276.   }
  277. else
  278.   {
  279.     typePtr = mframe_next_arg(typePtr, &local);
  280.     info->isReg = local.isReg;
  281.     info->offset = local.offset;
  282.   }
  283. break;
  284.       case _C_ATOM:
  285.       case _C_CHARPTR:
  286. info->size = sizeof(char*);
  287. info->align = __alignof__(char*);
  288. break;
  289.       case _C_ARY_B:
  290. {
  291.   int length = atoi(typePtr);
  292.   while (isDigit (*typePtr))
  293.             typePtr++;
  294.   typePtr = mframe_next_arg(typePtr, &local);
  295.   info->size = length * ROUND(local.size, local.align);
  296.   info->align = local.align;
  297.   typePtr++; /* Skip end-of-array */
  298. }
  299. break; 
  300.       case _C_STRUCT_B:
  301. {
  302.   struct { int x; double y; } fooalign;
  303.   int acc_size = 0;
  304.   int acc_align = __alignof__(fooalign);
  305.   /*
  306.    * Skip "<name>=" stuff.
  307.    */
  308.   while (*typePtr != _C_STRUCT_E)
  309.     {
  310.       if (*typePtr++ == '=')
  311. {
  312.   break;
  313. }
  314.     }
  315.   /*
  316.    * Base structure alignment on first element.
  317.    */
  318.   if (*typePtr != _C_STRUCT_E)
  319.     {
  320.       typePtr = mframe_next_arg(typePtr, &local);
  321.       if (typePtr == 0)
  322. {
  323.   return 0; /* error */
  324. }
  325.       acc_size = ROUND(acc_size, local.align);
  326.       acc_size += local.size;
  327.       acc_align = MAX(local.align, __alignof__(fooalign));
  328.     }
  329.   /*
  330.    * Continue accumulating structure size.
  331.    */
  332.   while (*typePtr != _C_STRUCT_E)
  333.     {
  334.       typePtr = mframe_next_arg(typePtr, &local);
  335.       if (typePtr == 0)
  336. {
  337.   return 0; /* error */
  338. }
  339.       acc_size = ROUND(acc_size, local.align);
  340.       acc_size += local.size;
  341.     }
  342.   info->size = acc_size;
  343.   info->align = acc_align;
  344.   typePtr++; /* Skip end-of-struct */
  345. }
  346. break;
  347.       case _C_UNION_B:
  348. {
  349.   unsigned max_size = 0;
  350.   unsigned max_align = 0;
  351.   /*
  352.    * Skip "<name>=" stuff.
  353.    */
  354.   while (*typePtr != _C_UNION_E)
  355.     {
  356.       if (*typePtr++ == '=')
  357. {
  358.   break;
  359. }
  360.     }
  361.   while (*typePtr != _C_UNION_E)
  362.     {
  363.       typePtr = mframe_next_arg(typePtr, &local);
  364.       if (typePtr == 0)
  365. {
  366.   return 0; /* error */
  367. }
  368.       max_size = MAX(max_size, local.size);
  369.       max_align = MAX(max_align, local.align);
  370.     }
  371.   info->size = max_size;
  372.   info->align = max_align;
  373.   typePtr++; /* Skip end-of-union */
  374. }
  375. break;
  376.       case _C_VOID:
  377. info->size = 0;
  378. info->align = __alignof__(char*);
  379. break;
  380.       default:
  381. return 0;
  382.     }
  383.   if (typePtr == 0)
  384.     { /* Error condition. */
  385.       return 0;
  386.     }
  387.   /*
  388.    * If we had a pointer argument, we will already have gathered
  389.    * (and skipped past) the argframe offset information - so we
  390.    * don't need to (and can't) do it here.
  391.    */
  392.   if (info->type[0] != _C_PTR || info->type[1] == '?')
  393.     {
  394.       BOOL negFlag = NO;
  395.       /*
  396.        * May tell the caller if the item is stored in a register.
  397.        */
  398.       if (*typePtr == '-')
  399.         {
  400.           typePtr++;
  401.           negFlag = YES;
  402.           info->isReg = NO;
  403.         }
  404.       else if (*typePtr == '+')
  405. {
  406.   typePtr++;
  407.   info->isReg = YES;
  408. }
  409.       else
  410.         info->isReg = NO;
  411.       /*
  412.        * May tell the caller what the stack/register offset is for
  413.        * this argument.
  414.        */
  415.       info->offset = 0;
  416.       while (isDigit (*typePtr))
  417.         info->offset = info->offset * 10 + (*typePtr++ - '0');
  418.       if (negFlag)
  419.         info->offset *= -1;
  420.     }
  421.   return typePtr;
  422. }
  423. /* Return the number of arguments that the method MTH expects.  Note
  424.    that all methods need two implicit arguments `self' and `_cmd'.  */
  425. int
  426. method_types_get_number_of_arguments (const char *type)
  427. {
  428.   int i = 0;
  429.   while (*type)
  430.     {
  431.       type = objc_skip_argspec (type);
  432.       i += 1;
  433.     }
  434.   return i - 1;
  435. }
  436. /* Return the size of the argument block needed on the stack to invoke
  437.   the method MTH.  This may be zero, if all arguments are passed in
  438.   registers.  */
  439. int
  440. method_types_get_size_of_stack_arguments (const char *type)
  441. {
  442.   type = objc_skip_typespec (type);
  443.   return atoi (type);
  444. }
  445. int
  446. method_types_get_size_of_register_arguments(const char *types)
  447. {
  448.   const char* type = strrchr(types, '+');
  449.   if (type)
  450.     {
  451.       return atoi(++type) + sizeof(void*);
  452.     }
  453.   else
  454.     {
  455.       return 0;
  456.     }
  457. }
  458. /* To fix temporary bug in method_get_next_argument() on NeXT boxes */
  459. /* xxx Perhaps this isn't working with the NeXT runtime? */
  460. char*
  461. method_types_get_next_argument (arglist_t argf, const char **type)
  462. {
  463.   const char *t = objc_skip_argspec (*type);
  464.   arglist_t argframe;
  465.   argframe = (void*)argf;
  466.   if (*t == '')
  467.     {
  468.       return 0;
  469.     }
  470.   *type = t;
  471.   t = objc_skip_typespec (t);
  472.   if (*t == '+')
  473.     {
  474.       return argframe->arg_regs + atoi(++t);
  475.     }
  476.   else
  477.     {
  478.       /* xxx What's going on here?  This -8 needed on my 68k NeXT box. */
  479. #if NeXT
  480.       return argframe->arg_ptr + (atoi(t) - 8);
  481. #else
  482.       return argframe->arg_ptr + atoi(t);
  483. #endif
  484.     }
  485. }
  486. /* mframe_dissect_call()
  487.    This function encodes the arguments of a method call.
  488.    Call it with an ARGFRAME that was returned by __builtin_args(), and
  489.    a TYPE string that describes the input and return locations,
  490.    i.e. from sel_get_types() or Method->method_types.
  491.    The function ENCODER will be called once with each input argument.
  492.    Returns YES iff there are any outparameters---parameters that for
  493.    which we will have to get new values after the method is run,
  494.    e.g. an argument declared (out char*). */
  495. BOOL
  496. mframe_dissect_call_opts (arglist_t argframe, const char *type,
  497.      void (*encoder)(int,void*,const char*,int),
  498. BOOL pass_pointers)
  499. {
  500.   unsigned flags;
  501.   char *datum;
  502.   int argnum;
  503.   BOOL out_parameters = NO;
  504.   if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
  505.     datum = alloca((strlen(type)+1)*10);
  506.     type = mframe_build_signature(type, 0, 0, datum);
  507.   }
  508.   /* Enumerate all the arguments in ARGFRAME, and call ENCODER for
  509.      each one.  METHOD_TYPES_GET_NEXT_ARGUEMENT() returns 0 when
  510.      there are no more arguments, otherwise it returns a pointer to the
  511.      argument in the ARGFRAME. */
  512.   for (datum = method_types_get_next_argument(argframe, &type), argnum=0;
  513.        datum;
  514.        datum = method_types_get_next_argument(argframe, &type), argnum++)
  515.     {
  516.       /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
  517.       flags = objc_get_type_qualifiers(type);
  518.       /* Skip over the type qualifiers, so now TYPE is pointing directly
  519.  at the char corresponding to the argument's type, as defined
  520.  in <objc/objc-api.h> */
  521.       type = objc_skip_type_qualifiers(type);
  522.       /* Decide how, (or whether or not), to encode the argument
  523.  depending on its FLAGS and TYPE.  Only the first two cases
  524.  involve parameters that may potentially be passed by
  525.  reference, and thus only the first two may change the value
  526.  of OUT_PARAMETERS. */
  527.       switch (*type)
  528. {
  529. case _C_CHARPTR:
  530.   /* Handle a (char*) argument. */
  531.   /* If the char* is qualified as an OUT parameter, or if it
  532.      not explicitly qualified as an IN parameter, then we will
  533.      have to get this char* again after the method is run,
  534.      because the method may have changed it.  Set
  535.      OUT_PARAMETERS accordingly. */
  536.   if ((flags & _F_OUT) || !(flags & _F_IN))
  537.     out_parameters = YES;
  538.   /* If the char* is qualified as an IN parameter, or not
  539.              explicity qualified as an OUT parameter, then encode
  540.              it. */
  541.   if ((flags & _F_IN) || !(flags & _F_OUT))
  542.     (*encoder) (argnum, datum, type, flags);
  543.   break;
  544. case _C_PTR:
  545.   /* If the pointer's value is qualified as an OUT parameter,
  546.      or if it not explicitly qualified as an IN parameter,
  547.      then we will have to get the value pointed to again after
  548.      the method is run, because the method may have changed
  549.      it.  Set OUT_PARAMETERS accordingly. */
  550.   if ((flags & _F_OUT) || !(flags & _F_IN))
  551.     out_parameters = YES;
  552.   if (pass_pointers) {
  553.     if ((flags & _F_IN) || !(flags & _F_OUT))
  554.       (*encoder) (argnum, datum, type, flags);
  555.   }
  556.   else {
  557.     /* Handle an argument that is a pointer to a non-char.  But
  558.        (void*) and (anything**) is not allowed. */
  559.     /* The argument is a pointer to something; increment TYPE
  560.  so we can see what it is a pointer to. */
  561.     type++;
  562.     /* If the pointer's value is qualified as an IN parameter,
  563.        or not explicity qualified as an OUT parameter, then
  564.        encode it. */
  565.     if ((flags & _F_IN) || !(flags & _F_OUT))
  566.       (*encoder) (argnum, *(void**)datum, type, flags);
  567.   }
  568.   break;
  569. case _C_STRUCT_B:
  570. case _C_UNION_B:
  571. case _C_ARY_B:
  572.   /* Handle struct and array arguments. */
  573.   /* Whether DATUM points to the data, or points to a pointer
  574.      that points to the data, depends on the value of
  575.      MFRAME_STRUCT_BYREF.  Do the right thing
  576.      so that ENCODER gets a pointer to directly to the data. */
  577. #if MFRAME_STRUCT_BYREF
  578.   (*encoder) (argnum, *(void**)datum, type, flags);
  579. #else
  580.   (*encoder) (argnum, datum, type, flags);
  581. #endif
  582.   break;
  583. default:
  584.   /* Handle arguments of all other types. */
  585.   (*encoder) (argnum, datum, type, flags);
  586. }
  587.     }
  588.   /* Return a BOOL indicating whether or not there are parameters that
  589.      were passed by reference; we will need to get those values again
  590.      after the method has finished executing because the execution of
  591.      the method may have changed them.*/
  592.   return out_parameters;
  593. }
  594. BOOL
  595. mframe_dissect_call (arglist_t argframe, const char *type,
  596.      void (*encoder)(int,void*,const char*,int))
  597. {
  598.   return mframe_dissect_call_opts(argframe, type, encoder, NO);
  599. }
  600. /* mframe_do_call()
  601.    This function decodes the arguments of method call, builds an
  602.    argframe of type arglist_t, and invokes the method using
  603.    __builtin_apply; then it encodes the return value and any
  604.    pass-by-reference arguments.
  605.    ENCODED_TYPES should be a string that describes the return value
  606.    and arguments.  It's argument types and argument type qualifiers
  607.    should match exactly those that were used when the arguments were
  608.    encoded with mframe_dissect_call()---mframe_do_call() uses
  609.    ENCODED_TYPES to determine which variable types it should decode.
  610.    ENCODED_TYPES is used to get the types and type qualifiers, but not
  611.    to get the register and stack locations---we get that information
  612.    from the selector type of the SEL that is decoded as the second
  613.    argument.  In this way, the ENCODED_TYPES may come from a machine
  614.    of a different architecture.  Having the original ENCODED_TYPES is
  615.    good, just in case the machine running mframe_do_call() has some
  616.    slightly different qualifiers.  Using different qualifiers for
  617.    encoding and decoding could lead to massive confusion.
  618.    DECODER should be a pointer to a function that obtains the method's
  619.    argument values.  For example:
  620.      void my_decoder (int argnum, void *data, const char *type)
  621.      ARGNUM is the number of the argument, beginning at 0.
  622.      DATA is a pointer to the memory where the value should be placed.
  623.      TYPE is a pointer to the type string of this value.
  624.      mframe_do_call() calls this function once for each of the methods
  625.      arguments.  The DECODER function should place the ARGNUM'th
  626.      argument's value at the memory location DATA.
  627.      mframe_do_call() calls this function once with ARGNUM -1, DATA 0,
  628.      and TYPE 0 to denote completion of decoding.
  629.      If DECODER malloc's new memory in the course of doing its
  630.      business, then DECODER is responsible for making sure that the
  631.      memory will get free eventually.  For example, if DECODER uses
  632.      -decodeValueOfCType:at:withName: to decode a char* string, you
  633.      should remember that -decodeValueOfCType:at:withName: malloc's
  634.      new memory to hold the string, and DECODER should autorelease the
  635.      malloc'ed pointer, using the NSData class.
  636.    ENCODER should be a pointer to a function that records the method's
  637.    return value and pass-by-reference values.  For example:
  638.      void my_encoder (int argnum, void *data, const char *type, int flags)
  639.      ARGNUM is the number of the argument; this will be -1 for the
  640.        return value, and the argument index for the pass-by-reference
  641.        values; the indices start at 0.
  642.      DATA is a pointer to the memory where the value can be found.
  643.      TYPE is a pointer to the type string of this value.
  644.      FLAGS is a copy of the type qualifier flags for this argument; 
  645.        (see <objc/objc-api.h>).
  646.      mframe_do_call() calls this function after the method has been
  647.      run---once for the return value, and once for each of the
  648.      pass-by-reference parameters.  The ENCODER function should place
  649.      the value at memory location DATA wherever the user wants to
  650.      record the ARGNUM'th return value.
  651.   PASS_POINTERS is a flag saying whether pointers should be passed
  652.   as pointers (for local stuff) or should be assumed to point to a
  653.   single data item (for distributed objects).
  654. */
  655. void
  656. mframe_do_call_opts (const char *encoded_types,
  657. void(*decoder)(int,void*,const char*),
  658. void(*encoder)(int,void*,const char*,int),
  659. BOOL pass_pointers)
  660. {
  661.   /* The method type string obtained from the target's OBJC_METHOD 
  662.      structure for the selector we're sending. */
  663.   const char *type;
  664.   /* A pointer into the local variable TYPE string. */
  665.   const char *tmptype;
  666.   /* A pointer into the argument ENCODED_TYPES string. */
  667.   const char *etmptype;
  668.   /* The target object that will receive the message. */
  669.   id object;
  670.   /* The selector for the message we're sending to the TARGET. */
  671.   SEL selector;
  672.   /* The OBJECT's implementation of the SELECTOR. */
  673.   IMP method_implementation;
  674.   /* The number bytes for holding arguments passed on the stack. */
  675.   int stack_argsize;
  676.   /* The number bytes for holding arguments passed in registers. */
  677.   int reg_argsize;
  678.   /* The structure for holding the arguments to the method. */
  679.   arglist_t argframe;
  680.   /* A pointer into the ARGFRAME; points at individual arguments. */
  681.   char *datum;
  682.   /* Type qualifier flags; see <objc/objc-api.h>. */
  683.   unsigned flags;
  684.   /* Which argument number are we processing now? */
  685.   int argnum;
  686.   /* A pointer to the memory holding the return value of the method. */
  687.   void *retframe;
  688.   /* Does the method have any arguments that are passed by reference?
  689.      If so, we need to encode them, since the method may have changed them. */
  690.   BOOL out_parameters = NO;
  691.   /* For extracting a return value of type `float' from RETFRAME. */
  692.   float retframe_float (void *rframe)
  693.     {
  694.       __builtin_return (rframe);
  695.     }
  696.   /* For extracting a return value of type `double' from RETFRAME. */
  697.   double retframe_double (void *rframe)
  698.     {
  699.       __builtin_return (rframe);
  700.     }
  701.   /* For extracting a return value of type `char' from RETFRAME */
  702.   char retframe_char (void *rframe)
  703.     {
  704.       __builtin_return (rframe);
  705.     }
  706.   /* For extracting a return value of type `short' from RETFRAME */
  707.   short retframe_short (void *rframe)
  708.     {
  709.       __builtin_return (rframe);
  710.     }
  711.   /* Decode the object, (which is always the first argument to a method),
  712.      into the local variable OBJECT. */
  713.   (*decoder) (0, &object, @encode(id));
  714.   NSCParameterAssert (object);
  715.   /* Decode the selector, (which is always the second argument to a
  716.      method), into the local variable SELECTOR. */
  717.   /* xxx @encode(SEL) produces "^v" in gcc 2.5.8.  It should be ":" */
  718.   (*decoder) (1, &selector, ":");
  719.   NSCParameterAssert (selector);
  720.   /* Get the "selector type" for this method.  The "selector type" is
  721.      a string that lists the return and argument types, and also
  722.      indicates in which registers and where on the stack the arguments
  723.      should be placed before the method call.  The selector type
  724.      string we get here should have the same argument and return types
  725.      as the ENCODED_TYPES string, but it will have different register
  726.      and stack locations if the ENCODED_TYPES came from a machine of a
  727.      different architecture. */
  728. #if NeXT_runtime
  729.   {
  730.     Method m;
  731.     m = class_getInstanceMethod(object->isa, selector);
  732.     if (!m) 
  733.       abort();
  734.     type = m->method_types;
  735.   }
  736. #elif 0
  737.   {
  738.     Method_t m;
  739.     m = class_get_instance_method (object->class_pointer,
  740.    selector);
  741.     NSCParameterAssert (m);
  742.     type = m->method_types;
  743.   }
  744. #else
  745.   type = sel_get_type (selector);
  746. #endif /* NeXT_runtime */
  747.   /* Make sure we successfully got the method type, and that its
  748.      types match the ENCODED_TYPES. */
  749.   NSCParameterAssert (type);
  750.   NSCParameterAssert (sel_types_match(encoded_types, type));
  751.   /*
  752.    * The compiler/runtime doesn't always seem to get the encoding right
  753.    * for our purposes - so we generate our own encoding as required by
  754.    * __builtin_apply().
  755.    */
  756.   if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B) {
  757.     tmptype = alloca((strlen(type)+1)*10);
  758.     type = mframe_build_signature(type, 0, 0, (char*)tmptype);
  759.   }
  760.   /* Allocate an argframe, using memory on the stack */
  761.   /* Calculate the amount of memory needed for storing variables that
  762.      are passed in registers, and the amount of memory for storing
  763.      variables that are passed on the stack. */
  764.   stack_argsize = method_types_get_size_of_stack_arguments (type);
  765.   reg_argsize = method_types_get_size_of_register_arguments (type);
  766.   /* Allocate the space for variables passed in registers. */
  767.   argframe = (arglist_t) alloca(sizeof(char*) + reg_argsize);
  768.   /* Allocate the space for variables passed on the stack. */
  769.   if (stack_argsize)
  770.     argframe->arg_ptr = alloca (stack_argsize);
  771.   else
  772.     argframe->arg_ptr = 0;
  773.   if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B)
  774.     {
  775.       void *buf;
  776.     /* If we are passing a pointer to return a structure in, we must allocate
  777.        the memory for it and put it in the correct place in the argframe. */
  778.       buf = alloca(objc_sizeof_type(type));
  779.       MFRAME_SET_STRUCT_ADDR(argframe, type, buf);
  780.     }
  781.   /* Put OBJECT and SELECTOR into the ARGFRAME. */
  782.   /* Initialize our temporary pointers into the method type strings. */
  783.   tmptype = type;
  784.   etmptype = objc_skip_argspec (encoded_types);
  785.   /* Get a pointer into ARGFRAME, pointing to the location where the
  786.      first argument is to be stored. */
  787.   datum = method_types_get_next_argument (argframe, &tmptype);
  788.   NSCParameterAssert (datum);
  789.   NSCParameterAssert (*tmptype == _C_ID);
  790.   /* Put the target object there. */
  791.   *(id*)datum = object;
  792.   /* Get a pointer into ARGFRAME, pointing to the location where the
  793.      second argument is to be stored. */
  794.   etmptype = objc_skip_argspec(etmptype);
  795.   datum = method_types_get_next_argument(argframe, &tmptype);
  796.   NSCParameterAssert (datum);
  797.   NSCParameterAssert (*tmptype == _C_SEL);
  798.   /* Put the selector there. */
  799.   *(SEL*)datum = selector;
  800.   /* Decode arguments after OBJECT and SELECTOR, and put them into the
  801.      ARGFRAME.  Step TMPTYPE and ETMPTYPE in lock-step through their
  802.      method type strings. */
  803.   for (datum = method_types_get_next_argument (argframe, &tmptype),
  804.        etmptype = objc_skip_argspec (etmptype), argnum = 2;
  805.        datum;
  806.        datum = method_types_get_next_argument (argframe, &tmptype),
  807.        etmptype = objc_skip_argspec (etmptype), argnum++)
  808.     {
  809.       /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
  810.       flags = objc_get_type_qualifiers (etmptype);
  811.       /* Skip over the type qualifiers, so now TYPE is pointing directly
  812.  at the char corresponding to the argument's type, as defined
  813.  in <objc/objc-api.h> */
  814.       tmptype = objc_skip_type_qualifiers(tmptype);
  815.       /* Decide how, (or whether or not), to decode the argument
  816.  depending on its FLAGS and TMPTYPE.  Only the first two cases
  817.  involve parameters that may potentially be passed by
  818.  reference, and thus only the first two may change the value
  819.  of OUT_PARAMETERS.  *** Note: This logic must match exactly
  820.  the code in mframe_dissect_call(); that function should
  821.  encode exactly what we decode here. *** */
  822.       switch (*tmptype)
  823. {
  824. case _C_CHARPTR:
  825.   /* Handle a (char*) argument. */
  826.   /* If the char* is qualified as an OUT parameter, or if it
  827.      not explicitly qualified as an IN parameter, then we will
  828.      have to get this char* again after the method is run,
  829.      because the method may have changed it.  Set
  830.      OUT_PARAMETERS accordingly. */
  831.   if ((flags & _F_OUT) || !(flags & _F_IN))
  832.     out_parameters = YES;
  833.   /* If the char* is qualified as an IN parameter, or not
  834.      explicity qualified as an OUT parameter, then decode it.
  835.      Note: the decoder allocates memory for holding the
  836.      string, and it is also responsible for making sure that
  837.      the memory gets freed eventually, (usually through the
  838.      autorelease of NSData object). */
  839.   if ((flags & _F_IN) || !(flags & _F_OUT))
  840.     (*decoder) (argnum, datum, tmptype);
  841.   break;
  842. case _C_PTR:
  843.   /* If the pointer's value is qualified as an OUT parameter,
  844.      or if it not explicitly qualified as an IN parameter,
  845.      then we will have to get the value pointed to again after
  846.      the method is run, because the method may have changed
  847.      it.  Set OUT_PARAMETERS accordingly. */
  848.   if ((flags & _F_OUT) || !(flags & _F_IN))
  849.     out_parameters = YES;
  850.   if (pass_pointers)
  851.     {
  852.       if ((flags & _F_IN) || !(flags & _F_OUT))
  853. (*decoder) (argnum, datum, tmptype);
  854.     }
  855.   else
  856.     {
  857.       /* Handle an argument that is a pointer to a non-char.  But
  858.  (void*) and (anything**) is not allowed. */
  859.       /* The argument is a pointer to something; increment TYPE
  860.    so we can see what it is a pointer to. */
  861.       tmptype++;
  862.       /* Allocate some memory to be pointed to, and to hold the
  863.  value.  Note that it is allocated on the stack, and
  864.  methods that want to keep the data pointed to, will have
  865.  to make their own copies. */
  866.       *(void**)datum = alloca (objc_sizeof_type (tmptype));
  867.       /* If the pointer's value is qualified as an IN parameter,
  868.  or not explicity qualified as an OUT parameter, then
  869.  decode it. */
  870.       if ((flags & _F_IN) || !(flags & _F_OUT))
  871. (*decoder) (argnum, *(void**)datum, tmptype);
  872.     }
  873.   break;
  874. case _C_STRUCT_B:
  875. case _C_UNION_B:
  876. case _C_ARY_B:
  877.   /* Handle struct and array arguments. */
  878.   /* Whether DATUM points to the data, or points to a pointer
  879.      that points to the data, depends on the value of
  880.      MFRAME_STRUCT_BYREF.  Do the right thing
  881.      so that ENCODER gets a pointer to directly to the data. */
  882. #if MFRAME_STRUCT_BYREF
  883.   /* Allocate some memory to be pointed to, and to hold the
  884.      data.  Note that it is allocated on the stack, and
  885.      methods that want to keep the data pointed to, will have
  886.      to make their own copies. */
  887.   *(void**)datum = alloca (objc_sizeof_type(tmptype));
  888.   (*decoder) (argnum, *(void**)datum, tmptype);
  889. #else
  890.   (*decoder) (argnum, datum, tmptype);
  891. #endif
  892.   break;
  893. default:
  894.   /* Handle arguments of all other types. */
  895.   /* NOTE FOR OBJECTS: Unlike [Decoder decodeObjectAt:..],
  896.      this function does not generate a reference to the
  897.      object; the object may be autoreleased; if the method
  898.      wants to keep a reference to the object, it will have to
  899.      -retain it. */
  900.   (*decoder) (argnum, datum, tmptype);
  901. }
  902.     }
  903.   /* End of the for() loop that enumerates the method's arguments. */
  904.   (*decoder) (-1, 0, 0);
  905.   /* Invoke the method! */
  906.   /* Find the target object's implementation of this selector. */
  907.   method_implementation = objc_msg_lookup (object, selector);
  908.   NSCParameterAssert (method_implementation);
  909.   /* Do it!  Send the message to the target, and get the return value
  910.      in RETFRAME.  The arguments will still be in ARGFRAME, so we can
  911.      get the pass-by-reference info from there. */
  912.   retframe = __builtin_apply((void(*)(void))method_implementation, 
  913.      argframe, 
  914.      stack_argsize);
  915.   /* Encode the return value and pass-by-reference values, if there
  916.      are any.  This logic must match exactly that in
  917.      mframe_build_return(). */
  918.   /* OUT_PARAMETERS should be true here in exactly the same
  919.      situations as it was true in mframe_dissect_call(). */
  920.   /* Get the qualifier type of the return value. */
  921.   flags = objc_get_type_qualifiers (encoded_types);
  922.   /* Get the return type; store it our two temporary char*'s. */
  923.   etmptype = objc_skip_type_qualifiers (encoded_types);
  924.   tmptype = objc_skip_type_qualifiers (type);
  925.   /* Only encode return values if there is a non-void return value,
  926.      a non-oneway void return value, or if there are values that were
  927.      passed by reference. */
  928.   /* If there is a return value, encode it. */
  929.   switch (*tmptype)
  930.     {
  931.     case _C_VOID:
  932.       if ((flags & _F_ONEWAY) == 0)
  933. {
  934.    int dummy = 0;
  935.           (*encoder) (-1, (void*)&dummy, @encode(int), 0);
  936. }
  937.       /* No return value to encode; do nothing. */
  938.       break;
  939.     case _C_PTR:
  940.       if (pass_pointers)
  941. {
  942.   (*encoder) (-1, retframe, tmptype, flags);
  943. }
  944.       else
  945. {
  946.   /* The argument is a pointer to something; increment TYPE
  947.      so we can see what it is a pointer to. */
  948.   tmptype++;
  949.   /* Encode the value that was pointed to. */
  950.   (*encoder) (-1, *(void**)retframe, tmptype, flags);
  951. }
  952.       break;
  953.     case _C_STRUCT_B:
  954.     case _C_UNION_B:
  955.     case _C_ARY_B:
  956.       /* The argument is a structure or array returned by value.
  957.  (In C, are array's allowed to be returned by value?) */
  958.       (*encoder)(-1, MFRAME_GET_STRUCT_ADDR(argframe, tmptype), tmptype, flags);
  959.       break;
  960.     case _C_FLT:
  961.       {
  962. float ret = retframe_float (retframe);
  963. (*encoder) (-1, &ret, tmptype, flags);
  964. break;
  965.       }
  966.     case _C_DBL:
  967.       {
  968. double ret = retframe_double (retframe);
  969. (*encoder) (-1, &ret, tmptype, flags);
  970. break;
  971.       }
  972.     case _C_SHT:
  973.     case _C_USHT:
  974.       /* On some (but not all) architectures, for C variable types
  975.  smaller than int, like short, the RETFRAME doesn't actually
  976.  point to the beginning of the short, it points to the
  977.  beginning of an int.  So we let RETFRAME_SHORT() take care of
  978.  it. */
  979.       {
  980. short ret = retframe_short (retframe);
  981. (*encoder) (-1, &ret, tmptype, flags);
  982. break;
  983.       }
  984.     case _C_CHR:
  985.     case _C_UCHR:
  986.       /* On some (but not all) architectures, for C variable types
  987.          smaller than int, like char, the RETFRAME doesn't actually
  988.          point to the beginning of the char, it points to the
  989.          beginning of an int.   So we let RETFRAME_SHORT() take care of
  990.  it. */
  991.       {
  992. char ret = retframe_char (retframe);
  993. (*encoder) (-1, &ret, tmptype, flags);
  994. break;
  995.       }
  996.     default:
  997.       /* case _C_INT: case _C_UINT: case _C_LNG: case _C_ULNG:
  998.  case _C_CHARPTR: case: _C_ID: */
  999.       /* xxx I think this assumes that sizeof(int)==sizeof(void*) */
  1000.       (*encoder) (-1, retframe, tmptype, flags);
  1001.     }
  1002.   /* Encode the values returned by reference.  Note: this logic
  1003.      must match exactly the code in mframe_build_return(); that
  1004.      function should decode exactly what we encode here. */
  1005.   if (out_parameters)
  1006.     {
  1007.       /* Step through all the arguments, finding the ones that were
  1008.  passed by reference. */
  1009.       for (datum = method_types_get_next_argument (argframe, &tmptype), 
  1010.      argnum = 1,
  1011.      etmptype = objc_skip_argspec (etmptype);
  1012.    datum;
  1013.    datum = method_types_get_next_argument (argframe, &tmptype), 
  1014.      argnum++,
  1015.      etmptype = objc_skip_argspec (etmptype))
  1016. {
  1017.   /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
  1018.   flags = objc_get_type_qualifiers(etmptype);
  1019.   /* Skip over the type qualifiers, so now TYPE is pointing directly
  1020.      at the char corresponding to the argument's type, as defined
  1021.      in <objc/objc-api.h> */
  1022.   tmptype = objc_skip_type_qualifiers (tmptype);
  1023.   /* Decide how, (or whether or not), to encode the argument
  1024.      depending on its FLAGS and TMPTYPE. */
  1025.   if ((*tmptype == _C_PTR) 
  1026.       && ((flags & _F_OUT) || !(flags & _F_IN)))
  1027.     {
  1028.       /* The argument is a pointer (to a non-char), and the
  1029.  pointer's value is qualified as an OUT parameter, or
  1030.  it not explicitly qualified as an IN parameter, then
  1031.  it is a pass-by-reference argument.*/
  1032.       /* The argument is a pointer to something; increment TYPE
  1033.  so we can see what it is a pointer to. */
  1034.       tmptype++;
  1035.       /* Encode it. */
  1036.       (*encoder) (argnum, *(void**)datum, tmptype, flags);
  1037.     }
  1038.   else if (*tmptype == _C_CHARPTR
  1039.    && ((flags & _F_OUT) || !(flags & _F_IN)))
  1040.     {
  1041.       /* The argument is a pointer char string, and the
  1042.  pointer's value is qualified as an OUT parameter, or
  1043.  it not explicitly qualified as an IN parameter, then
  1044.  it is a pass-by-reference argument.  Encode it.*/
  1045.       /* xxx Perhaps we could save time and space by saving
  1046.  a copy of the string before the method call, and then
  1047.  comparing it to this string; if it didn't change, don't
  1048.  bother to send it back again. */
  1049.       (*encoder) (argnum, datum, tmptype, flags);
  1050.     }
  1051. }
  1052.     }
  1053.   return;
  1054. }
  1055. void
  1056. mframe_do_call (const char *encoded_types,
  1057. void(*decoder)(int,void*,const char*),
  1058. void(*encoder)(int,void*,const char*,int))
  1059. {
  1060.   mframe_do_call_opts(encoded_types, decoder, encoder, NO);
  1061. }
  1062. /* mframe_build_return()
  1063.    This function decodes the values returned from a method call,
  1064.    builds a retframe of type retval_t that can be passed to GCC's
  1065.    __builtin_return(), and updates the pass-by-reference arguments in
  1066.    ARGFRAME.  This function returns a retframe pointer.
  1067.    In the function that calls this one, be careful about calling more
  1068.    functions after this one.  The memory for the retframe is
  1069.    alloca()'ed, not malloc()'ed, and therefore is on the stack and can
  1070.    be tromped-on by future function calls.
  1071.    The callback function is finally called with the 'type' set to a nul pointer
  1072.    to tell it that the return value and all return parameters have been
  1073.    dealt with.  This permits the function to do any tidying up necessary.
  1074. */
  1075. retval_t 
  1076. mframe_build_return_opts (arglist_t argframe, 
  1077.      const char *type, 
  1078.      BOOL out_parameters,
  1079.      void(*decoder)(int,void*,const char*,int),
  1080.      BOOL pass_pointers)
  1081. {
  1082.   /* A pointer to the memory that will hold the return value. */
  1083.   retval_t retframe = NULL;
  1084.   /* The size, in bytes, of memory pointed to by RETFRAME. */
  1085.   unsigned retsize;
  1086.   /* Which argument number are we processing now? */
  1087.   int argnum;
  1088.   /* Type qualifier flags; see <objc/objc-api.h>. */
  1089.   int flags;
  1090.   /* A pointer into the TYPE string. */
  1091.   const char *tmptype;
  1092.   /* A pointer into the ARGFRAME; points at individual arguments. */
  1093.   void *datum;
  1094.   const char *rettype;
  1095.   /* For returning strucutres etc */
  1096.   typedef struct { id many[8];} __big;
  1097.   __big return_block (void* data)
  1098.     {
  1099.       return *(__big*)data;
  1100.     }
  1101.   /* For returning a char (or unsigned char) */
  1102.   char return_char (char data)
  1103.     {
  1104.       return data;
  1105.     }
  1106.   /* For returning a double */
  1107.   double return_double (double data)
  1108.     {
  1109.       return data;
  1110.     }
  1111.   /* For returning a float */
  1112.   float return_float (float data)
  1113.     {
  1114.       return data;
  1115.     }
  1116.   /* For returning a short (or unsigned short) */
  1117.   short return_short (short data)
  1118.     {
  1119.       return data;
  1120.     }
  1121.   retval_t apply_block(void* data)
  1122.     {
  1123.       void* args = __builtin_apply_args();
  1124.       return __builtin_apply((apply_t)return_block, args, sizeof(void*));
  1125.     }
  1126.   retval_t apply_char(char data)
  1127.     {
  1128.       void* args = __builtin_apply_args();
  1129.       return __builtin_apply((apply_t)return_char, args, sizeof(void*));
  1130.     }
  1131.   retval_t apply_float(float data)
  1132.     {
  1133.       void* args = __builtin_apply_args();
  1134.       return __builtin_apply((apply_t)return_float, args, sizeof(float));
  1135.     }
  1136.   retval_t apply_double(double data)
  1137.     {
  1138.       void* args = __builtin_apply_args();
  1139.       return __builtin_apply((apply_t)return_double, args, sizeof(double));
  1140.     }
  1141.   retval_t apply_short(short data)
  1142.     {
  1143.       void* args = __builtin_apply_args();
  1144.       return __builtin_apply((apply_t)return_short, args, sizeof(void*));
  1145.     }
  1146.   if (*type == _C_STRUCT_B || *type == _C_UNION_B || *type == _C_ARY_B)
  1147.     {
  1148.       tmptype = alloca((strlen(type)+1)*10);
  1149.       type = mframe_build_signature(type, 0, 0, (char*)tmptype);
  1150.     }
  1151.   /* Get the return type qualifier flags, and the return type. */
  1152.   flags = objc_get_type_qualifiers(type);
  1153.   tmptype = objc_skip_type_qualifiers(type);
  1154.   rettype = tmptype;
  1155.   /* Decode the return value and pass-by-reference values, if there
  1156.      are any.  OUT_PARAMETERS should be the value returned by
  1157.      mframe_dissect_call(). */
  1158.   if (out_parameters || *tmptype != _C_VOID || (flags & _F_ONEWAY) == 0)
  1159.     /* xxx What happens with method declared "- (oneway) foo: (out int*)ip;" */
  1160.     /* xxx What happens with method declared "- (in char *) bar;" */
  1161.     /* xxx Is this right?  Do we also have to check _F_ONEWAY? */
  1162.     {
  1163.       /* ARGNUM == -1 signifies to DECODER() that this is the return
  1164.          value, not an argument. */
  1165.       /* If there is a return value, decode it, and put it in retframe. */
  1166.       if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0)
  1167. {
  1168.   /* Get the size of the returned value. */
  1169.           if (*tmptype == _C_VOID)
  1170.     retsize = sizeof(void*);
  1171.   else
  1172.     retsize = objc_sizeof_type (tmptype);
  1173.   /* Allocate memory on the stack to hold the return value.
  1174.              It should be at least 4 * sizeof(void*). */
  1175.   /* xxx We need to test retsize's less than 4.  Also note that
  1176.      if we return structures using a structure-value-address, we
  1177.      are potentially alloca'ing much more than we need here. */
  1178.   /* xxx Find out about returning structures by reference
  1179.      on non--structure-value-address machines, and potentially
  1180.      just always alloca(RETFRAME_SIZE == sizeof(void*)*4) */
  1181.   retframe = alloca (MAX(retsize, sizeof(void*)*4));
  1182.   
  1183.   switch (*tmptype)
  1184.     {
  1185.     case _C_PTR:
  1186.       if (pass_pointers)
  1187. {
  1188.   (*decoder) (-1, retframe, tmptype, flags);
  1189. }
  1190.       else
  1191. {
  1192.   unsigned retLength;
  1193.   /* We are returning a pointer to something. */
  1194.   /* Increment TYPE so we can see what it is a pointer to. */
  1195.   tmptype++;
  1196.   retLength = objc_sizeof_type(tmptype);
  1197.   /* Allocate memory to hold the value we're pointing to. */
  1198.   *(void**)retframe = 
  1199.     objc_malloc (retLength);
  1200. #if 0
  1201.   /* We are responsible for making sure this memory gets free'd
  1202.      eventually.  Ask NSData class to autorelease it. */
  1203.   [NSData dataWithBytesNoCopy: *(void**)retframe
  1204.        length: retLength];
  1205. #endif
  1206.   /* Decode the return value into the memory we allocated. */
  1207.   (*decoder) (-1, *(void**)retframe, tmptype, flags);
  1208. }
  1209.       break;
  1210.     case _C_STRUCT_B: 
  1211.     case _C_UNION_B:
  1212.     case _C_ARY_B:
  1213.       /* The argument is a structure or array returned by value.
  1214.  (In C, are array's allowed to be returned by value?) */
  1215.       *(void**)retframe = MFRAME_GET_STRUCT_ADDR(argframe, tmptype);
  1216.       /* Decode the return value into the memory we allocated. */
  1217.       (*decoder) (-1, *(void**)retframe, tmptype, flags);
  1218.       break;
  1219.     case _C_FLT: 
  1220.     case _C_DBL:
  1221.       (*decoder) (-1, ((char*)retframe), tmptype, flags);
  1222.       break;
  1223.     case _C_VOID:
  1224. {
  1225.   (*decoder) (-1, retframe, @encode(int), 0);
  1226. }
  1227. break;
  1228.     default:
  1229.       /* (Among other things, _C_CHARPTR is handled here). */
  1230.       /* Special case BOOL (and other types smaller than int)
  1231.  because retframe doesn't actually point to the char */
  1232.       /* xxx What about structures smaller than int's that
  1233.  are passed by reference on true structure reference-
  1234.  passing architectures? */
  1235.       /* xxx Is this the right test?  Use sizeof(int) instead? */
  1236.       if (retsize < sizeof(void*))
  1237. {
  1238. #if 1
  1239.   /* Frith-Macdonald said this worked better 21 Nov 96. */
  1240.   (*decoder) (-1, retframe, tmptype, flags);
  1241. #else
  1242.   *(void**)retframe = 0;
  1243.   (*decoder) (-1, ((char*)retframe)+sizeof(void*)-retsize,
  1244.       tmptype, flags);
  1245. #endif
  1246. }
  1247.       else
  1248. {
  1249.   (*decoder) (-1, retframe, tmptype, flags);
  1250. }
  1251.     }
  1252. }
  1253.       
  1254.       /* Decode the values returned by reference.  Note: this logic
  1255.  must match exactly the code in mframe_do_call(); that
  1256.  function should decode exactly what we encode here. */
  1257.       if (out_parameters)
  1258. {
  1259.   /* Step through all the arguments, finding the ones that were
  1260.      passed by reference. */
  1261.   for (datum = method_types_get_next_argument(argframe, &tmptype), 
  1262.        argnum=0;
  1263.        datum;
  1264.        (datum = method_types_get_next_argument(argframe, &tmptype)), 
  1265.        argnum++)
  1266.     {
  1267.       /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
  1268.       flags = objc_get_type_qualifiers(tmptype);
  1269.       /* Skip over the type qualifiers, so now TYPE is
  1270.  pointing directly at the char corresponding to the
  1271.  argument's type, as defined in <objc/objc-api.h> */
  1272.       tmptype = objc_skip_type_qualifiers(tmptype);
  1273.       /* Decide how, (or whether or not), to encode the
  1274.  argument depending on its FLAGS and TMPTYPE. */
  1275.       if (*tmptype == _C_PTR
  1276.   && ((flags & _F_OUT) || !(flags & _F_IN)))
  1277. {
  1278.   /* The argument is a pointer (to a non-char), and
  1279.      the pointer's value is qualified as an OUT
  1280.      parameter, or it not explicitly qualified as an
  1281.      IN parameter, then it is a pass-by-reference
  1282.      argument.*/
  1283.   /* The argument is a pointer to something; increment
  1284.      TYPE so we can see what it is a pointer to. */
  1285.   tmptype++;
  1286.   /* xxx Note that a (char**) is malloc'ed anew here.
  1287.      Yucky, or worse than yucky.  If the returned string
  1288.      is smaller than the original, we should just put it
  1289.      there; if the returned string is bigger, I don't know
  1290.      what to do. */
  1291.   /* xxx __builtin_return can't return structures by value? */
  1292.   (*decoder) (argnum, *(void**)datum, tmptype, flags);
  1293. }
  1294.       else if (*tmptype == _C_CHARPTR
  1295.        && ((flags & _F_OUT) || !(flags & _F_IN)))
  1296. {
  1297.   /* The argument is a pointer char string, and the
  1298.      pointer's value is qualified as an OUT parameter,
  1299.      or it not explicitly qualified as an IN
  1300.      parameter, then it is a pass-by-reference
  1301.      argument.  Encode it.*/
  1302.   /* xxx Perhaps we could save time and space by
  1303.      saving a copy of the string before the method
  1304.      call, and then comparing it to this string; if it
  1305.      didn't change, don't bother to send it back
  1306.      again. */
  1307.   (*decoder) (argnum, datum, tmptype, flags);
  1308. }
  1309.     }
  1310. }
  1311.       (*decoder) (0, 0, 0, 0); /* Tell it we have finished. */
  1312.     }
  1313.   else /* matches `if (out_parameters)' */
  1314.     {
  1315.       /* We are just returning void, but retframe needs to point to
  1316.          something or else we can crash. */
  1317.       retframe = alloca (sizeof(void*));
  1318.     }
  1319.   switch (*rettype) {
  1320.     case _C_CHR:
  1321.     case _C_UCHR:
  1322. return apply_char(*(char*)retframe);
  1323.     case _C_DBL:
  1324. return apply_double(*(double*)retframe);
  1325.     case _C_FLT:
  1326. return apply_float(*(float*)retframe);
  1327.     case _C_SHT:
  1328.     case _C_USHT:
  1329. return apply_short(*(short*)retframe);
  1330. #if 0
  1331.     case _C_ARY_B:
  1332.     case _C_UNION_B:
  1333.     case _C_STRUCT_B:
  1334. if (objc_sizeof_type(rettype) > 8) {
  1335.     return apply_block(*(void**)retframe);
  1336. }
  1337. #endif
  1338.   }
  1339.   /* Return the retval_t pointer to the return value. */
  1340.   return retframe;
  1341. }
  1342. retval_t 
  1343. mframe_build_return (arglist_t argframe, 
  1344.      const char *type, 
  1345.      BOOL out_parameters,
  1346.      void(*decoder)(int,void*,const char*,int))
  1347. {
  1348.   return mframe_build_return_opts(argframe,type,out_parameters,decoder,NO);
  1349. }
  1350. arglist_t
  1351. mframe_create_argframe(const char *types, void** retbuf)
  1352. {
  1353.   arglist_t argframe = objc_calloc(MFRAME_ARGS_SIZE, 1);
  1354.   const char* rtype = objc_skip_type_qualifiers(types);
  1355.   int stack_argsize = atoi(objc_skip_typespec(rtype));
  1356.     /*
  1357.      * Allocate the space for variables passed on the stack.
  1358.      */
  1359.   if (stack_argsize)
  1360.     {
  1361.       argframe->arg_ptr = objc_calloc(stack_argsize, 1);
  1362.     }
  1363.   else
  1364.     {
  1365.       argframe->arg_ptr = 0;
  1366.     }
  1367.   if (*rtype == _C_STRUCT_B || *rtype == _C_UNION_B || *rtype == _C_ARY_B)
  1368.     {
  1369.       /*
  1370.        * If we haven't been passed a pointer to the location in which
  1371.        * to store a returned structure - allocate space and return
  1372.        * the address of the allocated space.
  1373.        */
  1374.       if (*retbuf == 0)
  1375. {
  1376.   *retbuf = objc_calloc(objc_sizeof_type(rtype), 1);
  1377. }
  1378.       MFRAME_SET_STRUCT_ADDR(argframe, rtype, *retbuf);
  1379.     }
  1380.   return argframe;
  1381. }
  1382. void
  1383. mframe_destroy_argframe(const char *types, arglist_t argframe)
  1384. {
  1385.   const char* rtype = objc_skip_type_qualifiers(types);
  1386.   int stack_argsize = atoi(objc_skip_typespec(rtype));
  1387.   if (stack_argsize)
  1388.     {
  1389.       objc_free(argframe->arg_ptr);
  1390.     }
  1391.   objc_free(argframe);
  1392. }
  1393. static void
  1394. getSizeAndAlignment(const char *typePtr, unsigned *sizep, unsigned *alignp)
  1395. {
  1396.   NSArgumentInfo        info;
  1397.   typePtr = mframe_next_arg(typePtr, &info);
  1398.   if (sizep)
  1399.     *sizep = info.size;
  1400.   if (alignp)
  1401.     *alignp = info.align;
  1402. BOOL
  1403. mframe_decode_return (const char *type, void* buffer, void* retframe)
  1404. {
  1405.   int size = 0;
  1406.   type = objc_skip_type_qualifiers(type);
  1407.   getSizeAndAlignment(type, &size, 0);
  1408.   switch (*type)
  1409.     {
  1410.     case _C_ID:
  1411.       {
  1412. inline id retframe_id(void *rframe)
  1413. {
  1414.   __builtin_return (rframe);
  1415. }
  1416. *(id*)buffer = retframe_id(retframe);
  1417. break;
  1418.       }
  1419.     case _C_CLASS:
  1420.       {
  1421. inline Class retframe_Class(void *rframe)
  1422. {
  1423.   __builtin_return (rframe);
  1424. }
  1425. *(Class*)buffer = retframe_Class(retframe);
  1426. break;
  1427.       }
  1428.     case _C_SEL:
  1429.       {
  1430. inline SEL retframe_SEL(void *rframe)
  1431. {
  1432.   __builtin_return (rframe);
  1433. }
  1434. *(SEL*)buffer = retframe_SEL(retframe);
  1435. break;
  1436.       }
  1437.     case _C_CHR:
  1438.     case _C_UCHR:
  1439.       {
  1440. inline unsigned char retframe_char(void *rframe)
  1441. {
  1442.   __builtin_return (rframe);
  1443. }
  1444. *(unsigned char*)buffer = retframe_char(retframe);
  1445. break;
  1446.       }
  1447.     case _C_SHT:
  1448.     case _C_USHT:
  1449.       {
  1450. inline unsigned short retframe_short(void *rframe)
  1451. {
  1452.   __builtin_return (rframe);
  1453. }
  1454. *(unsigned short*)buffer = retframe_short(retframe);
  1455. break;
  1456.       }
  1457.     case _C_INT:
  1458.     case _C_UINT:
  1459.       {
  1460. inline unsigned int retframe_int(void *rframe)
  1461. {
  1462.   __builtin_return (rframe);
  1463. }
  1464. *(unsigned int*)buffer = retframe_int(retframe);
  1465. break;
  1466.       }
  1467.     case _C_LNG:
  1468.     case _C_ULNG:
  1469.       {
  1470. inline unsigned long retframe_long(void *rframe)
  1471. {
  1472.   __builtin_return (rframe);
  1473. }
  1474. *(unsigned long*)buffer = retframe_long(retframe);
  1475. break;
  1476.       }
  1477. #ifdef _C_LNG_LNG
  1478.     case _C_LNG_LNG:
  1479.     case _C_ULNG_LNG:
  1480.       {
  1481. inline unsigned long long retframe_longlong(void *rframe)
  1482. {
  1483.   __builtin_return (rframe);
  1484. }
  1485. *(unsigned long long*)buffer = retframe_longlong(retframe);
  1486. break;
  1487.       }
  1488. #endif
  1489.     case _C_FLT:
  1490.       {
  1491. inline float retframe_float(void *rframe)
  1492. {
  1493.   __builtin_return (rframe);
  1494. }
  1495. *(float*)buffer = retframe_float(retframe);
  1496. break;
  1497.       }
  1498.     case _C_DBL:
  1499.       {
  1500. inline double retframe_double(void *rframe)
  1501. {
  1502.   __builtin_return (rframe);
  1503. }
  1504. *(double*)buffer = retframe_double(retframe);
  1505. break;
  1506.       }
  1507.     case _C_PTR:
  1508.     case _C_ATOM:
  1509.     case _C_CHARPTR:
  1510.       {
  1511. inline char* retframe_pointer(void *rframe)
  1512. {
  1513.   __builtin_return (rframe);
  1514. }
  1515. *(char**)buffer = retframe_pointer(retframe);
  1516. break;
  1517.       }
  1518.     case _C_ARY_B:
  1519.     case _C_STRUCT_B:
  1520.     case _C_UNION_B:
  1521.       {
  1522. typedef struct {
  1523.   char val[size];
  1524. } block;
  1525. inline block retframe_block(void *rframe)
  1526. {
  1527.   __builtin_return (rframe);
  1528. }
  1529. #ifndef __CHECKER__
  1530.         /* Checker-equipped compiler barfs on this on sparc-sun-solaris2.7. */
  1531. *(block *) buffer = retframe_block (retframe);
  1532. #else
  1533. #warning Disabling code in mframe for Checker
  1534. #endif
  1535. break;
  1536.       }
  1537.     case _C_VOID:
  1538.       break;
  1539.     default:
  1540.       return NO; /* Unknown type. */
  1541.     }
  1542.   return YES;
  1543. }
  1544. void*
  1545. mframe_handle_return(const char* type, void* retval, arglist_t argframe)
  1546. {
  1547.   retval_t retframe;
  1548.   typedef struct { id many[8];} __big;
  1549.   __big return_block (void* data)
  1550.   {
  1551.     return *(__big*)data;
  1552.   }
  1553.   /* For returning a char (or unsigned char) */
  1554.   char return_char (char data)
  1555.   {
  1556.     return data;
  1557.   }
  1558.   /* For returning a double */
  1559.   double return_double (double data)
  1560.   {
  1561.     return data;
  1562.   }
  1563.   /* For returning a float */
  1564.   float return_float (float data)
  1565.   {
  1566.     return data;
  1567.   }
  1568.   /* For returning a short (or unsigned short) */
  1569.   short return_short (short data)
  1570.   {
  1571.     return data;
  1572.   }
  1573.   retval_t apply_block(void* data)
  1574.   {
  1575.     void* args = __builtin_apply_args();
  1576.     return __builtin_apply((apply_t)return_block, args, sizeof(void*));
  1577.   }
  1578.   retval_t apply_char(char data)
  1579.   {
  1580.     void* args = __builtin_apply_args();
  1581.     return __builtin_apply((apply_t)return_char, args, sizeof(void*));
  1582.   }
  1583.   retval_t apply_float(float data)
  1584.   {
  1585.     void* args = __builtin_apply_args();
  1586.     return __builtin_apply((apply_t)return_float, args, sizeof(float));
  1587.   }
  1588.   retval_t apply_double(double data)
  1589.   {
  1590.     void* args = __builtin_apply_args();
  1591.     return __builtin_apply((apply_t)return_double, args, sizeof(double));
  1592.   }
  1593.   retval_t apply_short(short data)
  1594.   {
  1595.     void* args = __builtin_apply_args();
  1596.     return __builtin_apply((apply_t)return_short, args, sizeof(void*));
  1597.   }
  1598.   retframe = alloca(MFRAME_RESULT_SIZE);
  1599.   switch (*type)
  1600.     {
  1601.       case _C_VOID:
  1602. break;
  1603.       case _C_CHR:
  1604.       case _C_UCHR:
  1605. return apply_char(*(char*)retval);
  1606.       case _C_DBL:
  1607. return apply_double(*(double*)retval);
  1608.       case _C_FLT:
  1609. return apply_float(*(float*)retval);
  1610.       case _C_SHT:
  1611.       case _C_USHT:
  1612. return apply_short(*(short*)retval);
  1613.       case _C_ARY_B:
  1614.       case _C_UNION_B:
  1615.       case _C_STRUCT_B:
  1616. {
  1617.   int    size = objc_sizeof_type(type);
  1618. #if 1
  1619.   void *dest;
  1620.   dest = MFRAME_GET_STRUCT_ADDR(argframe, type);
  1621.   memcpy(dest, retval, size);
  1622. #else
  1623.   if (size > 8)
  1624.     {
  1625.       return apply_block(*(void**)retval);
  1626.     }
  1627.   else
  1628.     {
  1629.       memcpy(retframe, retval, size);
  1630.     }
  1631. #endif
  1632.   break;
  1633. }
  1634.       default:
  1635. memcpy(retframe, retval, objc_sizeof_type(type));
  1636. break;
  1637.     }
  1638.   return retframe;
  1639. }