<html>
<head>
<style>
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
FONT-SIZE: 10pt;
FONT-FAMILY:Tahoma
}
</style>
</head>
<body class='hmmessage'>I'm being lazy...<BR>
<BR>Tony can you explain this stuff?<BR>
<BR>Comparison of function pointers..<BR>What are the various representations and rules?<BR>
<BR>What does it mean to compare nested functions?<BR>
<BR>What does it mean to compare a function to NIL?<BR>
<BR>I'll poke around more.<BR>
<BR>What I am seeing is that comparison of function pointers to NIL is surprisingly<BR>expensive, and probably somewhat buggy. Or at least some of the runtime<BR>generated "metadata-ish" stuff is produced or typed incorrectly.<BR>
<BR>In particular, RTLinker.m3:<BR>
<BR>PROCEDURE AddUnit (b: RT0.Binder) =<BR>  VAR m: RT0.ModulePtr;<BR>  BEGIN<BR>    IF (b = NIL) THEN RETURN END;   line 119<BR>    m := b(0);                      line 120<BR>    IF (m = NIL) THEN RETURN END;   line 121<BR>    AddUnitI(m);                    line 122 <BR>  END AddUnit;<BR>
<BR>generates a lot of code, just for the first line:<BR>
  (556) set_source_line  <BR>    source line  119  <BR>  (557) load  <BR>    m3cg_load (M3_DjPxE5_b): offset 0x0, convert 0xb -> 0xb  <BR>  (558) load_nil  <BR>  (559) if_eq  <BR>  (560) load  <BR>    m3cg_load (M3_DjPxE5_b): offset 0x0, convert 0xb -> 0xb  <BR>  (561) load_indirect  <BR>    load address offset 0x0 src_t 0x5 dst_t 0x5  <BR>  (562) load_integer  <BR>    integer n_bytes 0x0 hi 0x0 low 0x1 sign -1  <BR>  (563) if_eq  <BR>  (564) set_label  <BR>  (565) load_nil  <BR>  (566) load  <BR>    m3cg_load (M3_DjPxE5_b): offset 0x0, convert 0xb -> 0xb  <BR>  (567) if_ne  <BR>  (568) set_label  <BR>  (569) exit_proc  <BR>  (570) set_label  <BR>  (571) set_source_line  <BR>    source line  120  <BR>
