Should evaluating a function return a tagged pointer.
I've recently came across code like this. Not that this is from an unoptimized build and I think it's a rare issue in optimized builds.
case GHC.Utils.Outputable.ftext of conrep32_sPya [Occ=Once1] {
However the conrep32_sPya
turned out to have no tag bits set despite being evaluated.
This was from a debug build so we had no LFInfo about ftext
and therefore evaluated it via an unknown call.
R1 = GHC.Utils.Outputable.ftext_closure;
P64[Sp] = _sPy9::P64;
Sp = Sp - 8;
unwind Sp = Just Sp + 272;
call stg_ap_0_fast(R1) returns to c1jJX, args: 8, res: 8, upd: 8;
However this doesn't actually tag the result. Because stg_ap_0_fast ends up calling the ENTER macro which is defined such:
#define ENTER_(ret,x) \
again: \
W_ info; \
LOAD_INFO(ret,x) \
/* See Note [Heap memory barriers] in SMP.h */ \
prim_read_barrier; \
switch [INVALID_OBJECT .. N_CLOSURE_TYPES] \
(TO_W_( %INFO_TYPE(%STD_INFO(info)) )) { \
case \
IND, \
IND_STATIC: \
{ \
x = StgInd_indirectee(x); \
goto again; \
} \
case \
FUN, \
FUN_1_0, \
FUN_0_1, \
FUN_2_0, \
FUN_1_1, \
FUN_0_2, \
FUN_STATIC, \
BCO, \
PAP: \
{ \
ret(x); \
} \
default: \
{ \
x = UNTAG_IF_PROF(x); \
jump %ENTRY_CODE(info) (x); \
} \
}
That is for functions/paps we simply return the argument as-is.
The obvious downside is that we are less likely to be able to tell the arity of functions without inspecting their info table. However it makes the "entry" code of functions really trivial.
If we were to change this we would merely have to extract the arity from the info table in the various FUN_* branches and tag the pointer with it.
However in an optimized build almost all references to functions should come into existence already tagged so I don't think this is likely to significantly change runtime performance.
Maybe I will look at changing this at some point but given it's low impact I don't think it's a priority.