Skip to content

Commit 969ed9b

Browse files
authored
Merge pull request #3817 from onflow/supun/refactor-vm-values
[Compiler] Refactor `vm.Value` and related operations to be independent of the `vm.Config`
2 parents e6f27ac + 6e1e8f5 commit 969ed9b

28 files changed

+309
-219
lines changed

bbq/vm/config.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
package vm
2020

2121
import (
22+
"github.com/onflow/atree"
23+
2224
"github.com/onflow/cadence/bbq/commons"
2325
"github.com/onflow/cadence/common"
26+
"github.com/onflow/cadence/errors"
2427
"github.com/onflow/cadence/interpreter"
2528
"github.com/onflow/cadence/sema"
2629
"github.com/onflow/cadence/stdlib"
@@ -55,6 +58,12 @@ type Config struct {
5558
TypeLoader func(location common.Location, typeID interpreter.TypeID) sema.CompositeKindedType
5659
}
5760

61+
var _ ReferenceTracker = &Config{}
62+
var _ StaticTypeContext = &Config{}
63+
var _ TransferContext = &Config{}
64+
var _ interpreter.StaticTypeConversionHandler = &Config{}
65+
var _ interpreter.ValueComparisonContext = &Config{}
66+
5867
func NewConfig(storage interpreter.Storage) *Config {
5968
return &Config{
6069
Storage: storage,
@@ -102,6 +111,107 @@ func (c *Config) Interpreter() *interpreter.Interpreter {
102111
return c.inter
103112
}
104113

114+
func (c *Config) MeterMemory(usage common.MemoryUsage) error {
115+
if c.MemoryGauge == nil {
116+
return nil
117+
}
118+
119+
return c.MemoryGauge.MeterMemory(usage)
120+
}
121+
122+
func (c *Config) TrackReferencedResourceKindedValue(
123+
id atree.ValueID,
124+
value *EphemeralReferenceValue,
125+
) {
126+
values := c.referencedResourceKindedValues[id]
127+
if values == nil {
128+
values = map[*EphemeralReferenceValue]struct{}{}
129+
c.referencedResourceKindedValues[id] = values
130+
}
131+
values[value] = struct{}{}
132+
}
133+
134+
func (c *Config) ReferencedResourceKindedValues(valueID atree.ValueID) map[*EphemeralReferenceValue]struct{} {
135+
return c.referencedResourceKindedValues[valueID]
136+
}
137+
138+
func (c *Config) ClearReferenceTracking(valueID atree.ValueID) {
139+
delete(c.referencedResourceKindedValues, valueID)
140+
}
141+
142+
func (c *Config) ReadStored(storageAddress common.Address, domain common.StorageDomain, identifier interpreter.StorageMapKey) interpreter.Value {
143+
accountStorage := c.GetDomainStorageMap(
144+
c.Interpreter(),
145+
storageAddress,
146+
domain,
147+
false,
148+
)
149+
if accountStorage == nil {
150+
return nil
151+
}
152+
153+
return accountStorage.ReadValue(c, identifier)
154+
}
155+
156+
func (c *Config) WriteStored(
157+
storageAddress common.Address,
158+
domain common.StorageDomain,
159+
key interpreter.StorageMapKey,
160+
value interpreter.Value,
161+
) (existed bool) {
162+
inter := c.Interpreter()
163+
accountStorage := c.GetDomainStorageMap(inter, storageAddress, domain, true)
164+
165+
return accountStorage.WriteValue(
166+
inter,
167+
key,
168+
value,
169+
)
170+
}
171+
172+
func (c *Config) ConvertStaticToSemaType(staticType interpreter.StaticType) (sema.Type, error) {
173+
inter := c.Interpreter()
174+
return inter.ConvertStaticToSemaType(staticType)
175+
}
176+
177+
func (c *Config) IsSubType(subType interpreter.StaticType, superType interpreter.StaticType) bool {
178+
inter := c.Interpreter()
179+
return inter.IsSubType(subType, superType)
180+
}
181+
182+
func (c *Config) IsSubTypeOfSemaType(staticSubType interpreter.StaticType, superType sema.Type) bool {
183+
inter := c.Interpreter()
184+
return inter.IsSubTypeOfSemaType(staticSubType, superType)
185+
}
186+
187+
func (c *Config) GetEntitlementType(typeID interpreter.TypeID) (*sema.EntitlementType, error) {
188+
//TODO
189+
panic(errors.NewUnreachableError())
190+
}
191+
192+
func (c *Config) GetEntitlementMapType(typeID interpreter.TypeID) (*sema.EntitlementMapType, error) {
193+
//TODO
194+
panic(errors.NewUnreachableError())
195+
}
196+
197+
func (c *Config) GetInterfaceType(
198+
location common.Location,
199+
qualifiedIdentifier string,
200+
typeID interpreter.TypeID,
201+
) (*sema.InterfaceType, error) {
202+
//TODO
203+
panic(errors.NewUnreachableError())
204+
}
205+
206+
func (c *Config) GetCompositeType(
207+
location common.Location,
208+
qualifiedIdentifier string,
209+
typeID interpreter.TypeID,
210+
) (*sema.CompositeType, error) {
211+
//TODO
212+
panic(errors.NewUnreachableError())
213+
}
214+
105215
type ContractValueHandler func(conf *Config, location common.Location) *CompositeValue
106216

107217
type AddressPath struct {

bbq/vm/reference_tracking.go

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626

2727
type ReferencedResourceKindedValues map[atree.ValueID]map[*EphemeralReferenceValue]struct{}
2828

29-
func maybeTrackReferencedResourceKindedValue(conf *Config, value Value) {
29+
func maybeTrackReferencedResourceKindedValue(referenceTracker ReferenceTracker, value Value) {
3030
referenceValue, ok := value.(*EphemeralReferenceValue)
3131
if !ok {
3232
return
@@ -37,26 +37,12 @@ func maybeTrackReferencedResourceKindedValue(conf *Config, value Value) {
3737
return
3838
}
3939

40-
trackReferencedResourceKindedValue(
41-
conf,
40+
referenceTracker.TrackReferencedResourceKindedValue(
4241
referenceTRackedValue.ValueID(),
4342
referenceValue,
4443
)
4544
}
4645

47-
func trackReferencedResourceKindedValue(
48-
conf *Config,
49-
id atree.ValueID,
50-
value *EphemeralReferenceValue,
51-
) {
52-
values := conf.referencedResourceKindedValues[id]
53-
if values == nil {
54-
values = map[*EphemeralReferenceValue]struct{}{}
55-
conf.referencedResourceKindedValues[id] = values
56-
}
57-
values[value] = struct{}{}
58-
}
59-
6046
func checkInvalidatedResourceOrResourceReference(value Value) {
6147

6248
switch value := value.(type) {
@@ -92,7 +78,7 @@ func checkInvalidatedResourceOrResourceReference(value Value) {
9278
}
9379

9480
func invalidateReferencedResources(
95-
conf *Config,
81+
context TransferContext,
9682
value Value,
9783
) {
9884
// skip non-resource typed values
@@ -106,9 +92,9 @@ func invalidateReferencedResources(
10692
switch value := resourceKinded.(type) {
10793
case *CompositeValue:
10894
value.ForEachReadOnlyLoadedField(
109-
conf,
95+
context,
11096
func(_ string, fieldValue Value) (resume bool) {
111-
invalidateReferencedResources(conf, fieldValue)
97+
invalidateReferencedResources(context, fieldValue)
11298
// continue iteration
11399
return true
114100
},
@@ -117,34 +103,34 @@ func invalidateReferencedResources(
117103

118104
case *DictionaryValue:
119105
value.IterateReadOnlyLoaded(
120-
conf,
106+
context,
121107
func(_, value Value) (resume bool) {
122-
invalidateReferencedResources(conf, value)
108+
invalidateReferencedResources(context, value)
123109
return true
124110
},
125111
)
126112
valueID = value.ValueID()
127113

128114
case *ArrayValue:
129115
value.IterateReadOnlyLoaded(
130-
conf,
116+
context,
131117
func(element Value) (resume bool) {
132-
invalidateReferencedResources(conf, element)
118+
invalidateReferencedResources(context, element)
133119
return true
134120
},
135121
)
136122
valueID = value.ValueID()
137123

138124
case *SomeValue:
139-
invalidateReferencedResources(conf, value.value)
125+
invalidateReferencedResources(context, value.value)
140126
return
141127

142128
default:
143129
// skip non-container typed values.
144130
return
145131
}
146132

147-
values := conf.referencedResourceKindedValues[valueID]
133+
values := context.ReferencedResourceKindedValues(valueID)
148134
if values == nil {
149135
return
150136
}
@@ -157,5 +143,5 @@ func invalidateReferencedResources(
157143
// So no need to track those stale resources anymore. We will not need to update/clear them again.
158144
// Therefore, remove them from the mapping.
159145
// This is only to allow GC. No impact to the behavior.
160-
delete(conf.referencedResourceKindedValues, valueID)
146+
context.ClearReferenceTracking(valueID)
161147
}

bbq/vm/storage.go

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,56 +34,36 @@ import (
3434

3535
func StoredValue(gauge common.MemoryGauge, storable atree.Storable, storage interpreter.Storage) Value {
3636
value := interpreter.StoredValue(gauge, storable, storage)
37-
return InterpreterValueToVMValue(storage, value)
37+
return InterpreterValueToVMValue(value)
3838
}
3939

40-
func MustConvertStoredValue(gauge common.MemoryGauge, storage interpreter.Storage, storedValue atree.Value) Value {
40+
func MustConvertStoredValue(gauge common.MemoryGauge, storedValue atree.Value) Value {
4141
value := interpreter.MustConvertStoredValue(gauge, storedValue)
42-
return InterpreterValueToVMValue(storage, value)
42+
return InterpreterValueToVMValue(value)
4343
}
4444

4545
func ReadStored(
46-
config *Config,
46+
storageReader interpreter.StorageReader,
4747
address common.Address,
4848
domain string,
4949
identifier string,
5050
) Value {
51-
storage := config.Storage
52-
5351
storageDomain, _ := common.StorageDomainFromIdentifier(domain)
54-
55-
accountStorage := storage.GetDomainStorageMap(
56-
config.Interpreter(),
57-
address,
58-
storageDomain,
59-
false,
60-
)
61-
if accountStorage == nil {
62-
return nil
63-
}
64-
65-
referenced := accountStorage.ReadValue(config.MemoryGauge, interpreter.StringStorageMapKey(identifier))
66-
return InterpreterValueToVMValue(storage, referenced)
52+
referenced := storageReader.ReadStored(address, storageDomain, interpreter.StringStorageMapKey(identifier))
53+
return InterpreterValueToVMValue(referenced)
6754
}
6855

6956
func WriteStored(
70-
config *Config,
57+
storageContext StorageContext,
7158
storageAddress common.Address,
7259
domain common.StorageDomain,
7360
key interpreter.StorageMapKey,
7461
value Value,
7562
) (existed bool) {
7663

77-
inter := config.Interpreter()
78-
79-
accountStorage := config.Storage.GetDomainStorageMap(inter, storageAddress, domain, true)
80-
interValue := VMValueToInterpreterValue(config, value)
64+
interValue := VMValueToInterpreterValue(storageContext, value)
8165

82-
return accountStorage.WriteValue(
83-
inter,
84-
key,
85-
interValue,
86-
)
66+
return storageContext.WriteStored(storageAddress, domain, key, interValue)
8767
//interpreter.recordStorageMutation()
8868
}
8969

bbq/vm/types.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@ import (
2323
"github.com/onflow/cadence/interpreter"
2424
)
2525

26-
func IsSubType(config *Config, sourceType, targetType bbq.StaticType) bool {
27-
// TODO: Avoid conversion to sema types.
28-
inter := config.Interpreter()
29-
return inter.IsSubType(sourceType, targetType)
30-
}
31-
3226
// UnwrapOptionalType returns the type if it is not an optional type,
3327
// or the inner-most type if it is (optional types are repeatedly unwrapped)
3428
func UnwrapOptionalType(ty bbq.StaticType) bbq.StaticType {

bbq/vm/value.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,58 @@ import (
2222
"github.com/onflow/atree"
2323

2424
"github.com/onflow/cadence/bbq"
25+
"github.com/onflow/cadence/common"
2526
"github.com/onflow/cadence/interpreter"
2627
)
2728

2829
type Value interface {
2930
isValue()
30-
StaticType(*Config) bbq.StaticType
31+
StaticType(StaticTypeContext) bbq.StaticType
3132
Transfer(
32-
config *Config,
33+
transferContext TransferContext,
3334
address atree.Address,
3435
remove bool,
3536
storable atree.Storable,
3637
) Value
3738
String() string
3839
}
3940

41+
type StaticTypeContext = interpreter.ValueStaticTypeContext
42+
43+
type StorageContext interface {
44+
StaticTypeContext
45+
common.MemoryGauge
46+
interpreter.Storage
47+
interpreter.StorageWriter
48+
}
49+
50+
type TransferContext interface {
51+
StorageContext
52+
ReferenceTracker
53+
}
54+
55+
type ReferenceTracker interface {
56+
TrackReferencedResourceKindedValue(id atree.ValueID, value *EphemeralReferenceValue)
57+
ReferencedResourceKindedValues(atree.ValueID) map[*EphemeralReferenceValue]struct{}
58+
ClearReferenceTracking(atree.ValueID)
59+
}
60+
61+
type TypeConverterContext interface {
62+
Interpreter() *interpreter.Interpreter
63+
}
64+
4065
type MemberAccessibleValue interface {
66+
// TODO: See whether `Config` parameter can be removed from the below functions.
67+
// Currently it's unknown because `AccountCapabilityControllerValue` members
68+
// are not yet implemented.
69+
4170
GetMember(config *Config, name string) Value
42-
SetMember(conf *Config, name string, value Value)
71+
SetMember(config *Config, name string, value Value)
4372
}
4473

4574
type ResourceKindedValue interface {
4675
Value
76+
// TODO:
4777
//Destroy(interpreter *Interpreter, locationRange LocationRange)
4878
//IsDestroyed() bool
4979
//isInvalidatedResource(*Interpreter) bool

bbq/vm/value_account.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ func recordStorageCapabilityController(
383383
)
384384

385385
referenced := accountStorage.ReadValue(config.MemoryGauge, interpreter.StringStorageMapKey(identifier))
386-
readValue := InterpreterValueToVMValue(config.Storage, referenced)
386+
readValue := InterpreterValueToVMValue(referenced)
387387

388388
setKey := capabilityIDValue
389389
setValue := Nil

0 commit comments

Comments
 (0)