Skip to content

Commit

Permalink
Merge pull request #2887 from onflow/bastian/per-location-base-activa…
Browse files Browse the repository at this point in the history
…tions
  • Loading branch information
turbolent authored Oct 23, 2023
2 parents 2f573e2 + d6f80e0 commit 6947cfa
Show file tree
Hide file tree
Showing 38 changed files with 845 additions and 295 deletions.
12 changes: 8 additions & 4 deletions runtime/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,10 @@ func DefaultCheckerConfig(
baseValueActivation.DeclareValue(stdlib.NewLogFunction(StandardOutputLogger{}))

return &sema.Config{
BaseValueActivation: baseValueActivation,
AccessCheckMode: sema.AccessCheckModeStrict,
BaseValueActivationHandler: func(_ common.Location) *sema.VariableActivation {
return baseValueActivation
},
AccessCheckMode: sema.AccessCheckModeStrict,
ImportHandler: func(
checker *sema.Checker,
importedLocation common.Location,
Expand Down Expand Up @@ -192,8 +194,10 @@ func PrepareInterpreter(filename string, debugger *interpreter.Debugger) (*inter
interpreter.Declare(baseActivation, stdlib.NewLogFunction(StandardOutputLogger{}))

config := &interpreter.Config{
BaseActivation: baseActivation,
Storage: storage,
BaseActivationHandler: func(_ common.Location) *interpreter.VariableActivation {
return baseActivation
},
Storage: storage,
UUIDHandler: func() (uint64, error) {
defer func() { uuid++ }()
return uuid, nil
Expand Down
200 changes: 176 additions & 24 deletions runtime/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ import (
type Environment interface {
ArgumentDecoder

DeclareValue(valueDeclaration stdlib.StandardLibraryValue)
DeclareType(typeDeclaration stdlib.StandardLibraryType)
DeclareValue(
valueDeclaration stdlib.StandardLibraryValue,
location common.Location,
)
DeclareType(
typeDeclaration stdlib.StandardLibraryType,
location common.Location,
)
Configure(
runtimeInterface Interface,
codesAndPrograms CodesAndPrograms,
Expand Down Expand Up @@ -79,9 +85,37 @@ type interpreterEnvironmentReconfigured struct {

type interpreterEnvironment struct {
interpreterEnvironmentReconfigured
baseTypeActivation *sema.VariableActivation
baseValueActivation *sema.VariableActivation
baseActivation *interpreter.VariableActivation

// defaultBaseTypeActivation is the base type activation that applies to all locations by default.
defaultBaseTypeActivation *sema.VariableActivation
// The base type activations for individual locations.
// location == nil is the base type activation that applies to all locations,
// unless there is a base type activation for the given location.
//
// Base type activations are lazily / implicitly created
// by DeclareType / semaBaseActivationFor
baseTypeActivationsByLocation map[common.Location]*sema.VariableActivation

// defaultBaseValueActivation is the base value activation that applies to all locations by default.
defaultBaseValueActivation *sema.VariableActivation
// The base value activations for individual locations.
// location == nil is the base value activation that applies to all locations,
// unless there is a base value activation for the given location.
//
// Base value activations are lazily / implicitly created
// by DeclareValue / semaBaseActivationFor
baseValueActivationsByLocation map[common.Location]*sema.VariableActivation

// defaultBaseActivation is the base activation that applies to all locations by default
defaultBaseActivation *interpreter.VariableActivation
// The base activations for individual locations.
// location == nil is the base activation that applies to all locations,
// unless there is a base activation for the given location.
//
// Base activations are lazily / implicitly created
// by DeclareValue / interpreterBaseActivationFor
baseActivationsByLocation map[common.Location]*interpreter.VariableActivation

InterpreterConfig *interpreter.Config
CheckerConfig *sema.Config
deployedContractConstructorInvocation *stdlib.DeployedContractConstructorInvocation
Expand Down Expand Up @@ -109,16 +143,16 @@ var _ ArgumentDecoder = &interpreterEnvironment{}
var _ common.MemoryGauge = &interpreterEnvironment{}

func newInterpreterEnvironment(config Config) *interpreterEnvironment {
baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation)
baseTypeActivation := sema.NewVariableActivation(sema.BaseTypeActivation)
baseActivation := activations.NewActivation[*interpreter.Variable](nil, interpreter.BaseActivation)
defaultBaseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation)
defaultBaseTypeActivation := sema.NewVariableActivation(sema.BaseTypeActivation)
defaultBaseActivation := activations.NewActivation(nil, interpreter.BaseActivation)

env := &interpreterEnvironment{
config: config,
baseValueActivation: baseValueActivation,
baseTypeActivation: baseTypeActivation,
baseActivation: baseActivation,
stackDepthLimiter: newStackDepthLimiter(config.StackDepthLimit),
config: config,
defaultBaseValueActivation: defaultBaseValueActivation,
defaultBaseTypeActivation: defaultBaseTypeActivation,
defaultBaseActivation: defaultBaseActivation,
stackDepthLimiter: newStackDepthLimiter(config.StackDepthLimit),
}
env.InterpreterConfig = env.newInterpreterConfig()
env.CheckerConfig = env.newCheckerConfig()
Expand All @@ -129,7 +163,7 @@ func (e *interpreterEnvironment) newInterpreterConfig() *interpreter.Config {
return &interpreter.Config{
InvalidatedResourceValidationEnabled: true,
MemoryGauge: e,
BaseActivation: e.baseActivation,
BaseActivationHandler: e.getBaseActivation,
OnEventEmitted: e.newOnEventEmittedHandler(),
OnAccountLinked: e.newOnAccountLinkedHandler(),
InjectedCompositeFieldsHandler: e.newInjectedCompositeFieldsHandler(),
Expand Down Expand Up @@ -161,8 +195,8 @@ func (e *interpreterEnvironment) newInterpreterConfig() *interpreter.Config {
func (e *interpreterEnvironment) newCheckerConfig() *sema.Config {
return &sema.Config{
AccessCheckMode: sema.AccessCheckModeStrict,
BaseValueActivation: e.baseValueActivation,
BaseTypeActivation: e.baseTypeActivation,
BaseValueActivationHandler: e.getBaseValueActivation,
BaseTypeActivationHandler: e.getBaseTypeActivation,
ValidTopLevelDeclarationsHandler: validTopLevelDeclarations,
LocationHandler: e.newLocationHandler(),
ImportHandler: e.resolveImport,
Expand All @@ -176,15 +210,15 @@ func (e *interpreterEnvironment) newCheckerConfig() *sema.Config {
func NewBaseInterpreterEnvironment(config Config) *interpreterEnvironment {
env := newInterpreterEnvironment(config)
for _, valueDeclaration := range stdlib.DefaultStandardLibraryValues(env) {
env.DeclareValue(valueDeclaration)
env.DeclareValue(valueDeclaration, nil)
}
return env
}

func NewScriptInterpreterEnvironment(config Config) Environment {
env := newInterpreterEnvironment(config)
for _, valueDeclaration := range stdlib.DefaultScriptStandardLibraryValues(env) {
env.DeclareValue(valueDeclaration)
env.DeclareValue(valueDeclaration, nil)
}
return env
}
Expand All @@ -203,13 +237,63 @@ func (e *interpreterEnvironment) Configure(
e.stackDepthLimiter.depth = 0
}

func (e *interpreterEnvironment) DeclareValue(valueDeclaration stdlib.StandardLibraryValue) {
e.baseValueActivation.DeclareValue(valueDeclaration)
interpreter.Declare(e.baseActivation, valueDeclaration)
func (e *interpreterEnvironment) DeclareValue(valueDeclaration stdlib.StandardLibraryValue, location common.Location) {
e.semaBaseActivationFor(
location,
&e.baseValueActivationsByLocation,
e.defaultBaseValueActivation,
).DeclareValue(valueDeclaration)

activation := e.interpreterBaseActivationFor(location)
interpreter.Declare(activation, valueDeclaration)
}

func (e *interpreterEnvironment) DeclareType(typeDeclaration stdlib.StandardLibraryType, location common.Location) {
e.semaBaseActivationFor(
location,
&e.baseTypeActivationsByLocation,
e.defaultBaseTypeActivation,
).DeclareType(typeDeclaration)
}

func (e *interpreterEnvironment) DeclareType(typeDeclaration stdlib.StandardLibraryType) {
e.baseTypeActivation.DeclareType(typeDeclaration)
func (e *interpreterEnvironment) semaBaseActivationFor(
location common.Location,
baseActivationsByLocation *map[Location]*sema.VariableActivation,
defaultBaseActivation *sema.VariableActivation,
) (baseActivation *sema.VariableActivation) {
if location == nil {
return defaultBaseActivation
}

if *baseActivationsByLocation == nil {
*baseActivationsByLocation = map[Location]*sema.VariableActivation{}
} else {
baseActivation = (*baseActivationsByLocation)[location]
}
if baseActivation == nil {
baseActivation = sema.NewVariableActivation(defaultBaseActivation)
(*baseActivationsByLocation)[location] = baseActivation
}
return baseActivation
}

func (e *interpreterEnvironment) interpreterBaseActivationFor(
location common.Location,
) *interpreter.VariableActivation {
defaultBaseActivation := e.defaultBaseActivation
if location == nil {
return defaultBaseActivation
}

baseActivation := e.baseActivationsByLocation[location]
if baseActivation == nil {
baseActivation = activations.NewActivation[*interpreter.Variable](nil, defaultBaseActivation)
if e.baseActivationsByLocation == nil {
e.baseActivationsByLocation = map[common.Location]*interpreter.VariableActivation{}
}
e.baseActivationsByLocation[location] = baseActivation
}
return baseActivation
}

func (e *interpreterEnvironment) NewAuthAccountValue(address interpreter.AddressValue) interpreter.Value {
Expand Down Expand Up @@ -908,7 +992,8 @@ func (e *interpreterEnvironment) newCompositeTypeHandler() interpreter.Composite

case nil:
qualifiedIdentifier := string(typeID)
ty := sema.TypeActivationNestedType(e.baseTypeActivation, qualifiedIdentifier)
baseTypeActivation := e.getBaseTypeActivation(location)
ty := sema.TypeActivationNestedType(baseTypeActivation, qualifiedIdentifier)
if ty == nil {
return nil
}
Expand Down Expand Up @@ -1096,3 +1181,70 @@ func (e *interpreterEnvironment) CommitStorage(inter *interpreter.Interpreter) e

return nil
}

// getBaseValueActivation returns the base activation for the given location.
// If a value was declared for the location (using DeclareValue),
// then the specific base value activation for this location is returned.
// Otherwise, the default base activation that applies for all locations is returned.
func (e *interpreterEnvironment) getBaseValueActivation(
location common.Location,
) (
baseValueActivation *sema.VariableActivation,
) {
baseValueActivationsByLocation := e.baseValueActivationsByLocation
// Use the base value activation for the location, if any
// (previously implicitly created using DeclareValue)
baseValueActivation = baseValueActivationsByLocation[location]
if baseValueActivation == nil {
// If no base value activation for the location exists
// (no value was previously, specifically declared for the location using DeclareValue),
// return the base value activation that applies to all locations by default
baseValueActivation = e.defaultBaseValueActivation
}
return

}

// getBaseTypeActivation returns the base activation for the given location.
// If a type was declared for the location (using DeclareType),
// then the specific base type activation for this location is returned.
// Otherwise, the default base activation that applies for all locations is returned.
func (e *interpreterEnvironment) getBaseTypeActivation(
location common.Location,
) (
baseTypeActivation *sema.VariableActivation,
) {
// Use the base type activation for the location, if any
// (previously implicitly created using DeclareType)
baseTypeActivationsByLocation := e.baseTypeActivationsByLocation
baseTypeActivation = baseTypeActivationsByLocation[location]
if baseTypeActivation == nil {
// If no base type activation for the location exists
// (no type was previously, specifically declared for the location using DeclareType),
// return the base type activation that applies to all locations by default
baseTypeActivation = e.defaultBaseTypeActivation
}
return
}

// getBaseActivation returns the base activation for the given location.
// If a value was declared for the location (using DeclareValue),
// then the specific base activation for this location is returned.
// Otherwise, the default base activation that applies for all locations is returned.
func (e *interpreterEnvironment) getBaseActivation(
location common.Location,
) (
baseActivation *interpreter.VariableActivation,
) {
// Use the base activation for the location, if any
// (previously implicitly created using DeclareValue)
baseActivationsByLocation := e.baseActivationsByLocation
baseActivation = baseActivationsByLocation[location]
if baseActivation == nil {
// If no base activation for the location exists
// (no value was previously, specifically declared for the location using DeclareValue),
// return the base activation that applies to all locations by default
baseActivation = e.defaultBaseActivation
}
return
}
6 changes: 3 additions & 3 deletions runtime/interpreter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ type Config struct {
// UUIDHandler is used to handle the generation of UUIDs
UUIDHandler UUIDHandlerFunc
// CompositeTypeHandler is used to load composite types
CompositeTypeHandler CompositeTypeHandlerFunc
BaseActivation *VariableActivation
Debugger *Debugger
CompositeTypeHandler CompositeTypeHandlerFunc
BaseActivationHandler func(location common.Location) *VariableActivation
Debugger *Debugger
// OnStatement is triggered when a statement is about to be executed
OnStatement OnStatementFunc
// OnLoopIteration is triggered when a loop iteration is about to be executed
Expand Down
8 changes: 7 additions & 1 deletion runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,15 @@ func NewInterpreterWithSharedState(
sharedState.allInterpreters[location] = interpreter
}

// Initialize activations

interpreter.activations = activations.NewActivations[*Variable](interpreter)

baseActivation := sharedState.Config.BaseActivation
var baseActivation *VariableActivation
baseActivationHandler := sharedState.Config.BaseActivationHandler
if baseActivationHandler != nil {
baseActivation = baseActivationHandler(location)
}
if baseActivation == nil {
baseActivation = BaseActivation
}
Expand Down
Loading

0 comments on commit 6947cfa

Please sign in to comment.