diff --git a/src/script_opt/ZAM/Expr.cc b/src/script_opt/ZAM/Expr.cc index ea5af97939..9c2a38ea93 100644 --- a/src/script_opt/ZAM/Expr.cc +++ b/src/script_opt/ZAM/Expr.cc @@ -953,8 +953,12 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n) { op = OP_WHENCALLN_V; } - else if ( indirect ) - op = n ? OP_INDCALLN_VV : OP_INDCALLN_V; + else if ( indirect ) { + if ( func_id->IsGlobal() ) + op = n ? OP_INDCALLN_V : OP_INDCALLN_X; + else + op = n ? OP_LOCAL_INDCALLN_VV : OP_LOCAL_INDCALLN_V; + } else op = n ? OP_CALLN_V : OP_CALLN_X; @@ -968,11 +972,14 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n) { auto n_slot = Frame1Slot(n, OP1_WRITE); if ( indirect ) { - if ( func_id->IsGlobal() ) - z = ZInstI(op, n_slot, -1); - else + if ( func_id->IsGlobal() ) { + z = ZInstI(op, n_slot); + z.op_type = OP_V; + } + else { z = ZInstI(op, n_slot, FrameSlot(func)); - z.op_type = OP_VV; + z.op_type = OP_VV; + } } else { @@ -981,11 +988,8 @@ const ZAMStmt ZAMCompiler::DoCall(const CallExpr* c, const NameExpr* n) { } } else { - if ( indirect ) { - if ( func_id->IsGlobal() ) - z = ZInstI(op, -1); - else - z = ZInstI(op, FrameSlot(func)); + if ( indirect && ! func_id->IsGlobal() ) { + z = ZInstI(op, FrameSlot(func)); z.op_type = OP_V; } else { diff --git a/src/script_opt/ZAM/Ops.in b/src/script_opt/ZAM/Ops.in index 3ffbeb6462..dd092689bf 100644 --- a/src/script_opt/ZAM/Ops.in +++ b/src/script_opt/ZAM/Ops.in @@ -183,8 +183,11 @@ # version for assigning to a frame variable # # indirect-call the operation represents an indirect call (through -# a variable, rather than directly). Only meaningful -# if num-call-args is also specified. +# a global variable, rather than directly). Only +# meaningful if num-call-args is also specified. +# +# indirect-local-call same, but via a local variable rather than +# global # # method-post C++ code to add to the end of the method that # dynamically generates ZAM code @@ -1587,22 +1590,36 @@ side-effects OP_CALLN_X OP_X assign-val v num-call-args n -# Same, but for indirect calls via a local variable. +# Same, but for indirect calls via a global variable. internal-op IndCallN -op1-read -type V +type X side-effects indirect-call num-call-args n # Same with a return value. internal-assignment-op IndCallN -type VV -side-effects OP_INDCALLN_V OP_V +type V +side-effects OP_INDCALLN_X OP_X assign-val v indirect-call num-call-args n +# And versions with a local variable rather than a global. +internal-op Local-IndCallN +op1-read +type V +side-effects +indirect-local-call +num-call-args n + +internal-assignment-op Local-IndCallN +type VV +side-effects OP_LOCAL_INDCALLN_V OP_V +assign-val v +indirect-local-call +num-call-args n + # A call made in a "when" context. These always have assignment targets. # To keep things simple, we just use one generic flavor (for N arguments, # doing a less-streamlined-but-simpler Val-based assignment).