stackmap.go raw
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 rt
18
19 import (
20 `fmt`
21 `strings`
22 `unsafe`
23
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 func (b *Bitmap) String() string {
66 var buf strings.Builder
67 for _, byteVal := range b.B {
68 fmt.Fprintf(&buf, "%08b ", byteVal)
69 }
70 return fmt.Sprintf("Bits: %s(total %d bits, %d bytes)", buf.String(), b.N, len(b.B))
71 }
72
73 type BitVec struct {
74 N uintptr
75 B unsafe.Pointer
76 }
77
78 func (self BitVec) Bit(i uintptr) byte {
79 return (*(*byte)(unsafe.Pointer(uintptr(self.B) + i / 8)) >> (i % 8)) & 1
80 }
81
82 func (self BitVec) String() string {
83 var i uintptr
84 var v []string
85
86 /* add each bit */
87 for i = 0; i < self.N; i++ {
88 v = append(v, fmt.Sprintf("%d", self.Bit(i)))
89 }
90
91 /* join them together */
92 return fmt.Sprintf(
93 "BitVec { %s }",
94 strings.Join(v, ", "),
95 )
96 }
97
98 /*
99 reference Golang 1.22.0 code:
100
101 ```
102 args := bitvec.New(int32(maxArgs / int64(types.PtrSize)))
103 aoff := objw.Uint32(&argsSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
104 aoff = objw.Uint32(&argsSymTmp, aoff, uint32(args.N)) // number of bits in each bitmap
105
106 locals := bitvec.New(int32(maxLocals / int64(types.PtrSize)))
107 loff := objw.Uint32(&liveSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
108 loff = objw.Uint32(&liveSymTmp, loff, uint32(locals.N)) // number of bits in each bitmap
109
110 for _, live := range lv.stackMaps {
111 args.Clear()
112 locals.Clear()
113
114 lv.pointerMap(live, lv.vars, args, locals)
115
116 aoff = objw.BitVec(&argsSymTmp, aoff, args)
117 loff = objw.BitVec(&liveSymTmp, loff, locals)
118 }
119 ```
120
121 */
122
123 type StackMap struct {
124 // number of bitmaps
125 N int32
126 // number of bits of each bitmap
127 L int32
128 // bitmap1, bitmap2, ... bitmapN
129 B [1]byte
130 }
131
132 func (self *StackMap) Get(i int) BitVec {
133 return BitVec {
134 N: uintptr(self.L),
135 B: unsafe.Pointer(uintptr(unsafe.Pointer(&self.B)) + uintptr(i * self.BitmapBytes())),
136 }
137 }
138
139 func (self *StackMap) String() string {
140 sb := strings.Builder{}
141 sb.WriteString("StackMap {")
142
143 /* dump every stack map */
144 for i := 0; i < int(self.N); i++ {
145 sb.WriteRune('\n')
146 sb.WriteString(" " + self.Get(i).String())
147 }
148
149 /* close the stackmap */
150 sb.WriteString("\n}")
151 return sb.String()
152 }
153
154 func (self *StackMap) BitmapLen() int {
155 return int(self.L)
156 }
157
158 func (self *StackMap) BitmapBytes() int {
159 return int(self.L + 7) >> 3
160 }
161
162 func (self *StackMap) BitmapNums() int {
163 return int(self.N)
164 }
165
166 func (self *StackMap) StackMapHeaderSize() int {
167 return int(unsafe.Sizeof(self.L)) + int(unsafe.Sizeof(self.N))
168 }
169
170 func (self *StackMap) MarshalBinary() ([]byte, error) {
171 size := self.BinaryLen()
172 return BytesFrom(unsafe.Pointer(self), size, size), nil
173 }
174
175 func (self *StackMap) BinaryLen() int {
176 return self.StackMapHeaderSize() + self.BitmapBytes() * self.BitmapNums()
177 }
178
179 var (
180 byteType = UnpackEface(byte(0)).Type
181 )
182
183 const (
184 _StackMapSize = unsafe.Sizeof(StackMap{})
185 )
186
187 //go:linkname mallocgc runtime.mallocgc
188 //goland:noinspection GoUnusedParameter
189 func mallocgc(nb uintptr, vt *GoType, zero bool) unsafe.Pointer
190
191 type StackMapBuilder struct {
192 b Bitmap
193 }
194
195
196 //go:nocheckptr
197 func (self *StackMapBuilder) Build() (p *StackMap) {
198 nb := len(self.b.B)
199 allocatedSize := _StackMapSize + uintptr(nb) - 1
200 bm := mallocgc(allocatedSize, byteType, false)
201
202 /* initialize as 1 bitmap of N bits */
203 p = (*StackMap)(bm)
204 p.N, p.L = 1, int32(self.b.N)
205 copy(BytesFrom(unsafe.Pointer(&p.B), nb, nb), self.b.B)
206
207 /* assert length */
208 if allocatedSize < uintptr(p.BinaryLen()) {
209 panic(fmt.Sprintf("stackmap allocation too small: allocated %d, required %d", allocatedSize, p.BinaryLen()))
210 }
211 return
212 }
213
214 func (self *StackMapBuilder) AddField(ptr bool) {
215 if ptr {
216 self.b.Append(1)
217 } else {
218 self.b.Append(0)
219 }
220 }
221
222 func (self *StackMapBuilder) AddFields(n int, ptr bool) {
223 if ptr {
224 self.b.AppendMany(n, 1)
225 } else {
226 self.b.AppendMany(n, 0)
227 }
228 }