Updated feature list
API:
-
luau_load(module | bytecode, env, settings?)
Accepts a Luau module or bytecode. Returns the main prototype wrapped and a luau_close
function to kill the interpreter if needed.
-
luau_deserialize(bytecode, settings?)
Used to deserialise bytecode.
-
luau_newsettings()
Used to create a table of default settings.
-
luau_validatesettings(settings)
Used to validate the passed settings.
-
luau_getcoverage(module, protoid, callback)
Collects LOP_COVERAGE
hits and calls callback
with (proto_debugname, proto_linedefined, proto_depth, hit_buffer, max_line)
Settings:
vectorCtor
- Vector constructor function
vectorSize
- Vector size
useNativeNamecall
- Boolean to indicate if namecallHandler
should be used
namecallHandler
- Function handler for native namecalling
extensions
- Table of injectable globals
callHooks
- VM callback behaviour emulators
errorHandling
- Error handling by the VM for line information and opcode information
generalizedIteration
- Use generalized iteration in the VM
staticEnvironment
- Table of globals for option useImportConstants
useImportConstants
- Boolean to indicate if fiu should optimize GETIMPORT
using staticEnvironment
decodeOp
- Function that passes an op
argument, which is the instruction number and can be processed for any encoded bytecode
Vector constant support
Vector constants can be supported by setting vectorCtor
and vectorSize
. vectorSize
can be 3 or 4, vectorCtor
on Roblox would be Vector3.new
.
Native namecall support
Namecalling is impossible to support dynamically so in environments where only __namecall
is implemented without __index
you can define a namecallHandler
and set useNativeNamecall
to true. In the namecall handler you must return a boolean as the first return value.
Example:
luau_settings.namecallHandler = function(namecallMethod, self, ...)
if namecallMethod == "FindFirstChild" then
return true, self:FindFirstChild(...)
end
return false
end
Stack frame, running thread and errors
The interpreter can be accurate 1:1 to existing stack frames if errorHandling
is disabled.
Generalized iteration can also cause issues because it requires a new thread to be created so anything that gets iterated will go deeper in the C stack depth limit and __iter
and __call
will have a different thread when coroutine.running
is called. If generialized iteration is disabled with generializedIteration
__call
will still function but __iter
and iterating over tables without an iterator will no longer work.
Fiu cannot provide perfect errors, if errorHandling
is enabled all errors are processed by Fiu and will be turned into strings if they are not. If you want to be able to error a table and then grab the table enable allowProxyErrors
which will error the errored object again. Note that when errorHandling
is disabled this behaviour is done by default because Fiu will not interfere with errors.
Injectable globals
The vm allows globals to be injected into the VM with extensions
, these injected globals can never be deleted by the interpreter and any attempts will just result in environment globals being set to nil
.
Example:
luau_settings.extensions["foo"] = function()
print('hello world!')
end
VM callback behaviour
The Luau VM provides simple hooks to see into the VM at certain points, the Fiu VM emulates 4 of these callbacks.
breakHook(stack, debugging, proto, module, upvals)
- When a LOP_BREAK
/breakpoint is encountered breakHook
will be called, the first return must be true
or false
to specify if the VM is meant to exit and return instead
interruptHook(stack, debugging, proto, module, upvals)
- When a vm interrupt occurs the interruptHook
will be called
panicHook(message, stack, debugging, proto, module, upvals)
- When an unprotected error occurs within the VM the panicHook
will be called if errorHandling
is enabled
stepHook(stack, debugging, proto, module, upvals)
- When a VM step (In Fiu, when the PC increases) occurs stepHook
will be called
Example:
settings.callHooks.stepHook = function(stack, debugging)
print('step occured', debugging.name, debugging.pc)
end
settings.callHooks.panicHook = function(message, stack, debugging)
print(debugging.name, message)
for i,v in stack do
print(i,v)
end
end
settings.callHooks.interruptHook = function(stack, debugging)
print(debugging.name, "interrupted!")
end
Debug Hook Example:
settings.callHooks.breakHook = function()
return true, "Hooked by LOP_BREAK!"
end
-- later
print(luau_load()()) --> Hooked by LOP_BREAK!