Script Machine Registers

Seeking some thoughts/feedback on this idea. This may or may not be already implemented in other coins, it is not exactly a novel idea.
I was looking at some cashscript stuff and it occurred to me that the variable abstraction would be a lot easier to work with if the script machine had some direct access data storage instead of relying on purely sequential access.

I named this script machine registers because the naming convention for the opcodes matches the LOAD and STORE assembley instructions that load/store data to a register.

This is not meant to be a formal chip.

Title: Script Machine Registers
Maintainer: Griffith
Status: Draft
Initial Publication Date: 2024-07-13
Latest Revision Date: 2024-07-13
Version: 0.1

Script Machine Registers

How would they work

By using two opcodes LOAD and STORE we can save up to X variables into script machine registers for easier use later in the script as a more performant alternative to ROLL and PICK. Initially allow for up to 8 (arbitrary value) registers to be used

script machine registers implemented as std::array<StackItem, 8> vRegisters; in the script machine.

OP_STORE implementation

const StackItem &register_value = stackItemAt(-2);
int64_t register_num CScriptNum(stacktop(-1), fRequireMinimal, maxIntegerSize).getint64();
// in the script machine there are only 8 registers (0-7)
// a register number higher than this a failure
if register_num > 7:
    script failure

// store the value in the register
vRegisters[register_num] = register_value
PopStack(); // pop the register number off the stack
PopStack(); // pop the stored value off the stack

Example:

push 10
push 5
OP_STORE # stores the value 10 into register #5

OP_LOAD implementation

int64_t register_num CScriptNum(stacktop(-1), fRequireMinimal, maxIntegerSize).getint64();
// in the script machine there are only 8 registers (0-7)
// a register number higher than this a failure
if register_num > 7:
    script failure

// load the value in the register
const StackItem register_value& = vRegisters[register_num];
PopStack(); // pop the register number off the stack
PushStack(value) // push the loaded value on to the stack

Example:

push 5
OP_LOAD # pops the top stack item (5) and replaces it with the contents of that register

TODO - consider clearing the register after the value is pushed on to the stack?

Final script state

It is not required that all registers be empty for the script to complete successfully. If values remain when the script is finished, they are cleared/ignored

Changelog

2 Likes

Nice! It would make it easier for anyone coding contracts in raw Script, as stack juggling is a big mental overhead :slight_smile:. It would also reduce script sizes as you’d likely need less opcodes for equivalent operation using current set of opcodes.

I saw a proposal for OP_UNROLL too, or just tweak OP_ROLL so negative index would move the current stack item down the stack.

I wonder, what would the efficiency gains be between status quo and unroll/negroll, and then between unroll/negroll and load/unload.

1 Like