Skip to content

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) ...
If A is located 10 below the stack top, and B 5 below, the NEXA script would look like:
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.