github.com/cloudwego/frugal@v0.1.15/internal/atm/pgen/pgen_gcwb_go121_121_amd64.go (about)

     1  //go:build go1.21 && !go1.23
     2  // +build go1.21,!go1.23
     3  
     4  /*
     5   * Copyright 2022 ByteDance Inc.
     6   *
     7   * Licensed under the Apache License, Version 2.0 (the "License");
     8   * you may not use this file except in compliance with the License.
     9   * You may obtain a copy of the License at
    10   *
    11   *     http://www.apache.org/licenses/LICENSE-2.0
    12   *
    13   * Unless required by applicable law or agreed to in writing, software
    14   * distributed under the License is distributed on an "AS IS" BASIS,
    15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16   * See the License for the specific language governing permissions and
    17   * limitations under the License.
    18   */
    19  
    20  package pgen
    21  
    22  import (
    23      `github.com/cloudwego/iasm/x86_64`
    24  
    25      `github.com/cloudwego/frugal/internal/atm/abi`
    26      `github.com/cloudwego/frugal/internal/atm/hir`
    27      `github.com/cloudwego/frugal/internal/atm/rtx`
    28  )
    29  
    30  /*
    31   * wbStorePointer is the underlying logic for hir.OP_sp (sp: Store Pointer)
    32   * It checks rtx.V_pWriteBarrier first.
    33   * IF the flag equals to zero, we only need to update the pointer; go GC is not involved at all.
    34   * ELSE we jump to the label `_wb_store`, which (following the go1.21 way):
    35   *   1. Calls runtime.gcWriteBarrier2
    36   *   2. Stores new/old pointers to the allocated slots, with R11 as the beginning address
    37   *   3. Updates the pointer
    38   *   4. Jumps back to label `_wb_return`
    39   * Since it's unlikely to go the `ELSE` path, we postpone the translation, to make generated binary
    40   * more compact, which can make most use of the program cache of x86_64 architecture.
    41   */
    42  func (self *CodeGen) wbStorePointer(p *x86_64.Program, s hir.PointerRegister, d *x86_64.MemoryOperand) {
    43      wb := x86_64.CreateLabel("_wb_store")
    44      rt := x86_64.CreateLabel("_wb_return")
    45  
    46      /* check for write barrier */
    47      p.MOVQ(uintptr(rtx.V_pWriteBarrier), RAX)
    48      p.CMPB(0, Ptr(RAX, 0))
    49      p.JNE(wb) /* jump to wbStoreFn (write barrier store pointer) */
    50  
    51      /* replace with the new pointer */
    52      wbUpdatePointer := func() {
    53          if s == hir.Pn {
    54              p.MOVQ(0, d)
    55          } else {
    56              p.MOVQ(self.r(s), d)
    57          }
    58      }
    59  
    60      /* Save new pointer to 0[R11] as required by gcWriteBarrier2 */
    61      wbStoreNewPointerForGC := func(r11 x86_64.Register64) {
    62          if s == hir.Pn { /* Pointer to Nil */
    63              p.MOVQ(0, Ptr(r11, 0))
    64          } else {
    65              p.MOVQ(self.r(s), Ptr(r11, 0))
    66          }
    67      }
    68  
    69      /* Save old pointer to 8[R11] as required by gcWriteBarrier2 */
    70      wbStoreOldPointerForGC := func(r11 x86_64.Register64) {
    71          p.MOVQ(d, RDI)
    72          p.MOVQ(RDI, Ptr(r11, abi.PtrSize))
    73      }
    74  
    75      /* write barrier wrapper */
    76      wbStoreFn := func(p *x86_64.Program) {
    77          self.abiSpillReserved(p)
    78          self.abiLoadReserved(p)
    79          p.MOVQ(R11, RAX) /* Save R11 -> RAX since R11 will be clobbered by gcWriteBarrier2 */
    80          p.MOVQ(uintptr(rtx.F_gcWriteBarrier2), RSI)
    81          p.CALLQ(RSI)      /* apply 2 slots and save the beginning address in R11 */
    82          p.XCHGQ(RAX, R11) /* Restore R11 <- RAX, and save R11(slotAddr) -> RAX */
    83          self.abiSaveReserved(p)
    84          self.abiRestoreReserved(p)
    85          wbStoreNewPointerForGC(RAX) /* MOV r(s), 0[R11] */
    86          wbStoreOldPointerForGC(RAX) /* MOV RDI, 8[R11] */
    87          p.JMP(rt)
    88      }
    89  
    90      /* defer the call to the end of generated code */
    91      p.Link(rt)
    92      wbUpdatePointer() /* Need to do it in go1.21+ both for direct_store or wb_store */
    93      self.later(wb, wbStoreFn)
    94  }