From 9d5e420540d77779f32117795dd1711768b83a8f Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 13 Jul 2023 12:33:28 +0200 Subject: docs: add information about memory management and operator precedence Signed-off-by: Jo-Philipp Wich --- docs/README.md | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) (limited to 'docs') diff --git a/docs/README.md b/docs/README.md index 660f175..05761f9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -657,3 +657,151 @@ operator which removes a property from an object value. print(a); // { } %} ``` + +##### 5.7. Precedence + +Operator precedence determines the order in which operators are evaluated in an +expression. In ucode, operators have different precedence levels, as outline +in the table below. + +| Precedence | Operator type | Associativity | +|------------|-----------------------------------|----------------| +| 19 | Grouping `( … )` | n/a | +| 18 | Property access `… . …` | left-to-right | +| 18 | Optional chaining `… ?. …` | left-to-right | +| 18 | Computed propery access `… [ … ]` | n/a | +| 18 | Function call `… (…)` | n/a | +| 17 | Postfix increment `… ++` | n/a | +| 17 | Postfix decrement `… --` | n/a | +| 16 | Logical not `! …` | n/a | +| 16 | Bitwise not `~ …` | n/a | +| 16 | Unary plus `+ …` | n/a | +| 16 | Unary negation `- …` | n/a | +| 16 | Prefix increment `++ …` | n/a | +| 16 | Prefix decrement `-- …` | n/a | +| 16 | Property deletion `delete …` | n/a | +| 15 | Exponentiation `… ** …` | right-to-left | +| 14 | Multiplication `… * …` | left-to-right | +| 14 | Division `… / …` | left-to-right | +| 14 | Remainder `… % …` | left-to-right | +| 13 | Addition `… + …` | left-to-right | +| 13 | Substraction `… - …` | left-to-right | +| 12 | Bitwise left shift `… << …` | left-to-right | +| 12 | Bitwise right shift `… >> …` | left-to-right | +| 11 | Less than `… < …` | left-to-right | +| 11 | Less than or equal `… <= …` | left-to-right | +| 11 | Greater than `… > …` | left-to-right | +| 11 | Greater than or equal `… >= …` | left-to-right | +| 11 | In `… in …` | left-to-right | +| 10 | Equality `… == …` | left-to-right | +| 10 | Inequality `… != …` | left-to-right | +| 10 | Strict equality `… === …` | left-to-right | +| 10 | Strict inequality `… !== …` | left-to-right | +| 9 | Bitwise AND `… & …` | left-to-right | +| 8 | Bitwise XOR `… ^ …` | left-to-right | +| 7 | Bitwise OR `… | …` | left-to-right | +| 6 | Logical AND `… && …` | left-to-right | +| 5 | Logical OR `… || …` | left-to-right | +| 5 | Nullish coalescing `… ?? …` | left-to-right | +| 4 | Assignment `… = …` | right-to-left | +| 4 | Assignment `… += …` | right-to-left | +| 4 | Assignment `… -= …` | right-to-left | +| 4 | Assignment `… **= …` | right-to-left | +| 4 | Assignment `… *= …` | right-to-left | +| 4 | Assignment `… /= …` | right-to-left | +| 4 | Assignment `… %= …` | right-to-left | +| 4 | Assignment `… <<= …` | right-to-left | +| 4 | Assignment `… >>= …` | right-to-left | +| 4 | Assignment `… &= …` | right-to-left | +| 4 | Assignment `… ^= …` | right-to-left | +| 4 | Assignment `… |= …` | right-to-left | +| 4 | Assignment `… &&= …` | right-to-left | +| 4 | Assignment `… ||= …` | right-to-left | +| 4 | Assignment `… ??= …` | right-to-left | +| 3 | Ternary `… ? … : …` | right-to-left | +| 2 | Arrow `… => …` | right-to-left | +| 2 | Spread `... …` | n/a | +| 1 | Sequence `… , …` | left-to-right | + +Operators with a higher precedence value are evaluated before operators with a +lower precedence value. When operators have the same precedence, their +associativity determines the order of evaluation +(e.g., left-to-right or right-to-left). + + +## Memory Management + +The ucode scripting language utilizes a reference count-based garbage collector +as its primary method of memory management. When assigning an array or object +value, the reference count is incremented. When a local variable holding a +reference goes out of scope, the reference count is decremented. If the +reference count reaches zero, a recursive traversal is performed to decrease the +reference count of any nested references. Once the traversal is complete, the +top-level array or object structure is freed. + +Example 1: +```javascript +x = [ { a: 1 }, { b: 2 }, { c: 3 } ]; +// `x` holds a reference to `[...]` (refcount 1) +// `x[0]` holds a reference to `{ a: 1 }` (refcount 1) +// `x[1]` holds a reference to `{ b: 2 }` (refcount 1) +// `x[2]` holds a reference to `{ c: 3 }` (refcount 1) + +x = null; +// refcount of `[...]` drops to 0; refcount decreasing cascades +// down, `{ a: 1 }`, `{ b: 2 }` and { c: 3 }` refcounts reach +// zero as well; `{ a: 1 }`, `{ b: 2 }`, `{ c: 3 }` and `[ ... ]` +// are freed +``` + +Example 2: +```javascript +x = [ { a: 1 }, { b: 2 }, { c: 3 } ]; +y = x[1]; +// `x` holds a reference to `[...]` (refcount 1) +// `x[0]` holds a reference to `{ a: 1 }` (refcount 1) +// `x[1]` and `y` hold a reference to `{ b: 2 }` (refcount 2) +// `x[2]` holds a reference to `{ c: 3 }` (refcount 1) + +x = null; +// refcount of `[...]` drops to 0, refcount decreasing cascades +// down, `{ a: 1 }` and `{ c: 3 }` refcounts reach zero while +// `{ b: 2 }` refcount is down to one. +// `{ a: 1 }`, `{ c: 3 }` and `[ ... ]` are freed +// `{ b: 2 }` is still alive with refcount 1, pointed to by `y` +``` + +Although the reference count-based garbage collector efficiently manages memory, +it cannot handle cyclic structures, leading to memory leaks. + +Example 1: +```javascript +o = { }; o.x = o; +// `o` holds a reference to itself (refcount 1) + +``` + +Example 2: +```javascript +a = [ ]; a[0] = a; +// `a` holds a reference to itself (refcount 1) +``` + +Example 3: +```javascript +x = { y: { z: [ ] } }; x.y.z = x; +// `x` holds a reference to itself through `x.y.z` (refcount 1) +``` + +In these examples, cyclic references are created where objects or arrays point +back to themselves or create a circular chain. Since each element within the +cycle maintains a reference, the reference count for each object or array never +reaches zero, resulting in a memory leak. The reference count-based garbage +collector cannot automatically reclaim memory in such cases. + +To address cyclic structures and avoid memory leaks, ucode provides a secondary +mark-and-sweep garbage collector. This collector can be enabled by passing the +`-g` flag to the ucode interpreter or manually triggered using the +[`gc()`](/module-core.html#gc) function during runtime. The mark-and-sweep +collector identifies and frees unreachable objects, including those involved in +cyclic references. -- cgit v1.2.3