OP_PLACE
Copies a stack item to another position
Syntax and Stack
item count OP_PLACE => item?
- item: the item copied
- count: how far back to count. Count 0 is item.
Binary representation
OP_PLACE is defined as the single byte 0xe9.
Operation
This opcode is the inverse of OP_PICK. When combined with pick, it allows stack items to be essentially used as RAM locations -- script authors or compilers can implement read-modify-write semantics on "variables" that were previously bound to a stack position.
For example, the following diagram shows how OP_PICK and OP_PLACE are used to grab two "variable" from deep in the stack, add them, overwrite one variable and use the result. In pseudo-code:
B = A + B
if (B != 0) ...
10 PICK 6 PICK ADD 6 PLACE IF ... ENDIF
sequenceDiagram
participant D as Deep Stack
participant A as Active Stack
Note right of A: Grab the variables
D->>A: 10 PICK
D->>A: 6 PICK
A->>A: ADD
Note right of A: overwrite B
A->>D: 5 PLACE
Note right of A: Use the sum...
A->>A: OP_IF
count must be a BigNum, CScriptNum, or little-endian encoded sign-magnitude number (T.O1). count is popped from the stack. The BMD is not applied during this operation (T.0.8).
Indexing backwards
If count is positive, fail if the stack is <= count (T.O2). Otherwise, set stack item[stack length - 1 - count] to item, assuming zero-based array indexing (T.O3). For clarity, if count == 0, this opcode overwrites item with itself.
Indexing forwards
If count is < 0 (treat -0 as 0: T.O4), set stack item[abs(count)-1] to item (T.O5). Fail if abs(count) > stack length (T.O6).
Note that item MUST be popped from the stack before any stack length checks are made (T.O7).
Design considerations
Bidirectional Indexing
In some scripts or situations it may be simpler to count forward from the beginning of the stack. Access in this manner is analogous to using "global variables". However, doing so for "local variables" would complicate macro instantiation since one would need to identify the stack depth at compile or runtime to properly index items.
Given two different access semantics, it makes sense to have two different access methods.
Note that it may be desired to pass the index of a "local variable" into the instantiation of a macro (effectively passing a pointer to that variable to the macro). To accomplish this elegantly, one would need an opcode that return the current stack length. However, to avoid this opcode, it is possible to pass the local variable's current stack depth, and have the macro add its stack usage. Or use N OP_PICK to place the variable on the stack top (essentially pass-by-value), instantiate the macro, and use N OP_PLACE OP_DROP to copy it back.
Indexing Direction
The indexing direction was chosen to be compatible with OP_PICK.