Skip to content

Commit c268f35

Browse files
authored
Make FrameAwaitFunValue handle multiple arguments at once (#7281)
* Make `FrameAwaitFunValue` handle multiple arguments at once * Have multi-apply as an extra context frame * use original argstack * optimize * refactor * comment
1 parent 800c67d commit c268f35

File tree

2 files changed

+42
-30
lines changed

2 files changed

+42
-30
lines changed

plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/Internal.hs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ module UntypedPlutusCore.Evaluation.Machine.Cek.Internal
3737
, DischargeResult(..)
3838
, dischargeResultToTerm
3939
, ArgStack(..)
40-
, transferArgStack
4140
, CekUserError(..)
4241
, CekEvaluationException
4342
, CekBudgetSpender(..)
@@ -573,11 +572,10 @@ instance Pretty CekUserError where
573572
]
574573
pretty CekEvaluationFailure = "The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'."
575574

576-
-- | Convert the given 'ArgStack' to a list by reversing it.
575+
-- | Convert the given 'ArgStack' to a list.
577576
argStackToList :: ArgStack uni fun ann -> [CekValue uni fun ann]
578-
argStackToList = go [] where
579-
go acc EmptyStack = acc
580-
go acc (ConsStack arg rest) = go (arg : acc) rest
577+
argStackToList EmptyStack = []
578+
argStackToList (ConsStack arg rest) = arg : argStackToList rest
581579

582580
-- | The result of 'dischargeCekValue'.
583581
data DischargeResult uni fun
@@ -671,6 +669,8 @@ data Context uni fun ann
671669
-- ^ @[_ N]@
672670
| FrameAwaitFunValue !(CekValue uni fun ann) !(Context uni fun ann)
673671
-- ^ @[_ V]@
672+
| FrameAwaitFunValueN !(ArgStack uni fun ann) !(Context uni fun ann)
673+
-- ^ @[_ V1 .. Vn]@
674674
| FrameForce !(Context uni fun ann)
675675
-- ^ @(force _)@
676676
-- See Note [Accumulators for terms]
@@ -700,19 +700,13 @@ pass them to a function they need to be evaluated to values, which means that in
700700
machine the evaluated arguments are going to be reversed: you evaluate the first argument and put
701701
the result into a 'FrameConstr', then the second one and put it in a 'FrameConstr' again, this time
702702
prepending it to the one that is already there etc -- in the end you get the arguments in reversed
703-
order. Which is why 'transferArgStack' is a left fold (just like 'reverse').
703+
order.
704704
705705
But in case of 'Spine' the builtins machinery directly produces values, not terms. Meaning, a
706706
'Spine' that we get from the builtins machinery isn't reversed, hence we can pass its contents
707707
directly to the head of the application. Which is why 'transferSpine' is a right fold.
708708
-}
709709

