2016-03-01 22:57:46 +00:00
// Copyright 2013 The Go Authors. All rights reserved.
2015-02-27 22:57:28 -05:00
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ld
import (
"cmd/internal/obj"
"log"
2015-12-29 10:16:40 -05:00
"os"
"path/filepath"
2015-02-27 22:57:28 -05:00
)
// iteration over encoded pcdata tables.
func getvarint ( pp * [ ] byte ) uint32 {
2015-03-02 12:35:15 -05:00
v := uint32 ( 0 )
p := * pp
for shift := 0 ; ; shift += 7 {
2015-02-27 22:57:28 -05:00
v |= uint32 ( p [ 0 ] & 0x7F ) << uint ( shift )
tmp4 := p
p = p [ 1 : ]
if tmp4 [ 0 ] & 0x80 == 0 {
break
}
}
* pp = p
return v
}
func pciternext ( it * Pciter ) {
it . pc = it . nextpc
if it . done != 0 {
return
}
if - cap ( it . p ) >= - cap ( it . d . P [ len ( it . d . P ) : ] ) {
it . done = 1
return
}
// value delta
2015-03-02 12:35:15 -05:00
v := getvarint ( & it . p )
2015-02-27 22:57:28 -05:00
if v == 0 && it . start == 0 {
it . done = 1
return
}
it . start = 0
2015-03-02 12:35:15 -05:00
dv := int32 ( v >> 1 ) ^ ( int32 ( v << 31 ) >> 31 )
2015-02-27 22:57:28 -05:00
it . value += dv
// pc delta
v = getvarint ( & it . p )
it . nextpc = it . pc + v * it . pcscale
}
func pciterinit ( ctxt * Link , it * Pciter , d * Pcdata ) {
it . d = * d
it . p = it . d . P
it . pc = 0
it . nextpc = 0
it . value = - 1
it . start = 1
it . done = 0
2016-04-06 12:01:40 -07:00
it . pcscale = uint32 ( ctxt . Arch . MinLC )
2015-02-27 22:57:28 -05:00
pciternext ( it )
}
func addvarint ( d * Pcdata , val uint32 ) {
2015-03-02 12:35:15 -05:00
n := int32 ( 0 )
for v := val ; v >= 0x80 ; v >>= 7 {
2015-02-27 22:57:28 -05:00
n ++
}
n ++
old := len ( d . P )
for cap ( d . P ) < len ( d . P ) + int ( n ) {
d . P = append ( d . P [ : cap ( d . P ) ] , 0 )
}
d . P = d . P [ : old + int ( n ) ]
2015-03-02 12:35:15 -05:00
p := d . P [ old : ]
var v uint32
2015-02-27 22:57:28 -05:00
for v = val ; v >= 0x80 ; v >>= 7 {
p [ 0 ] = byte ( v | 0x80 )
p = p [ 1 : ]
}
p [ 0 ] = byte ( v )
}
2016-08-19 22:40:38 -04:00
func addpctab ( ctxt * Link , ftab * Symbol , off int32 , d * Pcdata ) int32 {
2015-06-28 22:26:35 -04:00
var start int32
if len ( d . P ) > 0 {
start = int32 ( len ( ftab . P ) )
2016-09-20 15:31:26 +12:00
Addbytes ( ftab , d . P )
2015-06-28 22:26:35 -04:00
}
2016-08-19 22:40:38 -04:00
return int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , uint32 ( start ) ) )
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
func ftabaddstring ( ctxt * Link , ftab * Symbol , s string ) int32 {
2015-03-02 12:35:15 -05:00
n := int32 ( len ( s ) ) + 1
start := int32 ( len ( ftab . P ) )
2016-09-20 15:31:26 +12:00
Symgrow ( ftab , int64 ( start ) + int64 ( n ) + 1 )
2015-02-27 22:57:28 -05:00
copy ( ftab . P [ start : ] , s )
return start
}
2016-08-19 11:35:54 -04:00
func renumberfiles ( ctxt * Link , files [ ] * Symbol , d * Pcdata ) {
var f * Symbol
2015-02-27 22:57:28 -05:00
// Give files numbers.
2015-03-02 12:35:15 -05:00
for i := 0 ; i < len ( files ) ; i ++ {
2015-02-27 22:57:28 -05:00
f = files [ i ]
2015-04-19 19:33:58 -07:00
if f . Type != obj . SFILEPATH {
2016-04-22 10:10:08 +12:00
ctxt . Filesyms = append ( ctxt . Filesyms , f )
f . Value = int64 ( len ( ctxt . Filesyms ) )
2015-04-19 19:33:58 -07:00
f . Type = obj . SFILEPATH
2015-12-29 10:16:40 -05:00
f . Name = expandGoroot ( f . Name )
2015-02-27 22:57:28 -05:00
}
}
2015-03-02 12:35:15 -05:00
newval := int32 ( - 1 )
2015-03-02 14:22:05 -05:00
var out Pcdata
2015-03-02 12:35:15 -05:00
var it Pciter
2015-02-27 22:57:28 -05:00
for pciterinit ( ctxt , & it , d ) ; it . done == 0 ; pciternext ( & it ) {
// value delta
2016-04-20 14:22:20 -04:00
oldval := it . value
2015-02-27 22:57:28 -05:00
2016-04-20 14:22:20 -04:00
var val int32
2015-02-27 22:57:28 -05:00
if oldval == - 1 {
val = - 1
} else {
if oldval < 0 || oldval >= int32 ( len ( files ) ) {
log . Fatalf ( "bad pcdata %d" , oldval )
}
val = int32 ( files [ oldval ] . Value )
}
2016-04-20 14:22:20 -04:00
dv := val - newval
2015-02-27 22:57:28 -05:00
newval = val
2016-04-20 14:22:20 -04:00
v := ( uint32 ( dv ) << 1 ) ^ uint32 ( dv >> 31 )
2015-02-27 22:57:28 -05:00
addvarint ( & out , v )
// pc delta
addvarint ( & out , ( it . nextpc - it . pc ) / it . pcscale )
}
// terminating value delta
addvarint ( & out , 0 )
* d = out
}
2016-08-19 11:35:54 -04:00
func container ( s * Symbol ) int {
2015-02-27 22:57:28 -05:00
// We want to generate func table entries only for the "lowest level" symbols,
// not containers of subsymbols.
2015-06-27 12:57:06 -07:00
if s != nil && s . Type & obj . SCONTAINER != 0 {
2015-02-27 22:57:28 -05:00
return 1
}
return 0
}
// pclntab initializes the pclntab symbol with
// runtime function and file name information.
2016-08-22 10:33:13 -04:00
var pclntabZpcln FuncInfo
2015-02-27 22:57:28 -05:00
2015-04-07 12:55:02 +12:00
// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
2015-03-16 11:53:08 +13:00
var pclntabNfunc int32
var pclntabFiletabOffset int32
var pclntabPclntabOffset int32
2016-08-19 11:35:54 -04:00
var pclntabFirstFunc * Symbol
var pclntabLastFunc * Symbol
2015-03-16 11:53:08 +13:00
2016-08-19 22:40:38 -04:00
func ( ctxt * Link ) pclntab ( ) {
2016-08-22 10:33:13 -04:00
funcdataBytes := int64 ( 0 )
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
ftab := ctxt . Syms . Lookup ( "runtime.pclntab" , 0 )
2015-04-19 19:33:58 -07:00
ftab . Type = obj . SPCLNTAB
2016-03-02 07:59:49 -05:00
ftab . Attr |= AttrReachable
2015-02-27 22:57:28 -05:00
// See golang.org/s/go12symtab for the format. Briefly:
// 8-byte header
// nfunc [thearch.ptrsize bytes]
// function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
// end PC [thearch.ptrsize bytes]
// offset to file table [4 bytes]
2015-03-02 12:35:15 -05:00
nfunc := int32 ( 0 )
2015-02-27 22:57:28 -05:00
2015-06-27 12:57:06 -07:00
// Find container symbols, mark them with SCONTAINER
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2016-04-19 14:02:21 -04:00
if s . Outer != nil {
s . Outer . Type |= obj . SCONTAINER
2015-06-27 12:57:06 -07:00
}
}
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2016-04-19 14:02:21 -04:00
if container ( s ) == 0 {
2015-02-27 22:57:28 -05:00
nfunc ++
}
}
2015-03-16 11:53:08 +13:00
pclntabNfunc = nfunc
2016-09-20 15:31:26 +12:00
Symgrow ( ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) + int64 ( SysArch . PtrSize ) + 4 )
2016-08-19 22:40:38 -04:00
setuint32 ( ctxt , ftab , 0 , 0xfffffffb )
setuint8 ( ctxt , ftab , 6 , uint8 ( SysArch . MinLC ) )
setuint8 ( ctxt , ftab , 7 , uint8 ( SysArch . PtrSize ) )
setuintxx ( ctxt , ftab , 8 , uint64 ( nfunc ) , int64 ( SysArch . PtrSize ) )
2016-04-06 12:01:40 -07:00
pclntabPclntabOffset = int32 ( 8 + SysArch . PtrSize )
2015-02-27 22:57:28 -05:00
nfunc = 0
2016-08-19 11:35:54 -04:00
var last * Symbol
2016-09-17 10:01:17 -04:00
for _ , s := range ctxt . Textp {
last = s
if container ( s ) != 0 {
2015-02-27 22:57:28 -05:00
continue
}
2016-09-17 10:01:17 -04:00
pcln := s . FuncInfo
2015-02-27 22:57:28 -05:00
if pcln == nil {
2016-08-22 10:33:13 -04:00
pcln = & pclntabZpcln
2015-02-27 22:57:28 -05:00
}
2015-03-16 11:53:08 +13:00
if pclntabFirstFunc == nil {
2016-09-17 10:01:17 -04:00
pclntabFirstFunc = s
2015-03-16 11:53:08 +13:00
}
2016-04-20 14:22:20 -04:00
funcstart := int32 ( len ( ftab . P ) )
2016-04-06 12:01:40 -07:00
funcstart += int32 ( - len ( ftab . P ) ) & ( int32 ( SysArch . PtrSize ) - 1 )
2015-02-27 22:57:28 -05:00
2016-09-17 10:01:17 -04:00
setaddr ( ctxt , ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) , s )
2016-08-19 22:40:38 -04:00
setuintxx ( ctxt , ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) + int64 ( SysArch . PtrSize ) , uint64 ( funcstart ) , int64 ( SysArch . PtrSize ) )
2015-02-27 22:57:28 -05:00
// fixed size of struct, checked below
2016-04-20 14:22:20 -04:00
off := funcstart
2015-02-27 22:57:28 -05:00
2016-04-20 14:22:20 -04:00
end := funcstart + int32 ( SysArch . PtrSize ) + 3 * 4 + 5 * 4 + int32 ( len ( pcln . Pcdata ) ) * 4 + int32 ( len ( pcln . Funcdata ) ) * int32 ( SysArch . PtrSize )
2016-04-06 12:01:40 -07:00
if len ( pcln . Funcdata ) > 0 && ( end & int32 ( SysArch . PtrSize - 1 ) != 0 ) {
2015-02-27 22:57:28 -05:00
end += 4
}
2016-09-20 15:31:26 +12:00
Symgrow ( ftab , int64 ( end ) )
2015-02-27 22:57:28 -05:00
// entry uintptr
2016-09-17 10:01:17 -04:00
off = int32 ( setaddr ( ctxt , ftab , int64 ( off ) , s ) )
2015-02-27 22:57:28 -05:00
// name int32
2016-09-17 10:01:17 -04:00
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , uint32 ( ftabaddstring ( ctxt , ftab , s . Name ) ) ) )
2015-02-27 22:57:28 -05:00
// args int32
// TODO: Move into funcinfo.
2016-04-11 22:19:34 +03:00
args := uint32 ( 0 )
2016-09-17 10:01:17 -04:00
if s . FuncInfo != nil {
args = uint32 ( s . FuncInfo . Args )
2016-04-11 22:19:34 +03:00
}
2016-08-19 22:40:38 -04:00
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , args ) )
2015-02-27 22:57:28 -05:00
// frame int32
2015-03-04 16:50:59 -05:00
// This has been removed (it was never set quite correctly anyway).
// Nothing should use it.
// Leave an obviously incorrect value.
// TODO: Remove entirely.
2016-08-19 22:40:38 -04:00
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , 0x1234567 ) )
2015-02-27 22:57:28 -05:00
2016-08-22 10:33:13 -04:00
if pcln != & pclntabZpcln {
2016-08-19 22:40:38 -04:00
renumberfiles ( ctxt , pcln . File , & pcln . Pcfile )
2015-02-27 22:57:28 -05:00
if false {
// Sanity check the new numbering
2016-04-20 14:22:20 -04:00
var it Pciter
2016-08-19 22:40:38 -04:00
for pciterinit ( ctxt , & it , & pcln . Pcfile ) ; it . done == 0 ; pciternext ( & it ) {
if it . value < 1 || it . value > int32 ( len ( ctxt . Filesyms ) ) {
2016-09-17 10:01:17 -04:00
Errorf ( s , "bad file number in pcfile: %d not in range [1, %d]\n" , it . value , len ( ctxt . Filesyms ) )
2015-04-09 07:37:17 -04:00
errorexit ( )
2015-02-27 22:57:28 -05:00
}
}
}
}
// pcdata
2016-08-19 22:40:38 -04:00
off = addpctab ( ctxt , ftab , off , & pcln . Pcsp )
2015-02-27 22:57:28 -05:00
2016-08-19 22:40:38 -04:00
off = addpctab ( ctxt , ftab , off , & pcln . Pcfile )
off = addpctab ( ctxt , ftab , off , & pcln . Pcline )
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , uint32 ( len ( pcln . Pcdata ) ) ) )
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , uint32 ( len ( pcln . Funcdata ) ) ) )
2016-04-20 14:22:20 -04:00
for i := 0 ; i < len ( pcln . Pcdata ) ; i ++ {
2016-08-19 22:40:38 -04:00
off = addpctab ( ctxt , ftab , off , & pcln . Pcdata [ i ] )
2015-02-27 22:57:28 -05:00
}
// funcdata, must be pointer-aligned and we're only int32-aligned.
// Missing funcdata will be 0 (nil pointer).
2016-03-23 14:02:36 +02:00
if len ( pcln . Funcdata ) > 0 {
2016-04-06 12:01:40 -07:00
if off & int32 ( SysArch . PtrSize - 1 ) != 0 {
2015-02-27 22:57:28 -05:00
off += 4
}
2016-04-20 14:22:20 -04:00
for i := 0 ; i < len ( pcln . Funcdata ) ; i ++ {
2015-02-27 22:57:28 -05:00
if pcln . Funcdata [ i ] == nil {
2016-08-19 22:40:38 -04:00
setuintxx ( ctxt , ftab , int64 ( off ) + int64 ( SysArch . PtrSize ) * int64 ( i ) , uint64 ( pcln . Funcdataoff [ i ] ) , int64 ( SysArch . PtrSize ) )
2015-02-27 22:57:28 -05:00
} else {
// TODO: Dedup.
2016-08-22 10:33:13 -04:00
funcdataBytes += pcln . Funcdata [ i ] . Size
2015-02-27 22:57:28 -05:00
2016-08-19 22:40:38 -04:00
setaddrplus ( ctxt , ftab , int64 ( off ) + int64 ( SysArch . PtrSize ) * int64 ( i ) , pcln . Funcdata [ i ] , pcln . Funcdataoff [ i ] )
2015-02-27 22:57:28 -05:00
}
}
2016-04-06 12:01:40 -07:00
off += int32 ( len ( pcln . Funcdata ) ) * int32 ( SysArch . PtrSize )
2015-02-27 22:57:28 -05:00
}
if off != end {
2016-09-17 10:01:17 -04:00
Errorf ( s , "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)" , funcstart , off , end , len ( pcln . Pcdata ) , len ( pcln . Funcdata ) , SysArch . PtrSize )
2015-04-09 07:37:17 -04:00
errorexit ( )
2015-02-27 22:57:28 -05:00
}
nfunc ++
}
2015-03-16 11:53:08 +13:00
pclntabLastFunc = last
2015-02-27 22:57:28 -05:00
// Final entry of table is just end pc.
2016-08-19 22:40:38 -04:00
setaddrplus ( ctxt , ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) , last , last . Size )
2015-02-27 22:57:28 -05:00
// Start file table.
2015-03-02 12:35:15 -05:00
start := int32 ( len ( ftab . P ) )
2015-02-27 22:57:28 -05:00
2016-04-06 12:01:40 -07:00
start += int32 ( - len ( ftab . P ) ) & ( int32 ( SysArch . PtrSize ) - 1 )
2015-03-16 11:53:08 +13:00
pclntabFiletabOffset = start
2016-08-19 22:40:38 -04:00
setuint32 ( ctxt , ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) + int64 ( SysArch . PtrSize ) , uint32 ( start ) )
2015-02-27 22:57:28 -05:00
2016-09-20 15:31:26 +12:00
Symgrow ( ftab , int64 ( start ) + ( int64 ( len ( ctxt . Filesyms ) ) + 1 ) * 4 )
2016-09-15 19:52:40 -04:00
setuint32 ( ctxt , ftab , int64 ( start ) , uint32 ( len ( ctxt . Filesyms ) + 1 ) )
2016-08-19 22:40:38 -04:00
for i := len ( ctxt . Filesyms ) - 1 ; i >= 0 ; i -- {
s := ctxt . Filesyms [ i ]
setuint32 ( ctxt , ftab , int64 ( start ) + s . Value * 4 , uint32 ( ftabaddstring ( ctxt , ftab , s . Name ) ) )
2015-02-27 22:57:28 -05:00
}
ftab . Size = int64 ( len ( ftab . P ) )
2016-08-21 18:25:28 -04:00
if ctxt . Debugvlog != 0 {
2016-08-25 12:32:42 +10:00
ctxt . Logf ( "%5.2f pclntab=%d bytes, funcdata total %d bytes\n" , obj . Cputime ( ) , ftab . Size , funcdataBytes )
2015-02-27 22:57:28 -05:00
}
}
2015-12-29 10:16:40 -05:00
func expandGoroot ( s string ) string {
const n = len ( "$GOROOT" )
if len ( s ) >= n + 1 && s [ : n ] == "$GOROOT" && ( s [ n ] == '/' || s [ n ] == '\\' ) {
2016-09-09 08:13:16 -04:00
root := obj . GOROOT
2015-12-29 10:16:40 -05:00
if final := os . Getenv ( "GOROOT_FINAL" ) ; final != "" {
root = final
}
return filepath . ToSlash ( filepath . Join ( root , s [ n : ] ) )
}
return s
}
2015-02-27 22:57:28 -05:00
const (
BUCKETSIZE = 256 * MINFUNC
SUBBUCKETS = 16
SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
NOIDX = 0x7fffffff
)
// findfunctab generates a lookup table to quickly find the containing
2016-03-01 23:21:55 +00:00
// function for a pc. See src/runtime/symtab.go:findfunc for details.
2016-08-19 22:40:38 -04:00
func ( ctxt * Link ) findfunctab ( ) {
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
t := ctxt . Syms . Lookup ( "runtime.findfunctab" , 0 )
2015-04-19 19:33:58 -07:00
t . Type = obj . SRODATA
2016-03-02 07:59:49 -05:00
t . Attr |= AttrReachable
t . Attr |= AttrLocal
2015-02-27 22:57:28 -05:00
// find min and max address
2016-08-19 22:40:38 -04:00
min := ctxt . Textp [ 0 ] . Value
2015-03-02 12:35:15 -05:00
max := int64 ( 0 )
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2015-02-27 22:57:28 -05:00
max = s . Value + s . Size
}
// for each subbucket, compute the minimum of all symbol indexes
// that map to that subbucket.
2015-03-02 12:35:15 -05:00
n := int32 ( ( max - min + SUBBUCKETSIZE - 1 ) / SUBBUCKETSIZE )
2015-02-27 22:57:28 -05:00
2015-03-02 12:35:15 -05:00
indexes := make ( [ ] int32 , n )
for i := int32 ( 0 ) ; i < n ; i ++ {
2015-02-27 22:57:28 -05:00
indexes [ i ] = NOIDX
}
2015-03-02 12:35:15 -05:00
idx := int32 ( 0 )
2016-08-19 22:40:38 -04:00
for i , s := range ctxt . Textp {
2015-02-27 22:57:28 -05:00
if container ( s ) != 0 {
continue
}
2016-04-19 14:02:21 -04:00
p := s . Value
2016-08-19 11:35:54 -04:00
var e * Symbol
2016-04-19 14:02:21 -04:00
i ++
2016-08-19 22:40:38 -04:00
if i < len ( ctxt . Textp ) {
e = ctxt . Textp [ i ]
2016-04-19 14:02:21 -04:00
}
2016-08-19 22:40:38 -04:00
for container ( e ) != 0 && i < len ( ctxt . Textp ) {
e = ctxt . Textp [ i ]
2016-04-19 14:02:21 -04:00
i ++
2015-02-27 22:57:28 -05:00
}
2016-04-19 14:02:21 -04:00
q := max
2015-02-27 22:57:28 -05:00
if e != nil {
q = e . Value
}
//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
for ; p < q ; p += SUBBUCKETSIZE {
2016-04-19 14:02:21 -04:00
i = int ( ( p - min ) / SUBBUCKETSIZE )
2015-02-27 22:57:28 -05:00
if indexes [ i ] > idx {
indexes [ i ] = idx
}
}
2016-04-19 14:02:21 -04:00
i = int ( ( q - 1 - min ) / SUBBUCKETSIZE )
2015-02-27 22:57:28 -05:00
if indexes [ i ] > idx {
indexes [ i ] = idx
}
idx ++
}
// allocate table
2015-03-02 12:35:15 -05:00
nbuckets := int32 ( ( max - min + BUCKETSIZE - 1 ) / BUCKETSIZE )
2015-02-27 22:57:28 -05:00
2016-09-20 15:31:26 +12:00
Symgrow ( t , 4 * int64 ( nbuckets ) + int64 ( n ) )
2015-02-27 22:57:28 -05:00
// fill in table
2015-03-02 12:35:15 -05:00
for i := int32 ( 0 ) ; i < nbuckets ; i ++ {
2016-04-19 14:02:21 -04:00
base := indexes [ i * SUBBUCKETS ]
2015-02-27 22:57:28 -05:00
if base == NOIDX {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "hole in findfunctab" )
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
setuint32 ( ctxt , t , int64 ( i ) * ( 4 + SUBBUCKETS ) , uint32 ( base ) )
2016-04-19 14:02:21 -04:00
for j := int32 ( 0 ) ; j < SUBBUCKETS && i * SUBBUCKETS + j < n ; j ++ {
2015-02-27 22:57:28 -05:00
idx = indexes [ i * SUBBUCKETS + j ]
if idx == NOIDX {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "hole in findfunctab" )
2015-02-27 22:57:28 -05:00
}
if idx - base >= 256 {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "too many functions in a findfunc bucket! %d/%d %d %d" , i , nbuckets , j , idx - base )
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
setuint8 ( ctxt , t , int64 ( i ) * ( 4 + SUBBUCKETS ) + 4 + int64 ( j ) , uint8 ( idx - base ) )
2015-02-27 22:57:28 -05:00
}
}
}