Message forwarding in GCC

Message forwarding in GCC

Post by Frank Mitchel » Wed, 16 Jul 2003 12:50:39



Attached is a (perhaps overlong) program testing messaging forwarding in
GCC.  It core-dumps when compiled with GCC 2.95.3 on Linux running on an
ancient IBM ThinkPad 380 ED.

For comparison, I adapted it for the POC, which works as expected.
Unfortunately, I was hoping to use POC to create an XML-RPC proxy class
along the lines of Distributed Objects (or the Ruby XML-RPC library),
but POC's forwarding support seems pretty limited.

Could someone tell me:

1. Is there a problem with the program as written, which doesn't show up
in the POC?

2. Is the GCC support for Objective-C known to be broken in 2.95.3?
I've seen oblique references to an "Objective-C patch", but never
actually found it.

3. Will I have to upgrade to GCC 3.x?

4. Should I use libFoundation and NSInvocation instead?

For reference, here's the full output:
---------------------------------------------
Test: 0x8058910 testNoArgs
Test: 0x8058910 testObject:     #<Test 0x8058910>
        0xbffff9c8
Test: 0x8058910 testObject:object:      #<Test 0x8058910> #<Object 0x8058be0>
        0xbffff9c8      0xbffff9cc
Test: 0x8058910 testString:     test
        0xbffff9c8
Test: 0x8058910 testInt:        42
        0xbffff9c8
Test: 0x8058910 testInt:string: 42      test2
        0xbffff9c8      0xbffff9cc
Test: 0x8058910 testBool:       1
        0xbffff9b7
Test: 0x8058910 testChar:       +
        0xbffff9b7
Test: 0x8058910 testFloat:      2.400000
        0xbffff9c8
Test: 0x8058910 testDouble:     4.800000
        0xbffff9c8
Forwarder 0x8058a90: Sending testNoArgs to 0x8058910 with 0xbffff9a8
Test: 0xbffff858        testNoArgs
Forwarder 0x8058a90: Sending testObject: to 0x8058910 with 0xbffff9a8
Segmentation fault (core dumped)

--
Frank Mitchell (frankm each bayarea period net)

Please avoid sending me Word or PowerPoint attachments.
See http://www.fsf.org/philosophy/no-word-attachments.html

[ fwdtest.m 3K ]
#ifndef __PORTABLE_OBJC__
#include <objc/objc.h>
#include <objc/objc-api.h>
#include <objc/Object.h>
#include <objc/NXConstStr.h>
#else /* __PORTABLE_OBJC__ */
#include <objc.h>
#endif /* __PORTABLE_OBJC__ */

{
  id delegate;

Quote:}



- init
{
  delegate = nil;
  return self;

Quote:}

- setDelegate: aDelegate
{
  delegate = aDelegate;
  return self;

Quote:}

#ifdef __PORTABLE_OBJC__
- doesNotUnderstand: aMessage
{
  const char *selname =  selName([aMessage selector]);

  if (delegate != nil) {
    printf("Forwarder %p: Sending %s to %p\n",
           self, selname, delegate);
    [aMessage sentTo: delegate];
    return self;
  } else {
    printf("Ignoring %s\n", selname);
    return nil;
  }

Quote:}

#else /* not __PORTABLE_OBJC__ */
- (retval_t)forward:(SEL)sel :(arglist_t)stackFrame
{
  const char *selname =  sel_get_name(sel);

  if (delegate != nil) {
    printf("Forwarder %p: Sending %s to %p with %p\n",
           self, selname, delegate, stackFrame);
    return [delegate performv:sel :stackFrame];
  } else {
    printf("Ignoring %s\n", selname);
    return nil;
  }

Quote:}

#endif /* __PORTABLE_OBJC__ */


- run;
- runWith: target;

- testNoArgs;
- testObject: obj1;
- testObject: obj1 object: obj2;
- testString: (const char*)aString;
- testInt: (int)anInt;
- testInt: (int)anInt string: (const char *)aString;
- testBool: (BOOL)aBool;
- testChar: (char)aChar;
- testFloat: (float)aFloat;


- run
{
  id forwarder = [Forwarder new];

  [forwarder setDelegate: self];

  [self runWith: self];

  [self runWith: forwarder];

  [forwarder free];

  return self;

Quote:}

- runWith: target
{
  id other = [Object new];

  [target testNoArgs];

  [target testObject: self];
  [target testObject: self object: other];

  [target testString: "test"];
  [target testInt: 42];
  [target testInt: 42 string:"test2"];

  [target testBool: YES];
  [target testChar: '+'];

  [target testFloat: (float)2.4];
  [target testDouble: (double)4.8];

  [other free];

  return self;

Quote:}

