diff --git a/bbq/compiler/compiler.go b/bbq/compiler/compiler.go index 5d006afb4..257c20208 100644 --- a/bbq/compiler/compiler.go +++ b/bbq/compiler/compiler.go @@ -4274,6 +4274,11 @@ func (c *Compiler[_, _]) getOrAddType(ty sema.Type) uint16 { data := c.typeGen.CompileType(staticType) index = c.addCompiledType(ty, data) c.typesInPool[typeID] = index + + semaTypeCache := c.Config.GetSemaTypeCache() + if semaTypeCache != nil { + semaTypeCache[typeID] = ty + } } return index diff --git a/bbq/compiler/config.go b/bbq/compiler/config.go index ae1f865a4..1a1048713 100644 --- a/bbq/compiler/config.go +++ b/bbq/compiler/config.go @@ -22,12 +22,15 @@ import ( "github.com/onflow/cadence/activations" "github.com/onflow/cadence/bbq/commons" "github.com/onflow/cadence/common" + "github.com/onflow/cadence/sema" ) type BuiltinGlobalsProvider func(location common.Location) *activations.Activation[GlobalImport] type ElaborationResolver func(location common.Location) (*DesugaredElaboration, error) +type GetSemaTypeCache func() map[sema.TypeID]sema.Type + type Config struct { MemoryGauge common.MemoryGauge ImportHandler commons.ImportHandler @@ -38,4 +41,6 @@ type Config struct { BuiltinGlobalsProvider BuiltinGlobalsProvider PeepholeOptimizationsEnabled bool + + GetSemaTypeCache GetSemaTypeCache } diff --git a/bbq/vm/config.go b/bbq/vm/config.go index b9991826a..4997ff2f2 100644 --- a/bbq/vm/config.go +++ b/bbq/vm/config.go @@ -74,6 +74,8 @@ type Config struct { StackDepthLimit uint64 debugEnabled bool + + GetSemaTypeCache GetSemaTypeCache } func NewConfig(storage interpreter.Storage) *Config { @@ -85,6 +87,9 @@ func NewConfig(storage interpreter.Storage) *Config { storage: storage, StackDepthLimit: math.MaxInt, Tracer: tracer, + GetSemaTypeCache: func() map[sema.TypeID]sema.Type { + return nil + }, } } @@ -301,6 +306,8 @@ type ContractValueHandler func( type ElaborationResolver func(location common.Location) (*sema.Elaboration, error) +type GetSemaTypeCache func() map[sema.TypeID]sema.Type + type EntitlementTypeHandlerFunc func(location common.Location, typeID interpreter.TypeID) *sema.EntitlementType type EntitlementMapTypeHandlerFunc func(location common.Location, typeID interpreter.TypeID) *sema.EntitlementMapType diff --git a/bbq/vm/context.go b/bbq/vm/context.go index 9053802e5..bb12277a7 100644 --- a/bbq/vm/context.go +++ b/bbq/vm/context.go @@ -19,6 +19,8 @@ package vm import ( + "fmt" + "github.com/onflow/atree" "github.com/onflow/cadence/bbq" @@ -29,6 +31,9 @@ import ( "github.com/onflow/cadence/sema" ) +var cacheHitCount int = 0 +var cacheMissCount int = 0 + // Context holds the information about the current execution at any given point of time. // It consists of: // - Re-usable configurations (Config). @@ -76,7 +81,8 @@ var _ interpreter.InvocationContext = &Context{} func NewContext(config *Config) *Context { return &Context{ - Config: config, + Config: config, + semaTypeCache: config.GetSemaTypeCache(), } } @@ -427,6 +433,7 @@ func (c *Context) SemaTypeFromStaticType(staticType interpreter.StaticType) sema typeID := staticType.ID() semaType, ok := c.semaTypeCache[typeID] if ok { + cacheHitCount++ return semaType } @@ -438,6 +445,8 @@ func (c *Context) SemaTypeFromStaticType(staticType interpreter.StaticType) sema } c.semaTypeCache[typeID] = semaType + cacheMissCount++ + return semaType } @@ -551,3 +560,13 @@ func (c *Context) SemaAccessFromStaticAuthorization(auth interpreter.Authorizati return semaAccess, nil } + +func (c *Context) GetCacheStatistics() { + fmt.Printf("Cache hit count: %d\n", cacheHitCount) + fmt.Printf("Cache miss count: %d\n", cacheMissCount) +} + +func (c *Context) ResetCacheStatistics() { + cacheHitCount = 0 + cacheMissCount = 0 +} diff --git a/bbq/vm/test/ft_test.go b/bbq/vm/test/ft_test.go index 4527259cb..5ab2b9493 100644 --- a/bbq/vm/test/ft_test.go +++ b/bbq/vm/test/ft_test.go @@ -61,6 +61,8 @@ func compiledFTTransfer(tb testing.TB) { nonFungibleTokenLocation := common.NewAddressLocation(nil, contractsAddress, "NonFungibleToken") flowTokenLocation := common.NewAddressLocation(nil, contractsAddress, "FlowToken") + semaTypeCache := make(map[sema.TypeID]sema.Type) + codes := map[common.Location][]byte{ burnerLocation: []byte(contracts.RealBurnerContract), viewResolverLocation: []byte(contracts.RealViewResolverContract), @@ -91,7 +93,10 @@ func compiledFTTransfer(tb testing.TB) { compilerConfig := &compiler.Config{ LocationHandler: locationHandler, - ImportHandler: importHandler, + GetSemaTypeCache: func() map[sema.TypeID]sema.Type { + return semaTypeCache + }, + ImportHandler: importHandler, ElaborationResolver: func(location common.Location) (*compiler.DesugaredElaboration, error) { imported, ok := compiledPrograms[location] if !ok { @@ -164,6 +169,10 @@ func compiledFTTransfer(tb testing.TB) { vmConfig := vm.NewConfig(storage) + // vmConfig.GetSemaTypeCache = func() map[sema.TypeID]sema.Type { + // return semaTypeCache + // } + vmConfig.CapabilityBorrowHandler = func( context interpreter.BorrowCapabilityControllerContext, address interpreter.AddressValue, @@ -483,6 +492,8 @@ func compiledFTTransfer(tb testing.TB) { ) } } + + tokenTransferTxVM.Context().GetCacheStatistics() } func TestFTTransfer(t *testing.T) { diff --git a/bbq/vm/vm.go b/bbq/vm/vm.go index d30ab8de0..a07c96212 100644 --- a/bbq/vm/vm.go +++ b/bbq/vm/vm.go @@ -1079,7 +1079,7 @@ func checkMemberAccessTargetType( context := vm.context - // TODO: Avoid sema type conversion. + // TODO: Avoid sema type conversion accessedSemaType := context.SemaTypeFromStaticType(accessedType) interpreter.CheckMemberAccessTargetType(