"Fossies" - the Fresh Open Source Software Archive

Member "FreeBASIC-1.07.1-source/src/compiler/symb-mangling.bas" (27 Sep 2019, 32100 Bytes) of package /linux/privat/FreeBASIC-1.07.1-source.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Visual Basic source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "symb-mangling.bas": 1.07.0_vs_1.07.1.

    1 '' symbol mangling module (compatible with the GCC 3.x ABI)
    2 ''
    3 '' chng: may/2006 written [v1ctor]
    4 
    5 
    6 #include once "fb.bi"
    7 #include once "fbint.bi"
    8 #include once "flist.bi"
    9 #include once "hash.bi"
   10 #include once "ir.bi"
   11 
   12 type FB_MANGLEABBR
   13     idx             as integer
   14     dtype           as integer
   15     subtype         as FBSYMBOL ptr
   16 end type
   17 
   18 type FB_MANGLECTX
   19     flist           as TFLIST                   '' of FB_MANGLEABBR
   20     cnt             as integer
   21 
   22     tempstr         as zstring * 6 + 10 + 1
   23     uniqueidcount       as integer
   24     uniquelabelcount    as integer
   25     profilelabelcount   as integer
   26 end type
   27 
   28 const FB_INITMANGARGS = 96
   29 
   30 declare function hDoCppMangling( byval sym as FBSYMBOL ptr ) as integer
   31 declare sub hMangleProc( byval sym as FBSYMBOL ptr )
   32 declare sub hMangleVariable( byval sym as FBSYMBOL ptr )
   33 declare sub hGetProcParamsTypeCode _
   34     ( _
   35         byref mangled as string, _
   36         byval sym as FBSYMBOL ptr, _
   37         byval is_real_proc as integer _
   38     )
   39 declare sub hMangleNamespace _
   40     ( _
   41         byref mangled as string, _
   42         byval ns as FBSYMBOL ptr, _
   43         byval dohashing as integer, _
   44         byval isconst as integer _
   45     )
   46 
   47 '' inside a namespace or class?
   48 #define hIsNested(s) (symbGetNamespace( s ) <> @symbGetGlobalNamespc( ))
   49 
   50 '' globals
   51     dim shared as FB_MANGLECTX ctx
   52 
   53 sub symbMangleInit( )
   54     flistInit( @ctx.flist, FB_INITMANGARGS, len( FB_MANGLEABBR ) )
   55     ctx.cnt = 0
   56     ctx.uniqueidcount = 0
   57     ctx.uniquelabelcount = 0
   58     ctx.profilelabelcount = 0
   59 end sub
   60 
   61 sub symbMangleEnd( )
   62     flistEnd( @ctx.flist  )
   63 end sub
   64 
   65 function symbUniqueId( ) as zstring ptr
   66     if( env.clopt.backend = FB_BACKEND_GCC ) then
   67         ctx.tempstr = "tmp$"
   68         ctx.tempstr += str( ctx.uniqueidcount )
   69     else
   70         ctx.tempstr = "Lt_"
   71         ctx.tempstr += *hHexUInt( ctx.uniqueidcount )
   72     end if
   73 
   74     ctx.uniqueidcount += 1
   75 
   76     function = @ctx.tempstr
   77 end function
   78 
   79 function symbUniqueLabel( ) as zstring ptr
   80     if( env.clopt.backend = FB_BACKEND_GCC ) then
   81         ctx.tempstr = "label$"
   82         ctx.tempstr += str( ctx.uniquelabelcount )
   83         ctx.uniquelabelcount += 1
   84     else
   85         ctx.tempstr = ".Lt_"
   86         ctx.tempstr += *hHexUInt( ctx.uniqueidcount )
   87         ctx.uniqueidcount += 1
   88     end if
   89 
   90     function = @ctx.tempstr
   91 end function
   92 
   93 function symbMakeProfileLabelName( ) as zstring ptr
   94     ctx.tempstr = "LP_" + *hHexUInt( ctx.profilelabelcount )
   95     ctx.profilelabelcount += 1
   96     function = @ctx.tempstr
   97 end function
   98 
   99 function symbGetDBGName( byval sym as FBSYMBOL ptr ) as zstring ptr
  100     '' GDB will demangle the symbols automatically
  101     if( hDoCppMangling( sym ) ) then
  102         select case as const symbGetClass( sym )
  103         '' but UDT's, they shouldn't include any mangling at all..
  104         case FB_SYMBCLASS_ENUM, FB_SYMBCLASS_STRUCT, _
  105              FB_SYMBCLASS_CLASS, FB_SYMBCLASS_NAMESPACE
  106 
  107             '' check if an alias wasn't given
  108             dim as zstring ptr res = sym->id.alias
  109             if( res = NULL ) then
  110                 res = sym->id.name
  111             end if
  112 
  113             return res
  114 
  115         case else
  116             return symbGetMangledName( sym )
  117         end select
  118     end if
  119 
  120     '' Respect ALIAS for array descriptor types, to avoid exposing their
  121     '' internal mangling
  122     if( symbIsStruct( sym ) and symbIsDescriptor( sym ) ) then
  123         if( sym->id.alias ) then
  124             return sym->id.alias
  125         end if
  126     end if
  127 
  128     '' no mangling, return as-is
  129     function = sym->id.name
  130 end function
  131 
  132 sub symbSetName( byval s as FBSYMBOL ptr, byval name_ as zstring ptr )
  133     dim as integer slen = any
  134 
  135     '' assuming only params will change names, no mangling reseted
  136 
  137     if( s->id.name <> NULL ) then
  138         poolDelItem( @symb.namepool, s->id.name ) 'ZstrFree( s->id.name )
  139     end if
  140 
  141     slen = len( *name_ )
  142     if( slen = 0 ) then
  143         s->id.name = NULL
  144     else
  145         s->id.name = poolNewItem( @symb.namepool, slen + 1 ) 'ZStrAllocate( slen )
  146         *s->id.name = *name_
  147     end if
  148 end sub
  149 
  150 private sub symbSetMangledId( byval sym as FBSYMBOL ptr, byref mangled as string )
  151     assert( sym->id.mangled = NULL )
  152     sym->id.mangled = ZStrAllocate( len( mangled ) )
  153     *sym->id.mangled = mangled
  154 end sub
  155 
  156 private sub hMangleUdtId( byref mangled as string, byval sym as FBSYMBOL ptr )
  157     dim as integer arraydtype = any
  158     dim as FBSYMBOL ptr arraysubtype = any
  159 
  160     '' Itanium C++ ABI: All identifiers are encoded as:
  161     '' <length><id>
  162     if( sym->id.alias ) then
  163         mangled += str( len( *sym->id.alias ) )
  164         mangled += *sym->id.alias
  165     else
  166         mangled += str( len( *sym->id.name ) )
  167         mangled += *sym->id.name
  168     end if
  169 
  170     ''
  171     '' Array descriptor mangling: '__FBARRAY[1-8]<dtype>'
  172     '' (based on the ALIAS specified in symbAddArrayDescriptorType())
  173     ''
  174     '' The dimension count is already encoded in the ALIAS (also see
  175     '' symbAddArrayDescriptorType()); and we'll encode the
  176     '' arraydtype as template argument here - this allows C++
  177     '' demanglers to decode the arraydtype nicely.
  178     ''
  179     '' The dimension count and arraydtype must be encoded in the
  180     '' name mangling, because FB allows overloading based on that.
  181     ''
  182     if( symbIsStruct( sym ) and symbIsDescriptor( sym ) ) then
  183         mangled += "I" '' begin of template argument list
  184 
  185         symbGetDescTypeArrayDtype( sym, arraydtype, arraysubtype )
  186         symbMangleType( mangled, arraydtype, arraysubtype, FB_MANGLEOPT_KEEPTOPCONST )
  187 
  188         mangled += "E" '' end of template argument list
  189     end if
  190 end sub
  191 
  192 function symbGetMangledName( byval sym as FBSYMBOL ptr ) as zstring ptr
  193     if( sym->id.mangled ) then
  194         return sym->id.mangled
  195     end if
  196 
  197     assert( ctx.cnt = 0 )
  198 
  199     select case as const( symbGetClass( sym ) )
  200     case FB_SYMBCLASS_PROC
  201         hMangleProc( sym )
  202     case FB_SYMBCLASS_ENUM, FB_SYMBCLASS_STRUCT, FB_SYMBCLASS_FWDREF, _
  203          FB_SYMBCLASS_CLASS, FB_SYMBCLASS_NAMESPACE
  204         dim as string mangled
  205         hMangleNamespace( mangled, symbGetNamespace( sym ), TRUE, FALSE )
  206         hMangleUdtId( mangled, sym )
  207         if( hIsNested( sym ) ) then
  208             mangled += "E"
  209         end if
  210         symbSetMangledId( sym, mangled )
  211     case FB_SYMBCLASS_VAR
  212         hMangleVariable( sym )
  213     case else
  214         return sym->id.alias
  215     end select
  216 
  217     symbMangleResetAbbrev( )
  218 
  219     '' Periods in symbol names?  not allowed in C, must be replaced.
  220     if( env.clopt.backend = FB_BACKEND_GCC ) then
  221         if( fbLangOptIsSet( FB_LANG_OPT_PERIODS ) ) then
  222             hReplaceChar( sym->id.mangled, asc( "." ), asc( "$" ) )
  223         end if
  224     end if
  225 
  226     function = sym->id.mangled
  227 end function
  228 
  229 '' Reset the abbreviation list.
  230 '' Every symbMangleType() will add abbreviations, and the list must be reset
  231 '' every time (after a symbol was mangled), to prevent the abbreviations from
  232 '' leaking into the mangling process of the next symbol.
  233 sub symbMangleResetAbbrev( )
  234     flistReset( @ctx.flist )
  235     ctx.cnt = 0
  236 end sub
  237 
  238 private function hAbbrevFind _
  239     ( _
  240         byval dtype as integer, _
  241         byval subtype as FBSYMBOL ptr _
  242     ) as integer
  243 
  244     dim as FB_MANGLEABBR ptr n = any
  245 
  246     if( ctx.cnt = 0 ) then
  247         return -1
  248     end if
  249 
  250     '' for each item..
  251     n = flistGetHead( @ctx.flist )
  252     do while( n <> NULL )
  253         '' same type?
  254         if( n->subtype = subtype ) then
  255             if( n->dtype = dtype ) then
  256                 return n->idx
  257             end if
  258         end if
  259 
  260         n = flistGetNext( n )
  261     loop
  262 
  263     function = -1
  264 end function
  265 
  266 '' Add qualified/non-built-in type to lookup table for substitution/compression
  267 '' according to Itanium C++ ABI.
  268 private function hAbbrevAdd _
  269     ( _
  270         byval dtype as integer, _
  271         byval subtype as FBSYMBOL ptr _
  272     ) as FB_MANGLEABBR ptr
  273 
  274     dim as FB_MANGLEABBR ptr n = any
  275 
  276     n = flistNewItem( @ctx.flist )
  277     n->idx = ctx.cnt
  278 
  279     n->dtype = dtype
  280     n->subtype = subtype
  281 
  282     ctx.cnt += 1
  283 
  284     function = n
  285 end function
  286 
  287 private sub hAbbrevGet( byref mangled as string, byval idx as integer )
  288     mangled += "S"
  289 
  290     '' abbreviation index   mangling
  291     ''   0                    S_
  292     ''   1                    S0_
  293     ''   2                    S1_
  294     '' etc.
  295 
  296     if( idx > 0 ) then
  297         if( idx <= 10 ) then
  298             mangled += chr( asc( "0" ) + (idx - 1) )
  299         elseif( idx <= 33 ) then
  300             mangled += chr( asc( "A" ) + (idx - 11) )
  301         else
  302             '' 2 digits are enough for 333 abbreviations
  303             mangled += chr( idx \ 33 )
  304             idx mod= 33
  305             if( idx <= 10 ) then
  306                 mangled += chr( asc( "0" ) + (idx - 1) )
  307             elseif( idx <= 33 ) then
  308                 mangled += chr( asc( "A" ) + (idx - 11) )
  309             end if
  310         end if
  311     end if
  312 
  313     mangled += "_"
  314 end sub
  315 
  316 function hMangleBuiltInType _
  317     ( _
  318         byval dtype as integer, _
  319         byref add_abbrev as integer _
  320     ) as zstring ptr
  321 
  322     assert( dtype = (typeGetDtOnly( dtype ) or (dtype and FB_DT_MANGLEMASK)) )
  323 
  324     ''
  325     '' Plain unqualified C++ built-in types are not considered for abbreviation.
  326     '' However, custom/vendor-specific types still are.
  327     ''
  328     '' This only matters when hMangleBuiltInType() is called from
  329     '' symbMangleType(), but it does not matter when hMangleBuiltInType() is
  330     '' just used encode type suffixes into variable names for the C backend.
  331     ''
  332     add_abbrev = FALSE
  333 
  334     if( dtype = FB_DATATYPE_STRING ) then
  335         add_abbrev = TRUE
  336         return @"8FBSTRING"
  337     end if
  338 
  339     ''
  340     '' Integer/Long mangling:
  341     ''
  342     ''           32bit        64bit
  343     '' Integer   long         long (Unix) or INTEGER (Windows)
  344     '' Long      int          int
  345     '' LongInt   long long    long long
  346     ''
  347     ''  - Fundamental problem: FB and C++ types are different, an exact mapping
  348     ''    is impossible
  349     ''
  350     ''  - mangling should match the C/C++ binding recommendations, i.e. use Long
  351     ''    for int and Integer for things like ssize_t. On linux-x86_64 Integer
  352     ''    can be mangled as long, but on win64 the only 64bit integer type is
  353     ''    long long and that's already used for LongInt. So it seems that we have
  354     ''    to use a custom mangling for that case (INTEGER).
  355     ''
  356     ''  - 32bit fbc used to mangle Integer as int and Long as long, but to match
  357     ''    64bit fbc it was reversed, allowing the same FB and C++ code to work
  358     ''    together on both 32bit and 64bit.
  359     ''
  360     ''  - as special exception for windows 64bit, to get a 32bit type that will
  361     ''    mangle to C++ long, allow 'as [u]long alias "[u]long"' declarations.
  362     ''    The size of LONG/ULONG does not change, it's 32bit, only the mangling,
  363     ''    so fbc programs can call C++ code requiring 'long int' arguments.
  364 
  365     if( fbIs64bit( ) and ((env.target.options and FB_TARGETOPT_UNIX) = 0) ) then
  366         '' Windows 64bit
  367 
  368         '' check for remapping of dtype mangling
  369         if( typeHasMangleDt( dtype ) ) then
  370             dtype = typeGetMangleDt( dtype )
  371             '' Windows 64bit
  372             select case( dtype )
  373             case FB_DATATYPE_INTEGER : return @"l"  '' long
  374             case FB_DATATYPE_UINT    : return @"m"  '' unsigned long
  375             end select
  376         else
  377             '' Itanium C++ ABI compatible mangling of non-C++ built-in types (vendor extended types):
  378             ''    u <length-of-id> <id>
  379             select case( dtype )
  380             case FB_DATATYPE_INTEGER : add_abbrev = TRUE : return @"u7INTEGER"  '' seems like a good choice
  381             case FB_DATATYPE_UINT    : add_abbrev = TRUE : return @"u8UINTEGER"
  382             end select
  383         end if
  384 
  385     else
  386         '' 32bit, Unix 64bit
  387         select case( dtype )
  388         case FB_DATATYPE_INTEGER : return @"l"  '' long
  389         case FB_DATATYPE_UINT    : return @"m"  '' unsigned long
  390         end select
  391     end if
  392 
  393     '' Still have a mangle data type? remap.
  394     if( typeHasMangleDt( dtype ) ) then
  395         dtype = typeGetMangleDt( dtype )
  396     end if
  397 
  398     '' dtype should be a FB_DATATYPE by now
  399     assert( dtype = typeGetDtOnly( dtype ) )
  400 
  401     static as zstring ptr typecodes(0 to FB_DATATYPES-1) => _
  402     { _
  403         @"v", _ '' void
  404         @"b", _ '' boolean
  405         @"a", _ '' Byte: signed char
  406         @"h", _ '' UByte: unsigned char
  407         @"c", _ '' char
  408         @"s", _ '' short
  409         @"t", _ '' ushort
  410         @"w", _ '' wchar
  411         NULL, _ '' Integer
  412         NULL, _ '' UInteger
  413         NULL, _ '' enum
  414         @"i", _ '' Long: int
  415         @"j", _ '' ULong: unsigned int
  416         @"x", _ '' LongInt: long long
  417         @"y", _ '' ULongInt: unsigned long long
  418         @"f", _ '' Single: float
  419         @"d", _ '' double
  420         NULL, _ '' var-len string
  421         NULL, _ '' fix-len string
  422         @"c", _ '' va_list
  423         NULL, _ '' struct
  424         NULL, _ '' namespace
  425         NULL, _ '' function
  426         NULL, _ '' fwd-ref
  427         NULL  _ '' pointer
  428     }
  429 
  430     assert( typecodes(dtype) <> NULL )
  431     function = typecodes(dtype)
  432 end function
  433 
  434 sub symbMangleType _
  435     ( _
  436         byref mangled as string, _
  437         byval dtype as integer, _
  438         byval subtype as FBSYMBOL ptr, _
  439         byval options as FB_MANGLEOPT = FB_MANGLEOPT_NONE _
  440     )
  441 
  442     dim as FBSYMBOL ptr ns = any
  443     dim as integer add_abbrev = any
  444 
  445     '' Lookup abbreviation for this type/namespace (if the current procedure
  446     '' name already contains the type somewhere, it can be referred to
  447     '' through an index instead of by repeating the full name, as specified
  448     '' in the Itanium C++ ABI)
  449     dim as integer idx = hAbbrevFind( dtype, subtype )
  450     if( idx <> -1 ) then
  451         hAbbrevGet( mangled, idx )
  452         exit sub
  453     end if
  454 
  455     '' forward type?
  456     if( typeGet( dtype ) = FB_DATATYPE_FWDREF ) then
  457         '' Remap to STRUCT for mangling purposes
  458         dtype = typeJoin( dtype and (not FB_DATATYPE_INVALID), FB_DATATYPE_STRUCT )
  459     end if
  460 
  461     '' reference?
  462     if( typeIsRef( dtype ) ) then
  463         mangled += "R"
  464 
  465         symbMangleType( mangled, typeUnsetIsRef( dtype ), subtype, _
  466             options or FB_MANGLEOPT_HASREF or FB_MANGLEOPT_KEEPTOPCONST)
  467 
  468         hAbbrevAdd( dtype, subtype )
  469         exit sub
  470     end if
  471 
  472     '' const?
  473     if( typeIsConst( dtype ) ) then
  474 
  475         '' The type has some CONST bits. For C++ mangling we remove the
  476         '' toplevel one and recursively mangle the rest of the type.
  477         ''
  478         '' It could be a BYVAL x as CONST foo type. In this case the
  479         '' CONST is not encoded in the C++ mangling, because it makes no
  480         '' difference. It's not allowed to have overloads that differ
  481         '' only in BYVAL CONSTness. The CONST only matters if it's a
  482         '' pointer or BYREF type.
  483 
  484         if( (options and FB_MANGLEOPT_KEEPTOPCONST) <> 0 ) then
  485             mangled += "K"
  486         end if
  487 
  488         symbMangleType( mangled, typeUnsetIsConst( dtype ), subtype, _
  489             options and not FB_MANGLEOPT_KEEPTOPCONST )
  490 
  491         hAbbrevAdd( dtype, subtype )
  492         exit sub
  493     end if
  494 
  495     '' pointer?
  496     if( typeIsPtr( dtype ) ) then
  497         mangled += "P"
  498 
  499         symbMangleType( mangled, typeDeref( dtype ), subtype, _
  500             options or FB_MANGLEOPT_HASPTR or FB_MANGLEOPT_KEEPTOPCONST )
  501 
  502         hAbbrevAdd( dtype, subtype )
  503         exit sub
  504     end if
  505 
  506     '' struct with __builtin_va_list mangle modifier?
  507     '' use the stuct name instead
  508     if( typeHasMangleDt( dtype ) ) then
  509         if( typeGetDtOnly( dtype ) = FB_DATATYPE_STRUCT ) then
  510             if( typeGetMangleDt( dtype ) = FB_DATATYPE_VA_LIST ) then
  511 
  512                 '' if the type was passed as byval ptr or byref
  513                 '' need to mangle in "A1_" to indicate the array type, but
  514                 '' not on aarch64, __va_list is a plain struct, it doesn't
  515                 '' need the array type specifier.
  516 
  517                 if( symbIsValistStructArray( dtype, subtype ) ) then
  518                     if( (options and (FB_MANGLEOPT_HASREF or FB_MANGLEOPT_HASPTR)) <> 0 ) then
  519                         mangled += "A1_"
  520                     else
  521                         mangled += "P"
  522                     end if
  523                 end if
  524 
  525                 dtype = typeSetMangleDt( dtype, 0 )
  526             end if
  527         end if
  528     end if
  529 
  530     ''
  531     '' Plain type without reference/pointer/const bits
  532     ''
  533     assert( dtype = (typeGetDtOnly( dtype ) or (dtype and FB_DT_MANGLEMASK)) )
  534 
  535     select case( dtype )
  536     case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM
  537         ns = symbGetNamespace( subtype )
  538         if( ns = @symbGetGlobalNamespc( ) ) then
  539             hMangleUdtId( mangled, subtype )
  540         else
  541             mangled += "N"
  542             symbMangleType( mangled, symbGetFullType( ns ), ns )
  543             hMangleUdtId( mangled, subtype )
  544             mangled += "E"
  545         end if
  546 
  547         hAbbrevAdd( dtype, subtype )
  548 
  549     case FB_DATATYPE_NAMESPC
  550         if( subtype = @symbGetGlobalNamespc( ) ) then
  551             exit sub
  552         end if
  553 
  554         ns = symbGetNamespace( subtype )
  555         if( ns ) then
  556             symbMangleType( mangled, FB_DATATYPE_NAMESPC, ns )
  557         end if
  558         hMangleUdtId( mangled, subtype )
  559 
  560         hAbbrevAdd( dtype, subtype )
  561 
  562     case FB_DATATYPE_FUNCTION
  563         '' F(byref)(const)(return_type)(params - recursive, reuses hash)E
  564         mangled += "F"
  565 
  566         '' return BYREF?
  567         if( symbIsRef( subtype ) ) then
  568             mangled += "R"
  569         end if
  570 
  571         '' const?
  572         '' (for function results, even BYVAL CONST is encoded into the
  573         '' C++ mangling, unlike for parameters)
  574         if( typeIsConst( symbGetFullType( subtype ) ) ) then
  575             mangled += "K"
  576         end if
  577 
  578         symbMangleType( mangled, symbGetFullType( subtype ), symbGetSubtype( subtype ) )
  579         hGetProcParamsTypeCode( mangled, subtype, FALSE )
  580 
  581         mangled += "E"
  582 
  583         hAbbrevAdd( dtype, subtype )
  584 
  585     case else
  586         mangled += *hMangleBuiltInType( dtype, add_abbrev )
  587         if( add_abbrev ) then
  588             hAbbrevAdd( dtype, subtype )
  589         end if
  590     end select
  591 
  592 end sub
  593 
  594 sub symbMangleParam( byref mangled as string, byval param as FBSYMBOL ptr )
  595     select case as const( symbGetParamMode( param ) )
  596     case FB_PARAMMODE_BYVAL
  597         symbMangleType( mangled, param->typ, param->subtype )
  598 
  599     case FB_PARAMMODE_BYREF
  600         symbMangleType( mangled, typeSetIsRef( param->typ ), param->subtype )
  601 
  602     case FB_PARAMMODE_BYDESC
  603         '' Mangling array params as 'FBARRAY[1-8]<dtype>&' because
  604         '' that's what they really are from C++'s point of view.
  605         assert( symbIsDescriptor( param->param.bydescrealsubtype ) )
  606         symbMangleType( mangled, typeSetIsRef( FB_DATATYPE_STRUCT ), param->param.bydescrealsubtype, FB_MANGLEOPT_KEEPTOPCONST )
  607 
  608     case FB_PARAMMODE_VARARG
  609         mangled += "z"
  610     end select
  611 end sub
  612 
  613 private function hAddUnderscore( ) as integer
  614     '' C backend? don't add underscores; gcc will already do it.
  615     if( env.clopt.backend = FB_BACKEND_GCC ) then
  616         function = FALSE
  617     else
  618         '' For ASM, add underscores if the target requires it
  619         function = env.underscoreprefix
  620     end if
  621 end function
  622 
  623 private function hDoCppMangling( byval sym as FBSYMBOL ptr ) as integer
  624     '' C++?
  625     if( symbGetMangling( sym ) = FB_MANGLING_CPP ) then
  626         return TRUE
  627     end if
  628 
  629     '' RTL or exclude parent?
  630     if( ( (symbGetStats( sym ) and (FB_SYMBSTATS_RTL or FB_SYMBSTATS_EXCLPARENT)) <> 0 ) _
  631         or ( symbGetMangling( sym ) = FB_MANGLING_RTLIB ) ) then
  632         return FALSE
  633     end if
  634 
  635     '' inside a namespace or class?
  636     if( symbGetNamespace( sym ) <> @symbGetGlobalNamespc( ) ) then
  637         return TRUE
  638     end if
  639 
  640     if( sym->class = FB_SYMBCLASS_PROC ) then
  641         '' overloaded? (this will handle operators too)
  642         if( symbIsOverloaded( sym ) ) then
  643             return TRUE
  644         end if
  645     end if
  646 
  647     function = FALSE
  648 end function
  649 
  650 private sub hMangleNamespace _
  651     ( _
  652         byref mangled as string, _
  653         byval ns as FBSYMBOL ptr, _
  654         byval dohashing as integer, _
  655         byval isconst as integer _
  656     )
  657 
  658     static as FBSYMBOL ptr nsStk(0 to FB_MAXNAMESPCRECLEVEL-1)
  659     dim as integer tos = any
  660 
  661     if( ns = NULL ) then
  662         exit sub
  663     end if
  664 
  665     if( ns = @symbGetGlobalNamespc( ) ) then
  666         exit sub
  667     end if
  668 
  669     if( dohashing ) then
  670         '' Just add the abbreviation for this if not yet done
  671         '' (just doing hAbbrevFind()/hAbbrevAdd() is not enough,
  672         '' because the parent namespaces may need to be abbreviated too,
  673         '' which symbMangleType() will do recursively)
  674         dim as string unused
  675         symbMangleType( unused, symbGetFullType( ns ), ns )
  676     end if
  677 
  678     '' create a stack
  679     tos = -1
  680     do
  681         tos += 1
  682         nsStk(tos) = ns
  683         ns = symbGetNamespace( ns )
  684     loop until( ns = @symbGetGlobalNamespc( ) )
  685 
  686     '' return the chain starting from base parent
  687     mangled += "N"
  688     if( isconst ) then
  689         mangled += "K"
  690     end if
  691     do
  692         ns = nsStk(tos)
  693         hMangleUdtId( mangled, ns )
  694         tos -= 1
  695     loop until( tos < 0 )
  696 end sub
  697 
  698 private sub hMangleVariable( byval sym as FBSYMBOL ptr )
  699     static as string id
  700     static as integer varcounter
  701     dim as string mangled
  702     dim as zstring ptr p = any
  703     dim as integer docpp = any, isglobal = any
  704 
  705     '' local? no mangling
  706     if( sym->scope > FB_MAINSCOPE ) then
  707         docpp = FALSE
  708     else
  709         docpp = hDoCppMangling( sym )
  710     end if
  711 
  712     '' prefix
  713     '' public global/static?
  714     if( sym->attrib and (FB_SYMBATTRIB_PUBLIC or FB_SYMBATTRIB_EXTERN or _
  715                          FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_COMMON or _
  716                          FB_SYMBATTRIB_STATIC) ) then
  717         '' LLVM: @ prefix for global symbols
  718         if( env.clopt.backend = FB_BACKEND_LLVM ) then
  719             mangled += "@"
  720         end if
  721 
  722         '' Win32 underscore prefix
  723         if( hAddUnderscore( ) ) then
  724             mangled += "_"
  725         end if
  726 
  727         select case( env.clopt.target )
  728         case FB_COMPTARGET_WIN32, FB_COMPTARGET_CYGWIN
  729             '' Win32 import? Add same prefix as done by gcc
  730             if( symbIsImport( sym ) ) then
  731                 mangled += "_imp__"
  732             end if
  733         end select
  734 
  735         if( docpp ) then
  736             '' Note: This adds the _Z prefix to all global variables,
  737             '' unlike GCC, which does C++ mangling only for globals inside
  738             '' namespaces, but not globals from the toplevel namespace.
  739             mangled += "_Z"
  740 
  741             if( sym->stats and FB_SYMBSTATS_RTTITABLE ) then
  742                 mangled += "TS"
  743             elseif( sym->stats and FB_SYMBSTATS_VTABLE ) then
  744                 mangled += "TV"
  745             end if
  746         end if
  747     else
  748         '' LLVM: % prefix for local symbols
  749         if( env.clopt.backend = FB_BACKEND_LLVM ) then
  750             mangled += "%"
  751         end if
  752     end if
  753 
  754     '' namespace
  755     if( docpp ) then
  756         hMangleNamespace( mangled, symbGetNamespace( sym ), FALSE, FALSE )
  757     end if
  758 
  759     '' class (once static member variables are added)
  760 
  761     '' rtti/vtables don't have an id, their mangled name is just the prefixes
  762     '' plus the parent UDT namespace(s), all done above already
  763     if( sym->stats and (FB_SYMBSTATS_RTTITABLE or FB_SYMBSTATS_VTABLE) ) then
  764         id = ""
  765     '' id
  766     elseif( sym->stats and FB_SYMBSTATS_HASALIAS ) then
  767         '' Explicit var ALIAS given, overriding the default id
  768         id = *sym->id.alias
  769     else
  770         '' shared, public, extern or inside a ns?
  771         isglobal = ((sym->attrib and (FB_SYMBATTRIB_PUBLIC or FB_SYMBATTRIB_EXTERN or _
  772                                       FB_SYMBATTRIB_SHARED or FB_SYMBATTRIB_COMMON)) <> 0)
  773 
  774         if( isglobal or docpp ) then
  775             '' BASIC? use the upper-cased name
  776             if( symbGetMangling( sym ) = FB_MANGLING_BASIC ) then
  777                 id = *sym->id.name
  778                 if( env.clopt.backend = FB_BACKEND_GCC ) then
  779                     id += "$"
  780                 end if
  781             '' else, the case-sensitive name saved in the alias..
  782             else
  783                 id = *sym->id.alias
  784             end if
  785 
  786             '' suffixed?
  787             if( symbIsSuffixed( sym ) ) then
  788                 id += *hMangleBuiltInType( symbGetType( sym ) )
  789                 if( env.clopt.backend = FB_BACKEND_GCC ) then
  790                     id += "$"
  791                 end if
  792             end if
  793         else
  794             select case( env.clopt.backend )
  795             case FB_BACKEND_GCC
  796                 '' ir-hlc emits statics with dtors as globals,
  797                 '' so they need a unique name. Other statics are
  798                 '' still emitted locally, so they can keep their
  799                 '' own name, like other local vars.
  800                 if( symbIsStatic( sym ) and symbHasDtor( sym ) ) then
  801                     id = *symbUniqueId( )
  802                 else
  803                     if( symbGetMangling( sym ) = FB_MANGLING_BASIC ) then
  804                         '' BASIC mangling, use the upper-cased name
  805                         id = *sym->id.name
  806 
  807                         '' Using '$' to prevent collision with C keywords etc.
  808                         '' ('$' isn't allowed as part of FB ids)
  809                         id += "$"
  810 
  811                         '' Type suffix?
  812                         if( symbIsSuffixed( sym ) ) then
  813                             '' Encode the type to prevent collisions with other variables
  814                             '' using the same base id but different type suffix.
  815                             id += *hMangleBuiltInType( symbGetType( sym ) )
  816                             id += "$"
  817                         end if
  818 
  819                         '' Append the scope level to prevent collisions with symbols
  820                         '' from parent scopes or from the toplevel namespace.
  821                         '' Note: locals from the main scope will start at level 0,
  822                         '' while locals from procedures start at level 1,
  823                         '' but that's ok as long as globals aren't suffixed with
  824                         '' a level at all.
  825                         id += str( sym->scope )
  826                     else
  827                         '' Use the case-sensitive name saved in the alias
  828                         id = *sym->id.alias
  829                     end if
  830                 end if
  831             case FB_BACKEND_LLVM
  832                 if( symbGetMangling( sym ) = FB_MANGLING_BASIC ) then
  833                     '' BASIC mangling, use the upper-cased name
  834                     id = *sym->id.name
  835 
  836                     '' Type suffix?
  837                     if( symbIsSuffixed( sym ) ) then
  838                         id += *hMangleBuiltInType( symbGetType( sym ) )
  839                     end if
  840 
  841                     '' Make the symbol unique - LLVM IR doesn't have scopes.
  842                     '' (appending the scope level wouldn't be enough due to
  843                     '' conflicts between sibling scopes)
  844                     id += "." + str( varcounter )
  845                     varcounter += 1
  846                 else
  847                     '' Use the case-sensitive name saved in the alias
  848                     id = *sym->id.alias
  849                 end if
  850             case else '' ASM backend
  851                 if( symbIsStatic( sym ) ) then
  852                     id = *symbUniqueId( )
  853                 else
  854                     id = *irProcGetFrameRegName( )
  855                 end if
  856             end select
  857         end if
  858     end if
  859 
  860     if( len( id ) > 0 ) then
  861         '' id length (C++ only) followed by the id itself
  862         if( docpp ) then
  863             mangled += str( len( id ) )
  864         end if
  865         mangled += id
  866     end if
  867 
  868     if( docpp ) then
  869         '' nested? (namespace or class)
  870         if( hIsNested( sym ) ) then
  871             mangled += "E"
  872         end if
  873     end if
  874 
  875     symbSetMangledId( sym, mangled )
  876 end sub
  877 
  878 private sub hGetProcParamsTypeCode _
  879     ( _
  880         byref mangled as string, _
  881         byval sym as FBSYMBOL ptr, _
  882         byval is_real_proc as integer _
  883     )
  884 
  885     dim as FBSYMBOL ptr param = any
  886 
  887     param = symbGetProcHeadParam( sym )
  888     if( param <> NULL ) then
  889         ''
  890         '' When doing C++ mangling for method, the THIS pointer isn't
  891         '' included in the mangled name.
  892         ''
  893         '' However, when producing the unique internal id for a
  894         '' procedure pointer, we need to encode even the THIS pointer.
  895         '' Also see symbAddProcPtr(). This can happen with the symbols
  896         '' created by symbAddProcPtrFromFunction() when calling a
  897         '' virtual method through the procedure pointer in the vtable.
  898         ''
  899         if( is_real_proc and symbIsInstanceParam( param ) ) then
  900             param = symbGetParamNext( param )
  901         end if
  902     end if
  903 
  904     '' no params?
  905     if( param = NULL ) then
  906         '' void
  907         mangled += "v"
  908         exit sub
  909     end if
  910 
  911     '' for each param...
  912     do
  913         symbMangleParam( mangled, param )
  914         param = symbGetParamNext( param )
  915     loop while( param )
  916 end sub
  917 
  918 private function hGetOperatorName( byval proc as FBSYMBOL ptr ) as const zstring ptr
  919     ''
  920     '' Most operators follow the "Operator Encodings" section of the
  921     '' Itanium C++ ABI.
  922     ''
  923     '' However, FB has some operators that C++ doesn't have, these "custom"
  924     '' operators should use the predefined scheme of the ABI, to allow
  925     '' C++-compatible tools to demangle them:
  926     ''    v <num-args> <length> <name>
  927     '' where <num-args> is the operand count as a single decimal
  928     '' digit, and <length> is the length of <name>.
  929     ''
  930     select case as const symbGetProcOpOvl( proc )
  931     case AST_OP_ASSIGN
  932         function = @"aS"
  933 
  934     case AST_OP_ADD
  935         function = @"pl"
  936 
  937     case AST_OP_ADD_SELF
  938         function = @"pL"
  939 
  940     case AST_OP_SUB
  941         function = @"mi"
  942 
  943     case AST_OP_SUB_SELF
  944         function = @"mI"
  945 
  946     case AST_OP_MUL
  947         function = @"ml"
  948 
  949     case AST_OP_MUL_SELF
  950         function = @"mL"
  951 
  952     case AST_OP_DIV
  953         function = @"dv"
  954 
  955     case AST_OP_DIV_SELF
  956         function = @"dV"
  957 
  958     case AST_OP_INTDIV
  959         function = @"v24idiv"
  960 
  961     case AST_OP_INTDIV_SELF
  962         function = @"v28selfidiv"
  963 
  964     case AST_OP_MOD
  965         function = @"rm"
  966 
  967     case AST_OP_MOD_SELF
  968         function = @"rM"
  969 
  970     case AST_OP_AND
  971         function = @"an"
  972 
  973     case AST_OP_AND_SELF
  974         function = @"aN"
  975 
  976     case AST_OP_OR
  977         function = @"or"
  978 
  979     case AST_OP_OR_SELF
  980         function = @"oR"
  981 
  982     '' Note: The ANDALSO/ORELSE operators can't currently be
  983     '' overloaded, much less the self versions
  984     case AST_OP_ANDALSO
  985         function = @"aa"
  986 
  987     case AST_OP_ANDALSO_SELF
  988         function = @"aA" '' FB-specific
  989 
  990     case AST_OP_ORELSE
  991         function = @"oo"
  992 
  993     case AST_OP_ORELSE_SELF
  994         function = @"oO" '' FB-specific
  995 
  996     case AST_OP_XOR
  997         function = @"eo"
  998 
  999     case AST_OP_XOR_SELF
 1000         function = @"eO"
 1001 
 1002     case AST_OP_EQV
 1003         function = @"v23eqv"
 1004 
 1005     case AST_OP_EQV_SELF
 1006         function = @"v27selfeqv"
 1007 
 1008     case AST_OP_IMP
 1009         function = @"v23imp"
 1010 
 1011     case AST_OP_IMP_SELF
 1012         function = @"v27selfimp"
 1013 
 1014     case AST_OP_SHL
 1015         function = @"ls"
 1016 
 1017     case AST_OP_SHL_SELF
 1018         function = @"lS"
 1019 
 1020     case AST_OP_SHR
 1021         function = @"rs"
 1022 
 1023     case AST_OP_SHR_SELF
 1024         function = @"rS"
 1025 
 1026     case AST_OP_POW
 1027         function = @"v23pow"
 1028 
 1029     case AST_OP_POW_SELF
 1030         function = @"v27selfpow"
 1031 
 1032     case AST_OP_CONCAT
 1033         function = @"v23cat"
 1034 
 1035     case AST_OP_CONCAT_SELF
 1036         function = @"v27selfcat"
 1037 
 1038     case AST_OP_EQ
 1039         function = @"eq"
 1040 
 1041     case AST_OP_GT
 1042         function = @"gt"
 1043 
 1044     case AST_OP_LT
 1045         function = @"lt"
 1046 
 1047     case AST_OP_NE
 1048         function = @"ne"
 1049 
 1050     case AST_OP_GE
 1051         function = @"ge"
 1052 
 1053     case AST_OP_LE
 1054         function = @"le"
 1055 
 1056     case AST_OP_NOT
 1057         function = @"co"
 1058 
 1059     case AST_OP_NEG
 1060         function = @"ng"
 1061 
 1062     case AST_OP_PLUS
 1063         function = @"ps"
 1064 
 1065     case AST_OP_ABS
 1066         function = @"v13abs"
 1067 
 1068     case AST_OP_FIX
 1069         function = @"v13fix"
 1070 
 1071     case AST_OP_FRAC
 1072         function = @"v14frac"
 1073 
 1074     case AST_OP_LEN
 1075         function = @"v13len"
 1076 
 1077     case AST_OP_SGN
 1078         function = @"v13sgn"
 1079 
 1080     case AST_OP_FLOOR
 1081         function = @"v13int"
 1082 
 1083     case AST_OP_EXP
 1084         function = @"v13exp"
 1085 
 1086     case AST_OP_LOG
 1087         function = @"v13log"
 1088 
 1089     case AST_OP_SIN
 1090         function = @"v13sin"
 1091 
 1092     case AST_OP_ASIN
 1093         function = @"v14asin"
 1094 
 1095     case AST_OP_COS
 1096         function = @"v13cos"
 1097 
 1098     case AST_OP_ACOS
 1099         function = @"v14acos"
 1100 
 1101     case AST_OP_TAN
 1102         function = @"v13tan"
 1103 
 1104     case AST_OP_ATAN
 1105         function = @"v13atn"
 1106 
 1107     case AST_OP_SQRT
 1108         function = @"v13sqr"
 1109 
 1110     case AST_OP_NEW, AST_OP_NEW_SELF
 1111         function = @"nw"
 1112 
 1113     case AST_OP_NEW_VEC, AST_OP_NEW_VEC_SELF
 1114         function = @"na"
 1115 
 1116     case AST_OP_DEL, AST_OP_DEL_SELF
 1117         function = @"dl"
 1118 
 1119     case AST_OP_DEL_VEC, AST_OP_DEL_VEC_SELF
 1120         function = @"da"
 1121 
 1122     case AST_OP_DEREF
 1123         function = @"de"
 1124 
 1125     case AST_OP_FLDDEREF
 1126         function = @"pt"
 1127 
 1128     case AST_OP_PTRINDEX
 1129         function = @"ix"
 1130 
 1131     case AST_OP_ADDROF
 1132         function = @"ad"
 1133 
 1134     case AST_OP_FOR
 1135         '' operator T.for( [ as T ] )
 1136         if( symbGetProcParams( proc ) = 2 ) then
 1137             function = @"v13for"
 1138         else
 1139             assert( symbGetProcParams( proc ) = 1 )
 1140             function = @"v03for"
 1141         end if
 1142 
 1143     case AST_OP_STEP
 1144         '' operator T.step( [ as T ] )
 1145         if( symbGetProcParams( proc ) = 2 ) then
 1146             function = @"v14step"
 1147         else
 1148             assert( symbGetProcParams( proc ) = 1 )
 1149             function = @"v04step"
 1150         end if
 1151 
 1152     case AST_OP_NEXT
 1153         '' operator T.next( as T [ , as T ] )
 1154         if( symbGetProcParams( proc ) = 3 ) then
 1155             function = @"v24next"
 1156         else
 1157             assert( symbGetProcParams( proc ) = 2 )
 1158             function = @"v14next"
 1159         end if
 1160 
 1161     end select
 1162 end function
 1163 
 1164 private sub hMangleProc( byval sym as FBSYMBOL ptr )
 1165     dim as string mangled
 1166     dim as integer length = any, docpp = any, add_stdcall_suffix = any
 1167     dim as zstring ptr id = any
 1168 
 1169     docpp = hDoCppMangling( sym )
 1170 
 1171     '' Should the @N win32 stdcall suffix be added for this procedure?
 1172     '' * only for stdcall, not stdcallms/cdecl/pascal
 1173     ''   (that also makes it win32-only)
 1174     '' * only on x86, since these calling conventions matter there only
 1175     '' * only for ASM/LLVM backends, but not for the C backend, because gcc
 1176     ''   will do it already
 1177     add_stdcall_suffix = (sym->proc.mode = FB_FUNCMODE_STDCALL) and _
 1178                 (fbGetCpuFamily( ) = FB_CPUFAMILY_X86) and _
 1179                 (env.clopt.backend <> FB_BACKEND_GCC)
 1180 
 1181     '' LLVM: @ prefix for global symbols
 1182     if( env.clopt.backend = FB_BACKEND_LLVM ) then
 1183         mangled += "@"
 1184 
 1185         '' Going to add @N stdcall suffix below?
 1186         if( add_stdcall_suffix ) then
 1187             '' In LLVM, @ is a special char, identifiers using it must be quoted
 1188             mangled += """"
 1189         end if
 1190     end if
 1191 
 1192     '' Win32 underscore prefix
 1193     if( hAddUnderscore( ) ) then
 1194         mangled += "_"
 1195     end if
 1196 
 1197     '' C++ prefix
 1198     '' global overloaded operators need the prefix
 1199     if( docpp or symbIsOperator( sym ) ) then
 1200         mangled += "_Z"
 1201     end if
 1202 
 1203     '' namespace or class
 1204     if( docpp ) then
 1205         hMangleNamespace( mangled, symbGetNamespace( sym ), TRUE, symbIsConstant( sym ) )
 1206     end if
 1207 
 1208     '' id
 1209     if( (sym->stats and FB_SYMBSTATS_HASALIAS) <> 0 ) then
 1210         '' Explicit proc ALIAS given, overriding the default id
 1211         '' (even for constructors, operators and properties)
 1212         '' id length (C++ only)
 1213         if( docpp ) then
 1214             mangled += str( len( *sym->id.alias ) )
 1215         end if
 1216         '' id
 1217         mangled += *sym->id.alias
 1218     elseif( symbIsOperator( sym ) ) then
 1219         if( symbGetProcOpOvl( sym ) = AST_OP_CAST ) then
 1220             mangled += "cv"
 1221             '' mangle the return type
 1222             symbMangleType( mangled, symbGetFullType( sym ), symbGetSubtype( sym ) )
 1223         else
 1224             mangled += *hGetOperatorName( sym )
 1225         end if
 1226     elseif( symbIsConstructor( sym ) ) then
 1227         mangled += "C1"
 1228     elseif( symbIsDestructor( sym ) ) then
 1229         mangled += "D1"
 1230     else
 1231         if( symbGetMangling( sym ) = FB_MANGLING_BASIC ) then
 1232             '' BASIC, use the upper-cased name
 1233             id = sym->id.name
 1234         else
 1235             '' use the case-sensitive name saved in the alias
 1236             id = sym->id.alias
 1237         end if
 1238 
 1239         '' id length (C++ only)
 1240         if( docpp ) then
 1241             length = len( *id )
 1242             if( symbIsProperty( sym ) ) then
 1243                 length += 7  '' __get__ or __set__ (see below)
 1244             end if
 1245             mangled += str( length )
 1246         end if
 1247 
 1248         '' id
 1249         mangled += *id
 1250         if( symbIsProperty( sym ) ) then
 1251             '' custom property mangling,
 1252             '' since the base id is the same for setters/getters
 1253             '' GET?
 1254             if( symbGetType( sym ) = FB_DATATYPE_VOID ) then
 1255                 mangled += "__set__"
 1256             else
 1257                 mangled += "__get__"
 1258             end if
 1259         end if
 1260     end if
 1261 
 1262     '' params
 1263     if( docpp ) then
 1264         '' nested? (namespace or class)
 1265         if( hIsNested( sym ) ) then
 1266             mangled += "E"
 1267         end if
 1268         hGetProcParamsTypeCode( mangled, sym, TRUE )
 1269     end if
 1270 
 1271     '' @N win32 stdcall suffix
 1272     if( add_stdcall_suffix ) then
 1273         mangled += "@" + str( symbProcCalcStdcallSuffixN( sym ) )
 1274 
 1275         if( env.clopt.backend = FB_BACKEND_LLVM ) then
 1276             '' In LLVM, @ is a special char, identifiers using it must be quoted
 1277             mangled += """"
 1278         end if
 1279     end if
 1280 
 1281     symbSetMangledId( sym, mangled )
 1282 end sub