summaryrefslogtreecommitdiffhomepage
path: root/vm.c
AgeCommit message (Collapse)Author
2022-07-30vm: introduce import and export opcodesJo-Philipp Wich
Introduce new opcodes to realize module imports and exports. The export operation will capture a local variable as upvalue and store it in VM wide module export registry while the import operation will connect an upvalue from the module export registry with a preallocated upvalue in the running function scope. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-07-30vm: honor constant flag of objects and arraysJo-Philipp Wich
Reject modifications on object and array values with a type exception when the constant flag is set on the value operated upon. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-07-30vm: transparently resolve upvalue referencesJo-Philipp Wich
Resolve upvalue references to their actual values when pushing such references onto the stack (or when attempting to call them as method). This allows constructing objects of pointers, as needed for wildcard module imports. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-07-30vm: gracefully handle unresolved upvaluesJo-Philipp Wich
Upcoming module support will rely on upresolved upvalues which are patched at runtime to realize module imports, make sure the VM trace code does not choke on such unresolved upvalues. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-07-30program: add infrastructure to handle multiple sources per programJo-Philipp Wich
The upcoming module support requires maintaining multiple source objects within the same program, so add the necessary infrastructure for it. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-04-13vm: stop executing bytecode on return of nested callsJo-Philipp Wich
When a managed function is indirectly invoked during bytecode execution, e.g. when calling the tostring() method of an object prototype during string concatenation, the invoked function must stop executing bytecode upon return to hand control back to caller. Extend `uc_vm_execute_chunk()` to track the amount of nested function calls it performs and hand back control to the caller once the toplevel callframe returns. Also bubble unhandled exceptions only as far as up to the original caller. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-04-07vm: move unhandled exception reporting out of `uc_vm_execute_chunk()`Jo-Philipp Wich
Move the invocation of the unhandled exception callback handler out of `uc_vm_execute_chunk()` into both `uc_vm_execute()` and `uc_vm_invoke()` in order to consistently report exceptions exactly once regardless of whether a native or managed code function is executed as topmost VM call. This solves cases where the unhandled exception callback was either called multiple times or never at all. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-04-07vm: fix callframe double free on unhanded exceptionsJo-Philipp Wich
When invoking a native function as toplevel VM call which indirectly triggers an unhandled exception in managed code, the callframes are completely reset before the C function returns, leading to invalid memory accesses when `uc_vm_call_native()` subsequently popped it's own callframe again. This issue did not surface by executing script code through the interpreter since in this case the VM will always execute a managed code as toplevel call, but it could be triggered by invoking a native function triggering an exception through the C API using `uc_vm_call()` on a fresh `uc_vm_t` context or by utilizing the CLI interpreters `-l` flag to preload a native code library triggering an exception. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-03-14vm: fix crash on object literals with non-string computed propertiesJo-Philipp Wich
When executing an object literal declaration using non-string computed property name values, the VM crashed caused by an attempt to use a NULL pointer (result of ucv_string_get() on a non-string value) as hash table key. Fix this issue by using the `ucv_key_set()` infrastructure which deals with the implicit stringification of non-string key values. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-03-07syntax: support add new operatorsJo-Philipp Wich
- Support ES2016 exponentiation (**) and exponentiation assignment (**=) - Support ES2020 nullish coalescing (??) and logical nullish assignment (??=) - Support ES2021 logical and assignment (&&=) and logical or assignment (||=) Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-03-02vm: release this context on exception in managed method callJo-Philipp Wich
When attempting to invoke a non-function value as method or when the the internal recursion limit was exceeded, `uc_vm_call_function()` emitted and internal runtime exception and freed the function value but not the `this` context associated with the method call. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-02-07treewide: rework function memory modelJo-Philipp Wich
- Instead of treating individual program functions as managed ucode types, demote uc_function_t values to pointers into a uc_program_t entity - Promote uc_program_t to a managed type - Let uc_closure_t claim references to the owning program of the enclosed uc_function_t - Redefine public APIs uc_compile() and uc_vm_execute() APIs to return and expect an uc_program_t object respectively - Remove vallist indirection for function loading and let the compiler emit the function id directly when producing function construction code Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-02-03vm: ensure consistent trace output between gcc and clang compiled ucodeJo-Philipp Wich
Clang emits code which evaluates function call argument expressions in a different order, causing `uc_dump_insn()` to receive the instruction pointer address after decoding the instruction, not before. Avoid that problem by explicitly caching the pre-decode address in a temporary variable which is then passed to `uc_dump_insn()`. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-02-03vm: fix leaking function value on call exceptionJo-Philipp Wich
The internal uc_vm_call_function() helper may fail in different ways before the stack frame has been set up, e.g. if the provided function value was not actually a callable function. In such cases an exception is raised but the actual function value is leaked since there's not yet a stackframe referring to it. Solve the issue by freeing the function value explicitly in these exit cases. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-02-03vm: NULL-initialize pointer to make cppcheck happyJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-01-18source: refactor source file handlingJo-Philipp Wich
- Move source object pointer into program entity which is referenced by each function - Move lineinfo related routines into source.c and use them from lexer.c since lineinfo encoding does not belong into the lexical analyzer. - Implement initial infrastructure for detecting source file type, this is required later to differentiate between plaintext and precompiled bytecode files Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-01-18compiler, vm: use a program wide constant listJo-Philipp Wich
Instead of storing constant values per function, maintain a global program wide list for all constant values within the current compilation unit. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-01-18types: add initial infrastructure for function serializationJo-Philipp Wich
- Introduce a new "program" entity which holds the list of functions created during compilation - Instead of storing pointers to the in-memory function representation in the constant list, store the index of the function within the program's function list - When loading functions from the constant list, retrieve the function by index from the program entity Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-01-04vm: optimize string concatenationJo-Philipp Wich
When concatenating strings, avoid allocating three times the required memory in the worst case. Instead of first allocating the string representations of the operands followed by the memory for the final string, allocate a string buffer and print the operands into it. This will grow the target memory as needed and avoid redundant internal copies of the involved strings. Also handle the special where the final string fits into a tagged pointer and deal with it accordingly. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-01-04treewide: rework numeric value handlingJo-Philipp Wich
- Parse integer literals as unsigned numeric values in order to be able to represent the entire unsigned 64bit value range - Stop parsing minus-prefixed integer literals as negative numbers but treat them as separate minus operator followed by a positive integer instead - Only store unsigned numeric constants in bytecode - Rework numeric comparison logic to be able to handle full 64bit unsigned integers - If possible, yield unsigned 64 bit results for additions - Simplify numeric value conversion API - Compile code with -fwrapv for defined signed overflow semantics Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-12-08vm: introduce value registryJo-Philipp Wich
Introduce a new, lazily allocated value registry which can be used by C code to store values which should not be garbage collected. The registry is a plain ucode object internally and treated as GC root but not exposed to ucode script code, this allows it to retain references to values which are otherwise completely unreachable from ucode scripts. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-12-07treewide: fix "resource" misspellingsJo-Philipp Wich
Fix various misspelling of "resource". This commit changes the exported libucode ABI. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-12-07treewide: fix upvalue reference type nameJo-Philipp Wich
No functional changes. Fixes: ff52440 ("treewide: consolidate typedef naming") Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-12-05vm: support object property access on resource value typesJo-Philipp Wich
Allow querying object properties on resource values. A resource value may have a prototype object set whose properties should be enumerable. Support that use case in the VM. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-11-01treewide: fix typo in exported function names and typesJo-Philipp Wich
Fix instances of misspelled "resource". This commit breaks the exported libucode ABI. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-10-12Merge pull request #22 from jow-/introduce-optional-chaining-operatorsJo-Philipp Wich
syntax: introduce optional chaining operators
2021-10-11syntax: introduce optional chaining operatorsJo-Philipp Wich
Introduce new operators `?.`, `?.[…]` and `?.(…)` to simplify looking up deeply nested property chain in a secure manner. The `?.` operator behaves like the `.` property access operator but yields `null` if the left hand side is `null` or not an object. Like `?.`, the `?.[…]` operator behaves like the `[…]` computed property access but yields `null` if the left hand side is `null` or neither an object or array. Finally the `?.(…)` operator behaves like the function call operator `(…)` but yields `null` if the left hand side is `null` or not a callable function. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-09-24vm: reset callframes before invoking unhandled exception handlerJo-Philipp Wich
Reset all callframes when dealing with an unhandled exception to avoid resuming the code which raised the exception when restarting the VM later, e.g. through uc_vm_call() or uc_vm_invoke(). Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-09-24vm: clear exception information before calling managed code functionsJo-Philipp Wich
If execution in an existing VM that threw an exception was resumed through uc_vm_call() or uc_vm_invoke(), the exception was never cleared, causing all subsequent calls to return with an exception status as well. Ensure that any preexisting exception information is discarded before executing the requested function in order to start from a clean state. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-30vm: fix toplevel function call protocolJo-Philipp Wich
In success case, always push the function return value onto the stack even if no call frames are remaining after the function returned. This is needed for host program code invoking ucode functions within a VM context that already ran to completion. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11treewide: harmonize function namingJo-Philipp Wich
- Ensure that most functions follow the subject_verb naming schema - Move type related function from value.c to types.c - Rename value.c to vallist.c Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11types, vm: adjust GC apiJo-Philipp Wich
Provide separate public ucv_gc() and ucv_freeall() functions to perform an incremental and complete GC run respectively. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11treewide: move header files into dedicated directoryJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11treewide: consolidate typedef namingJo-Philipp Wich
Ensure that all custom typedef and vector declaration type names end with a "_t" suffix. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: add API to control trace modeJo-Philipp Wich
Add a public getter and setter to read and set the VM trace level respectively. Use the new API to control the trace mode with a newly introduced `-t` command line switch. Drop support for honouring the `TRACE` environment variable as host programs embedding ucode might want to prevent that behaviour or handle it differently. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: make root exception handler configurableJo-Philipp Wich
So far, the VM simply printed exception information to stderr if the exception was not catched in managed code. Host programs embedding ucode might want to customize that behaviour, so refactor the current defualt behaviour into a callback function and add a public getter and setter to allow changing the exception handler callback. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: fix invalid memory access on toplevel function callsJo-Philipp Wich
When a function is invoked directly, e.g. through uc_vm_invoke(), the call stack is empty, so avoid accessing the first call frame unless we actually need to, which is only the case if the function is invoked with spread args which can only happen with calls from manged code. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: fix handling exceptions in top-level function callsJo-Philipp Wich
When a toplevel function call raises an exception, the call stack will be empty when invoking the exception handler, ensure to handle this case appropriately. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11lib, vm: reimplement exit() as exception typeJo-Philipp Wich
Instead of invoking exit(3) from uc_exit(), use a new EXCEPTION_EXIT exception type to instruct the VM to shutdown cleanly. This is required to not terminate the host program in case libucode is embedded and loaded scripts invoke the exit() function. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: extend API to allow returning result value from VM executionJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: remove module preloading logicJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: add uc_vm_invoke() helperJo-Philipp Wich
The uc_vm_invoke() function simplifies calling a named ucode function with arbitrary arguments. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: cosmetic fix for outputting exceptions without source contextJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: move global scope allocation into uc_vm_init()Jo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11vm: add getter and setter for vm globals scopeJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11treewide: replace a number of unnecessary type castsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-11treewide: move ressource type registry into vm instanceJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-07-08vm: fix potential invalid memory access in uc_vm_get_error_context()Jo-Philipp Wich
If there's only native function calls on the call stack, the code incorrectly accessed an invalid memory location. Avoid that issue by stopping the search for non-native callframes before the last frame. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-06-08vm: add support for I_LE and I_GE instructionsJo-Philipp Wich
Since we need to ensure that NaN values are properly handled, we cannot transform `x <= y` and `x >= y` into `!(x > y)` and `!(x < y)` respectively. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2021-06-08treewide: let uc_cmp() use instruction instead of token numbersJo-Philipp Wich
This allows us to drop some token->instruction mapping case switches in the VM. Signed-off-by: Jo-Philipp Wich <jo@mein.io>