github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/encoder/compile_cache.go (about) 1 package encoder 2 3 import ( 4 "sync/atomic" 5 "unsafe" 6 7 "github.com/trim21/go-phpserialize/internal/runtime" 8 ) 9 10 var ( 11 cachedEncoder []encoder 12 cachedEncoderMap unsafe.Pointer // map[uintptr]*OpcodeSet 13 typeAddr *runtime.TypeAddr 14 ) 15 16 func init() { 17 typeAddr = runtime.AnalyzeTypeAddr() 18 if typeAddr == nil { 19 typeAddr = &runtime.TypeAddr{} 20 } 21 22 cachedEncoder = make([]encoder, typeAddr.AddrRange>>typeAddr.AddrShift+1) 23 } 24 25 func compileToGetEncoderSlowPath(typeID uintptr) (encoder, error) { 26 opcodeMap := loadEncoderMap() 27 if codeSet, exists := opcodeMap[typeID]; exists { 28 return codeSet, nil 29 } 30 codeSet, err := compileTypeID(typeID) 31 if err != nil { 32 return nil, err 33 } 34 storeEncoder(typeID, codeSet, opcodeMap) 35 return codeSet, nil 36 } 37 38 func loadEncoderMap() map[uintptr]encoder { 39 p := atomic.LoadPointer(&cachedEncoderMap) 40 return *(*map[uintptr]encoder)(unsafe.Pointer(&p)) 41 } 42 43 func storeEncoder(typ uintptr, set encoder, m map[uintptr]encoder) { 44 newEncoderMap := make(map[uintptr]encoder, len(m)+1) 45 newEncoderMap[typ] = set 46 47 for k, v := range m { 48 newEncoderMap[k] = v 49 } 50 51 atomic.StorePointer(&cachedEncoderMap, *(*unsafe.Pointer)(unsafe.Pointer(&newEncoderMap))) 52 } 53 54 func compileWithCache(rt *runtime.Type) (encoder, error) { 55 typeID := uintptr(unsafe.Pointer(rt)) 56 return compileToGetCodeSet(typeID) 57 } 58 59 func compileTypeIDWithCache(typeID uintptr) (encoder, error) { 60 return compileToGetCodeSet(typeID) 61 }