github.com/bytedance/mockey@v1.2.10/internal/monkey/inst/generic_extra.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 inst
    18  
    19  import (
    20  	_ "unsafe"
    21  )
    22  
    23  //go:linkname duffcopy runtime.duffcopy
    24  func duffcopy()
    25  
    26  //go:linkname duffzero runtime.duffzero
    27  func duffzero()
    28  
    29  var duffcopyStart, duffcopyEnd, duffzeroStart, duffzeroEnd uintptr
    30  
    31  func init() {
    32  	duffcopyStart, duffcopyEnd = calcFnAddrRange("duffcopy", duffcopy)
    33  	duffzeroStart, duffzeroEnd = calcFnAddrRange("duffzero", duffzero)
    34  }
    35  
    36  // proxyCallRace exclude functions used for race check in unit test
    37  //
    38  // If we use '-race' in test command, golang may use 'racefuncenter' and 'racefuncexit' in generic
    39  // functions's proxy, which is toxic for us to find the original generic function implementation.
    40  //
    41  // So we need to exclude them. We simply exclude most of race functions defined in runtime.
    42  var proxyCallRace = map[uintptr]string{}
    43  
    44  // isGenericProxyCallExtra checks if generic function's proxy called an extra internal function
    45  // We check duffcopy/duffzero for passing huge params/returns and race-functions for -race option
    46  func isGenericProxyCallExtra(addr uintptr) (bool, string) {
    47  	/*
    48  		When function argument size is too big, golang will use duff-copy
    49  		to get better performance. Thus we will see more call-instruction
    50  		in asm code.
    51  		For example, assume struct type like this:
    52  			```
    53  			type Large15 struct _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ string}
    54  			```
    55  		when we use `Large15` as generic function's argument or return types,
    56  		the wrapper `function[Large15]` will call `duffcopy` and `duffzero`
    57  		before passing arguments and after receiving returns.
    58  
    59  		Notice that `duff` functions are very special, they are always called
    60  		in the middle of function body(not at beginning). So we should check
    61  		the `call` instruction's target address with a range.
    62  	*/
    63  	if addr >= duffcopyStart && addr <= duffcopyEnd {
    64  		return true, "diffcopy"
    65  	}
    66  
    67  	if addr >= duffzeroStart && addr <= duffzeroEnd {
    68  		return true, "duffzero"
    69  	}
    70  
    71  	if name, ok := proxyCallRace[addr]; ok {
    72  		return true, name
    73  	}
    74  	return false, ""
    75  }