710-
-- See Note [ArgStack vs Spine].
711-
-- | Transfers an 'ArgStack' to a series of 'Context' frames.
712-
transferArgStack :: ArgStack uni fun ann -> Context uni fun ann -> Context uni fun ann
713-
transferArgStack EmptyStack c = c
714-
transferArgStack (ConsStack arg rest) c = transferArgStack rest (FrameAwaitFunValue arg c)
715-
716710
-- | Transfers a 'Spine' of constant values onto the stack. The first argument will be at the top of the stack.
717711
transferConstantSpine
718712
:: Spine (Some (ValueOf uni))
@@ -847,15 +841,26 @@ enterComputeCek = computeCek
847841
-- FIXME: add rule for VBuiltin once it's in the specification.
848842
returnCek (FrameAwaitArg fun ctx) arg =
849843
applyEvaluate ctx fun arg
850-
-- s , [_ V] ◅ lam x (M,ρ) s ; ρ [ x ↦ V ] ▻ M
844+
-- s , [_ V] ◅ lam x (M,ρ) s ; ρ [ x ↦ V ] ▻ M
851845
returnCek (FrameAwaitFunValue arg ctx) fun =
852846
applyEvaluate ctx fun arg
847+
-- s , [_ V1 .. Vn] ◅ lam x (M,ρ) ↦ s , [_ V2 .. Vn]; ρ [ x ↦ V1 ] ▻ M
848+
returnCek (FrameAwaitFunValueN args ctx) fun =
849+
case args of
850+
EmptyStack -> returnCek ctx fun
851+
ConsStack arg rest ->
852+
applyEvaluate (FrameAwaitFunValueN rest ctx) fun arg
853853
-- s , constr I V0 ... Vj-1 _ (Tj+1 ... Tn, ρ) ◅ Vj ↦ s , constr i V0 ... Vj _ (Tj+2... Tn, ρ) ; ρ ▻ Tj+1
854854
returnCek (FrameConstr env i todo done ctx) e = do
855-
let done' = ConsStack e done
855+
let
856+
reverseArgStack = go EmptyStack
857+
where
858+
go acc EmptyStack = acc
859+
go acc (ConsStack x xs) = go (ConsStack x acc) xs
860+
done' = ConsStack e done
856861
case todo of
857862
(next : todo') -> computeCek (FrameConstr env i todo' done' ctx) env next
858-
[] -> returnCek ctx $ VConstr i done'
863+
[] -> returnCek ctx $ VConstr i (reverseArgStack done')
859864
-- s , case _ (C0 ... CN, ρ) ◅ constr i V1 .. Vm ↦ s , [_ V1 ... Vm] ; ρ ▻ Ci
860865
returnCek (FrameCases env cs ctx) e = case e of
861866
-- If the index is larger than the max bound of an Int, or negative, then it's a bad index
@@ -866,7 +871,7 @@ enterComputeCek = computeCek
866871
throwErrorDischarged (StructuralError (MissingCaseBranchMachineError i)) e
867872
-- Otherwise, we can safely convert the index to an Int and use it.
868873
(VConstr i args) -> case (V.!?) cs (fromIntegral i) of
869-
Just t -> computeCek (transferArgStack args ctx) env t
874+
Just t -> computeCek (FrameAwaitFunValueN args ctx) env t
870875
Nothing -> throwErrorDischarged (StructuralError $ MissingCaseBranchMachineError i) e
871876
-- Proceed with caser when expression given is not Constr.
872877
VCon val -> case unCaserBuiltin ?cekCaserBuiltin val cs of

plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/SteppableCek/Internal.hs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ import PlutusPrelude
5050
import UntypedPlutusCore.Core
5151
import UntypedPlutusCore.Evaluation.Machine.Cek.CekMachineCosts (CekMachineCosts,
5252
CekMachineCostsBase (..))
53-
import UntypedPlutusCore.Evaluation.Machine.Cek.Internal hiding (Context (..), runCekDeBruijn,
54-
transferArgStack)
53+
import UntypedPlutusCore.Evaluation.Machine.Cek.Internal hiding (Context (..), runCekDeBruijn)
5554
import UntypedPlutusCore.Evaluation.Machine.Cek.StepCounter
5655

5756
import Control.Lens hiding (Context)
@@ -98,6 +97,7 @@ data Context uni fun ann
9897
= FrameAwaitArg ann !(CekValue uni fun ann) !(Context uni fun ann) -- ^ @[V _]@
9998
| FrameAwaitFunTerm ann !(CekValEnv uni fun ann) !(NTerm uni fun ann) !(Context uni fun ann) -- ^ @[_ N]@
10099
| FrameAwaitFunValue ann !(CekValue uni fun ann) !(Context uni fun ann)
100+
| FrameAwaitFunValueN ann !(ArgStack uni fun ann) !(Context uni fun ann)
101101
| FrameForce ann !(Context uni fun ann) -- ^ @(force _)@
102102
| FrameConstr ann !(CekValEnv uni fun ann) {-# UNPACK #-} !Word64 ![NTerm uni fun ann] !(ArgStack uni fun ann) !(Context uni fun ann)
103103
| FrameCases ann !(CekValEnv uni fun ann) !(V.Vector (NTerm uni fun ann)) !(Context uni fun ann)
@@ -106,16 +106,10 @@ data Context uni fun ann
106106
deriving stock instance (GShow uni, Everywhere uni Show, Show fun, Show ann, Closed uni)
107107
=> Show (Context uni fun ann)
108108

109-
-- | Transfers an 'ArgStack' to a series of 'Context' frames.
110-
transferArgStack :: ann -> ArgStack uni fun ann -> Context uni fun ann -> Context uni fun ann
111-
transferArgStack ann = go
112-
where
113-
go EmptyStack c = c
114-
go (ConsStack arg rest) c = go rest (FrameAwaitFunValue ann arg c)
115-
116109
-- | Transfers a 'Spine' of contant values onto the stack. The first argument will be at the top of the stack.
117110
transferConstantSpine :: ann -> Spine (Some (ValueOf uni)) -> Context uni fun ann -> Context uni fun ann
118-
transferConstantSpine ann args ctx = foldr (FrameAwaitFunValue ann . VCon) ctx args
111+
transferConstantSpine ann args ctx =
112+
foldr (FrameAwaitFunValue ann . VCon) ctx args
119113

120114
computeCek
121115
:: forall uni fun ann s
@@ -191,13 +185,24 @@ returnCek (FrameAwaitArg _ fun ctx) arg =
191185
applyEvaluate ctx fun arg
192186
-- s , [_ V1 .. Vn] ◅ lam x (M,ρ) ↦ s , [_ V2 .. Vn]; ρ [ x ↦ V1 ] ▻ M
193187
returnCek (FrameAwaitFunValue _ arg ctx) fun =
194-
applyEvaluate ctx fun arg
188+
applyEvaluate ctx fun arg
189+
-- s , [_ V1 .. Vn] ◅ lam x (M,ρ) ↦ s , [_ V2 .. Vn]; ρ [ x ↦ V1 ] ▻ M
190+
returnCek (FrameAwaitFunValueN ann args ctx) fun =
191+
case args of
192+
EmptyStack -> returnCek ctx fun
193+
ConsStack arg rest ->
194+
applyEvaluate (FrameAwaitFunValueN ann rest ctx) fun arg
195195
-- s , constr I V0 ... Vj-1 _ (Tj+1 ... Tn, ρ) ◅ Vj ↦ s , constr i V0 ... Vj _ (Tj+2... Tn, ρ) ; ρ ▻ Tj+1
196196
returnCek (FrameConstr ann env i todo done ctx) e = do
197-
let done' = ConsStack e done
197+
let
198+
reverseArgStack = go EmptyStack
199+
where
200+
go acc EmptyStack = acc
201+
go acc (ConsStack x xs) = go (ConsStack x acc) xs
202+
done' = ConsStack e done
198203
case todo of
199204
(next : todo') -> computeCek (FrameConstr ann env i todo' done' ctx) env next
200-
[] -> returnCek ctx $ VConstr i done'
205+
[] -> returnCek ctx $ VConstr i (reverseArgStack done')
201206
-- s , case _ (C0 ... CN, ρ) ◅ constr i V1 .. Vm ↦ s , [_ V1 ... Vm] ; ρ ▻ Ci
202207
returnCek (FrameCases ann env cs ctx) e = case e of
203208
-- If the index is larger than the max bound of an Int, or negative, then it's a bad index
@@ -208,7 +213,7 @@ returnCek (FrameCases ann env cs ctx) e = case e of
208213
throwErrorDischarged (StructuralError $ MissingCaseBranchMachineError i) e
209214
(VConstr i args) -> case (V.!?) cs (fromIntegral i) of
210215
Just t ->
211-
let ctx' = transferArgStack ann args ctx
216+
let ctx' = FrameAwaitFunValueN ann args ctx
212217
in computeCek ctx' env t
213218
Nothing -> throwErrorDischarged (StructuralError $ MissingCaseBranchMachineError i) e
214219
VCon val -> case unCaserBuiltin ?cekCaserBuiltin val cs of
@@ -387,6 +392,7 @@ contextAnn = \case
387392
FrameAwaitArg ann _ _ -> pure ann
388393
FrameAwaitFunTerm ann _ _ _ -> pure ann
389394
FrameAwaitFunValue ann _ _ -> pure ann
395+
FrameAwaitFunValueN ann _ _ -> pure ann
390396
FrameForce ann _ -> pure ann
391397
FrameConstr ann _ _ _ _ _ -> pure ann
392398
FrameCases ann _ _ _ -> pure ann
@@ -400,6 +406,7 @@ lenContext = go 0
400406
FrameAwaitArg _ _ k -> go (n+1) k
401407
FrameAwaitFunTerm _ _ _ k -> go (n+1) k
402408
FrameAwaitFunValue _ _ k -> go (n+1) k
409+
FrameAwaitFunValueN _ _ k -> go (n+1) k
403410
FrameForce _ k -> go (n+1) k
404411
FrameConstr _ _ _ _ _ k -> go (n+1) k
405412
FrameCases _ _ _ k -> go (n+1) k

0 commit comments

Comments
 (0)