- testNoArgs
{
  printf("Test: %p\ttestNoArgs\n", self);
  return self;

Quote:}

- testObject: obj1
{
  printf("Test: %p\ttestObject:\t#<%s %p>\n", self, [obj1 name], obj1);
  printf("\t%p\n", &obj1);
  return self;

Quote:}

- testObject: obj1 object: obj2
{
  printf("Test: %p\ttestObject:object:\t#<%s %p>\t#<%s %p>\n",
         self, [obj1 name], obj1, [obj2 name], obj2);
  printf("\t%p\t%p\n", &obj1, &obj2);
  return self;

Quote:}

- testString: (const char*)aString
{
  printf("Test: %p\ttestString:\t%s\n", self, aString);
  printf("\t%p\n", &aString);
  return self;

Quote:}

- testInt: (int)anInt
{
  printf("Test: %p\ttestInt:\t%d\n", self, anInt);
  printf("\t%p\n", &anInt);
  return self;

Quote:}

- testInt: (int)anInt string: (const char *)aString
{
  printf("Test: %p\ttestInt:string:\t%d\t%s\n", self, anInt, aString);
  printf("\t%p\t%p\n", &anInt, &aString);
  return self;

Quote:}

- testBool: (BOOL)aBool
{
  printf("Test: %p\ttestBool:\t%d\n", self, (int)aBool);
  printf("\t%p\n", &aBool);
  return self;

Quote:}

- testChar: (char)aChar
{
  printf("Test: %p\ttestChar:\t%c\n", self, aChar);
  printf("\t%p\n", &aChar);
  return self;

Quote:}

- testFloat: (float)aFloat
{
  printf("Test: %p\ttestFloat:\t%f\n", self, (double)aFloat);
  printf("\t%p\n", &aFloat);
  return self;

Quote:}

- testDouble: (double)aDouble
{
  printf("Test: %p\ttestDouble:\t%f\n", self, aDouble);
  printf("\t%p\n", &aDouble);
  return self;

}


int main(int argc, char* argv[])
{
  id instance = [Test new];
  [instance run];
  [instance free];
  return 0;

Quote:}

 
 
 

Message forwarding in GCC

Post by John C. Randolp » Thu, 17 Jul 2003 17:50:48



> 4. Should I use libFoundation and NSInvocation instead?

Yes.

-jcr

 
 
 

Message forwarding in GCC

Post by David Ste » Fri, 18 Jul 2003 00:43:37




>> 4. Should I use libFoundation and NSInvocation instead?

> Yes.

 Maybe you can ask Frank M. for the output of the (correct) POC program, so
that you have some reference on what the result should look like (in order
to fix the bug in your low-level assembly message forwarding routines).
 
 
 

Message forwarding in GCC

Post by Frank Mitchel » Fri, 18 Jul 2003 17:23:15




> > 4. Should I use libFoundation and NSInvocation instead?

> Yes.

After porting to libFoundation (0.9.0, compiled with GCC 2.95.3), I'm
getting the same problem.  As Mr. Stes suggested in another message, it
may be a problem with the stack handling in the GNU Objective-C compiler
and/or runtime.  I'm guessing Mac OS X has ironed that out, and maybe
GCC 3.x has as well.

I'm attaching a new version of the test program which supports POC,
vanilla GNU, and GNU + Foundation (with gcc -DUSE_FOUNDATION ...).  The
changes I made were:

- using NSObject instead of Object (via the ROOT_CLASS macro).

- renaming -run and -setDelegate to avoid conflicting with Foundation
method signatures.

- changing -forward:: to -forwardInvocation:

