summaryrefslogtreecommitdiffhomepage
path: root/vm.c
AgeCommit message (Collapse)Author
2024-03-13vm: rework `in` operator semanticsJo-Philipp Wich
- Ensure that testing for array membership does strict equality tests - Ensure that `(NaN in [ NaN ]) == true` - Do not perform implicit value conversion when testing for object keys, to avoid nonsensical results such as `([] in { "[ ]": true }) == true` - Add test cases for the `in` operator Fixes: #193 Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2024-02-21vm: rework object iterationJo-Philipp Wich
Ensure that deleting object keys during iteration is safe by keeping a global chain of per-object iterators which are advanced to the next key when the entry that is about to be iterated is deleted. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2023-11-01vm: fix unused result warningJo-Philipp Wich
When building against glibc with enabled source fortification, gcc reports the following issue: .../vm.c: In function ‘uc_vm_signal_raise’: .../vm.c:3161:9: error: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result] 3161 | write(vm->signal.sigpipe[1], &signum, sizeof(signum)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since we cannot do any meaningful handling of a potential write error in the affected signal handler context, simply solve this issue by wrapping the `write()` call into an empty `if ()` statement. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2023-08-09treewide: consolidate platform specific code in platform.cJo-Philipp Wich
Get rid of most __APPLE__ guards by introducing a central platform.c unit providing drop-in replacements for missing APIs. Also move system signal definitions into the new platform file to be able to share them with the upcoming debug library. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2023-07-27vm: introduce basic signal handling infrastructureJo-Philipp Wich
Introduce the basic facilities to implement UNIX process signal handling in ucode. The VM structure is extended by a bitmap keeping track of received signal numbers, a sigaction structure which holds a generic signal handler to update the bitmap, a pipe where the generic signal handler will send received signal numbers to and an array of managed signal handler functions, indexed by signal number. Additionally, three new C API functions are added to control signal delivery in the VM instance: - `uc_vm_signal_dispatch()` This function invokes signal handler callbacks for each received signal number, clears the bitmap and empties the pipe. The VM itself will invoke this function after each executed bytecode instruction. In some cases however it is useful for C code driving the VM to force immediate signal delivery, e.g. from within long running C functions that do not return to ucode (to the next bytecode instruction) in a timely manner. - `uc_vm_signal_raise()` This function will deliver the given signal number, so that it is picked up by the next call to `uc_vm_signal_dispatch()`. It is used by the generic C signal handler function to forward received signals to the VM instance. - `uc_vm_signal_notifyfd()` This functions returns the read end of the internal signal pipe. It is mainly useful for integration into select or poll based event loops, in order to be notified when there's pending signals for delivery into the VM instance. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2023-05-28vm: immediately release arguments on calls with invalid spreadsJo-Philipp Wich
Ensure to release the `this` context and the temporary argument stash when we raise a non iterable type exception due to non-iterable values while precessing spread operations in function call arguments. Those values would've been garbage collected eventually but explicitly releasing them here will allow the vm to free them immediately. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2023-05-27vm: clear vm->alloc_refs in uc_gc_commonFelix Fietkau
This avoids unnecessary gc calls when configuring a gc interval while also explicitly calling ucv_gc from C code embedding a vm at convenient points in time. Signed-off-by: Felix Fietkau <nbd@nbd.name>
2022-11-15compiler: fix `??=`, `||=` and `&&=` logical assignment semanticsJo-Philipp Wich
When compiling logical assignment expressions, ensure that the right hand side of the assignment is not evaluated when the assignment condition is unfulfilled. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-09-30vm: maintain export symbol tables per programJo-Philipp Wich
Instead of having one global export table per VM instance maintain one table per program instance. This is required to avoid clobbering the export list in case `import` using code is loaded at runtime through `require()`, `loadfile()` etc. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-08-12vm: support automatic periodic GC runsJo-Philipp Wich
Introduce two new VM api functions uc_vm_gc_start() and uc_vm_gc_stop() which allow starting and stopping automatic periodic garbage collection of cyclic objects in the VM context. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-08-06vm: introduce new I_DYNLOAD opcodeJo-Philipp Wich
The I_DYNLOAD opcode is basically a bytecode level instruction for uc_require() with semantics similar to I_IMPORT. It allows loading a dynamic extension library at runtime and treating values from the resulting module context object like exports from a compile time source module. For example the statement `import { readfile, writefile } from "fs"` would import the readfile() and writefile() functions of fs.so as readonly live bindings into the current file scope. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-08-06vm: don't treat offset 0 special for exceptionsJo-Philipp Wich
Try to resolve the source offset to line and character position and only fall back to report the location as instruction offset if we weren't able to determine the line number. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-08-05vm: don't initialize upvalues for module functionsJo-Philipp Wich
Module function upvalues are patched through import operations, ensure to leave them uninitialized when loading and executing the module constructor. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2022-07-30vm, cli: move search path into global configuration structureJo-Philipp Wich
The upcoming compile-time module support will require the configured extension search path in the compiler as well, so move it to the already shared uc_parse_config_t structure and add the appropriate utility functions to initialize, append and free the search path vector. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
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>