No, it returns what was in the variable x in the upvalue (i.e. the x part of the closure where it was compiled in scope), and not the x which may be defined anywhere else the function will be called, which is not bound to this closure created at compile time.
The upvalues are in some table (even if the LuaVM uses a faster approach using an array for the environment of function closures, which allows faster and direct indexing by it's internal opcode).
The opcodes however are not relevant, they are internals of the VM, just like the limitation of the closure array size. This array does not even necessarily exist at runtime when actually these opcodes may have already been transformed to another instruction set: these opcodes are not part of the language itself, they change across versions of Lua whose default VM changes regularly its virtual instructions set and formats; the chain really exists when this closure is bound before calling the function code to prepare the new "register file"). anyway I think that what the Lua authors name "registers" is abusive, it is just a frame format, except that it uses a separate store than the call stack, and that the callstack itself is not necessarily represented as a single vector but can as well be a chained list: VM are free to use the represetnation that is more convenient to them and the integration contraint or memory constraints.
Basically I don't see any different between the "registers" model of the Lua VM and the "[BP+n]" indexing used in most stack-based CPU instruction sets. In fact a VM just needs 3 pointer registers to work: some stack pointer, a base frame pointer, and an instruction pointer, eventually also a flags register if they are needed by chained instructions like conditional jumps (everything else can as well be in stack and other registers are just faster "caches" aliasing what is in the stack (including when there's a single accumulator, which is a cache of what is in the top of stack). Then you can model the instruction sets (opcodes) as you want. beside the instruction pointer, you can compile any language using a stack (independantly og how it is structured and allocated) and two registers for the bottom and top of stack, and between the locations in the stack indicated by these two pointers, there's the equivalent of the Lua "register file". Even absolute and relative jump instructions can be considered as basic arithmetic operations on generic registers, and it could be located directly at top of the stack, along with the base pointer, so only one register is needed: the stack pointer itself. Using actual registers outside the stack is just a local optimization.
When you realize that, you can see that there's a much wider way to implement a VM and its intruction set (generated by its internal compiler, which may be multistaged, with several kinds of instruction sets and opcodes).
So each timle you speak about opcodes, you are not speaking about Lua itself, but about another specific assembly language used by one of its VMs and its internal compiler. If you forget that inner detail, then conceptually at the Lua language level, there are tables for everything, the rest is only optimization made by the VM itself.