github.com/cloudwego/frugal@v0.1.15/internal/binary/decoder/initfn.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 decoder
    18  
    19  import (
    20      `fmt`
    21      `sync`
    22      `unsafe`
    23  
    24      `github.com/cloudwego/frugal/internal/atm/hir`
    25      `github.com/cloudwego/frugal/internal/rt`
    26  )
    27  
    28  var (
    29      initFnLock  = new(sync.RWMutex)
    30      initFnCache = make(map[unsafe.Pointer]*hir.CallHandle)
    31  )
    32  
    33  func toInitFn(fp unsafe.Pointer) (fn func(unsafe.Pointer)) {
    34      *(*unsafe.Pointer)(unsafe.Pointer(&fn)) = unsafe.Pointer(&fp)
    35      return
    36  }
    37  
    38  func addInitFn(fp unsafe.Pointer) *hir.CallHandle {
    39      var ok bool
    40      var fn *hir.CallHandle
    41  
    42      /* check function cache */
    43      initFnLock.RLock()
    44      fn, ok = initFnCache[fp]
    45      initFnLock.RUnlock()
    46  
    47      /* exists, use the cached value */
    48      if ok {
    49          return fn
    50      }
    51  
    52      /* lock in write mode */
    53      initFnLock.Lock()
    54      defer initFnLock.Unlock()
    55  
    56      /* double check */
    57      if fn, ok = initFnCache[fp]; ok {
    58          return fn
    59      }
    60  
    61      /* still not exists, register a new function */
    62      fn = hir.RegisterGCall(toInitFn(fp), func(ctx hir.CallContext) {
    63          if !ctx.Verify("*", "") {
    64              panic(fmt.Sprintf("invalid %s call", rt.FuncName(fp)))
    65          } else {
    66              toInitFn(fp)(ctx.Ap(0))
    67          }
    68      })
    69  
    70      /* update the cache */
    71      initFnCache[fp] = fn
    72      return fn
    73  }