- changing -free to -release (via #ifdef USE_FOUNDATION)

- changing calls to -name to an "inspect" function, which works (albeit
slightly differently) under Foundation and old-style APIs.

Under GNU/Linux (or at least the antiquated version I'm running), the
POC preprocessor approach supports forwarding better than GNUStep's
libFoundation.  Not enough for the XML-RPC project, though, so that's
out.

My other Objective-C toy project is a minimal web server written in
Objective-C, leveraging dynamic typing and basic message forwarding.
I'm leaning toward the POC at the moment, since (a) I don't have a Mac
OS X machine available, (b) I'm using Objective-C more for nostalgia
than for practicality, and (c) I only used the OPENSTEP/Cocoa interfaces
briefly and therefore have no preference.  [Assuming, of course, I don't
bag Objective-C entirely and move on to other projects in Ruby or Eiffel
...]

Anyway, thanks for the help.

---
Frank Mitchell (frankm each bayarea period net)

Please avoid sending me Word or PowerPoint attachments.
See http://www.fsf.org/philosophy/no-word-attachments.html

[ fwdtest.m 4K ]
#ifdef __PORTABLE_OBJC__
#include <objc.h>
#else /* __PORTABLE_OBJC__ */
# ifdef USE_FOUNDATION
# include <Foundation/Foundation.h>
# else
# include <objc/objc.h>
# include <objc/objc-api.h>
# include <objc/Object.h>
# include <objc/NXConstStr.h>
# endif /* USE_FOUNDATION */
#endif /* __PORTABLE_OBJC__ */

#if defined(USE_FOUNDATION) && !defined(__PORTABLE_OBJC__)
#define ROOT_CLASS NSObject
#else
#define ROOT_CLASS Object
#endif

const char * inspect(id object) {
#if USE_FOUNDATION
  return [[object description] cString];
#else
  return [object name];
#endif

}


{
  id delegate;
Quote:}



- init
{
  delegate = nil;
  return self;

Quote:}

- setTestDelegate: aDelegate
{
  delegate = aDelegate;
  return self;

Quote:}

#ifdef __PORTABLE_OBJC__
- doesNotUnderstand: aMessage
{
  const char *selname =  selName([aMessage selector]);

  if (delegate != nil) {
    printf("Forwarder %p: Sending %s to %p\n",
           self, selname, delegate);
    [aMessage sentTo: delegate];
    return self;
  } else {
    printf("Ignoring %s\n", selname);
    return nil;
  }

Quote:}

#else  /* not __PORTABLE_OBJC__ */

#ifdef USE_FOUNDATION

- (void)forwardInvocation: (NSInvocation *)aMessage
{
  const char *selname =  
    [NSStringFromSelector([aMessage selector]) cString];

  if (delegate != nil) {
    printf("Forwarder %p: Sending %s to %p\n",
           self, selname, delegate);
    [aMessage invokeWithTarget: delegate];
  } else {
    printf("Ignoring %s\n", selname);
  }

Quote:}

#else /* GNU Object */

- (retval_t)forward:(SEL)sel :(arglist_t)stackFrame
{
  const char *selname =  sel_get_name(sel);

  if (delegate != nil) {
    printf("Forwarder %p: Sending %s to %p with %p\n",
           self, selname, delegate, stackFrame);
    return [delegate performv:sel :stackFrame];
  } else {
    printf("Ignoring %s\n", selname);
    return nil;
  }

Quote:}

#endif /* USE_FOUNDATION */
#endif /* __PORTABLE_OBJC__ */


- runTest;
- runTestWith: target;

- testNoArgs;
- testObject: obj1;
- testObject: obj1 object: obj2;
- testString: (const char*)aString;
- testInt: (int)anInt;
- testInt: (int)anInt string: (const char *)aString;
- testBool: (BOOL)aBool;
- testChar: (char)aChar;
- testFloat: (float)aFloat;


- runTest
{
  id forwarder = [Forwarder new];

  [forwarder setTestDelegate: self];

  [self runTestWith: self];

  [self runTestWith: forwarder];

#ifdef USE_FOUNDATION
  [forwarder release];
#else
  [forwarder free];
#endif

  return self;

Quote:}

- runTestWith: target
{
  id other = [ROOT_CLASS new];

  [target testNoArgs];

  [target testObject: self];
  [target testObject: self object: other];

  [target testString: "test"];
  [target testInt: 42];
  [target testInt: 42 string:"test2"];

  [target testBool: YES];
  [target testChar: '+'];

  [target testFloat: (float)2.4];
  [target testDouble: (double)4.8];

#ifdef USE_FOUNDATION
  [other release];
#else
  [other free];
#endif

  return self;

Quote:}

- testNoArgs
{
  printf("Test: %p\ttestNoArgs\n", self);
  return self;

Quote:}

- testObject: obj1
{
  printf("Test: %p\ttestObject:\t#<%s %p>\n", self, inspect(obj1), obj1);
  printf("\t%p\n", &obj1);
  return self;

Quote:}

- testObject: obj1 object: obj2
{
  printf("Test: %p\ttestObject:object:\t#<%s %p>\t#<%s %p>\n",
         self, inspect(obj1), obj1, inspect(obj2), obj2);
  printf("\t%p\t%p\n", &obj1, &obj2);
  return self;

Quote:}

- testString: (const char*)aString
{
  printf("Test: %p\ttestString:\t%s\n", self, aString);
  printf("\t%p\n", &aString);
  return self;

Quote:}

- testInt: (int)anInt
{
  printf("Test: %p\ttestInt:\t%d\n", self, anInt);
  printf("\t%p\n", &anInt);
  return self;

Quote:}

- testInt: (int)anInt string: (const char *)aString
{
  printf("Test: %p\ttestInt:string:\t%d\t%s\n", self, anInt, aString);
  printf("\t%p\t%p\n", &anInt, &aString);
  return self;

Quote:}

- testBool: (BOOL)aBool
{
  printf("Test: %p\ttestBool:\t%d\n", self, (int)aBool);
  printf("\t%p\n", &aBool);
  return self;

Quote:}

- testChar: (char)aChar
{
  printf("Test: %p\ttestChar:\t%c\n", self, aChar);
  printf("\t%p\n", &aChar);
  return self;

Quote:}

- testFloat: (float)aFloat
{
  printf("Test: %p\ttestFloat:\t%f\n", self, (double)aFloat);
  printf("\t%p\n", &aFloat);
  return self;

Quote:}

- testDouble: (double)aDouble
{
  printf("Test: %p\ttestDouble:\t%f\n", self, aDouble);
  printf("\t%p\n", &aDouble);
  return self;

}


int main(int argc, char* argv[])
{
  id instance = [Test new];
  [instance runTest];
#ifdef USE_FOUNDATION
  [instance release];
#else
  [instance free];
#endif
  return 0;

Quote:}

 
 
 

Message forwarding in GCC

Post by David Ste » Sat, 19 Jul 2003 05:48:04



> Under GNU/Linux (or at least the antiquated version I'm running), the
> POC preprocessor approach supports forwarding better than GNUStep's
> libFoundation.

A couple of years ago, Steve Naroff (then of NeXT, now of Apple, the
head of their JAVA department (interesingly enough not of their Obj-C
departement ...)), well, a couple of years ago he claimed that the
C messenger was incompatible with message forwarding.

I was sceptical about this claim.

I then started to work on this (because I was wondering whether message
forwarding could be done in a portable way).  The Stepstone compiler didn't
have it.

The POC implementation is unique because it does a form of message forwarding
(with messages such as -sentTo: and a class Message, that I modeled after
SQUEAK).  I choose the names of the selectors to be the same as in Squeak.

In the end, it turned out that it is possible to do a form of message forward
in a portable ANSI C way (without using stack frame handling)

So the claim that the C messenger is incompatible with message forwarding,
is not entirely correct.  Let's say the POC implementation was a test to
see whether the claim that forwarding has to be done in such a low level way
as in GNU/Apple, was correct ...

The implementation of POC is decent, I am fairly satisfied with it; it has
the drawback however that it generates more code than without forwarding
enabled.

So if you compile with -noFwd the POC compiler will produce smaller object
files (.o files).    If you specifiy the -C option (to keep intermediate
output) you can see that the -noFwd option makes the "stubs" for forwarding
to be omitted.

Let's say that POC offers a completely way of forwarding messages, at the
expense of additional code that is being generated by the compiler.

This was OK for me, since I just wanted to see whether the message forwarding
was possible in an ANSI C way.

Basically I think the claim that the C messenger is incompatible with msg.
forwarding is simply false.

 
 
 

1. Q: How to forward a standard ail message stored on disk with CDO

Hello Everyone,

I'd like to create a script (preverably JScript or VBscript) that forwards a
mesage stored in standard mail format .msg

I thought of someting like
<%
var FSO = CreateObject( "Scripting.FileSystemObject" );
var EmailMsg = FSO.getTextFile( "C:\\emailFolder\\emailToForeward.msg" );
var EmailObject = CreateObject( "CDONTS.NewMail" );


EmailObject.Send( EmailMsg );
%>

why does this not work?, How can I make it work?

thanks in advance,
Fouad Dani?ls
Amsterdam

2. I thought I would nev

3. ActiveX control forwarding messages to IE

4. 100baseTX and phone line

5. Forward message with Extended MAPI

6. Multi-Monitor Setup plan...

7. Forwarding a message

8. FS: PAR and TBCIV Priced for quick sale!

9. Telephone dialer with message forwarding

10. Smalltalk-like cascaded message(for gcc-2.6.3)

11. Warning messages from gcc

12. gcc 2.96 --> gcc 3.2 issue/question

13. gcc g++: File.h for gcc - did you ever seen