From 3aecd78747764aeb08cc1a169c9d324b7b8d24ed Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Fri, 7 Jul 2023 11:32:19 -0500 Subject: [PATCH] Track resources with atree.ValueID instead of SlabID Currently, Array.SlabID() and OrderedMap.SlabID() are used as identifier to track resources, etc because slab IDs are guaranteed to unique. However, atree slab ID should be only used to retrieve slabs (registers) from storage. Also, when Atree register inlining is implemented in the future, some resources may not be stored in separate slabs, so they will not have slab IDs anymore. This commit uses Array.ValueID() and OrderedMap.ValueID() to uniquely identify resources. --- runtime/interpreter/interpreter.go | 30 +++---- runtime/interpreter/interpreter_expression.go | 8 +- runtime/interpreter/sharedstate.go | 10 +-- runtime/interpreter/value.go | 88 +++++++++++-------- 4 files changed, 74 insertions(+), 62 deletions(-) diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index 614d91f35f..d9579211e4 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -239,7 +239,7 @@ type Storage interface { CheckHealth() error } -type ReferencedResourceKindedValues map[atree.SlabID]map[ReferenceTrackedResourceKindedValue]struct{} +type ReferencedResourceKindedValues map[atree.ValueID]map[ReferenceTrackedResourceKindedValue]struct{} type Interpreter struct { Location common.Location @@ -5100,12 +5100,12 @@ func (interpreter *Interpreter) ValidateAtreeValue(value atree.Value) { func (interpreter *Interpreter) maybeTrackReferencedResourceKindedValue(value Value) { if value, ok := value.(ReferenceTrackedResourceKindedValue); ok { - interpreter.trackReferencedResourceKindedValue(value.SlabID(), value) + interpreter.trackReferencedResourceKindedValue(value.ValueID(), value) } } func (interpreter *Interpreter) trackReferencedResourceKindedValue( - id atree.SlabID, + id atree.ValueID, value ReferenceTrackedResourceKindedValue, ) { values := interpreter.SharedState.referencedResourceKindedValues[id] @@ -5117,8 +5117,8 @@ func (interpreter *Interpreter) trackReferencedResourceKindedValue( } func (interpreter *Interpreter) updateReferencedResource( - currentID atree.SlabID, - newID atree.SlabID, + currentID atree.ValueID, + newID atree.ValueID, updateFunc func(value ReferenceTrackedResourceKindedValue), ) { values := interpreter.SharedState.referencedResourceKindedValues[currentID] @@ -5377,8 +5377,8 @@ func (interpreter *Interpreter) idCapabilityCheckFunction( ) } -func (interpreter *Interpreter) validateMutation(slabID atree.SlabID, locationRange LocationRange) { - _, present := interpreter.SharedState.containerValueIteration[slabID] +func (interpreter *Interpreter) validateMutation(valueID atree.ValueID, locationRange LocationRange) { + _, present := interpreter.SharedState.containerValueIteration[valueID] if !present { return } @@ -5387,32 +5387,32 @@ func (interpreter *Interpreter) validateMutation(slabID atree.SlabID, locationRa }) } -func (interpreter *Interpreter) withMutationPrevention(slabID atree.SlabID, f func()) { - oldIteration, present := interpreter.SharedState.containerValueIteration[slabID] - interpreter.SharedState.containerValueIteration[slabID] = struct{}{} +func (interpreter *Interpreter) withMutationPrevention(valueID atree.ValueID, f func()) { + oldIteration, present := interpreter.SharedState.containerValueIteration[valueID] + interpreter.SharedState.containerValueIteration[valueID] = struct{}{} f() if !present { - delete(interpreter.SharedState.containerValueIteration, slabID) + delete(interpreter.SharedState.containerValueIteration, valueID) } else { - interpreter.SharedState.containerValueIteration[slabID] = oldIteration + interpreter.SharedState.containerValueIteration[valueID] = oldIteration } } func (interpreter *Interpreter) withResourceDestruction( - slabID atree.SlabID, + valueID atree.ValueID, locationRange LocationRange, f func(), ) { - _, exists := interpreter.SharedState.destroyedResources[slabID] + _, exists := interpreter.SharedState.destroyedResources[valueID] if exists { panic(DestroyedResourceError{ LocationRange: locationRange, }) } - interpreter.SharedState.destroyedResources[slabID] = struct{}{} + interpreter.SharedState.destroyedResources[valueID] = struct{}{} f() } diff --git a/runtime/interpreter/interpreter_expression.go b/runtime/interpreter/interpreter_expression.go index 27f48e4e09..371c4c3943 100644 --- a/runtime/interpreter/interpreter_expression.go +++ b/runtime/interpreter/interpreter_expression.go @@ -937,8 +937,8 @@ func (interpreter *Interpreter) visitInvocationExpressionWithImplicitArgument(in if boundFunction, ok := function.(BoundFunctionValue); ok && boundFunction.Self != nil { self := *boundFunction.Self if resource, ok := self.(ReferenceTrackedResourceKindedValue); ok { - slabID := resource.SlabID() - interpreter.trackReferencedResourceKindedValue(slabID, resource) + valueID := resource.ValueID() + interpreter.trackReferencedResourceKindedValue(valueID, resource) } } @@ -1290,7 +1290,7 @@ func (interpreter *Interpreter) VisitAttachExpression(attachExpression *ast.Atta base, interpreter.MustSemaTypeOfValue(base).(*sema.CompositeType), ) - interpreter.trackReferencedResourceKindedValue(base.SlabID(), base) + interpreter.trackReferencedResourceKindedValue(base.ValueID(), base) attachment, ok := interpreter.visitInvocationExpressionWithImplicitArgument( attachExpression.Attachment, @@ -1302,7 +1302,7 @@ func (interpreter *Interpreter) VisitAttachExpression(attachExpression *ast.Atta } // Because `self` in attachments is a reference, we need to track the attachment if it's a resource - interpreter.trackReferencedResourceKindedValue(attachment.SlabID(), attachment) + interpreter.trackReferencedResourceKindedValue(attachment.ValueID(), attachment) base = base.Transfer( interpreter, diff --git a/runtime/interpreter/sharedstate.go b/runtime/interpreter/sharedstate.go index 682bd68bf2..6824d9ac6f 100644 --- a/runtime/interpreter/sharedstate.go +++ b/runtime/interpreter/sharedstate.go @@ -43,8 +43,8 @@ type SharedState struct { storageMutatedDuringIteration bool CapabilityControllerIterations map[AddressPath]int MutationDuringCapabilityControllerIteration bool - containerValueIteration map[atree.SlabID]struct{} - destroyedResources map[atree.SlabID]struct{} + containerValueIteration map[atree.ValueID]struct{} + destroyedResources map[atree.ValueID]struct{} } func NewSharedState(config *Config) *SharedState { @@ -59,11 +59,11 @@ func NewSharedState(config *Config) *SharedState { }, inStorageIteration: false, storageMutatedDuringIteration: false, - referencedResourceKindedValues: map[atree.SlabID]map[ReferenceTrackedResourceKindedValue]struct{}{}, + referencedResourceKindedValues: map[atree.ValueID]map[ReferenceTrackedResourceKindedValue]struct{}{}, resourceVariables: map[ResourceKindedValue]*Variable{}, CapabilityControllerIterations: map[AddressPath]int{}, - containerValueIteration: map[atree.SlabID]struct{}{}, - destroyedResources: map[atree.SlabID]struct{}{}, + containerValueIteration: map[atree.ValueID]struct{}{}, + destroyedResources: map[atree.ValueID]struct{}{}, } } diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 984b6d9e58..7920e69181 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -217,7 +217,7 @@ func maybeDestroy(interpreter *Interpreter, locationRange LocationRange, value V type ReferenceTrackedResourceKindedValue interface { ResourceKindedValue IsReferenceTrackedResourceKindedValue() - SlabID() atree.SlabID + ValueID() atree.ValueID } // ContractValue is the value of a contract. @@ -1717,7 +1717,7 @@ func (v *ArrayValue) Iterate(interpreter *Interpreter, f func(element Value) (re } if v.IsResourceKinded(interpreter) { - interpreter.withMutationPrevention(v.SlabID(), iterate) + interpreter.withMutationPrevention(v.ValueID(), iterate) } else { iterate() } @@ -1784,10 +1784,10 @@ func (v *ArrayValue) Destroy(interpreter *Interpreter, locationRange LocationRan }() } - slabID := v.SlabID() + valueID := v.ValueID() interpreter.withResourceDestruction( - slabID, + valueID, locationRange, func() { v.Walk(interpreter, func(element Value) { @@ -1803,8 +1803,8 @@ func (v *ArrayValue) Destroy(interpreter *Interpreter, locationRange LocationRan } interpreter.updateReferencedResource( - slabID, - slabID, + valueID, + valueID, func(value ReferenceTrackedResourceKindedValue) { arrayValue, ok := value.(*ArrayValue) if !ok { @@ -1948,7 +1948,7 @@ func (v *ArrayValue) SetKey(interpreter *Interpreter, locationRange LocationRang func (v *ArrayValue) Set(interpreter *Interpreter, locationRange LocationRange, index int, element Value) { - interpreter.validateMutation(v.SlabID(), locationRange) + interpreter.validateMutation(v.ValueID(), locationRange) // We only need to check the lower bound before converting from `int` (signed) to `uint64` (unsigned). // atree's Array.Set function will check the upper bound and report an atree.IndexOutOfBoundsError @@ -2022,7 +2022,7 @@ func (v *ArrayValue) MeteredString(memoryGauge common.MemoryGauge, seenReference func (v *ArrayValue) Append(interpreter *Interpreter, locationRange LocationRange, element Value) { - interpreter.validateMutation(v.SlabID(), locationRange) + interpreter.validateMutation(v.ValueID(), locationRange) // length increases by 1 dataSlabs, metaDataSlabs := common.AdditionalAtreeMemoryUsage( @@ -2070,7 +2070,7 @@ func (v *ArrayValue) InsertKey(interpreter *Interpreter, locationRange LocationR func (v *ArrayValue) Insert(interpreter *Interpreter, locationRange LocationRange, index int, element Value) { - interpreter.validateMutation(v.SlabID(), locationRange) + interpreter.validateMutation(v.ValueID(), locationRange) // We only need to check the lower bound before converting from `int` (signed) to `uint64` (unsigned). // atree's Array.Insert function will check the upper bound and report an atree.IndexOutOfBoundsError @@ -2125,7 +2125,7 @@ func (v *ArrayValue) RemoveKey(interpreter *Interpreter, locationRange LocationR func (v *ArrayValue) Remove(interpreter *Interpreter, locationRange LocationRange, index int) Value { - interpreter.validateMutation(v.SlabID(), locationRange) + interpreter.validateMutation(v.ValueID(), locationRange) // We only need to check the lower bound before converting from `int` (signed) to `uint64` (unsigned). // atree's Array.Remove function will check the upper bound and report an atree.IndexOutOfBoundsError @@ -2586,7 +2586,7 @@ func (v *ArrayValue) Transfer( }() } - currentSlabID := v.SlabID() + currentValueID := v.ValueID() array := v.array @@ -2655,11 +2655,11 @@ func (v *ArrayValue) Transfer( res = v } - newSlabID := array.SlabID() + newValueID := array.ValueID() interpreter.updateReferencedResource( - currentSlabID, - newSlabID, + currentValueID, + newValueID, func(value ReferenceTrackedResourceKindedValue) { arrayValue, ok := value.(*ArrayValue) if !ok { @@ -2767,6 +2767,10 @@ func (v *ArrayValue) StorageAddress() atree.Address { return v.array.Address() } +func (v *ArrayValue) ValueID() atree.ValueID { + return v.array.ValueID() +} + func (v *ArrayValue) GetOwner() common.Address { return common.Address(v.StorageAddress()) } @@ -15364,10 +15368,10 @@ func (v *CompositeValue) Destroy(interpreter *Interpreter, locationRange Locatio }() } - slabID := v.SlabID() + valueID := v.ValueID() interpreter.withResourceDestruction( - slabID, + valueID, locationRange, func() { // if this type has attachments, destroy all of them before invoking the destructor @@ -15419,8 +15423,8 @@ func (v *CompositeValue) Destroy(interpreter *Interpreter, locationRange Locatio } interpreter.updateReferencedResource( - slabID, - slabID, + valueID, + valueID, func(value ReferenceTrackedResourceKindedValue) { compositeValue, ok := value.(*CompositeValue) if !ok { @@ -16077,7 +16081,7 @@ func (v *CompositeValue) Transfer( }() } - currentSlabID := v.SlabID() + currentValueID := v.ValueID() currentAddress := v.StorageAddress() dictionary := v.dictionary @@ -16170,11 +16174,11 @@ func (v *CompositeValue) Transfer( res = v } - newSlabID := dictionary.SlabID() + newValueID := dictionary.ValueID() interpreter.updateReferencedResource( - currentSlabID, - newSlabID, + currentValueID, + newValueID, func(value ReferenceTrackedResourceKindedValue) { compositeValue, ok := value.(*CompositeValue) if !ok { @@ -16359,6 +16363,10 @@ func (v *CompositeValue) StorageAddress() atree.Address { return v.dictionary.Address() } +func (v *CompositeValue) ValueID() atree.ValueID { + return v.dictionary.ValueID() +} + func (v *CompositeValue) RemoveField( interpreter *Interpreter, _ LocationRange, @@ -16446,7 +16454,7 @@ func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeV // the base reference can only be borrowed with the declared type of the attachment's base v.base = NewEphemeralReferenceValue(interpreter, false, base, baseType) - interpreter.trackReferencedResourceKindedValue(base.SlabID(), base) + interpreter.trackReferencedResourceKindedValue(base.ValueID(), base) } func attachmentMemberName(ty sema.Type) string { @@ -16476,7 +16484,7 @@ func attachmentBaseAndSelfValues( base = v.getBaseValue(interpreter, locationRange) // in attachment functions, self is a reference value self = NewEphemeralReferenceValue(interpreter, false, v, interpreter.MustSemaTypeOfValue(v)) - interpreter.trackReferencedResourceKindedValue(v.SlabID(), v) + interpreter.trackReferencedResourceKindedValue(v.ValueID(), v) return } @@ -16527,7 +16535,7 @@ func (v *CompositeValue) GetTypeKey( attachment.setBaseValue(interpreter, v) attachmentRef := NewEphemeralReferenceValue(interpreter, false, attachment, ty) - interpreter.trackReferencedResourceKindedValue(attachment.SlabID(), attachment) + interpreter.trackReferencedResourceKindedValue(attachment.ValueID(), attachment) return NewSomeValueNonCopying(interpreter, attachmentRef) } @@ -16736,7 +16744,7 @@ func (v *DictionaryValue) Iterate(interpreter *Interpreter, f func(key, value Va } } if v.IsResourceKinded(interpreter) { - interpreter.withMutationPrevention(v.SlabID(), iterate) + interpreter.withMutationPrevention(v.ValueID(), iterate) } else { iterate() } @@ -16834,10 +16842,10 @@ func (v *DictionaryValue) Destroy(interpreter *Interpreter, locationRange Locati }() } - slabID := v.SlabID() + valueID := v.ValueID() interpreter.withResourceDestruction( - slabID, + valueID, locationRange, func() { v.Iterate(interpreter, func(key, value Value) (resume bool) { @@ -16857,8 +16865,8 @@ func (v *DictionaryValue) Destroy(interpreter *Interpreter, locationRange Locati } interpreter.updateReferencedResource( - slabID, - slabID, + valueID, + valueID, func(value ReferenceTrackedResourceKindedValue) { dictionaryValue, ok := value.(*DictionaryValue) if !ok { @@ -16913,7 +16921,7 @@ func (v *DictionaryValue) ForEachKey( } if v.IsResourceKinded(interpreter) { - interpreter.withMutationPrevention(v.SlabID(), iterate) + interpreter.withMutationPrevention(v.ValueID(), iterate) } else { iterate() } @@ -16985,7 +16993,7 @@ func (v *DictionaryValue) SetKey( keyValue Value, value Value, ) { - interpreter.validateMutation(v.SlabID(), locationRange) + interpreter.validateMutation(v.ValueID(), locationRange) config := interpreter.SharedState.Config @@ -17269,7 +17277,7 @@ func (v *DictionaryValue) Remove( keyValue Value, ) OptionalValue { - interpreter.validateMutation(v.SlabID(), locationRange) + interpreter.validateMutation(v.ValueID(), locationRange) valueComparator := newValueComparator(interpreter, locationRange) hashInputProvider := newHashInputProvider(interpreter, locationRange) @@ -17326,7 +17334,7 @@ func (v *DictionaryValue) Insert( keyValue, value Value, ) OptionalValue { - interpreter.validateMutation(v.SlabID(), locationRange) + interpreter.validateMutation(v.ValueID(), locationRange) // length increases by 1 dataSlabs, metaDataSlabs := common.AdditionalAtreeMemoryUsage(v.dictionary.Count(), v.elementSize, false) @@ -17579,7 +17587,7 @@ func (v *DictionaryValue) Transfer( }() } - currentSlabID := v.SlabID() + currentValueID := v.ValueID() dictionary := v.dictionary @@ -17663,11 +17671,11 @@ func (v *DictionaryValue) Transfer( res = v } - newSlabID := dictionary.SlabID() + newValueID := dictionary.ValueID() interpreter.updateReferencedResource( - currentSlabID, - newSlabID, + currentValueID, + newValueID, func(value ReferenceTrackedResourceKindedValue) { dictionaryValue, ok := value.(*DictionaryValue) if !ok { @@ -17794,6 +17802,10 @@ func (v *DictionaryValue) StorageAddress() atree.Address { return v.dictionary.Address() } +func (v *DictionaryValue) ValueID() atree.ValueID { + return v.dictionary.ValueID() +} + func (v *DictionaryValue) SemaType(interpreter *Interpreter) *sema.DictionaryType { if v.semaType == nil { // this function will panic already if this conversion fails