<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>