1/** Implementation of GSFFIInvocation for GNUStep
2   Copyright (C) 2000 Free Software Foundation, Inc.
3
4   Written: Adam Fedor <fedor@gnu.org>
5   Date: Apr 2002
6
7   This file is part of the GNUstep Base Library.
8
9   This library is free software; you can redistribute it and/or
10   modify it under the terms of the GNU Lesser General Public
11   License as published by the Free Software Foundation; either
12   version 2 of the License, or (at your option) any later version.
13
14   This library is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public
20   License along with this library; if not, write to the Free
21   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22   Boston, MA 02110 USA.
23   */
24
25#import "common.h"
26
27#if !defined (__GNU_LIBOBJC__)
28#  include <objc/encoding.h>
29#endif
30
31#define	EXPOSE_NSInvocation_IVARS	1
32#import "Foundation/NSException.h"
33#import "Foundation/NSCoder.h"
34#import "Foundation/NSDistantObject.h"
35#import "Foundation/NSData.h"
36#import "GSInvocation.h"
37#import "GNUstepBase/GSObjCRuntime.h"
38#import <pthread.h>
39#import "cifframe.h"
40#import "GSPrivate.h"
41
42#ifdef __GNUSTEP_RUNTIME__
43#include <objc/hooks.h>
44#endif
45
46#ifdef __GNU_LIBOBJC__
47#include <objc/message.h>
48#endif
49
50#ifndef GS_STATIC_INLINE
51#define GS_STATIC_INLINE static inline
52#endif
53
54/* Function that implements the actual forwarding */
55typedef void (*ffi_closure_fun) (ffi_cif*,void*,void**,void*);
56
57typedef void (*f_fun) ();
58
59static void GSFFIInvocationCallback(ffi_cif*, void*, void **, void*);
60
61/* This routine should return a typed selector corresponding to the
62   name of the specified selector.  If there is only one type, then we
63   can safely return that typed selector.  If not, then we can not be
64   certain which one is expected, and to prevent a crash if we return
65   the wrong type, we return NULL.
66
67   Older runtimes do not have facilities in the API to check for
68   conflicting types, hence would return a random selector in that
69   case.  */
70GS_STATIC_INLINE SEL
71gs_find_best_typed_sel (SEL sel)
72#ifdef __GNUSTEP_RUNTIME__
73{
74  const char *selName = sel_getName(sel);
75  const char *types;
76
77  /* If there is not exactly one typed selector with this name
78   * registered with the runtime, then give up - we can't safely use
79   * this function.  */
80  if (1 != sel_copyTypes_np (selName, NULL, 0))
81    return (SEL)0;
82
83  sel_copyTypes_np (selName, &types, 1);
84  return GSSelectorFromNameAndTypes(selName, types);
85}
86#elif defined (__GNU_LIBOBJC__)
87{
88/* The sel_getTypedSelector() function returns a typed selector if there
89 * is only one, nul if there are zero or more tha one.
90 */
91  return sel_getTypedSelector(sel_getName(sel));
92}
93#elif defined(NeXTRUNTIME)
94{
95  /* The NeXT runtime does not support typed selectors, so we simply
96   * return 0 here.  */
97  return (SEL)0;
98}
99#else
100{
101  /* We can't iterate over the selectors with the same name, but we
102   * can ask the runtime for a typed selector with a certain name.
103   * Usually this works, but it may produce unexpected results
104   * (including a crash) if more than one selector are registered with
105   * the same name but different types.  */
106  if (!GSTypesFromSelector(sel))
107    {
108      const char *name = sel_getName(sel);
109      if (name)
110        {
111          SEL tmp_sel = sel_get_any_typed_uid(name);
112          if (GSTypesFromSelector(tmp_sel))
113            return tmp_sel;
114        }
115    }
116  return sel;
117}
118#endif
119
120
121@implementation GSFFIInvocation
122
123static IMP gs_objc_msg_forward2 (id receiver, SEL sel)
124{
125  NSMethodSignature     *sig = nil;
126  GSCodeBuffer          *memory;
127  const char            *types;
128
129  /*
130   * If we're called with a typed selector, then use this when deconstructing
131   * the stack frame.  This deviates from OS X behaviour (where there are no
132   * typed selectors), but it always more reliable because the compiler will
133   * set the selector types to represent the layout of the call frame.  This
134   * means that the invocation will always deconstruct the call frame
135   * correctly.
136   */
137
138  if (NULL != (types = GSTypesFromSelector(sel)))
139    {
140      sig = [NSMethodSignature signatureWithObjCTypes: types];
141    }
142
143  /* Take care here ... the receiver may be nil (old runtimes) or may be
144   * a proxy which implements a method by forwarding it (so calling the
145   * method might cause recursion).  However, any sane proxy ought to at
146   * least implement -methodSignatureForSelector: in such a way that it
147   * won't cause infinite recursion, so we check for that method being
148   * implemented and call it.
149   * NB. object_getClass() and class_respondsToSelector() should both
150   * return NULL when given NULL arguments, so they are safe to use.
151   */
152  if (nil == sig)
153    {
154      Class 	c = object_getClass(receiver);
155
156      if (class_respondsToSelector(c, @selector(methodSignatureForSelector:)))
157        {
158          sig = [receiver methodSignatureForSelector: sel];
159        }
160      if (nil == sig
161	&& (NULL != (types = GSTypesFromSelector(gs_find_best_typed_sel(sel)))))
162	{
163	  sig = [NSMethodSignature signatureWithObjCTypes: types];
164	}
165      if (nil == sig)
166	{
167          if (nil == receiver)
168            {
169              /* If we have a nil receiver, so the runtime is probably trying
170               * to check for forwarding ... return NULL to let it fall back
171               * on the standard forwarding mechanism.
172               */
173              return NULL;
174            }
175	  [NSException raise: NSInvalidArgumentException
176	    format: @"%c[%s %s]: unrecognized selector sent to instance %p",
177	    (class_isMetaClass(c) ? '+' : '-'),
178	    class_getName(c), sel_getName(sel), receiver];
179	}
180    }
181
182  memory = cifframe_closure(sig, GSFFIInvocationCallback);
183
184  return (IMP)[memory executable];
185}
186
187static __attribute__ ((__unused__))
188IMP gs_objc_msg_forward (SEL sel)
189{
190  return gs_objc_msg_forward2 (nil, sel);
191}
192#ifdef __GNUSTEP_RUNTIME__
193pthread_key_t thread_slot_key;
194static struct objc_slot *
195gs_objc_msg_forward3(id receiver, SEL op)
196{
197  /* The slot has its version set to 0, so it can not be cached.  This makes it
198   * safe to free it when the thread exits. */
199  struct objc_slot *slot = pthread_getspecific(thread_slot_key);
200
201  if (NULL == slot)
202    {
203      slot = calloc(sizeof(struct objc_slot), 1);
204      pthread_setspecific(thread_slot_key, slot);
205    }
206  slot->method = gs_objc_msg_forward2(receiver, op);
207  return slot;
208}
209
210/** Hidden by legacy API define.  Declare it locally */
211BOOL class_isMetaClass(Class cls);
212BOOL class_respondsToSelector(Class cls, SEL sel);
213
214/**
215 * Runtime hook used to provide message redirections with libobjc2.
216 * If lookup fails but this function returns non-nil then the lookup
217 * will be retried with the returned value.
218 *
219 * Note: Every message sent by this function MUST be understood by the
220 * receiver.  If this is not the case then there is a potential for infinite
221 * recursion.
222 */
223static id gs_objc_proxy_lookup(id receiver, SEL op)
224{
225  id cls = object_getClass(receiver);
226  BOOL resolved = NO;
227
228  /* Note that __GNU_LIBOBJC__ implements +resolveClassMethod: and
229     +resolveInstanceMethod: directly in the runtime instead.  */
230
231  /* Let the class try to add a method for this thing. */
232  if (class_isMetaClass(cls))
233    {
234      if (class_respondsToSelector(cls, @selector(resolveClassMethod:)))
235	{
236	  resolved = [receiver resolveClassMethod: op];
237	}
238    }
239  else
240    {
241      if (class_respondsToSelector(object_getClass(cls),
242	@selector(resolveInstanceMethod:)))
243	{
244	  resolved = [cls resolveInstanceMethod: op];
245	}
246    }
247  if (resolved)
248    {
249      return receiver;
250    }
251  if (class_respondsToSelector(cls, @selector(forwardingTargetForSelector:)))
252    {
253      return [receiver forwardingTargetForSelector: op];
254    }
255  return nil;
256}
257#endif
258
259+ (void) load
260{
261#ifdef __GNUSTEP_RUNTIME__
262  pthread_key_create(&thread_slot_key, free);
263  __objc_msg_forward3 = gs_objc_msg_forward3;
264  __objc_msg_forward2 = gs_objc_msg_forward2;
265  objc_proxy_lookup = gs_objc_proxy_lookup;
266#else
267#if	HAVE_FORWARD2
268  __objc_msg_forward2 = gs_objc_msg_forward2;
269#else
270  __objc_msg_forward = gs_objc_msg_forward;
271#endif
272#endif
273}
274
275
276/*
277 *	This is the designated initialiser.
278 */
279- (id) initWithMethodSignature: (NSMethodSignature*)aSignature
280{
281  int	i;
282
283  if (aSignature == nil)
284    {
285      DESTROY(self);
286      return nil;
287    }
288  _sig = RETAIN(aSignature);
289  _numArgs = [aSignature numberOfArguments];
290  _info = [aSignature methodInfo];
291  _frame = cifframe_from_signature(_sig);
292  [_frame retain];
293  _cframe = [_frame mutableBytes];
294
295  /* Make sure we have somewhere to store the return value if needed.
296   */
297  _retval = _retptr = 0;
298  i = objc_sizeof_type (objc_skip_type_qualifiers ([_sig methodReturnType]));
299  if (i > 0)
300    {
301      if (i <= sizeof(_retbuf))
302	{
303	  _retval = _retbuf;
304	}
305      else
306	{
307	  _retptr = NSAllocateCollectable(i, NSScannedOption);
308	  _retval = _retptr;
309	}
310    }
311  return self;
312}
313
314/* Initializer used when we get a callback. uses the data provided by
315   the callback. The cifframe was allocated by the forwarding function,
316   but we own it now so we can free it */
317- (id) initWithCallback: (ffi_cif *)cif
318		 values: (void **)vals
319		  frame: (void *)frame
320	      signature: (NSMethodSignature*)aSignature
321{
322  cifframe_t *f;
323  int i;
324
325  _sig = RETAIN(aSignature);
326  _numArgs = [aSignature numberOfArguments];
327  _info = [aSignature methodInfo];
328  _frame = (NSMutableData*)frame;
329  [_frame retain];
330  _cframe = [_frame mutableBytes];
331  f = (cifframe_t *)_cframe;
332  f->cif = *cif;
333
334  /* Copy the arguments into our frame so that they are preserved
335   * in the NSInvocation if the stack is changed before the
336   * invocation is used.
337   */
338  for (i = 0; i < f->nargs; i++)
339    {
340      memcpy(f->values[i], vals[i], f->arg_types[i]->size);
341    }
342
343  /* Make sure we have somewhere to store the return value if needed.
344   */
345  _retval = _retptr = 0;
346  i = objc_sizeof_type (objc_skip_type_qualifiers ([_sig methodReturnType]));
347  if (i > 0)
348    {
349      if (i <= sizeof(_retbuf))
350	{
351	  _retval = _retbuf;
352	}
353      else
354	{
355	  _retptr = NSAllocateCollectable(i, NSScannedOption);
356	  _retval = _retptr;
357	}
358    }
359  return self;
360}
361
362/*
363 * This is implemented as a function so it can be used by other
364 * routines (like the DO forwarding)
365 */
366void
367GSFFIInvokeWithTargetAndImp(NSInvocation *inv, id anObject, IMP imp)
368{
369  /* Do it */
370  ffi_call(inv->_cframe, (f_fun)imp, (inv->_retval),
371	   ((cifframe_t *)inv->_cframe)->values);
372
373  /* Don't decode the return value here (?) */
374}
375
376- (void) invokeWithTarget: (id)anObject
377{
378  id		old_target;
379  const char	*type;
380  IMP		imp;
381
382  CLEAR_RETURN_VALUE_IF_OBJECT;
383  _validReturn = NO;
384  type = objc_skip_type_qualifiers([_sig methodReturnType]);
385
386  /*
387   *	A message to a nil object returns nil.
388   */
389  if (anObject == nil)
390    {
391      if (_retval)
392	{
393          memset(_retval, '\0', objc_sizeof_type (type));
394	}
395      _validReturn = YES;
396      return;
397    }
398
399  /* Make sure we have a typed selector for forwarding.
400   */
401  NSAssert(_selector != 0, @"you must set the selector before invoking");
402  if (0 == GSTypesFromSelector(_selector))
403    {
404      _selector = GSSelectorFromNameAndTypes(sel_getName(_selector),
405	[_sig methodType]);
406    }
407
408  /*
409   *	Temporarily set new target and copy it (and the selector) into the
410   *	_cframe.
411   */
412  old_target = RETAIN(_target);
413  [self setTarget: anObject];
414
415  cifframe_set_arg((cifframe_t *)_cframe, 0, &_target, sizeof(id));
416  cifframe_set_arg((cifframe_t *)_cframe, 1, &_selector, sizeof(SEL));
417
418  if (_sendToSuper == YES)
419    {
420      Class cls;
421      if (GSObjCIsInstance(_target))
422	cls = class_getSuperclass(object_getClass(_target));
423      else
424	cls = class_getSuperclass((Class)_target);
425      {
426        struct objc_super	s = {_target, cls};
427        imp = objc_msg_lookup_super(&s, _selector);
428      }
429    }
430  else
431    {
432      GSMethod method;
433      method = GSGetMethod((GSObjCIsInstance(_target)
434                            ? (Class)object_getClass(_target)
435                            : (Class)_target),
436                           _selector,
437                           GSObjCIsInstance(_target),
438                           YES);
439      imp = method_getImplementation(method);
440      /*
441       * If fast lookup failed, we may be forwarding or something ...
442       */
443      if (imp == 0)
444	{
445	  imp = objc_msg_lookup(_target, _selector);
446	}
447    }
448
449  [self setTarget: old_target];
450  RELEASE(old_target);
451
452  GSFFIInvokeWithTargetAndImp(self, anObject, imp);
453
454  /* Decode the return value */
455  if (*type != _C_VOID)
456    {
457      cifframe_decode_arg(type, _retval);
458    }
459
460  RETAIN_RETURN_VALUE;
461  _validReturn = YES;
462}
463
464@end
465
466/*
467 * Return YES if the selector contains protocol qualifiers.
468 */
469static BOOL
470gs_protocol_selector(const char *types)
471{
472  if (types == 0)
473    {
474      return NO;
475    }
476  while (*types != '\0')
477    {
478      if (*types == '+' || *types == '-')
479	{
480	  types++;
481	}
482      while (isdigit(*types))
483	{
484	  types++;
485	}
486      while (*types == _C_CONST || *types == _C_GCINVISIBLE)
487	{
488	  types++;
489	}
490      if (*types == _C_IN
491	|| *types == _C_INOUT
492	|| *types == _C_OUT
493	|| *types == _C_BYCOPY
494	|| *types == _C_BYREF
495	|| *types == _C_ONEWAY)
496	{
497	  return YES;
498	}
499      if (*types == '\0')
500	{
501	  return NO;
502	}
503      types = objc_skip_typespec(types);
504    }
505  return NO;
506}
507
508static void
509GSFFIInvocationCallback(ffi_cif *cif, void *retp, void **args, void *user)
510{
511  id			obj;
512  SEL			selector;
513  GSFFIInvocation	*invocation;
514  NSMethodSignature	*sig;
515
516  obj      = *(id *)args[0];
517  selector = *(SEL *)args[1];
518
519  if (!class_respondsToSelector(object_getClass(obj),
520    @selector(forwardInvocation:)))
521    {
522      [NSException raise: NSInvalidArgumentException
523		   format: @"GSFFIInvocation: Class '%s'(%s) does not respond"
524		           @" to forwardInvocation: for '%s'",
525		   GSClassNameFromObject(obj),
526		   GSObjCIsInstance(obj) ? "instance" : "class",
527		   selector ? sel_getName(selector) : "(null)"];
528    }
529
530  sig = nil;
531  if (gs_protocol_selector(GSTypesFromSelector(selector)) == YES)
532    {
533      sig = [NSMethodSignature signatureWithObjCTypes:
534	GSTypesFromSelector(selector)];
535    }
536  if (sig == nil)
537    {
538      sig = [obj methodSignatureForSelector: selector];
539    }
540
541  /*
542   * If we got a method signature from the receiving object,
543   * ensure that the selector we are using matches the types.
544   */
545  if (sig != nil)
546    {
547      const char	*receiverTypes = [sig methodType];
548      const char	*runtimeTypes = GSTypesFromSelector(selector);
549
550      if (NO == GSSelectorTypesMatch(receiverTypes, runtimeTypes))
551	{
552	  const char	*runtimeName = sel_getName(selector);
553
554	  selector = GSSelectorFromNameAndTypes(runtimeName, receiverTypes);
555	  if (runtimeTypes != 0)
556	    {
557	      /*
558	       * FIXME ... if we have a typed selector, it probably came
559	       * from the compiler, and the types of the proxied method
560	       * MUST match those that the compiler supplied on the stack
561	       * and the type it expects to retrieve from the stack.
562	       * We should therefore discriminate between signatures where
563	       * type qalifiers and sizes differ, and those where the
564	       * actual types differ.
565	       */
566	      NSDebugFLog(@"Changed type signature '%s' to '%s' for '%s'",
567		runtimeTypes, receiverTypes, runtimeName);
568	    }
569	}
570    }
571
572  if (sig == nil)
573    {
574      /* NB Don't overwrite selector prematurely, so we can show the untyped
575       * selector in the error message below if there is no best selector. */
576      SEL typed_sel = gs_find_best_typed_sel (selector);
577
578      if (typed_sel != 0)
579	{
580	  selector = typed_sel;
581	  if (GSTypesFromSelector(selector) != 0)
582	    {
583	      sig = [NSMethodSignature signatureWithObjCTypes:
584	        GSTypesFromSelector(selector)];
585	    }
586	}
587    }
588
589  if (sig == nil)
590    {
591      [NSException raise: NSInvalidArgumentException
592                   format: @"Can not determine type information for %s[%s %s]",
593                   GSObjCIsInstance(obj) ? "-" : "+",
594	 GSClassNameFromObject(obj),
595	 selector ? sel_getName(selector) : "(null)"];
596    }
597
598  invocation = [[GSFFIInvocation alloc] initWithCallback: cif
599					values: args
600 					frame: user
601					signature: sig];
602  IF_NO_GC([invocation autorelease];)
603  [invocation setTarget: obj];
604  [invocation setSelector: selector];
605
606  [obj forwardInvocation: invocation];
607
608  /* If we are returning a value, we must copy it from the invocation
609   * to the memory indicated by 'retp'.
610   */
611  if (retp != 0 && invocation->_validReturn == YES)
612    {
613      [invocation getReturnValue: retp];
614    }
615
616  /* We need to (re)encode the return type for it's trip back. */
617  if (retp)
618    cifframe_encode_arg([sig methodReturnType], retp);
619}
620
621@implementation NSInvocation (DistantCoding)
622
623/* An internal method used to help NSConnections code invocations
624   to send over the wire */
625- (BOOL) encodeWithDistantCoder: (NSCoder*)coder passPointers: (BOOL)passp
626{
627  int		i;
628  BOOL		out_parameters = NO;
629  const char	*type = [_sig methodType];
630
631  [coder encodeValueOfObjCType: @encode(char*) at: &type];
632
633  for (i = 0; i < _numArgs; i++)
634    {
635      int		flags = _inf[i+1].qual;
636      const char	*type = _inf[i+1].type;
637      void		*datum;
638
639      if (i == 0)
640	{
641	  datum = &_target;
642	}
643      else if (i == 1)
644	{
645	  datum = &_selector;
646	}
647      else
648	{
649	  datum = cifframe_arg_addr((cifframe_t *)_cframe, i);
650	}
651
652      /*
653       * Decide how, (or whether or not), to encode the argument
654       * depending on its FLAGS and TYPE.  Only the first two cases
655       * involve parameters that may potentially be passed by
656       * reference, and thus only the first two may change the value
657       * of OUT_PARAMETERS.
658       */
659
660      switch (*type)
661	{
662	  case _C_ID:
663	    if (flags & _F_BYCOPY)
664	      {
665		[coder encodeBycopyObject: *(id*)datum];
666	      }
667#ifdef	_F_BYREF
668	    else if (flags & _F_BYREF)
669	      {
670		[coder encodeByrefObject: *(id*)datum];
671	      }
672#endif
673	    else
674	      {
675		[coder encodeObject: *(id*)datum];
676	      }
677	    break;
678	  case _C_CHARPTR:
679	    /*
680	     * Handle a (char*) argument.
681	     * If the char* is qualified as an OUT parameter, or if it
682	     * not explicitly qualified as an IN parameter, then we will
683	     * have to get this char* again after the method is run,
684	     * because the method may have changed it.  Set
685	     * OUT_PARAMETERS accordingly.
686	     */
687	    if ((flags & _F_OUT) || !(flags & _F_IN))
688	      {
689		out_parameters = YES;
690	      }
691	    /*
692	     * If the char* is qualified as an IN parameter, or not
693	     * explicity qualified as an OUT parameter, then encode
694	     * it.
695	     */
696	    if ((flags & _F_IN) || !(flags & _F_OUT))
697	      {
698		[coder encodeValueOfObjCType: type at: datum];
699	      }
700	    break;
701
702	  case _C_PTR:
703	    /*
704	     * If the pointer's value is qualified as an OUT parameter,
705	     * or if it not explicitly qualified as an IN parameter,
706	     * then we will have to get the value pointed to again after
707	     * the method is run, because the method may have changed
708	     * it.  Set OUT_PARAMETERS accordingly.
709	     */
710	    if ((flags & _F_OUT) || !(flags & _F_IN))
711	      {
712		out_parameters = YES;
713	      }
714	    if (passp)
715	      {
716		if ((flags & _F_IN) || !(flags & _F_OUT))
717		  {
718		    [coder encodeValueOfObjCType: type at: datum];
719		  }
720	      }
721	    else
722	      {
723		/*
724		 * Handle an argument that is a pointer to a non-char.  But
725		 * (void*) and (anything**) is not allowed.
726		 * The argument is a pointer to something; increment TYPE
727		 * so we can see what it is a pointer to.
728		 */
729		type++;
730		/*
731		 * If the pointer's value is qualified as an IN parameter,
732		 * or not explicity qualified as an OUT parameter, then
733		 * encode it.
734		 */
735		if ((flags & _F_IN) || !(flags & _F_OUT))
736		  {
737		    [coder encodeValueOfObjCType: type at: *(void**)datum];
738		  }
739	      }
740	    break;
741
742	  case _C_STRUCT_B:
743	  case _C_UNION_B:
744	  case _C_ARY_B:
745	    /*
746	     * Handle struct and array arguments.
747	     * Whether DATUM points to the data, or points to a pointer
748	     * that points to the data, depends on the value of
749	     * CALLFRAME_STRUCT_BYREF.  Do the right thing
750	     * so that ENCODER gets a pointer to directly to the data.
751	     */
752	    [coder encodeValueOfObjCType: type at: datum];
753	    break;
754
755	  default:
756	    /* Handle arguments of all other types. */
757	    [coder encodeValueOfObjCType: type at: datum];
758	}
759    }
760
761  /*
762   * Return a BOOL indicating whether or not there are parameters that
763   * were passed by reference; we will need to get those values again
764   * after the method has finished executing because the execution of
765   * the method may have changed them.
766   */
767  return out_parameters;
768}
769
770@end
771