struct VmOp

Defined at line 102 of file ../../src/developer/debug/zxdb/expr/vm_op.h

Holds a bytecode operation type (VmOpType) and any parameters associated with it.

Most bytecode machines would encode any parameters like strings constants or a binary operator

type compactly, either in the byte string, or using a small representation of a reference to

some other stream.

Our programs are so small compared to the type of system we expect to run on we do not care

about space. Instead, this implementation prefers a safe, simple approach. As part of this,

each VM operation is a bytecode operation combined with a relatively large variant holding any

ancillary data required by the operation. For many operations, this is very wasteful, but means

we can avoid doing error-prone reading of variable data from the instruction stream and the

decode logic becomes trivial.

See vm_exec.cc for execution details.

Local variables

---------------

In most "real" stack-based bycode machines, the local variables would be stored on the stack

and referenced by index from the "stack pointer" (the position of the stack and the entrypoint

of the current function). It is simple and efficient.

But it requires very careful tracking of where variables can be declared such that the block

that contains them can pop its local variables when the block exits: a local variable declaration

must never be conditionally executed since then the containing block wouldn't know whether to

clean it up. Any mistakes will corrupt the VM stack and are difficult to debug.

Our parser supports multiple languages and plays a bit fast-and-loose with where declarations can

appear. This could be fixed but since we also care much more about debugability and simplicity

of the parser than of performance, we have dedicated storage for local variables.

As local variables are parsed, we assign each one an index based on the parser depth just like

the stack-based approach. But these refer into a separate array specific to local variables.

This adds a copy for each variable declaration and some extra memory allocations for the separate

array but neither of these matter to us. The local variables created inside a scope are cleared

by the kPopLocals command which will be emitted at the end of a block. The block knows the size

to shrink to because it knows how many local variables are in scope at the entry to the block.

But this approach doesn't care if a local variable declaration was skipped (that slot will just

be unused).

Example:

{ // The parser remembers the # of locals in scope at the opening of the block.

// This info is saved on the block parse node for the last step.

int i = 23; // The parser adds info about "i" and saves its index as the local variable

// slot. This slot is used in the op kSetLocal.

i = 19; // The parser looks up the variable index and uses it in a kGetLocal op.

} // At the exit of a block, the parser emits kPopLocals to set the # locals back

// the size it was at the opening of the block.

Variable assignment

-------------------

Our expression language doesn't have lvalues. The assignment operator (binary operator "=")

always fully evaluates the thing on the left-hand-side. This simplifies things by providing only

one code path for all evaluating (rather than having a code path to compute where the thing would

be without computing its value).

All ExprValues have an ExprValueSource which tracks where they came from originally. This

information is used to update the variable when modified. For program values this is normally a

memory address or a register. For debugger-local variables, we keep a refptr to the source of

the value. The LocalExprValue object is a refcounted container for local variables that can

have such references to them.

Break

-----

The "break" keyword (e.g. for a loop) is weird and difficult. You need to execute the cleanup

code for every construct between the break and the loop, but not any of the remaining code in

them.

Our break is implemented somewhat like an exception. At the top of a loop, the loop emits the

"PushBreak" opcode (like the "try" instruction of an exception handler). This sets the

destination stream address to jump to and saves the stack and local variable stack. The "break"

opcode jumps to the nearest "set break" destination (like a thrown exception), and pops the stack

and local variable stack size back to the values they were at the top of the loop (like exception

unwinding code).

The bottom of the loop executes a "PopBreak" command which releases the registration of that

loop.

Public Members

VmOpType op
ExprToken token
variant info
static const uint32_t kBadJumpDest

Public Methods

void SetJumpDest (uint32_t dest)

Sets the destination of the this operator's jump destination to the given value. This will

assert if this operation is not a jump.

This is used commonly because the destination of a jump is often unknown until additional code

is filled in.

Defined at line 14 of file ../../src/developer/debug/zxdb/expr/vm_op.cc

VmOp MakeError (Err err, ExprToken token)

Constructor helper functions.

Defined at line 124 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeUnary (ExprToken token)

Defined at line 127 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeBinary (ExprToken token)

Defined at line 130 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeExpandRef (ExprToken token)

Defined at line 133 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeDrop (ExprToken token)

Defined at line 136 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeDup (ExprToken token)

Defined at line 139 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeLiteral (ExprValue value, ExprToken token)

Defined at line 142 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeJump (uint32_t dest, ExprToken token)

Defined at line 147 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeJumpIfFalse (uint32_t dest, ExprToken token)

Defined at line 150 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeGetLocal (uint32_t slot, ExprToken token)

Defined at line 154 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeSetLocal (uint32_t slot, ExprToken token)

Defined at line 158 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakePopLocals (uint32_t entry_count, ExprToken token)

Defined at line 162 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakePushBreak (uint32_t dest, ExprToken token)

Defined at line 167 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakePopBreak (ExprToken token)

Defined at line 171 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeBreak (ExprToken token)

Defined at line 174 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeCallback0 (Callback0 cb, ExprToken token)

Defined at line 177 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeCallback1 (Callback1 cb, ExprToken token)

Defined at line 180 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeCallback2 (Callback2 cb, ExprToken token)

Defined at line 183 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeCallbackN (int num_params, CallbackN cb, ExprToken token)

Defined at line 186 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeAsyncCallback0 (AsyncCallback0 cb, ExprToken token)

Defined at line 191 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeAsyncCallback1 (AsyncCallback1 cb, ExprToken token)

Defined at line 194 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeAsyncCallback2 (AsyncCallback2 cb, ExprToken token)

Defined at line 197 of file ../../src/developer/debug/zxdb/expr/vm_op.h

VmOp MakeAsyncCallbackN (int num_params, AsyncCallbackN cb, ExprToken token)

Defined at line 200 of file ../../src/developer/debug/zxdb/expr/vm_op.h

Records