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  }