<BR>The details on the load_integer trace might not be completely correct. I will test a fix shortly.<BR>Esp. that n_bytes gets decremented to zero before the trace.<BR>
<BR>Ok, I see now why some of the bloat -- because the "then return end" is on the same line.<BR>If it were written as:<BR>  if (b = NIL THEN  <BR>    return <BR>  end   <BR>
It probably wouldn't look so bad. That took me a while to realize.<BR>
<BR>The following is generated for SPARC64_OPENBSD:<BR>
 <BR>
 line 119 <BR>
 .stabn 68,0,119,.LLM61-.LLFBB4 <BR>.LLM61:<BR> ldx [%fp+2175], %g1<BR> brz %g1, .LL26<BR>  nop<BR> ldx [%fp+2175], %g1<BR> ldx [%g1], %g1            bus error here? yes, probably this one<BR> cmp %g1, -1<BR> be %xcc, .LL27<BR>  nop<BR>.LL26:<BR> ldx [%fp+2175], %g1<BR> brz %g1, .LL33<BR>  nop<BR>.LL27:<BR>
 line 120 <BR>
 .stabn 68,0,120,.LLM62-.LLFBB4<BR>.LLM62:<BR>
 ldx [%fp+2175], %g1<BR> stx %g1, [%fp+2007]<BR> ldx [%fp+2007], %g1<BR> brz %g1, .LL30<BR>  nop<BR> ldx [%fp+2007], %g1<BR> ldx [%g1], %g1            or here ?<BR> cmp %g1, -1<BR> bne %xcc, .LL30<BR>  nop<BR> ldx [%fp+2007], %g1<BR> add %g1, 16, %g1<BR> ldx [%g1], %g1           or here? <BR> stx %g1, [%fp+2015]<BR> ldx [%fp+2007], %g1<BR> add %g1, 8, %g1<BR> ldx [%g1], %g1<BR> stx %g1, [%fp+2007]<BR>.LL30:<BR> ldx [%fp+2007], %g1<BR> ldx [%fp+2015], %g5<BR> mov 0, %o0<BR> call %g1, 0<BR>  nop<BR> mov %o0, %g1<BR> stx %g1, [%fp+2023]<BR> ldx [%fp+2023], %g1<BR> stx %g1, [%fp+1999]<BR>  <BR> line 121 <BR>
<BR> .stabn 68,0,121,.LLM63-.LLFBB4<BR>.LLM63:<BR> ldx [%fp+1999], %g1<BR> brz %g1, .LL33<BR>  nop<BR>.LL32:<BR> .stabn 68,0,122,.LLM64-.LLFBB4<BR>.LLM64:<BR>
<BR>g1 points to RTSignal_I3<BR>
<BR>(gdb) x/i $pc<BR>0x3ff0a8 <RTLinker__AddUnit+28>:        ldx  [ %g1 ], %g1<BR>
(gdb) x/i $g1<BR>0x4021f4 <RTParams_I3>: save  %sp, -208, %sp<BR>
<BR>I am willing to accept that a "function pointer" is a pair of pointers, or even three pointers.<BR>A pointer to code, a pointer to globals for position independent code, a frame pointer to locals.<BR>That equality comparison of function pointers requires comparing two (or three) pointers.<BR>
  (Though the global pointer shouldn't need comparing.)<BR>At least for nested functions. Less so for non-nested. ?<BR>Much less for comparison to NIL. ?<BR>
<BR>And either way, this code is reading bogus data.<BR>There isn't a pointer at the function address, there is code.<BR>
<BR>Something doesn't add up.<BR>
<BR>I'm going to try setting "aligned procedures" but that's quite bogus I think.<BR>
<BR>EqualExpr.m3 says<BR>
<BR>       Note: procedures pointers are always aligned!<BR>
<BR>but maybe not?<BR>
<BR>Yeah yeah I'm being lazy. I'll read more code..<BR>
<BR>I also wonder if a "function pointer" can be optimized for the case of not being to a nested function.<BR>It looks like calling a function pointer is very inefficient.<BR>It looks like..am I reading that correctly?.. that if the pointer points to -1, then it is nested and<BR>a pair of pointers, and not otherwise. That -1 is treated specially as the first bytes of a function?<BR>
Is that a Modula-3-ism or a SPARC-ism?<BR>It looks like a Modula-3-ism. And it seems dubious.<BR>But I'll have to read more..<BR>
 <BR>
NT386GNU does the same sort of wrong looking thing:<BR>
 <BR>
LFBB4:<BR> pushl %ebp<BR> movl %esp, %ebp<BR> subl $24, %esp<BR>LBB5:<BR> .stabn 68,0,117,LM60-LFBB4<BR>LM60:<BR> movl $0, -16(%ebp)<BR> .stabn 68,0,119,LM61-LFBB4<BR>LM61:<BR> movl 8(%ebp), %eax<BR> testl %eax, %eax<BR> je L26<BR> movl 8(%ebp), %eax<BR> movl (%eax), %eax                  BAD <BR> cmpl $-1, %eax                       BAD <BR> je L27<BR>L26:<BR> movl 8(%ebp), %eax<BR> testl %eax, %eax<BR> je L33<BR>L27:<BR> .stabn 68,0,120,LM62-LFBB4<BR>LM62:<BR><BR>
 <BR>
and NT386:<BR>
 <BR>
0:000> u<BR>cm3!RTLinker__AddUnit:<BR>00607864 55              push    ebp<BR>00607865 8bec            mov     ebp,esp<BR>00607867 81ec0c000000    sub     esp,0Ch<BR>0060786d 53              push    ebx<BR>0060786e 56              push    esi<BR>0060786f 57              push    edi<BR>00607870 c745fc00000000  mov     dword ptr [ebp-4],0<BR>00607877 837d0800        cmp     dword ptr [ebp+8],0<BR>0:000> u<BR>cm3!RTLinker__AddUnit+0x17:<BR>0060787b 0f840f000000    je      cm3!RTLinker__AddUnit+0x2c (00607890)<BR>00607881 8b7508          mov     esi,dword ptr [ebp+8]<BR>00607884 8b5e00          mov     ebx,dword ptr [esi]                            BAD  <BR>00607887 83fbff          cmp     ebx,0FFFFFFFFh                                  BAD <BR>0060788a 0f840f000000    je      cm3!RTLinker__AddUnit+0x3b (0060789f)<BR>00607890 837d0800        cmp     dword ptr [ebp+8],0<BR>00607894 0f8505000000    jne     cm3!RTLinker__AddUnit+0x3b (0060789f)<BR>0060789a e969000000      jmp     cm3!RTLinker__AddUnit+0xa4 (00607908)<BR>
 <BR>
cm3!RTLinker__AddUnit+0x20:<BR>00607884 8b5e00          mov     ebx,dword ptr [esi]  ds:002b:0062c950=81ec8b55<BR>0:000> u @esi<BR>cm3!RTLinker_I3:<BR>0062c950 55              push    ebp<BR>0062c951 8bec            mov     ebp,esp<BR>0062c953 81ec00000000    sub     esp,0<BR>0062c959 53              push    ebx<BR>0062c95a 56              push    esi<BR>0062c95b 57              push    edi<BR>0062c95c 837d0800        cmp     dword ptr [ebp+8],0<BR>0062c960 0f8400000000    je      cm3!RTLinker_I3+0x16 (0062c966)<BR>
 <BR>
This is just wrong.<BR>
Comparing bytes of code to -1.<BR>
 <BR>
I think the likely fix is for the "I3" code to be laid out as a "constant function pointer", a pointer to a pair of pointers where one points to the code and one is to -1. Something like that. That can't be quite correct given that the existing data is callable.<BR>
<BR>  - Jay<BR></body>
</html>