github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/loader/funcdata.go (about)

     1  /**
     2   * Copyright 2023 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package loader
    18  
    19  import (
    20  	"encoding"
    21  	"encoding/binary"
    22  	"fmt"
    23  	"reflect"
    24  	"strings"
    25  	"sync"
    26  	"unsafe"
    27  )
    28  
    29  const (
    30  	_MinLC   uint8 = 1
    31  	_PtrSize uint8 = 8
    32  )
    33  
    34  const (
    35  	_N_FUNCDATA              = 8
    36  	_INVALID_FUNCDATA_OFFSET = ^uint32(0)
    37  	_FUNC_SIZE               = unsafe.Sizeof(_func{})
    38  
    39  	_MINFUNC        = 16 // minimum size for a function
    40  	_BUCKETSIZE     = 256 * _MINFUNC
    41  	_SUBBUCKETS     = 16
    42  	_SUB_BUCKETSIZE = _BUCKETSIZE / _SUBBUCKETS
    43  )
    44  
    45  // Note: This list must match the list in runtime/symtab.go.
    46  const (
    47  	FuncFlag_TOPFRAME = 1 << iota
    48  	FuncFlag_SPWRITE
    49  	FuncFlag_ASM
    50  )
    51  
    52  // PCDATA and FUNCDATA table indexes.
    53  //
    54  // See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go.
    55  const (
    56  	_FUNCDATA_ArgsPointerMaps    = 0
    57  	_FUNCDATA_LocalsPointerMaps  = 1
    58  	_FUNCDATA_StackObjects       = 2
    59  	_FUNCDATA_InlTree            = 3
    60  	_FUNCDATA_OpenCodedDeferInfo = 4
    61  	_FUNCDATA_ArgInfo            = 5
    62  	_FUNCDATA_ArgLiveInfo        = 6
    63  	_FUNCDATA_WrapInfo           = 7
    64  
    65  	// ArgsSizeUnknown is set in Func.argsize to mark all functions
    66  	// whose argument size is unknown (C vararg functions, and
    67  	// assembly code without an explicit specification).
    68  	// This value is generated by the compiler, assembler, or linker.
    69  	ArgsSizeUnknown = -0x80000000
    70  )
    71  
    72  // moduledata used to cache the funcdata and findfuncbucket of one module
    73  var moduleCache = struct {
    74  	m map[*moduledata][]byte
    75  	sync.Mutex
    76  }{
    77  	m: make(map[*moduledata][]byte),
    78  }
    79  
    80  // Func contains information about a function.
    81  type Func struct {
    82  	ID          uint8  // see runtime/symtab.go
    83  	Flag        uint8  // see runtime/symtab.go
    84  	ArgsSize    int32  // args byte size
    85  	EntryOff    uint32 // start pc, offset to moduledata.text
    86  	TextSize    uint32 // size of func text
    87  	DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
    88  	FileIndex   uint32 // index into filetab
    89  	Name        string // name of function
    90  
    91  	// PC data
    92  	Pcsp            *Pcdata // PC -> SP delta
    93  	Pcfile          *Pcdata // PC -> file index
    94  	Pcline          *Pcdata // PC -> line number
    95  	PcUnsafePoint   *Pcdata // PC -> unsafe point, must be PCDATA_UnsafePointSafe or PCDATA_UnsafePointUnsafe
    96  	PcStackMapIndex *Pcdata // PC -> stack map index, relative to ArgsPointerMaps and LocalsPointerMaps
    97  	PcInlTreeIndex  *Pcdata // PC -> inlining tree index, relative to InlTree
    98  	PcArgLiveIndex  *Pcdata // PC -> arg live index, relative to ArgLiveInfo
    99  
   100  	// Func data, must implement encoding.BinaryMarshaler
   101  	ArgsPointerMaps    encoding.BinaryMarshaler // concrete type: *StackMap
   102  	LocalsPointerMaps  encoding.BinaryMarshaler // concrete type: *StackMap
   103  	StackObjects       encoding.BinaryMarshaler
   104  	InlTree            encoding.BinaryMarshaler
   105  	OpenCodedDeferInfo encoding.BinaryMarshaler
   106  	ArgInfo            encoding.BinaryMarshaler
   107  	ArgLiveInfo        encoding.BinaryMarshaler
   108  	WrapInfo           encoding.BinaryMarshaler
   109  }
   110  
   111  func getOffsetOf(data interface{}, field string) uintptr {
   112  	t := reflect.TypeOf(data)
   113  	fv, ok := t.FieldByName(field)
   114  	if !ok {
   115  		panic(fmt.Sprintf("field %s not found in struct %s", field, t.Name()))
   116  	}
   117  	return fv.Offset
   118  }
   119  
   120  func rnd(v int64, r int64) int64 {
   121  	if r <= 0 {
   122  		return v
   123  	}
   124  	v += r - 1
   125  	c := v % r
   126  	if c < 0 {
   127  		c += r
   128  	}
   129  	v -= c
   130  	return v
   131  }
   132  
   133  var (
   134  	byteOrder binary.ByteOrder = binary.LittleEndian
   135  )
   136  
   137  func funcNameParts(name string) (string, string, string) {
   138  	i := strings.IndexByte(name, '[')
   139  	if i < 0 {
   140  		return name, "", ""
   141  	}
   142  	// TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.
   143  	j := len(name) - 1
   144  	for j > i && name[j] != ']' {
   145  		j--
   146  	}
   147  	if j <= i {
   148  		return name, "", ""
   149  	}
   150  	return name[:i], "[...]", name[j+1:]
   151  }
   152  
   153  // func name table format:
   154  //
   155  //	 nameOff[0] -> namePartA namePartB namePartC \x00
   156  //	 nameOff[1] -> namePartA namePartB namePartC \x00
   157  //	...
   158  func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
   159  	offs = make([]int32, len(funcs))
   160  	offset := 1
   161  	tab = []byte{0}
   162  
   163  	for i, f := range funcs {
   164  		offs[i] = int32(offset)
   165  
   166  		a, b, c := funcNameParts(f.Name)
   167  		tab = append(tab, a...)
   168  		tab = append(tab, b...)
   169  		tab = append(tab, c...)
   170  		tab = append(tab, 0)
   171  		offset += len(a) + len(b) + len(c) + 1
   172  	}
   173  
   174  	return
   175  }
   176  
   177  // CU table format:
   178  //
   179  //	cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
   180  //	cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
   181  //	...
   182  //
   183  // file name table format:
   184  //
   185  //	filetabOffset[0] -> CUs[0].fileNames[0] \x00
   186  //	...
   187  //	filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
   188  //	...
   189  //	filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
   190  func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
   191  	cuOffsets = make([]uint32, len(cus))
   192  	cuOffset := 0
   193  	fileOffset := 0
   194  
   195  	for i, cu := range cus {
   196  		cuOffsets[i] = uint32(cuOffset)
   197  
   198  		for _, name := range cu.fileNames {
   199  			cutab = append(cutab, uint32(fileOffset))
   200  
   201  			fileOffset += len(name) + 1
   202  			filetab = append(filetab, name...)
   203  			filetab = append(filetab, 0)
   204  		}
   205  
   206  		cuOffset += len(cu.fileNames)
   207  	}
   208  
   209  	return
   210  }
   211  
   212  func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
   213  	fstart = len(*out)
   214  	*out = append(*out, byte(0))
   215  	offs := uint32(1)
   216  
   217  	funcdataOffs = make([][]uint32, len(funcs))
   218  	for i, f := range funcs {
   219  
   220  		var writer = func(fd encoding.BinaryMarshaler) {
   221  			var ab []byte
   222  			var err error
   223  			if fd != nil {
   224  				ab, err = fd.MarshalBinary()
   225  				if err != nil {
   226  					panic(err)
   227  				}
   228  				funcdataOffs[i] = append(funcdataOffs[i], offs)
   229  			} else {
   230  				ab = []byte{0}
   231  				funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
   232  			}
   233  			*out = append(*out, ab...)
   234  			offs += uint32(len(ab))
   235  		}
   236  
   237  		writer(f.ArgsPointerMaps)
   238  		writer(f.LocalsPointerMaps)
   239  		writer(f.StackObjects)
   240  		writer(f.InlTree)
   241  		writer(f.OpenCodedDeferInfo)
   242  		writer(f.ArgInfo)
   243  		writer(f.ArgLiveInfo)
   244  		writer(f.WrapInfo)
   245  	}
   246  	return
   247  }