gcwb.go raw

   1  // +build go1.21,!go1.25
   2  
   3  /*
   4   * Copyright 2021 ByteDance Inc.
   5   *
   6   * Licensed under the Apache License, Version 2.0 (the "License");
   7   * you may not use this file except in compliance with the License.
   8   * You may obtain a copy of the License at
   9   *
  10   *     http://www.apache.org/licenses/LICENSE-2.0
  11   *
  12   * Unless required by applicable law or agreed to in writing, software
  13   * distributed under the License is distributed on an "AS IS" BASIS,
  14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15   * See the License for the specific language governing permissions and
  16   * limitations under the License.
  17   */
  18  
  19  package rt
  20  
  21  import (
  22      `sync/atomic`
  23      `unsafe`
  24  
  25      `golang.org/x/arch/x86/x86asm`
  26  )
  27  
  28  //go:linkname GcWriteBarrier2 runtime.gcWriteBarrier2
  29  func GcWriteBarrier2()
  30  
  31  //go:linkname RuntimeWriteBarrier runtime.writeBarrier
  32  var RuntimeWriteBarrier uintptr
  33  
  34  const (
  35      _MaxInstr = 15
  36  )
  37  
  38  func isvar(arg x86asm.Arg) bool {
  39      v, ok := arg.(x86asm.Mem)
  40      return ok && v.Base == x86asm.RIP
  41  }
  42  
  43  func iszero(arg x86asm.Arg) bool {
  44      v, ok := arg.(x86asm.Imm)
  45      return ok && v == 0
  46  }
  47  
  48  func GcwbAddr() uintptr {
  49      var err error
  50      var off uintptr
  51      var ins x86asm.Inst
  52  
  53      /* get the function address */
  54      pc := uintptr(0)
  55      fp := FuncAddr(atomic.StorePointer)
  56  
  57      /* search within the first 16 instructions */
  58      for i := 0; i < 16; i++ {
  59          mem := unsafe.Pointer(uintptr(fp) + pc)
  60          buf := BytesFrom(mem, _MaxInstr, _MaxInstr)
  61  
  62          /* disassemble the instruction */
  63          if ins, err = x86asm.Decode(buf, 64); err != nil {
  64              panic("gcwbaddr: " + err.Error())
  65          }
  66  
  67          /* check for a byte comparison with zero */
  68          if ins.Op == x86asm.CMP && ins.MemBytes == 1 && isvar(ins.Args[0]) && iszero(ins.Args[1]) {
  69              off = pc + uintptr(ins.Len) + uintptr(ins.Args[0].(x86asm.Mem).Disp)
  70              break
  71          }
  72  
  73          /* move to next instruction */
  74          nb := ins.Len
  75          pc += uintptr(nb)
  76      }
  77  
  78      /* check for address */
  79      if off == 0 {
  80          panic("gcwbaddr: could not locate the variable `writeBarrier`")
  81      } else {
  82          return uintptr(fp) + off
  83      }
  84  }
  85  
  86