github.com/cloudwego/frugal@v0.1.15/internal/rt/stackmap.go (about) 1 /* 2 * Copyright 2022 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 rt 18 19 import ( 20 `fmt` 21 `strings` 22 `sync` 23 `unsafe` 24 ) 25 26 type Bitmap struct { 27 N int 28 B []byte 29 } 30 31 func (self *Bitmap) grow() { 32 if self.N >= len(self.B) * 8 { 33 self.B = append(self.B, 0) 34 } 35 } 36 37 func (self *Bitmap) mark(i int, bv int) { 38 if bv != 0 { 39 self.B[i / 8] |= 1 << (i % 8) 40 } else { 41 self.B[i / 8] &^= 1 << (i % 8) 42 } 43 } 44 45 func (self *Bitmap) Set(i int, bv int) { 46 if i >= self.N { 47 panic("bitmap: invalid bit position") 48 } else { 49 self.mark(i, bv) 50 } 51 } 52 53 func (self *Bitmap) Append(bv int) { 54 self.grow() 55 self.mark(self.N, bv) 56 self.N++ 57 } 58 59 func (self *Bitmap) AppendMany(n int, bv int) { 60 for i := 0; i < n; i++ { 61 self.Append(bv) 62 } 63 } 64 65 var ( 66 _stackMapLock = sync.Mutex{} 67 _stackMapCache = make(map[*StackMap]struct{}) 68 ) 69 70 type BitVec struct { 71 N uintptr 72 B unsafe.Pointer 73 } 74 75 func (self BitVec) Bit(i uintptr) byte { 76 return (*(*byte)(unsafe.Pointer(uintptr(self.B) + i / 8)) >> (i % 8)) & 1 77 } 78 79 func (self BitVec) String() string { 80 var i uintptr 81 var v []string 82 83 /* add each bit */ 84 for i = 0; i < self.N; i++ { 85 v = append(v, fmt.Sprintf("%d", self.Bit(i))) 86 } 87 88 /* join them together */ 89 return fmt.Sprintf( 90 "BitVec { %s }", 91 strings.Join(v, ", "), 92 ) 93 } 94 95 type StackMap struct { 96 N int32 97 L int32 98 B [1]byte 99 } 100 101 func (self *StackMap) add() { 102 _stackMapLock.Lock() 103 _stackMapCache[self] = struct{}{} 104 _stackMapLock.Unlock() 105 } 106 107 func (self *StackMap) Pin() uintptr { 108 self.add() 109 return uintptr(unsafe.Pointer(self)) 110 } 111 112 func (self *StackMap) Get(i int32) BitVec { 113 return BitVec { 114 N: uintptr(self.L), 115 B: unsafe.Pointer(uintptr(unsafe.Pointer(&self.B)) + uintptr(i * ((self.L + 7) >> 3))), 116 } 117 } 118 119 func (self *StackMap) String() string { 120 sb := strings.Builder{} 121 sb.WriteString("StackMap {") 122 123 /* dump every stack map */ 124 for i := int32(0); i < self.N; i++ { 125 sb.WriteRune('\n') 126 sb.WriteString(" " + self.Get(i).String()) 127 } 128 129 /* close the stackmap */ 130 sb.WriteString("\n}") 131 return sb.String() 132 } 133 134 var ( 135 byteType = UnpackEface(byte(0)).Type 136 ) 137 138 const ( 139 _StackMapSize = unsafe.Sizeof(StackMap{}) 140 ) 141 142 //go:linkname mallocgc runtime.mallocgc 143 //goland:noinspection GoUnusedParameter 144 func mallocgc(nb uintptr, vt *GoType, zero bool) unsafe.Pointer 145 146 type StackMapBuilder struct { 147 b Bitmap 148 } 149 150 func (self *StackMapBuilder) Build() (p *StackMap) { 151 nb := len(self.b.B) 152 bm := mallocgc(_StackMapSize + uintptr(nb) - 1, byteType, false) 153 154 /* initialize as 1 bitmap of N bits */ 155 p = (*StackMap)(bm) 156 p.N, p.L = 1, int32(self.b.N) 157 copy(BytesFrom(unsafe.Pointer(&p.B), nb, nb), self.b.B) 158 return 159 } 160 161 func (self *StackMapBuilder) AddField(ptr bool) { 162 if ptr { 163 self.b.Append(1) 164 } else { 165 self.b.Append(0) 166 } 167 } 168 169 func (self *StackMapBuilder) AddFields(n int, ptr bool) { 170 if ptr { 171 self.b.AppendMany(n, 1) 172 } else { 173 self.b.AppendMany(n, 0) 174 } 175 }