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 }