mem@sii.UUCP (Mark Mallett) (12/27/83)
b To the nargs() routine submitted by fortune!shah, I'd suggest recognizing an LEA stack adjustment instruction, i.e., LEA n*4(SP),SP While I know of no 68000 C compilers that generate this sort of fixup, it is the sort of thing that assembler language programmers would think of first (me, anyway); and it seems worth anticipating of future compilers. I'd also like to opine that looking at the instruction after the call instruction to determine the number of arguments is not a 100% accurate way to get the number of arguments passed, for these reasons: - It doesn't take into account different argument types (e.g. doubles). - I can imagine compilers generating stack-fixup instructions in dealing with variables bound to local scopes. Can't you? - The Whitesmith's compiler seems to keep a free location on the top of the stack to deal with calls to routines where only one value is passed. At least this is what it appears to do; I'm easily fooled. This is something that can't be detected by the subroutine, and is an optimization I'd easily expect of compiler writers. But I can't think of any other way to do it. Mark E. Mallett decvax!sii!mem
shah@fortune.UUCP (12/28/83)
#R:sii:-36300:fortune:6600006:000:1044 fortune!shah Dec 27 22:21:00 1983 * I agree with Mark Mallet (sii!mem); nargs should be used with caution. It is a simple hack that works well if your compiler is not too tricky smart and if it is used in a well understood context. That is, the caller of nargs() should *know* what kind of values may be passed to it. The version you saw was written for a co-routine package. We wanted to create co-routines out of any routine (with ANY number of arguments). As an example, you can create a co-routine out of routine "foo" with 3 arguments by saying fooProcess = createProc(stackAddress, stackSize, deathHandler, foo, arg1, arg2, arg3); Later on when you "resume(fooProcess)" it is as if you *called* foo with arg1, arg2, arg3. Our nargs() is used by routine createProc in copying arguments arg1, arg2, etc. to the co-routine stack. Ofcourse, nargs() *has* to stay in tune with the compiler. If that is not possible you have to resort to really messy hacks (as opposed to clean hacks) in such applications. -- Bakul fortune!shah
tjt@kobold.UUCP (T.J.Teixeira) (12/30/83)
Another stack adjustment instruction is: ADDW #n*4,SP Remember, the 68000 will sign extend any operand applied to an address register. This has the same time/space performance as the LEA n*4(SP),SP instruction mentioned by sii!mem (Mark Mallet), and *is* actually generated by the Masscomp C compiler. Of course, all the other caveats apply, leading to the unfortunate result of if you *really* want it done right, you have to do it yourself. Of course, since it is easy to miscount arguments, and the C language (and most runtime systems) won't provide it for you, you could try a special "end-of-argument-list" value (e.g. 0 in execv and variants). -- Tom Teixeira, Massachusetts Computer Corporation. Westford MA ...!{ihnp4,harpo,decvax,ucbcad,tektronix}!masscomp!tjt (617) 692-6200
minow@decvax.UUCP (Martin Minow) (12/30/83)
fortune!shah suggests using an nargs() function when creating processes in an operating system. For example (changing his slightly) procid = create_process(main_function, priority, stacksize, arg0, arg1, ... argn); Then, when the process starts, it is called as main_function(arg0, arg1, ... argn); A simpler solution, (which does require that you can access arguments in sequence) would be as follows: procid = create_process(main_function, priority, stacksize, argc, arg0, arg1, ... argn); The main_function would be called as main_function(argc, argv) int argc; char *argv[]; The implementation is quite straight-forward. Martin Minow decvax!minow
shah@fortune.UUCP (01/02/84)
#R:sii:-36300:fortune:6600009:000:2099 fortune!shah Jan 1 18:50:00 1984 `nargs' name is misleading as it really returns the size of argument block (in units of sizeof (long)). This is so because you can have structs as arguments. You can compute the size of argument block without nargs but it is painful. AND you, the user, has to know about how the compiler pushes arguments on the stack. A call to a version of createProc that does not use nargs would look something like process = createProc(stackArea, stackSize, deathHandler, SIZE(arg1) + SIZE(arg2) + .. + SIZE(argn), foo, arg1, arg2, .. , argn); where SIZE(x) is (((sizeof(x)+LONGSIZE-1) / LONGSIZE)) * LONGSIZE) where LONGSIZE is sizeof(long) Ughh! OR you can restrict the argument types to be non- structs! OR you can always restrict total argument size to be less than 2^N bytes -- wasteful and not easy to check. OR you can use a special value as the last argument to createProc and restrict other arguments to not use this special value! OR you can use the printf idea of specifying argument type (and hence size) in a string -- but how do you specify the size of a structure? We did consider some of these ideas before choosing nargs in favor of making the interface simpler and without any restrictions on the number of arguments or their types. It is really unfortunate that nargs is not portable. I like nargs because it is an easy to use tool and with it I can build easy to use tools. On top of the co-routine package we built a simulation kernel much like the one in Concurrent Euclid. Using this kernel we built a simple simulator for the Fortune 32:16 bus to find out worst case DMA latency etc. Each level presented a simple interface to the next one. I think that was one of the major reasons for being able to get our results in a short time. Ease of use is a very important attribute for software at every level. It does require you, the implementer, to look at your program from its users' point of view. By way of nargs and the couple examples I wanted to draw your attention to this belief. -- Bakul Shah fortune!shah