The Lua Virtual Machine [Part 2]

The Implementation of Lua Virtual Machine, This is an Advanced topic. Due to text contraints, this tutorial is a multi-parter.

by MemoryAddress0

Author Avatar

Goto Part 1 for Context of Part 2

ESTIMATED READ TIME: 8 minutes

##Instructions


Now that we've covered the various opcodes used by the Lua 5.1 Virtual Machine, let's take a look at how these instructions are actually executed.

The virtual machine operates on a stack of values, similar to a stack of plates in a cafeteria. Each value on the stack has a location called a register, which is a numerical index used to refer to the value. When an instruction is executed, it typically reads one or more values from the top of the stack (also known as the "stack top") and pushes the result of the operation back onto the stack.

For example, consider the ADD instruction, which adds two values from the top of the stack and pushes the result back onto the stack. The A register specifies the destination location on the stack for the result, and the B and C registers specify the locations of the values to be added. The ADD instruction would be written as "ADD A B C" in the bytecode, and it would be executed as follows:

The values at locations B and C on the stack are retrieved and added together. The result of the addition is pushed onto the stack at location A. The virtual machine moves to the next instruction in the bytecode. It's important to note that the values at locations B and C are not modified during the execution of the ADD instruction. Instead, the values are simply read from the stack and used in the operation. The result of the operation is then pushed onto the stack at the specified location, leaving the original values unchanged.

In addition to the registers specified in the instruction, the virtual machine also maintains several special registers to keep track of the current state of the execution. These include the program counter (PC), which specifies the location in the bytecode of the next instruction to be executed, and the stack base (SB), which specifies the base of the current stack frame. The virtual machine also has a number of other special registers for handling function calls, looping, and other operations, but we won't be covering them in detail in this tutorial.

##Execution


Now that you have a basic understanding of how instructions are executed in the Lua 5.1 Virtual Machine, let's take a look at some examples of how these instructions can be used to perform common operations in Lua. Next, we will cover how to use the MOVE, LOADK, and LOADBOOL instructions to manipulate values on the stack.

To better understand how the Lua 5.1 Virtual Machine executes instructions, let's consider an example of some simple Lua code and how it would be translated into opcodes.

Lets take a look on the following code:

a = 36
b = 33
c = a + b
print(c)

This code defines three variables (a, b, and c) and assigns values to them, then calculates the sum of a and b and assigns it to c. Finally, it prints the value of c to the console in terminal or your Roblox Studio.

Here is how this code would be translated into opcodes:

LOADK 0 36      ; push the value 36 onto the stack at location 0
LOADK 1 33      ; push the value 33 onto the stack at location 1
MOVE 2 0        ; copy the value at location 0 onto the stack at location 2
MOVE 3 1        ; copy the value at location 1 onto the stack at location 3
ADD 4 2 3       ; add the values at locations 2 and 3 and push the result onto the stack at location 4
MOVE 5 4        ; copy the value at location 4 onto the stack at location 5
LOADK 6 "print" ; push the string "print" onto the stack at location 6
GETGLOBAL 7 6   ; push the global function "print" onto the stack at location 7
MOVE 8 5        ; copy the value at location 5 onto the stack at location 8
CALL 7 1 1      ; call the function at location 7 with 1 argument and return 1 result

Now that we've covered the basics of how the Lua 5.1 Virtual Machine executes instructions and how to translate simple Lua code into opcodes.

##Optimization


There are several techniques you can use to optimize your code to run more efficiently on the Lua 5.1 Virtual Machine. Some of the most effective techniques include:

Minimizing stack usage Since the virtual machine operates on a stack of values, minimizing the number of values on the stack can help improve performance. This can be achieved by using local variables instead of global variables, reducing the number of function calls, and minimizing the use of complex data structures.

a = 0   ->   local a = 0

Optimizing instruction usage Some instructions are more expensive to execute than others, so using them sparingly can help improve performance. For example, using the ADD instruction to perform arithmetic operations is generally faster than using the MUL or DIV instructions. This does not mean MUL is worse than ADD, and in a lot of cases they are the same.

-- Simplifcation
print((10 * 10)/2)   ->   print(50)

Using upvalues wisely Upvalues are variables in a function's environment that are referenced from the function's stack frame. Accessing upvalues can be slower than accessing local variables.

local a = 0    ->     local a = 0    -OR->    do 
do             ->     print(a)       -OR->    	local a = 0
	print(a)   ->                    -OR->    	print(a)
end            ->                    -OR->    end

Avoiding unnecessary table access Accessing elements in a table can be slower than accessing local variables, minimizing table access can help improve performance.

local a = {b = 1}   ->     local b = 1
print(a.b)          ->     print(b)

Optimizing function calls Function calls can be expensive, so minimizing the number of function calls and using tail calls there possible can help improve performance.

function add(a, b)
     ->    function add(a, b)
 
	return a + b
       ->    	return a + b
end                    ->    end  



                       ->
function addOneTwo()
   ->    function addOneTwo()
	print(add(1, 2))
   ->    	return add(1, 2)
end

                    ->    end



                       ->
addOneTwo()            ->    print(addOneTwo())

Execution speeds are generally mostly based on your hardware, system, etc.

Hopefully by using these these tips, you can improve the performance of your code on the Lua 5.1 Virtual Machine and make it run more efficiently.

Conclusion


We covered the basics of how the Lua 5.1 Virtual Machine works, including the various opcodes and registers used to execute instructions. We also discussed some techniques for optimizing your code to run more efficiently on the virtual machine, including minimizing stack usage and optimizing instruction usage.

By understanding how a lua virtual machine works, you can write more efficient code and improve the performance of your programs. Whether you are new to Lua or an experienced developer, this tutorial should have provided you with a solid foundation for working with the virtual machine and optimizing your code.

I hope you found this tutorial helpful and informative. If you have any questions or feedback, please don't hesitate to let me know. Thank you for reading, and happy coding!

View in-game to comment, award, and more!