mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:22:26 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			245 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /**
 | |
|  * Copyright 2023 ByteDance Inc.
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package loader
 | |
| 
 | |
| import (
 | |
|     `encoding`
 | |
|     `encoding/binary`
 | |
|     `fmt`
 | |
|     `reflect`
 | |
|     `strings`
 | |
|     `sync`
 | |
|     `unsafe`
 | |
| )
 | |
| 
 | |
| const (
 | |
|     _MinLC uint8 = 1
 | |
|     _PtrSize uint8 = 8
 | |
| )
 | |
| 
 | |
| const (
 | |
|     _N_FUNCDATA = 8
 | |
|     _INVALID_FUNCDATA_OFFSET = ^uint32(0)
 | |
|     _FUNC_SIZE = unsafe.Sizeof(_func{})
 | |
|     
 | |
|     _MINFUNC = 16 // minimum size for a function
 | |
|     _BUCKETSIZE    = 256 * _MINFUNC
 | |
|     _SUBBUCKETS    = 16
 | |
|     _SUB_BUCKETSIZE = _BUCKETSIZE / _SUBBUCKETS
 | |
| )
 | |
| 
 | |
| // Note: This list must match the list in runtime/symtab.go.
 | |
| const (
 | |
| 	FuncFlag_TOPFRAME = 1 << iota
 | |
| 	FuncFlag_SPWRITE
 | |
| 	FuncFlag_ASM
 | |
| )
 | |
| 
 | |
| // PCDATA and FUNCDATA table indexes.
 | |
| //
 | |
| // See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go.
 | |
| const (
 | |
|     _FUNCDATA_ArgsPointerMaps    = 0
 | |
|     _FUNCDATA_LocalsPointerMaps  = 1
 | |
|     _FUNCDATA_StackObjects       = 2
 | |
|     _FUNCDATA_InlTree            = 3
 | |
|     _FUNCDATA_OpenCodedDeferInfo = 4
 | |
|     _FUNCDATA_ArgInfo            = 5
 | |
|     _FUNCDATA_ArgLiveInfo        = 6
 | |
|     _FUNCDATA_WrapInfo           = 7
 | |
| 
 | |
|     // ArgsSizeUnknown is set in Func.argsize to mark all functions
 | |
|     // whose argument size is unknown (C vararg functions, and
 | |
|     // assembly code without an explicit specification).
 | |
|     // This value is generated by the compiler, assembler, or linker.
 | |
|     ArgsSizeUnknown = -0x80000000
 | |
| )
 | |
| 
 | |
| // moduledata used to cache the funcdata and findfuncbucket of one module
 | |
| var moduleCache = struct {
 | |
|     m map[*moduledata][]byte
 | |
|     sync.Mutex
 | |
| }{
 | |
|     m: make(map[*moduledata][]byte),
 | |
| }
 | |
| 
 | |
| // Func contains information about a function.
 | |
| type Func struct {
 | |
|     ID          uint8  // see runtime/symtab.go
 | |
|     Flag        uint8  // see runtime/symtab.go
 | |
|     ArgsSize    int32  // args byte size
 | |
|     EntryOff    uint32 // start pc, offset to moduledata.text
 | |
|     TextSize    uint32 // size of func text
 | |
|     DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
 | |
|     FileIndex   uint32 // index into filetab 
 | |
|     Name        string // name of function
 | |
| 
 | |
|     // PC data
 | |
|     Pcsp            *Pcdata // PC -> SP delta
 | |
|     Pcfile          *Pcdata // PC -> file index
 | |
|     Pcline          *Pcdata // PC -> line number
 | |
|     PcUnsafePoint   *Pcdata // PC -> unsafe point, must be PCDATA_UnsafePointSafe or PCDATA_UnsafePointUnsafe
 | |
|     PcStackMapIndex *Pcdata // PC -> stack map index, relative to ArgsPointerMaps and LocalsPointerMaps
 | |
|     PcInlTreeIndex  *Pcdata // PC -> inlining tree index, relative to InlTree
 | |
|     PcArgLiveIndex  *Pcdata // PC -> arg live index, relative to ArgLiveInfo
 | |
|     
 | |
|     // Func data, must implement encoding.BinaryMarshaler
 | |
|     ArgsPointerMaps    encoding.BinaryMarshaler // concrete type: *StackMap
 | |
|     LocalsPointerMaps  encoding.BinaryMarshaler // concrete type: *StackMap
 | |
|     StackObjects       encoding.BinaryMarshaler
 | |
|     InlTree            encoding.BinaryMarshaler
 | |
|     OpenCodedDeferInfo encoding.BinaryMarshaler
 | |
|     ArgInfo            encoding.BinaryMarshaler
 | |
|     ArgLiveInfo        encoding.BinaryMarshaler
 | |
|     WrapInfo           encoding.BinaryMarshaler
 | |
| }
 | |
| 
 | |
| func getOffsetOf(data interface{}, field string) uintptr {
 | |
|     t := reflect.TypeOf(data)
 | |
|     fv, ok := t.FieldByName(field)
 | |
|     if !ok {
 | |
|         panic(fmt.Sprintf("field %s not found in struct %s", field, t.Name()))
 | |
|     }
 | |
|     return fv.Offset
 | |
| }
 | |
| 
 | |
| func rnd(v int64, r int64) int64 {
 | |
|     if r <= 0 {
 | |
|         return v
 | |
|     }
 | |
|     v += r - 1
 | |
|     c := v % r
 | |
|     if c < 0 {
 | |
|         c += r
 | |
|     }
 | |
|     v -= c
 | |
|     return v
 | |
| }
 | |
| 
 | |
| var (
 | |
|     byteOrder binary.ByteOrder = binary.LittleEndian
 | |
| )
 | |
| 
 | |
| func funcNameParts(name string) (string, string, string) {
 | |
|     i := strings.IndexByte(name, '[')
 | |
|     if i < 0 {
 | |
|         return name, "", ""
 | |
|     }
 | |
|     // TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.
 | |
|     j := len(name) - 1
 | |
|     for j > i && name[j] != ']' {
 | |
|         j--
 | |
|     }
 | |
|     if j <= i {
 | |
|         return name, "", ""
 | |
|     }
 | |
|     return name[:i], "[...]", name[j+1:]
 | |
| }
 | |
| 
 | |
| 
 | |
| // func name table format: 
 | |
| //   nameOff[0] -> namePartA namePartB namePartC \x00 
 | |
| //   nameOff[1] -> namePartA namePartB namePartC \x00
 | |
| //  ...
 | |
| func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
 | |
|     offs = make([]int32, len(funcs))
 | |
|     offset := 1
 | |
|     tab = []byte{0}
 | |
| 
 | |
|     for i, f := range funcs {
 | |
|         offs[i] = int32(offset)
 | |
| 
 | |
|         a, b, c := funcNameParts(f.Name)
 | |
|         tab = append(tab, a...)
 | |
|         tab = append(tab, b...)
 | |
|         tab = append(tab, c...)
 | |
|         tab = append(tab, 0)
 | |
|         offset += len(a) + len(b) + len(c) + 1
 | |
|     }
 | |
| 
 | |
|     return
 | |
| }
 | |
| 
 | |
| // CU table format:
 | |
| //  cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
 | |
| //  cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
 | |
| //  ...
 | |
| //
 | |
| // file name table format:
 | |
| //  filetabOffset[0] -> CUs[0].fileNames[0] \x00
 | |
| //  ...
 | |
| //  filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
 | |
| //  ...
 | |
| //  filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
 | |
| func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
 | |
|     cuOffsets = make([]uint32, len(cus))
 | |
|     cuOffset := 0
 | |
|     fileOffset := 0
 | |
| 
 | |
|     for i, cu := range cus {
 | |
|         cuOffsets[i] = uint32(cuOffset)
 | |
| 
 | |
|         for _, name := range cu.fileNames {
 | |
|             cutab = append(cutab, uint32(fileOffset))
 | |
| 
 | |
|             fileOffset += len(name) + 1
 | |
|             filetab = append(filetab, name...)
 | |
|             filetab = append(filetab, 0)
 | |
|         }
 | |
| 
 | |
|         cuOffset += len(cu.fileNames)
 | |
|     }
 | |
| 
 | |
|     return
 | |
| }
 | |
| 
 | |
| func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
 | |
|     fstart = len(*out)
 | |
|     *out = append(*out, byte(0))
 | |
|     offs := uint32(1)
 | |
| 
 | |
|     funcdataOffs = make([][]uint32, len(funcs))
 | |
|     for i, f := range funcs {
 | |
| 
 | |
|         var writer = func(fd encoding.BinaryMarshaler) {
 | |
|             var ab []byte
 | |
|             var err error
 | |
|             if fd != nil {
 | |
|                 ab, err = fd.MarshalBinary()
 | |
|                 if err != nil {
 | |
|                     panic(err)
 | |
|                 }
 | |
|                 funcdataOffs[i] = append(funcdataOffs[i], offs)
 | |
|             } else {
 | |
|                 ab = []byte{0}
 | |
|                 funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
 | |
|             }
 | |
|             *out = append(*out, ab...)
 | |
|             offs += uint32(len(ab))
 | |
|         }
 | |
| 
 | |
|         writer(f.ArgsPointerMaps)
 | |
|         writer(f.LocalsPointerMaps)
 | |
|         writer(f.StackObjects)
 | |
|         writer(f.InlTree)
 | |
|         writer(f.OpenCodedDeferInfo)
 | |
|         writer(f.ArgInfo)
 | |
|         writer(f.ArgLiveInfo)
 | |
|         writer(f.WrapInfo)
 | |
|     }
 | |
|     return 
 | |
| }
 |