backward inference

This commit is contained in:
2026-02-13 05:39:25 -06:00
parent 1df6553577
commit bf5fdbc688
17 changed files with 73758 additions and 71129 deletions

View File

@@ -27,7 +27,8 @@ Splits source text into tokens. Handles string interpolation by re-tokenizing te
Converts tokens into an AST. Also performs semantic analysis:
- **Scope records**: For each scope (global, function), builds a record mapping variable names to their metadata: `make` (var/def/function/input), `function_nr`, `nr_uses`, `closure` flag, and `level`.
- **Type tags**: When the right-hand side of a `def` is a syntactically obvious type, stamps `type_tag` on the scope record entry. Derivable types: `"integer"`, `"number"`, `"text"`, `"array"`, `"record"`, `"function"`, `"logical"`, `"null"`.
- **Type tags**: When the right-hand side of a `def` is a syntactically obvious type, stamps `type_tag` on the scope record entry. Derivable types: `"integer"`, `"number"`, `"text"`, `"array"`, `"record"`, `"function"`, `"logical"`. For `def` variables, type tags are also inferred from usage patterns: push (`x[] = v`) implies array, property access (`x.foo = v`) implies record, integer key implies array, text key implies record.
- **Type error detection**: For `def` variables with known type tags, provably wrong operations are reported as compile errors: property access on arrays, push on non-arrays, text keys on arrays, integer keys on records. Only `def` variables are checked because `var` can be reassigned.
- **Intrinsic resolution**: Names used but not locally bound are recorded in `ast.intrinsics`. Name nodes referencing intrinsics get `intrinsic: true`.
- **Access kind**: Subscript (`[`) nodes get `access_kind`: `"index"` for numeric subscripts, `"field"` for string subscripts, omitted otherwise.
- **Tail position**: Return statements where the expression is a call get `tail: true`.
@@ -40,8 +41,8 @@ Operates on the AST. Performs constant folding and type analysis:
- **Constant propagation**: Tracks `def` bindings whose values are known constants.
- **Type propagation**: Extends `type_tag` through operations. When both operands of an arithmetic op have known types, the result type is known. Propagates type tags to reference sites.
- **Intrinsic specialization**: When an intrinsic call's argument types are known, stamps a `hint` on the call node. For example, `length(x)` where x is a known array gets `hint: "array_length"`. Type checks like `is_array(known_array)` are folded to `true`.
- **Purity marking**: Stamps `pure: true` on expressions with no side effects (literals, name references, arithmetic on pure operands).
- **Dead code elimination**: Removes unreachable branches when conditions are known constants.
- **Purity analysis**: Expressions with no side effects are marked pure (literals, name references, arithmetic on pure operands, calls to pure intrinsics). The pure intrinsic set contains only `is_*` sensory functions — they are the only intrinsics guaranteed to never disrupt regardless of argument types. Other intrinsics like `text`, `number`, and `length` can disrupt on wrong argument types and are excluded.
- **Dead code elimination**: Removes unreachable branches when conditions are known constants. Removes unused `var`/`def` declarations with pure initializers. Removes standalone calls to pure intrinsics where the result is discarded.
### Mcode (`mcode.cm`)
@@ -51,6 +52,8 @@ Lowers the AST to a JSON-based intermediate representation with explicit operati
- **Decomposed calls**: Function calls are split into `frame` (create call frame) + `setarg` (set arguments) + `invoke` (execute call).
- **Intrinsic access**: Intrinsic functions are loaded via `access` with an intrinsic marker rather than global lookup.
- **Intrinsic inlining**: Type-check intrinsics (`is_array`, `is_text`, `is_number`, `is_integer`, `is_logical`, `is_null`, `is_function`, `is_object`, `is_stone`), `length`, and `push` are emitted as direct opcodes instead of frame/setarg/invoke call sequences.
- **Disruption handler labels**: When a function has a disruption handler, a label is emitted before the handler code. This allows the streamline optimizer's unreachable code elimination to safely nop dead code after `return` without accidentally eliminating the handler.
- **Tail call marking**: When a return statement's expression is a call and the function has no disruption handler, the final `invoke` is renamed to `tail_invoke`. This marks the call site for future tail call optimization. Functions with disruption handlers cannot use TCO because the handler frame must remain on the stack.
See [Mcode IR](mcode.md) for the instruction format and complete instruction reference.
@@ -58,12 +61,13 @@ See [Mcode IR](mcode.md) for the instruction format and complete instruction ref
Optimizes the Mcode IR through a series of independent passes. Operates per-function:
1. **Backward type inference**: Infers parameter types from how they are used in typed operators. Immutable `def` parameters keep their inferred type across label join points.
1. **Backward type inference**: Infers parameter types from how they are used in typed operators (`add_int`, `store_index`, `load_field`, `push`, `pop`, etc.). Immutable `def` parameters keep their inferred type across label join points.
2. **Type-check elimination**: When a slot's type is known, eliminates `is_<type>` + conditional jump pairs. Narrows `load_dynamic`/`store_dynamic` to typed variants.
3. **Algebraic simplification**: Rewrites identity operations (add 0, multiply 1, divide 1) and folds same-slot comparisons.
4. **Boolean simplification**: Fuses `not` + conditional jump into a single jump with inverted condition.
5. **Move elimination**: Removes self-moves (`move a, a`).
6. **Dead jump elimination**: Removes jumps to the immediately following label.
6. **Unreachable elimination**: Nops dead code after `return` until the next label.
7. **Dead jump elimination**: Removes jumps to the immediately following label.
See [Streamline Optimizer](streamline.md) for detailed pass descriptions.

View File

@@ -53,6 +53,10 @@ Backward inference rules:
| `store_index` (index operand) | T_INT |
| `store_field` (object operand) | T_RECORD |
| `push` (array operand) | T_ARRAY |
| `load_index` (object operand) | T_ARRAY |
| `load_index` (index operand) | T_INT |
| `load_field` (object operand) | T_RECORD |
| `pop` (array operand) | T_ARRAY |
When a slot appears with conflicting type inferences (e.g., used in both `add_int` and `concat` across different type-dispatch branches), the result is `unknown`. INT + FLOAT conflicts produce `num`.
@@ -127,11 +131,11 @@ Removes `move a, a` instructions where the source and destination are the same s
**Nop prefix:** `_nop_mv_`
### 6. eliminate_unreachable (dead code after return/disrupt)
### 6. eliminate_unreachable (dead code after return)
*Currently disabled.* Nops instructions after `return` or `disrupt` until the next real label.
Nops instructions after `return` until the next real label. Only `return` is treated as a terminal instruction; `disrupt` is not, because the disruption handler code immediately follows `disrupt` and must remain reachable.
Disabled because disruption handler code is placed after the `return`/`disrupt` instruction without a label boundary. The VM dispatches to handlers via the `disruption_pc` offset, not through normal control flow. Re-enabling this pass requires the mcode compiler to emit labels at disruption handler entry points.
The mcode compiler emits a label at disruption handler entry points (see `emit_label(gen_label("disruption"))` in mcode.cm), which provides the label boundary that stops this pass from eliminating handler code.
**Nop prefix:** `_nop_ur_`
@@ -151,7 +155,7 @@ eliminate_type_checks → uses param_types
simplify_algebra
simplify_booleans
eliminate_moves
(eliminate_unreachable) → disabled
eliminate_unreachable
eliminate_dead_jumps
```
@@ -192,6 +196,106 @@ Usage:
./cell --core . dump_types.cm <file.ce|file.cm>
```
## Tail Call Marking
When a function's return expression is a call (`stmt.tail == true` from the parser) and the function has no disruption handler, mcode.cm renames the final `invoke` instruction to `tail_invoke`. This is semantically identical to `invoke` in the current Mach VM, but marks the call site for future tail call optimization.
The disruption handler restriction exists because TCO would discard the current frame, but the handler must remain on the stack to catch disruptions from the callee.
`tail_invoke` is handled by the same passes as `invoke` in streamline (type tracking, algebraic simplification) and executes identically in the VM.
## Type Propagation Architecture
Type information flows through three compilation stages, each building on the previous:
### Stage 1: Parse-time type tags (parse.cm)
The parser assigns `type_tag` strings to scope variable entries when the type is syntactically obvious:
- **From initializers**: `def a = []``type_tag: "array"`, `def n = 42``type_tag: "integer"`, `def r = {}``type_tag: "record"`
- **From usage patterns** (def only): `def x = null; x[] = v` infers `type_tag: "array"` from the push. `def x = null; x.foo = v` infers `type_tag: "record"` from property access.
- **Type error detection** (def only): When a `def` variable has a known type_tag, provably wrong operations are compile errors:
- Property access (`.`) on array
- Push (`[]`) on non-array
- Text key on array
- Integer key on record
Only `def` (constant) variables participate in type inference and error detection. `var` variables can be reassigned, making their initializer type unreliable.
### Stage 2: Fold-time type propagation (fold.cm)
The fold pass extends type information through the AST:
- **Intrinsic folding**: `is_array(known_array)` folds to `true`. `length(known_array)` gets `hint: "array_length"`.
- **Purity analysis**: Expressions involving only `is_*` intrinsic calls with pure arguments are considered pure. This enables dead code elimination for unused `var`/`def` bindings with pure initializers, and elimination of standalone pure call statements.
- **Dead code**: Unused pure `var`/`def` declarations are removed. Standalone calls to pure intrinsics (where the result is discarded) are removed. Unreachable branches with constant conditions are removed.
The `pure_intrinsics` set currently contains only `is_*` sensory functions (`is_array`, `is_text`, `is_number`, `is_integer`, `is_function`, `is_logical`, `is_null`, `is_object`, `is_stone`). Other intrinsics like `text`, `number`, and `length` can disrupt on wrong argument types, so they are excluded — removing a call that would disrupt changes observable behavior.
### Stage 3: Streamline-time type tracking (streamline.cm)
The streamline optimizer uses a numeric type lattice (`T_INT`, `T_FLOAT`, `T_TEXT`, etc.) for fine-grained per-instruction tracking:
- **Backward inference** (pass 1): Scans typed operators to infer parameter types. Since parameters are `def` (immutable), inferred types persist across label boundaries.
- **Forward tracking** (pass 2): `track_types` follows instruction execution order, tracking the type of each slot. Typed arithmetic results set their destination type. Type checks on unknown slots narrow the type on fallthrough.
- **Type check elimination** (pass 2): When a slot's type is already known, `is_<type>` + conditional jump pairs are eliminated or converted to unconditional jumps.
- **Dynamic access narrowing** (pass 2): `load_dynamic`/`store_dynamic` are narrowed to `load_field`/`store_field` or `load_index`/`store_index` when the key type is known.
Type information resets at label join points (since control flow merges could bring different types), except for parameter types from backward inference.
## Future Work
### Copy Propagation
A basic-block-local copy propagation pass would replace uses of a copied variable with its source, enabling further move elimination. An implementation was attempted but encountered an unsolved bug where 2-position instruction operand replacement produces incorrect code during self-hosting (the replacement logic for 3-position instructions works correctly). The root cause is not yet understood. See the project memory files for detailed notes.
### Expanded Purity Analysis
The current purity set is conservative (only `is_*`). It could be expanded by:
- **Argument-type-aware purity**: If all arguments to an intrinsic are known to be the correct types (via type_tag or slot_types), the call cannot disrupt and is safe to eliminate. For example, `length(known_array)` is pure but `length(unknown)` is not.
- **User function purity**: Analyze user-defined function bodies during pre_scan. A function is pure if its body contains only pure expressions and calls to known-pure functions. This requires fixpoint iteration for mutual recursion.
- **Callback-aware purity**: Intrinsics like `filter`, `find`, `reduce`, `some`, `every` are pure if their callback argument is pure.
### Forward Type Narrowing from Typed Operations
After a typed operation like `add_int dest, a, b` executes successfully, we know `a` and `b` are integers. This could be used to eliminate subsequent type checks on the same slots within a basic block. An implementation was attempted but caused intermittent GC crashes during self-hosting, suggesting the type narrowing interacted badly with the runtime's garbage collector (possibly through changed instruction timing or register pressure). The approach is sound in principle but needs careful investigation of the GC interaction.
### Guard Hoisting for Parameters
When a type check on a parameter passes (falls through), the parameter's type could be promoted to `param_types` so it persists across label boundaries. This would allow the first type check on a parameter to prove its type for the entire function. However, this is unsound for polymorphic parameters — if a function is called with different argument types, the first check would wrongly eliminate checks for subsequent types.
A safe version would require proving that a parameter is monomorphic (called with only one type across all call sites), which requires interprocedural analysis.
### Tail Call Optimization
`tail_invoke` instructions are currently marked but execute identically to `invoke`. Actual TCO would reuse the current call frame instead of creating a new one. This requires:
- Ensuring argument count matches (or the frame can be resized)
- No live locals needed after the call (guaranteed by tail position)
- No disruption handler on the current function (already enforced by the marking)
- VM support in mach.c to rewrite the frame in place
### Interprocedural Type Inference
Currently all type inference is intraprocedural (within a single function). Cross-function analysis could:
- Infer return types from function bodies
- Propagate argument types from call sites to callees
- Specialize functions for known argument types (cloning)
### Strength Reduction
Common patterns that could be lowered to cheaper operations:
- `mul_int x, 2``add_int x, x` (shift left)
- `div_int x, 2` → arithmetic shift right
- `mod_int x, power_of_2` → bitwise and
### Loop-Invariant Code Motion
Type checks that are invariant across loop iterations (checking a variable that doesn't change in the loop body) could be hoisted above the loop. This would require identifying loop boundaries and proving invariance.
## Nop Convention
Eliminated instructions are replaced with strings matching `_nop_<prefix>_<counter>`. The prefix identifies which pass created the nop. Nop strings are:

23
fold.cm
View File

@@ -15,10 +15,18 @@ var fold = function(ast) {
return k == "number" || k == "text" || k == "true" || k == "false" || k == "null"
}
// Only intrinsics that can NEVER disrupt regardless of argument types
var pure_intrinsics = {
is_array: true, is_text: true, is_number: true, is_integer: true,
is_function: true, is_logical: true, is_null: true, is_object: true,
is_stone: true
}
var is_pure = function(expr) {
if (expr == null) return true
var k = expr.kind
var i = 0
var target = null
if (k == "number" || k == "text" || k == "true" || k == "false" ||
k == "null" || k == "name" || k == "this") return true
if (k == "function") return true
@@ -47,6 +55,17 @@ var fold = function(ast) {
if (k == "==" || k == "!=" || k == "&&" || k == "||") {
return is_pure(expr.left) && is_pure(expr.right)
}
if (k == "(") {
target = expr.expression
if (target != null && target.intrinsic == true && pure_intrinsics[target.name] == true) {
i = 0
while (i < length(expr.list)) {
if (!is_pure(expr.list[i])) return false
i = i + 1
}
return true
}
}
return false
}
@@ -676,6 +695,10 @@ var fold = function(ast) {
}
}
}
// Dead pure call elimination: standalone pure calls with no result
if (stmt.kind == "call" && is_pure(stmt.expression)) {
stmt.dead = true
}
// Dead function elimination
if (stmt.kind == "function" && stmt.name != null) {
sv = scope_var(fn_nr, stmt.name)

File diff suppressed because it is too large Load Diff

View File

@@ -55,10 +55,10 @@
["null", 13, 7, 10],
["setarg", 12, 0, 13, 7, 10],
["setarg", 12, 1, 7, 7, 10],
["invoke", 12, 10, 7, 10],
["tail_invoke", 12, 10, 7, 10],
["return", 10, 7, 10],
["null", 14, 7, 10],
["return", 14, 7, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "use_embed",
"filename": "internal/bootstrap.cm",
@@ -75,7 +75,7 @@
["get", 5, 20, 1, 21, 12],
["load_dynamic", 6, 5, 1, 21, 22],
["return", 6, 21, 22],
["jump", "if_end_9", 21, 22],
"_nop_ur_1",
"if_else_8",
"if_end_9",
["access", 7, "/", 22, 40],
@@ -108,8 +108,8 @@
["get", 17, 20, 1, 23, 3],
["store_dynamic", 17, 2, 1, 23, 13],
["return", 2, 24, 10],
["null", 18, 24, 10],
["return", 18, 24, 10]
"_nop_ur_2",
"_nop_ur_3"
],
"name": "use_basic",
"filename": "internal/bootstrap.cm",
@@ -338,9 +338,9 @@
["setarg", 51, 0, 52, 35, 12],
["setarg", 51, 1, 3, 35, 12],
["setarg", 51, 2, 2, 35, 12],
["invoke", 51, 49, 35, 12],
["tail_invoke", 51, 49, 35, 12],
["return", 49, 35, 12],
["jump", "if_end_35", 35, 12],
"_nop_ur_1",
"if_else_34",
"if_end_35",
["get", 54, 14, 1, 37, 7],
@@ -418,9 +418,9 @@
["setarg", 77, 1, 1, 39, 12],
["setarg", 77, 2, 5, 39, 12],
["setarg", 77, 3, 2, 39, 12],
["invoke", 77, 75, 39, 12],
["tail_invoke", 77, 75, 39, 12],
["return", 75, 39, 12],
["jump", "if_end_41", 39, 12],
"_nop_ur_2",
"if_else_40",
"if_end_41",
["access", 79, "error: missing bootstrap bytecode: ", 41, 9],
@@ -1591,8 +1591,8 @@
["invoke", 95, 93, 139, 9],
["move", 11, 93, 139, 9],
["return", 11, 140, 10],
["null", 97, 140, 10],
["return", 97, 140, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "analyze",
"filename": "internal/bootstrap.cm",
@@ -1826,9 +1826,9 @@
["setarg", 56, 0, 57, 156, 12],
["setarg", 56, 1, 6, 156, 12],
["setarg", 56, 2, 2, 156, 12],
["invoke", 56, 54, 156, 12],
["tail_invoke", 56, 54, 156, 12],
["return", 54, 156, 12],
["jump", "if_end_230", 156, 12],
"_nop_ur_1",
"if_else_229",
"if_end_230",
["get", 59, 14, 1, 158, 7],
@@ -1906,9 +1906,9 @@
["setarg", 82, 1, 1, 160, 12],
["setarg", 82, 2, 9, 160, 12],
["setarg", 82, 3, 2, 160, 12],
["invoke", 82, 80, 160, 12],
["tail_invoke", 82, 80, 160, 12],
["return", 80, 160, 12],
["jump", "if_end_236", 160, 12],
"_nop_ur_2",
"if_else_235",
"if_end_236",
[
@@ -2086,10 +2086,10 @@
["setarg", 132, 1, 1, 167, 10],
["setarg", 132, 2, 121, 167, 10],
["setarg", 132, 3, 2, 167, 10],
["invoke", 132, 130, 167, 10],
["tail_invoke", 132, 130, 167, 10],
["return", 130, 167, 10],
["null", 134, 167, 10],
["return", 134, 167, 10]
"_nop_ur_3",
"_nop_ur_4"
],
"name": "load_module",
"filename": "internal/bootstrap.cm",
@@ -2231,10 +2231,10 @@
["setarg", 42, 1, 1, 193, 10],
["setarg", 42, 2, 31, 193, 10],
["setarg", 42, 3, 3, 193, 10],
["invoke", 42, 40, 193, 10],
["tail_invoke", 42, 40, 193, 10],
["return", 40, 193, 10],
["null", 44, 193, 10],
["return", 44, 193, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "run_ast",
"filename": "internal/bootstrap.cm",
@@ -2289,10 +2289,10 @@
["setarg", 20, 1, 1, 199, 10],
["setarg", 20, 2, 9, 199, 10],
["setarg", 20, 3, 3, 199, 10],
["invoke", 20, 18, 199, 10],
["tail_invoke", 20, 18, 199, 10],
["return", 18, 199, 10],
["null", 22, 199, 10],
["return", 22, 199, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "run_ast_noopt",
"filename": "internal/bootstrap.cm",
@@ -2317,7 +2317,7 @@
["get", 12, 20, 1, 213, 12],
["load_dynamic", 13, 12, 1, 213, 22],
["return", 13, 213, 22],
["jump", "if_end_274", 213, 22],
"_nop_ur_1",
"if_else_273",
"if_end_274",
["access", 14, ".cm.mach", 216, 22],
@@ -2513,7 +2513,7 @@
["get", 64, 20, 1, 222, 5],
["store_dynamic", 64, 3, 1, 222, 15],
["return", 3, 223, 12],
["jump", "if_end_296", 223, 12],
"_nop_ur_2",
"if_else_295",
"if_end_296",
["access", 65, ".cm.mcode", 227, 23],
@@ -2726,7 +2726,7 @@
["get", 119, 20, 1, 233, 5],
["store_dynamic", 119, 3, 1, 233, 15],
["return", 3, 234, 12],
["jump", "if_end_322", 234, 12],
"_nop_ur_3",
"if_else_321",
"if_end_322",
["access", 120, ".cm", 238, 22],
@@ -2937,7 +2937,7 @@
["get", 178, 20, 1, 246, 5],
["store_dynamic", 178, 3, 1, 246, 15],
["return", 3, 247, 12],
["jump", "if_end_348", 247, 12],
"_nop_ur_4",
"if_else_347",
"if_end_348",
["access", 179, "/", 251, 36],
@@ -2970,8 +2970,8 @@
["get", 189, 20, 1, 252, 3],
["store_dynamic", 189, 3, 1, 252, 13],
["return", 3, 253, 10],
["null", 190, 253, 10],
["return", 190, 253, 10]
"_nop_ur_5",
"_nop_ur_6"
],
"name": "use_fn",
"filename": "internal/bootstrap.cm",
@@ -3112,9 +3112,9 @@
["setarg", 38, 0, 39, 266, 12],
["setarg", 38, 1, 2, 266, 12],
["setarg", 38, 2, 1, 266, 12],
["invoke", 38, 36, 266, 12],
["tail_invoke", 38, 36, 266, 12],
["return", 36, 266, 12],
["jump", "if_end_362", 266, 12],
"_nop_ur_1",
"if_else_361",
"if_end_362",
["get", 41, 14, 1, 268, 7],
@@ -3193,9 +3193,9 @@
["setarg", 65, 1, 62, 270, 12],
["setarg", 65, 2, 6, 270, 12],
["setarg", 65, 3, 1, 270, 12],
["invoke", 65, 63, 270, 12],
["tail_invoke", 65, 63, 270, 12],
["return", 63, 270, 12],
["jump", "if_end_368", 270, 12],
"_nop_ur_2",
"if_else_367",
"if_end_368",
[
@@ -3285,10 +3285,10 @@
["setarg", 92, 1, 89, 275, 10],
["setarg", 92, 2, 5, 275, 10],
["setarg", 92, 3, 1, 275, 10],
["invoke", 92, 90, 275, 10],
["tail_invoke", 92, 90, 275, 10],
["return", 90, 275, 10],
["null", 94, 275, 10],
["return", 94, 275, 10]
"_nop_ur_3",
"_nop_ur_4"
],
"name": "load_engine",
"filename": "internal/bootstrap.cm",

File diff suppressed because it is too large Load Diff

View File

@@ -52,6 +52,7 @@ var mcode = function(ast) {
var s_cur_line = 0
var s_cur_col = 0
var s_filename = null
var s_has_disruption = false
// Shared closure vars for binop helpers (avoids >4 param functions)
var _bp_dest = 0
@@ -78,7 +79,8 @@ var mcode = function(ast) {
function_nr: s_function_nr,
intrinsic_cache: s_intrinsic_cache,
cur_line: s_cur_line,
cur_col: s_cur_col
cur_col: s_cur_col,
has_disruption: s_has_disruption
}
}
@@ -99,6 +101,7 @@ var mcode = function(ast) {
s_intrinsic_cache = saved.intrinsic_cache
s_cur_line = saved.cur_line
s_cur_col = saved.cur_col
s_has_disruption = saved.has_disruption
}
// Slot allocation
@@ -2230,6 +2233,7 @@ var mcode = function(ast) {
var guard_t = 0
var guard_err = null
var guard_done = null
var last_instr = null
if (stmt == null) {
return null
@@ -2436,6 +2440,13 @@ var mcode = function(ast) {
expr = stmt.expression
if (expr != null) {
slot = gen_expr(expr, -1)
// Mark tail calls: rename last invoke to tail_invoke
if (stmt.tail == true && !s_has_disruption) {
last_instr = s_instructions[length(s_instructions) - 1]
if (is_array(last_instr) && last_instr[0] == "invoke") {
last_instr[0] = "tail_invoke"
}
}
emit_1("return", slot)
} else {
null_slot = alloc_slot()
@@ -2618,6 +2629,7 @@ var mcode = function(ast) {
s_label_map = {}
s_is_arrow = is_arrow
s_has_disruption = disrupt_clause != null && is_array(disrupt_clause)
s_function_nr = fn_nr_node != null ? fn_nr_node : 0
@@ -2726,6 +2738,7 @@ var mcode = function(ast) {
// Compile disruption clause
if (disrupt_clause != null && is_array(disrupt_clause)) {
emit_label(gen_label("disruption"))
disruption_start = length(s_instructions)
_i = 0
while (_i < length(disrupt_clause)) {

File diff suppressed because it is too large Load Diff

View File

@@ -1616,6 +1616,46 @@ var parse = function(tokens, src, filename, tokenizer) {
if (kind == "[" && left_node.right != null) {
sem_check_expr(scope, left_node.right)
}
// Type error detection for known-type constant objects
if (obj_expr != null && obj_expr.kind == "name" && obj_expr.name != null) {
v = sem_find_var(scope, obj_expr.name)
if (v != null && v.is_const && v.type_tag != null) {
if (kind == ".") {
if (v.type_tag == "array") {
sem_error(left_node, "cannot set property on array '" + obj_expr.name + "'")
}
} else if (kind == "[") {
if (left_node.right == null) {
// Push: a[] = val
if (v.type_tag != "array") {
sem_error(left_node, "push only works on arrays, not " + v.type_tag + " '" + obj_expr.name + "'")
}
} else if (v.type_tag == "array") {
if (left_node.right.kind == "text") {
sem_error(left_node, "cannot use text key on array '" + obj_expr.name + "'")
}
} else if (v.type_tag == "record") {
if (left_node.right.kind == "number" && is_integer(left_node.right.number)) {
sem_error(left_node, "cannot use integer key on record '" + obj_expr.name + "'; use text key")
}
}
}
} else if (v != null && v.is_const && v.type_tag == null) {
// Infer type_tag from usage pattern (def only)
if (kind == ".") {
v.type_tag = "record"
} else if (kind == "[") {
if (left_node.right == null) {
// Push: a[] = val → array
v.type_tag = "array"
} else if (left_node.right.kind == "number" && is_integer(left_node.right.number)) {
v.type_tag = "array"
} else if (left_node.right.kind == "text") {
v.type_tag = "record"
}
}
}
}
}
}
@@ -1861,7 +1901,7 @@ var parse = function(tokens, src, filename, tokenizer) {
sem_check_expr(scope, stmt.right)
if (name != null) {
tt = derive_type_tag(stmt.right)
if (tt != null) {
if (tt != null && tt != "null") {
existing = sem_find_var(scope, name)
if (existing != null) existing.type_tag = tt
}

File diff suppressed because it is too large Load Diff

View File

@@ -30,8 +30,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -73,8 +73,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -109,8 +109,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -145,8 +145,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -181,8 +181,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -217,8 +217,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -253,8 +253,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -329,8 +329,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -365,8 +365,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -401,8 +401,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -435,8 +435,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -495,8 +495,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -581,8 +581,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -617,8 +617,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -655,8 +655,8 @@
["setarg", 7, 2, 3, 1, 1],
["invoke", 7, 6, 1, 1],
["return", 6, 1, 1],
["null", 9, 1, 1],
["return", 9, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -690,8 +690,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -803,8 +803,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -899,8 +899,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -995,8 +995,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1105,8 +1105,8 @@
["setarg", 10, 2, 6, 1, 1],
["invoke", 10, 9, 1, 1],
["return", 9, 1, 1],
["null", 12, 1, 1],
["return", 12, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1194,8 +1194,8 @@
["setarg", 10, 2, 6, 1, 1],
["invoke", 10, 9, 1, 1],
["return", 9, 1, 1],
["null", 12, 1, 1],
["return", 12, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1403,8 +1403,8 @@
["setarg", 32, 2, 28, 1, 1],
["invoke", 32, 31, 1, 1],
["return", 31, 1, 1],
["null", 34, 1, 1],
["return", 34, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1435,10 +1435,10 @@
["setarg", 13, 2, 2, 496, 10],
["setarg", 13, 3, 3, 496, 10],
["setarg", 13, 4, 4, 496, 10],
["invoke", 13, 11, 496, 10],
["tail_invoke", 13, 11, 496, 10],
["return", 11, 496, 10],
["null", 15, 496, 10],
["return", 15, 496, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1469,10 +1469,10 @@
["setarg", 13, 2, 2, 501, 10],
["setarg", 13, 3, 3, 501, 10],
["setarg", 13, 4, 4, 501, 10],
["invoke", 13, 11, 501, 10],
["tail_invoke", 13, 11, 501, 10],
["return", 11, 501, 10],
["null", 15, 501, 10],
["return", 15, 501, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1503,10 +1503,10 @@
["setarg", 13, 2, 2, 506, 10],
["setarg", 13, 3, 3, 506, 10],
["setarg", 13, 4, 4, 506, 10],
["invoke", 13, 11, 506, 10],
["tail_invoke", 13, 11, 506, 10],
["return", 11, 506, 10],
["null", 15, 506, 10],
["return", 15, 506, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1537,10 +1537,10 @@
["setarg", 13, 2, 2, 511, 10],
["setarg", 13, 3, 3, 511, 10],
["setarg", 13, 4, 4, 511, 10],
["invoke", 13, 11, 511, 10],
["tail_invoke", 13, 11, 511, 10],
["return", 11, 511, 10],
["null", 15, 511, 10],
["return", 15, 511, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1571,10 +1571,10 @@
["setarg", 13, 2, 2, 516, 10],
["setarg", 13, 3, 3, 516, 10],
["setarg", 13, 4, 4, 516, 10],
["invoke", 13, 11, 516, 10],
["tail_invoke", 13, 11, 516, 10],
["return", 11, 516, 10],
["null", 15, 516, 10],
["return", 15, 516, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1671,8 +1671,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1745,8 +1745,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1819,8 +1819,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1862,8 +1862,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1919,8 +1919,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -1999,8 +1999,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2021,10 +2021,10 @@
["setarg", 8, 2, 2, 672, 10],
["setarg", 8, 3, 3, 672, 10],
["setarg", 8, 4, 4, 672, 10],
["invoke", 8, 6, 672, 10],
["tail_invoke", 8, 6, 672, 10],
["return", 6, 672, 10],
["null", 10, 672, 10],
["return", 10, 672, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2045,10 +2045,10 @@
["setarg", 8, 2, 2, 677, 10],
["setarg", 8, 3, 3, 677, 10],
["setarg", 8, 4, 4, 677, 10],
["invoke", 8, 6, 677, 10],
["tail_invoke", 8, 6, 677, 10],
["return", 6, 677, 10],
["null", 10, 677, 10],
["return", 10, 677, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2069,10 +2069,10 @@
["setarg", 8, 2, 2, 682, 10],
["setarg", 8, 3, 3, 682, 10],
["setarg", 8, 4, 4, 682, 10],
["invoke", 8, 6, 682, 10],
["tail_invoke", 8, 6, 682, 10],
["return", 6, 682, 10],
["null", 10, 682, 10],
["return", 10, 682, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2153,8 +2153,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2175,10 +2175,10 @@
["setarg", 8, 2, 2, 717, 10],
["setarg", 8, 3, 3, 717, 10],
["setarg", 8, 4, 4, 717, 10],
["invoke", 8, 6, 717, 10],
["tail_invoke", 8, 6, 717, 10],
["return", 6, 717, 10],
["null", 10, 717, 10],
["return", 10, 717, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2199,10 +2199,10 @@
["setarg", 8, 2, 2, 722, 10],
["setarg", 8, 3, 3, 722, 10],
["setarg", 8, 4, 4, 722, 10],
["invoke", 8, 6, 722, 10],
["tail_invoke", 8, 6, 722, 10],
["return", 6, 722, 10],
["null", 10, 722, 10],
["return", 10, 722, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2223,10 +2223,10 @@
["setarg", 8, 2, 2, 727, 10],
["setarg", 8, 3, 3, 727, 10],
["setarg", 8, 4, 4, 727, 10],
["invoke", 8, 6, 727, 10],
["tail_invoke", 8, 6, 727, 10],
["return", 6, 727, 10],
["null", 10, 727, 10],
["return", 10, 727, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2293,8 +2293,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2361,8 +2361,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2429,8 +2429,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2511,8 +2511,8 @@
["setarg", 10, 2, 6, 1, 1],
["invoke", 10, 9, 1, 1],
["return", 9, 1, 1],
["null", 12, 1, 1],
["return", 12, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2572,8 +2572,8 @@
["setarg", 10, 2, 6, 1, 1],
["invoke", 10, 9, 1, 1],
["return", 9, 1, 1],
["null", 12, 1, 1],
["return", 12, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2632,8 +2632,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2668,8 +2668,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2704,8 +2704,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2740,8 +2740,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2776,8 +2776,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2812,8 +2812,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2847,8 +2847,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2883,8 +2883,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2933,8 +2933,8 @@
["setarg", 9, 2, 5, 1, 1],
["invoke", 9, 8, 1, 1],
["return", 8, 1, 1],
["null", 11, 1, 1],
["return", 11, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2954,10 +2954,10 @@
["setarg", 8, 2, 3, 915, 46],
["setarg", 8, 3, 4, 915, 46],
["setarg", 8, 4, 5, 915, 46],
["invoke", 8, 6, 915, 46],
["tail_invoke", 8, 6, 915, 46],
["return", 6, 915, 46],
["null", 10, 915, 46],
["return", 10, 915, 46]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -2977,10 +2977,10 @@
["setarg", 8, 2, 3, 916, 46],
["setarg", 8, 3, 4, 916, 46],
["setarg", 8, 4, 5, 916, 46],
["invoke", 8, 6, 916, 46],
["tail_invoke", 8, 6, 916, 46],
["return", 6, 916, 46],
["null", 10, 916, 46],
["return", 10, 916, 46]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3000,10 +3000,10 @@
["setarg", 8, 2, 3, 917, 46],
["setarg", 8, 3, 4, 917, 46],
["setarg", 8, 4, 5, 917, 46],
["invoke", 8, 6, 917, 46],
["tail_invoke", 8, 6, 917, 46],
["return", 6, 917, 46],
["null", 10, 917, 46],
["return", 10, 917, 46]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3023,10 +3023,10 @@
["setarg", 8, 2, 3, 918, 46],
["setarg", 8, 3, 4, 918, 46],
["setarg", 8, 4, 5, 918, 46],
["invoke", 8, 6, 918, 46],
["tail_invoke", 8, 6, 918, 46],
["return", 6, 918, 46],
["null", 10, 918, 46],
["return", 10, 918, 46]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3046,10 +3046,10 @@
["setarg", 8, 2, 3, 919, 46],
["setarg", 8, 3, 4, 919, 46],
["setarg", 8, 4, 5, 919, 46],
["invoke", 8, 6, 919, 46],
["tail_invoke", 8, 6, 919, 46],
["return", 6, 919, 46],
["null", 10, 919, 46],
["return", 10, 919, 46]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3069,10 +3069,10 @@
["setarg", 8, 2, 3, 920, 46],
["setarg", 8, 3, 4, 920, 46],
["setarg", 8, 4, 5, 920, 46],
["invoke", 8, 6, 920, 46],
["tail_invoke", 8, 6, 920, 46],
["return", 6, 920, 46],
["null", 10, 920, 46],
["return", 10, 920, 46]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3116,8 +3116,8 @@
["setarg", 11, 2, 7, 1, 1],
["invoke", 11, 10, 1, 1],
["return", 10, 1, 1],
["null", 13, 1, 1],
["return", 13, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3138,10 +3138,10 @@
["setarg", 8, 2, 2, 933, 58],
["setarg", 8, 3, 3, 933, 58],
["setarg", 8, 4, 4, 933, 58],
["invoke", 8, 6, 933, 58],
["tail_invoke", 8, 6, 933, 58],
["return", 6, 933, 58],
["null", 10, 933, 58],
["return", 10, 933, 58]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3162,10 +3162,10 @@
["setarg", 8, 2, 2, 934, 58],
["setarg", 8, 3, 3, 934, 58],
["setarg", 8, 4, 4, 934, 58],
["invoke", 8, 6, 934, 58],
["tail_invoke", 8, 6, 934, 58],
["return", 6, 934, 58],
["null", 10, 934, 58],
["return", 10, 934, 58]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3186,10 +3186,10 @@
["setarg", 8, 2, 2, 935, 58],
["setarg", 8, 3, 3, 935, 58],
["setarg", 8, 4, 4, 935, 58],
["invoke", 8, 6, 935, 58],
["tail_invoke", 8, 6, 935, 58],
["return", 6, 935, 58],
["null", 10, 935, 58],
["return", 10, 935, 58]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3210,10 +3210,10 @@
["setarg", 8, 2, 2, 936, 58],
["setarg", 8, 3, 3, 936, 58],
["setarg", 8, 4, 4, 936, 58],
["invoke", 8, 6, 936, 58],
["tail_invoke", 8, 6, 936, 58],
["return", 6, 936, 58],
["null", 10, 936, 58],
["return", 10, 936, 58]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3234,10 +3234,10 @@
["setarg", 8, 2, 2, 937, 58],
["setarg", 8, 3, 3, 937, 58],
["setarg", 8, 4, 4, 937, 58],
["invoke", 8, 6, 937, 58],
["tail_invoke", 8, 6, 937, 58],
["return", 6, 937, 58],
["null", 10, 937, 58],
["return", 10, 937, 58]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3258,10 +3258,10 @@
["setarg", 8, 2, 2, 938, 58],
["setarg", 8, 3, 3, 938, 58],
["setarg", 8, 4, 4, 938, 58],
["invoke", 8, 6, 938, 58],
["tail_invoke", 8, 6, 938, 58],
["return", 6, 938, 58],
["null", 10, 938, 58],
["return", 10, 938, 58]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3310,8 +3310,8 @@
["setarg", 13, 2, 9, 1, 1],
["invoke", 13, 12, 1, 1],
["return", 12, 1, 1],
["null", 15, 1, 1],
["return", 15, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3334,10 +3334,10 @@
["setarg", 9, 2, 2, 953, 73],
["setarg", 9, 3, 3, 953, 73],
["setarg", 9, 4, 4, 953, 73],
["invoke", 9, 7, 953, 73],
["tail_invoke", 9, 7, 953, 73],
["return", 7, 953, 73],
["null", 11, 953, 73],
["return", 11, 953, 73]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3360,10 +3360,10 @@
["setarg", 9, 2, 2, 954, 73],
["setarg", 9, 3, 3, 954, 73],
["setarg", 9, 4, 4, 954, 73],
["invoke", 9, 7, 954, 73],
["tail_invoke", 9, 7, 954, 73],
["return", 7, 954, 73],
["null", 11, 954, 73],
["return", 11, 954, 73]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3386,10 +3386,10 @@
["setarg", 9, 2, 2, 955, 74],
["setarg", 9, 3, 3, 955, 74],
["setarg", 9, 4, 4, 955, 74],
["invoke", 9, 7, 955, 74],
["tail_invoke", 9, 7, 955, 74],
["return", 7, 955, 74],
["null", 11, 955, 74],
["return", 11, 955, 74]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3412,10 +3412,10 @@
["setarg", 9, 2, 2, 956, 74],
["setarg", 9, 3, 3, 956, 74],
["setarg", 9, 4, 4, 956, 74],
["invoke", 9, 7, 956, 74],
["tail_invoke", 9, 7, 956, 74],
["return", 7, 956, 74],
["null", 11, 956, 74],
["return", 11, 956, 74]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3438,10 +3438,10 @@
["setarg", 9, 2, 2, 957, 74],
["setarg", 9, 3, 3, 957, 74],
["setarg", 9, 4, 4, 957, 74],
["invoke", 9, 7, 957, 74],
["tail_invoke", 9, 7, 957, 74],
["return", 7, 957, 74],
["null", 11, 957, 74],
["return", 11, 957, 74]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3464,10 +3464,10 @@
["setarg", 9, 2, 2, 958, 74],
["setarg", 9, 3, 3, 958, 74],
["setarg", 9, 4, 4, 958, 74],
["invoke", 9, 7, 958, 74],
["tail_invoke", 9, 7, 958, 74],
["return", 7, 958, 74],
["null", 11, 958, 74],
["return", 11, 958, 74]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3507,8 +3507,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3548,8 +3548,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3589,8 +3589,8 @@
["setarg", 8, 2, 4, 1, 1],
["invoke", 8, 7, 1, 1],
["return", 7, 1, 1],
["null", 10, 1, 1],
["return", 10, 1, 1]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe.cm",
@@ -3850,8 +3850,8 @@
["store_field", 168, 62, "ne_bool", 1081, 12],
["store_field", 168, 72, "is_identical", 1083, 17],
["return", 168, 1083, 17],
["null", 171, 1083, 17],
["return", 171, 1083, 17]
"_nop_ur_1",
"_nop_ur_2"
]
},
"filename": "qbe.cm",

View File

@@ -88,8 +88,8 @@
["disrupt", 23, 18],
"add_done_8",
["return", 12, 23, 18],
["null", 15, 23, 18],
["return", 15, 23, 18]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe_emit.cm",
@@ -139,8 +139,8 @@
["disrupt", 27, 19],
"add_done_12",
["return", 7, 27, 19],
["null", 10, 27, 19],
["return", 10, 27, 19]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe_emit.cm",
@@ -320,8 +320,8 @@
["invoke", 49, 47, 38, 9],
["move", 2, 47, 38, 9],
["return", 2, 39, 12],
["null", 51, 39, 12],
["return", 51, 39, 12]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe_emit.cm",
@@ -383,7 +383,7 @@
["get", 11, 9, 1, 47, 40],
["load_dynamic", 12, 11, 1, 47, 50],
["return", 12, 47, 50],
["jump", "if_end_15", 47, 50],
"_nop_ur_1",
"if_else_14",
"if_end_15",
["access", 13, "$d_str_", 48, 17],
@@ -613,8 +613,8 @@
["get", 60, 9, 1, 54, 5],
["store_dynamic", 60, 2, 1, 54, 15],
["return", 2, 55, 12],
["null", 61, 55, 12],
["return", 61, 55, 12]
"_nop_ur_2",
"_nop_ur_3"
],
"name": "<anonymous>",
"filename": "qbe_emit.cm",
@@ -625,14 +625,14 @@
"nr_slots": 18,
"nr_close_slots": 0,
"instructions": [
["is_text", 2, 1, 63, 17],
["jump_false", 2, "if_else_54", 63, 17],
"_nop_tc_1",
["jump", "if_else_54", 63, 17],
["return", 1, 63, 28],
["jump", "if_end_55", 63, 28],
"_nop_ur_1",
"if_else_54",
"if_end_55",
["is_record", 3, 1, 64, 19],
["jump_false", 3, "if_else_56", 64, 19],
"_nop_tc_2",
"_nop_tc_3",
["load_field", 4, 1, "name", 65, 11],
["null", 5, 65, 21],
["is_identical", 6, 4, 5, 65, 21],
@@ -682,7 +682,7 @@
["jump_false", 6, "if_else_58", 65, 21],
["load_field", 9, 1, "name", 65, 34],
["return", 9, 65, 34],
["jump", "if_end_59", 65, 34],
"_nop_ur_2",
"if_else_58",
"if_end_59",
["load_field", 10, 1, "value", 66, 11],
@@ -734,7 +734,7 @@
["jump_false", 12, "if_else_68", 66, 22],
["load_field", 15, 1, "value", 66, 35],
["return", 15, 66, 35],
["jump", "if_end_69", 66, 35],
"_nop_ur_3",
"if_else_68",
"if_end_69",
["jump", "if_end_57", 66, 35],
@@ -742,8 +742,8 @@
"if_end_57",
["null", 16, 68, 12],
["return", 16, 68, 12],
["null", 17, 68, 12],
["return", 17, 68, 12]
"_nop_ur_4",
"_nop_ur_5"
],
"name": "<anonymous>",
"filename": "qbe_emit.cm",
@@ -12910,10 +12910,10 @@
["setarg", 81, 0, 82, 754, 10],
["setarg", 81, 1, 5, 754, 10],
["setarg", 81, 2, 78, 754, 10],
["invoke", 81, 79, 754, 10],
["tail_invoke", 81, 79, 754, 10],
["return", 79, 754, 10],
["null", 83, 754, 10],
["return", 83, 754, 10]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "qbe_emit.cm",
@@ -12928,8 +12928,8 @@
["function", 2, 8, 6, 16],
["move", 1, 2, 6, 16],
["return", 1, 757, 8],
["null", 3, 757, 8],
["return", 3, 757, 8]
"_nop_ur_1",
"_nop_ur_2"
]
},
"filename": "qbe_emit.cm",

View File

@@ -1971,7 +1971,7 @@ static int mcode_reg_items(cJSON *it, cJSON **out) {
{ ADD(1); return c; }
/* invoke: [1]=frame, [2]=dest (result register) */
if (!strcmp(op, "invoke")) { ADD(1); ADD(2); return c; }
if (!strcmp(op, "invoke") || !strcmp(op, "tail_invoke")) { ADD(1); ADD(2); return c; }
/* goinvoke: [1]=frame only (no result) */
if (!strcmp(op, "goinvoke")) { ADD(1); return c; }
@@ -2518,7 +2518,7 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
else if (strcmp(op, "setarg") == 0) {
EM(MACH_ABC(MACH_SETARG, A1, A2, A3));
}
else if (strcmp(op, "invoke") == 0) {
else if (strcmp(op, "invoke") == 0 || strcmp(op, "tail_invoke") == 0) {
EM(MACH_ABC(MACH_INVOKE, A1, A2, 0));
}
else if (strcmp(op, "goframe") == 0) {

View File

@@ -147,7 +147,7 @@ var streamline = function(ir, log) {
slot_types[text(instr[1])] = T_BOOL
} else if (op == "load_field" || op == "load_index" || op == "load_dynamic") {
slot_types[text(instr[1])] = T_UNKNOWN
} else if (op == "invoke") {
} else if (op == "invoke" || op == "tail_invoke") {
slot_types[text(instr[2])] = T_UNKNOWN
} else if (op == "pop" || op == "get") {
slot_types[text(instr[1])] = T_UNKNOWN
@@ -284,6 +284,13 @@ var streamline = function(ir, log) {
merge_backward(backward_types, instr[1], T_RECORD)
} else if (op == "push") {
merge_backward(backward_types, instr[1], T_ARRAY)
} else if (op == "load_index") {
merge_backward(backward_types, instr[2], T_ARRAY)
merge_backward(backward_types, instr[3], T_INT)
} else if (op == "load_field") {
merge_backward(backward_types, instr[2], T_RECORD)
} else if (op == "pop") {
merge_backward(backward_types, instr[2], T_ARRAY)
}
}
i = i + 1
@@ -867,7 +874,7 @@ var streamline = function(ir, log) {
}
// Clear value tracking for dest-producing ops (not reads-only)
if (op == "invoke") {
if (op == "invoke" || op == "tail_invoke") {
slot_values[text(instr[2])] = null
} else if (op != "int" && op != "access" && op != "true" &&
op != "false" && op != "move" && op != "null" &&
@@ -1050,7 +1057,7 @@ var streamline = function(ir, log) {
if (after_return) {
nc = nc + 1
instructions[i] = "_nop_ur_" + text(nc)
} else if (instr[0] == "return" || instr[0] == "disrupt") {
} else if (instr[0] == "return") {
after_return = true
}
}
@@ -1156,10 +1163,10 @@ var streamline = function(ir, log) {
return eliminate_moves(func, log)
})
if (verify_fn) verify_fn(func, "after eliminate_moves")
// NOTE: eliminate_unreachable is disabled because disruption handler
// code is placed after return/disrupt without label boundaries.
// Re-enable once mcode.cm emits labels for handler entry points.
//eliminate_unreachable(func)
run_pass(func, "eliminate_unreachable", function() {
return eliminate_unreachable(func)
})
if (verify_fn) verify_fn(func, "after eliminate_unreachable")
run_pass(func, "eliminate_dead_jumps", function() {
return eliminate_dead_jumps(func, log)
})

File diff suppressed because it is too large Load Diff

View File

@@ -34,15 +34,15 @@
["jump_false", 3, "if_else_0", 82, 16],
["access", 6, -1, 82, 28],
["return", 6, 82, 28],
["jump", "if_end_1", 82, 28],
"_nop_ur_1",
"if_else_0",
"if_end_1",
["get", 7, 44, 1, 83, 12],
["get", 8, 6, 1, 83, 15],
["load_dynamic", 9, 7, 8, 83, 15],
["return", 9, 83, 15],
["null", 10, 83, 15],
["return", 10, 83, 15]
"_nop_ur_2",
"_nop_ur_3"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -105,14 +105,14 @@
["jump_false", 8, "if_else_10", 88, 16],
["access", 11, -1, 88, 28],
["return", 11, 88, 28],
["jump", "if_end_11", 88, 28],
"_nop_ur_1",
"if_else_10",
"if_end_11",
["get", 12, 44, 1, 89, 12],
["load_dynamic", 13, 12, 2, 89, 15],
["return", 13, 89, 15],
["null", 14, 89, 15],
["return", 14, 89, 15]
"_nop_ur_2",
"_nop_ur_3"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -240,8 +240,8 @@
["put", 22, 31, 1, 99, 19],
"if_end_21",
["return", 1, 101, 12],
["null", 25, 101, 12],
["return", 25, 101, 12]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -305,8 +305,8 @@
["move", 6, 8, 105, 30],
"and_end_36",
["return", 6, 105, 30],
["null", 11, 105, 30],
["return", 11, 105, 30]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -482,8 +482,8 @@
["move", 21, 26, 109, 87],
"or_end_45",
["return", 21, 109, 87],
["null", 31, 109, 87],
["return", 31, 109, 87]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -565,7 +565,7 @@
["disrupt", 113, 44],
"num_done_86",
["return", 12, 113, 44],
["jump", "if_end_75", 113, 44],
"_nop_ur_1",
"if_else_74",
"if_end_75",
["get", 15, 50, 1, 114, 14],
@@ -659,7 +659,7 @@
["disrupt", 114, 51],
"add_done_104",
["return", 29, 114, 51],
["jump", "if_end_89", 114, 51],
"_nop_ur_2",
"if_else_88",
"if_end_89",
["get", 32, 38, 1, 115, 14],
@@ -753,13 +753,13 @@
["disrupt", 115, 51],
"add_done_122",
["return", 46, 115, 51],
["jump", "if_end_107", 115, 51],
"_nop_ur_3",
"if_else_106",
"if_end_107",
["access", 49, 0, 116, 12],
["return", 49, 116, 12],
["null", 50, 116, 12],
["return", 50, 116, 12]
"_nop_ur_4",
"_nop_ur_5"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -928,10 +928,10 @@
["null", 44, 126, 12],
["setarg", 43, 0, 44, 126, 12],
["setarg", 43, 1, 1, 126, 12],
["invoke", 43, 41, 126, 12],
["tail_invoke", 43, 41, 126, 12],
["return", 41, 126, 12],
["null", 45, 126, 12],
["return", 45, 126, 12]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -1051,8 +1051,8 @@
["move", 11, 16, 130, 59],
"or_end_147",
["return", 11, 130, 59],
["null", 21, 130, 59],
["return", 21, 130, 59]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -1080,8 +1080,8 @@
["move", 6, 7, 134, 27],
"or_end_166",
["return", 6, 134, 27],
["null", 11, 134, 27],
["return", 11, 134, 27]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -1187,8 +1187,8 @@
["move", 11, 13, 138, 54],
"or_end_167",
["return", 11, 138, 54],
["null", 16, 138, 54],
["return", 16, 138, 54]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -1382,8 +1382,8 @@
["move", 21, 23, 142, 89],
"or_end_181",
["return", 21, 142, 89],
["null", 26, 142, 89],
["return", 26, 142, 89]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -1412,10 +1412,10 @@
["setarg", 6, 1, 3, 146, 12],
["setarg", 6, 2, 1, 146, 12],
["setarg", 6, 3, 2, 146, 12],
["invoke", 6, 4, 146, 12],
["tail_invoke", 6, 4, 146, 12],
["return", 4, 146, 12],
["null", 8, 146, 12],
["return", 8, 146, 12]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -5893,7 +5893,7 @@
["jump_false", 11, "if_else_851", 362, 14],
["false", 14, 362, 25],
["return", 14, 362, 25],
["jump", "if_end_852", 362, 25],
"_nop_ur_1",
"if_else_851",
"if_end_852",
["get", 15, 10, 1, 364, 14],
@@ -5970,7 +5970,7 @@
"push_done_868",
["true", 33, 368, 14],
["return", 33, 368, 14],
["jump", "if_end_860", 368, 14],
"_nop_ur_2",
"if_else_859",
"if_end_860",
["get", 34, 14, 1, 370, 14],
@@ -6130,7 +6130,7 @@
"push_done_891",
["true", 70, 375, 14],
["return", 70, 375, 14],
["jump", "if_end_870", 375, 14],
"_nop_ur_3",
"if_else_869",
"if_end_870",
["get", 71, 72, 1, 377, 14],
@@ -6386,7 +6386,7 @@
"push_done_928",
["true", 121, 382, 14],
["return", 121, 382, 14],
["jump", "if_end_893", 382, 14],
"_nop_ur_4",
"if_else_892",
"if_end_893",
["get", 122, 63, 1, 384, 14],
@@ -6482,7 +6482,7 @@
["invoke", 133, 131, 384, 45],
["true", 135, 384, 68],
["return", 135, 384, 68],
["jump", "if_end_930", 384, 68],
"_nop_ur_5",
"if_else_929",
"if_end_930",
["get", 136, 39, 1, 385, 14],
@@ -6533,7 +6533,7 @@
["invoke", 142, 140, 385, 29],
["true", 144, 385, 53],
["return", 144, 385, 53],
["jump", "if_end_945", 385, 53],
"_nop_ur_6",
"if_else_944",
"if_end_945",
["get", 146, 55, 1, 386, 9],
@@ -6550,7 +6550,7 @@
["invoke", 151, 149, 386, 24],
["true", 153, 386, 46],
["return", 153, 386, 46],
["jump", "if_end_953", 386, 46],
"_nop_ur_7",
"if_else_952",
"if_end_953",
["get", 154, 43, 1, 387, 14],
@@ -6618,7 +6618,7 @@
["invoke", 170, 168, 387, 46],
["true", 172, 387, 68],
["return", 172, 387, 68],
["jump", "if_end_955", 387, 68],
"_nop_ur_8",
"if_else_954",
"if_end_955",
["get", 174, 9, 1, 388, 9],
@@ -6635,7 +6635,7 @@
["invoke", 179, 177, 388, 30],
["true", 181, 388, 50],
["return", 181, 388, 50],
["jump", "if_end_964", 388, 50],
"_nop_ur_9",
"if_else_963",
"if_end_964",
["get", 182, 67, 1, 389, 14],
@@ -6785,7 +6785,7 @@
["invoke", 207, 205, 390, 58],
["true", 209, 390, 81],
["return", 209, 390, 81],
["jump", "if_end_974", 390, 81],
"_nop_ur_10",
"if_else_973",
"if_end_974",
["access", 210, 1, 391, 17],
@@ -6847,7 +6847,7 @@
["invoke", 223, 221, 391, 32],
["true", 225, 391, 57],
["return", 225, 391, 57],
["jump", "if_end_989", 391, 57],
"_nop_ur_11",
"if_else_988",
"if_end_989",
["access", 226, 1, 392, 17],
@@ -6907,7 +6907,7 @@
["invoke", 238, 236, 392, 34],
["true", 240, 392, 56],
["return", 240, 392, 56],
["jump", "if_end_997", 392, 56],
"_nop_ur_12",
"if_else_996",
"if_end_997",
["access", 241, "/", 393, 15],
@@ -6921,7 +6921,7 @@
["invoke", 245, 243, 393, 7],
["true", 247, 393, 31],
["return", 247, 393, 31],
["jump", "if_end_966", 393, 31],
"_nop_ur_13",
"if_else_965",
"if_end_966",
["get", 248, 59, 1, 395, 14],
@@ -7070,7 +7070,7 @@
["invoke", 273, 271, 397, 36],
["true", 275, 397, 58],
["return", 275, 397, 58],
["jump", "if_end_1021", 397, 58],
"_nop_ur_14",
"if_else_1020",
"if_end_1021",
["access", 276, 2, 398, 19],
@@ -7132,7 +7132,7 @@
["invoke", 289, 287, 398, 34],
["true", 291, 398, 60],
["return", 291, 398, 60],
["jump", "if_end_1029", 398, 60],
"_nop_ur_15",
"if_else_1028",
"if_end_1029",
["access", 292, "**", 399, 17],
@@ -7146,7 +7146,7 @@
["invoke", 296, 294, 399, 9],
["true", 298, 399, 34],
["return", 298, 399, 34],
["jump", "if_end_1013", 399, 34],
"_nop_ur_16",
"if_else_1012",
"if_end_1013",
["access", 299, 1, 401, 17],
@@ -7208,7 +7208,7 @@
["invoke", 312, 310, 401, 32],
["true", 314, 401, 57],
["return", 314, 401, 57],
["jump", "if_end_1037", 401, 57],
"_nop_ur_17",
"if_else_1036",
"if_end_1037",
["access", 315, 1, 402, 17],
@@ -7268,7 +7268,7 @@
["invoke", 327, 325, 402, 34],
["true", 329, 402, 56],
["return", 329, 402, 56],
["jump", "if_end_1045", 402, 56],
"_nop_ur_18",
"if_else_1044",
"if_end_1045",
["access", 330, "*", 403, 15],
@@ -7282,7 +7282,7 @@
["invoke", 334, 332, 403, 7],
["true", 336, 403, 31],
["return", 336, 403, 31],
["jump", "if_end_1005", 403, 31],
"_nop_ur_19",
"if_else_1004",
"if_end_1005",
["get", 337, 46, 1, 405, 14],
@@ -7385,7 +7385,7 @@
["invoke", 354, 352, 406, 32],
["true", 356, 406, 57],
["return", 356, 406, 57],
["jump", "if_end_1061", 406, 57],
"_nop_ur_20",
"if_else_1060",
"if_end_1061",
["access", 357, 1, 407, 17],
@@ -7445,7 +7445,7 @@
["invoke", 369, 367, 407, 34],
["true", 371, 407, 56],
["return", 371, 407, 56],
["jump", "if_end_1069", 407, 56],
"_nop_ur_21",
"if_else_1068",
"if_end_1069",
["access", 372, "%", 408, 15],
@@ -7459,7 +7459,7 @@
["invoke", 376, 374, 408, 7],
["true", 378, 408, 31],
["return", 378, 408, 31],
["jump", "if_end_1053", 408, 31],
"_nop_ur_22",
"if_else_1052",
"if_end_1053",
["get", 379, 11, 1, 410, 14],
@@ -7562,7 +7562,7 @@
["invoke", 396, 394, 411, 32],
["true", 398, 411, 57],
["return", 398, 411, 57],
["jump", "if_end_1085", 411, 57],
"_nop_ur_23",
"if_else_1084",
"if_end_1085",
["access", 399, 1, 412, 17],
@@ -7624,7 +7624,7 @@
["invoke", 412, 410, 412, 34],
["true", 414, 412, 59],
["return", 414, 412, 59],
["jump", "if_end_1093", 412, 59],
"_nop_ur_24",
"if_else_1092",
"if_end_1093",
["access", 415, 1, 413, 17],
@@ -7684,7 +7684,7 @@
["invoke", 427, 425, 413, 34],
["true", 429, 413, 56],
["return", 429, 413, 56],
["jump", "if_end_1101", 413, 56],
"_nop_ur_25",
"if_else_1100",
"if_end_1101",
["access", 430, "+", 414, 15],
@@ -7698,7 +7698,7 @@
["invoke", 434, 432, 414, 7],
["true", 436, 414, 31],
["return", 436, 414, 31],
["jump", "if_end_1077", 414, 31],
"_nop_ur_26",
"if_else_1076",
"if_end_1077",
["get", 437, 36, 1, 416, 14],
@@ -7801,7 +7801,7 @@
["invoke", 454, 452, 417, 32],
["true", 456, 417, 57],
["return", 456, 417, 57],
["jump", "if_end_1117", 417, 57],
"_nop_ur_27",
"if_else_1116",
"if_end_1117",
["access", 457, 1, 418, 17],
@@ -7863,7 +7863,7 @@
["invoke", 470, 468, 418, 35],
["true", 472, 418, 60],
["return", 472, 418, 60],
["jump", "if_end_1125", 418, 60],
"_nop_ur_28",
"if_else_1124",
"if_end_1125",
["access", 473, 1, 419, 17],
@@ -7923,7 +7923,7 @@
["invoke", 485, 483, 419, 34],
["true", 487, 419, 56],
["return", 487, 419, 56],
["jump", "if_end_1133", 419, 56],
"_nop_ur_29",
"if_else_1132",
"if_end_1133",
["access", 488, "-", 420, 15],
@@ -7937,7 +7937,7 @@
["invoke", 492, 490, 420, 7],
["true", 494, 420, 31],
["return", 494, 420, 31],
["jump", "if_end_1109", 420, 31],
"_nop_ur_30",
"if_else_1108",
"if_end_1109",
["get", 495, 54, 1, 422, 14],
@@ -8089,7 +8089,7 @@
["invoke", 521, 519, 423, 55],
["true", 523, 423, 77],
["return", 523, 423, 77],
["jump", "if_end_1149", 423, 77],
"_nop_ur_31",
"if_else_1148",
"if_end_1149",
["access", 524, 1, 424, 17],
@@ -8151,7 +8151,7 @@
["invoke", 537, 535, 424, 32],
["true", 539, 424, 57],
["return", 539, 424, 57],
["jump", "if_end_1164", 424, 57],
"_nop_ur_32",
"if_else_1163",
"if_end_1164",
["access", 540, 1, 425, 17],
@@ -8259,7 +8259,7 @@
["invoke", 561, 559, 426, 36],
["true", 563, 426, 58],
["return", 563, 426, 58],
["jump", "if_end_1180", 426, 58],
"_nop_ur_33",
"if_else_1179",
"if_end_1180",
["access", 564, 2, 427, 19],
@@ -8321,7 +8321,7 @@
["invoke", 577, 575, 427, 34],
["true", 579, 427, 60],
["return", 579, 427, 60],
["jump", "if_end_1188", 427, 60],
"_nop_ur_34",
"if_else_1187",
"if_end_1188",
["access", 580, "<<", 428, 17],
@@ -8335,7 +8335,7 @@
["invoke", 584, 582, 428, 9],
["true", 586, 428, 34],
["return", 586, 428, 34],
["jump", "if_end_1172", 428, 34],
"_nop_ur_35",
"if_else_1171",
"if_end_1172",
["access", 587, 1, 430, 17],
@@ -8395,7 +8395,7 @@
["invoke", 599, 597, 430, 34],
["true", 601, 430, 56],
["return", 601, 430, 56],
["jump", "if_end_1196", 430, 56],
"_nop_ur_36",
"if_else_1195",
"if_end_1196",
["access", 602, "<", 431, 15],
@@ -8409,7 +8409,7 @@
["invoke", 606, 604, 431, 7],
["true", 608, 431, 31],
["return", 608, 431, 31],
["jump", "if_end_1141", 431, 31],
"_nop_ur_37",
"if_else_1140",
"if_end_1141",
["get", 609, 13, 1, 433, 14],
@@ -8561,7 +8561,7 @@
["invoke", 635, 633, 434, 55],
["true", 637, 434, 77],
["return", 637, 434, 77],
["jump", "if_end_1212", 434, 77],
"_nop_ur_38",
"if_else_1211",
"if_end_1212",
["access", 638, 1, 435, 17],
@@ -8623,7 +8623,7 @@
["invoke", 651, 649, 435, 32],
["true", 653, 435, 57],
["return", 653, 435, 57],
["jump", "if_end_1227", 435, 57],
"_nop_ur_39",
"if_else_1226",
"if_end_1227",
["access", 654, 1, 436, 17],
@@ -8779,7 +8779,7 @@
["invoke", 684, 682, 438, 38],
["true", 686, 438, 60],
["return", 686, 438, 60],
["jump", "if_end_1251", 438, 60],
"_nop_ur_40",
"if_else_1250",
"if_end_1251",
["access", 687, 3, 439, 21],
@@ -8841,7 +8841,7 @@
["invoke", 700, 698, 439, 36],
["true", 702, 439, 63],
["return", 702, 439, 63],
["jump", "if_end_1259", 439, 63],
"_nop_ur_41",
"if_else_1258",
"if_end_1259",
["access", 703, ">>>", 440, 19],
@@ -8855,7 +8855,7 @@
["invoke", 707, 705, 440, 11],
["true", 709, 440, 37],
["return", 709, 440, 37],
["jump", "if_end_1243", 440, 37],
"_nop_ur_42",
"if_else_1242",
"if_end_1243",
["access", 710, 2, 442, 19],
@@ -8915,7 +8915,7 @@
["invoke", 722, 720, 442, 36],
["true", 724, 442, 58],
["return", 724, 442, 58],
["jump", "if_end_1267", 442, 58],
"_nop_ur_43",
"if_else_1266",
"if_end_1267",
["access", 725, 2, 443, 19],
@@ -8977,7 +8977,7 @@
["invoke", 738, 736, 443, 34],
["true", 740, 443, 60],
["return", 740, 443, 60],
["jump", "if_end_1275", 443, 60],
"_nop_ur_44",
"if_else_1274",
"if_end_1275",
["access", 741, ">>", 444, 17],
@@ -8991,7 +8991,7 @@
["invoke", 745, 743, 444, 9],
["true", 747, 444, 34],
["return", 747, 444, 34],
["jump", "if_end_1235", 444, 34],
"_nop_ur_45",
"if_else_1234",
"if_end_1235",
["access", 748, 1, 446, 17],
@@ -9051,7 +9051,7 @@
["invoke", 760, 758, 446, 34],
["true", 762, 446, 56],
["return", 762, 446, 56],
["jump", "if_end_1283", 446, 56],
"_nop_ur_46",
"if_else_1282",
"if_end_1283",
["access", 763, ">", 447, 15],
@@ -9065,7 +9065,7 @@
["invoke", 767, 765, 447, 7],
["true", 769, 447, 31],
["return", 769, 447, 31],
["jump", "if_end_1204", 447, 31],
"_nop_ur_47",
"if_else_1203",
"if_end_1204",
["get", 770, 65, 1, 449, 14],
@@ -9216,7 +9216,7 @@
["invoke", 796, 794, 451, 34],
["true", 798, 451, 60],
["return", 798, 451, 60],
["jump", "if_end_1307", 451, 60],
"_nop_ur_48",
"if_else_1306",
"if_end_1307",
["access", 799, "==", 452, 17],
@@ -9230,7 +9230,7 @@
["invoke", 803, 801, 452, 9],
["true", 805, 452, 34],
["return", 805, 452, 34],
["jump", "if_end_1299", 452, 34],
"_nop_ur_49",
"if_else_1298",
"if_end_1299",
["access", 806, 1, 454, 17],
@@ -9292,7 +9292,7 @@
["invoke", 819, 817, 454, 32],
["true", 821, 454, 57],
["return", 821, 454, 57],
["jump", "if_end_1315", 454, 57],
"_nop_ur_50",
"if_else_1314",
"if_end_1315",
["access", 822, 1, 455, 17],
@@ -9352,7 +9352,7 @@
["invoke", 834, 832, 455, 34],
["true", 836, 455, 56],
["return", 836, 455, 56],
["jump", "if_end_1323", 455, 56],
"_nop_ur_51",
"if_else_1322",
"if_end_1323",
["access", 837, "=", 456, 15],
@@ -9366,7 +9366,7 @@
["invoke", 841, 839, 456, 7],
["true", 843, 456, 31],
["return", 843, 456, 31],
["jump", "if_end_1291", 456, 31],
"_nop_ur_52",
"if_else_1290",
"if_end_1291",
["get", 844, 20, 1, 458, 14],
@@ -9515,7 +9515,7 @@
["invoke", 869, 867, 460, 36],
["true", 871, 460, 58],
["return", 871, 460, 58],
["jump", "if_end_1347", 460, 58],
"_nop_ur_53",
"if_else_1346",
"if_end_1347",
["access", 872, 2, 461, 19],
@@ -9577,7 +9577,7 @@
["invoke", 885, 883, 461, 34],
["true", 887, 461, 60],
["return", 887, 461, 60],
["jump", "if_end_1355", 461, 60],
"_nop_ur_54",
"if_else_1354",
"if_end_1355",
["access", 888, "!=", 462, 17],
@@ -9591,7 +9591,7 @@
["invoke", 892, 890, 462, 9],
["true", 894, 462, 34],
["return", 894, 462, 34],
["jump", "if_end_1339", 462, 34],
"_nop_ur_55",
"if_else_1338",
"if_end_1339",
["access", 895, "!", 464, 15],
@@ -9605,7 +9605,7 @@
["invoke", 899, 897, 464, 7],
["true", 901, 464, 31],
["return", 901, 464, 31],
["jump", "if_end_1331", 464, 31],
"_nop_ur_56",
"if_else_1330",
"if_end_1331",
["get", 902, 76, 1, 466, 14],
@@ -9754,7 +9754,7 @@
["invoke", 927, 925, 468, 36],
["true", 929, 468, 58],
["return", 929, 468, 58],
["jump", "if_end_1379", 468, 58],
"_nop_ur_57",
"if_else_1378",
"if_end_1379",
["access", 930, 2, 469, 19],
@@ -9816,7 +9816,7 @@
["invoke", 943, 941, 469, 34],
["true", 945, 469, 60],
["return", 945, 469, 60],
["jump", "if_end_1387", 469, 60],
"_nop_ur_58",
"if_else_1386",
"if_end_1387",
["access", 946, "&&", 470, 17],
@@ -9830,7 +9830,7 @@
["invoke", 950, 948, 470, 9],
["true", 952, 470, 34],
["return", 952, 470, 34],
["jump", "if_end_1371", 470, 34],
"_nop_ur_59",
"if_else_1370",
"if_end_1371",
["access", 953, 1, 472, 17],
@@ -9892,7 +9892,7 @@
["invoke", 966, 964, 472, 32],
["true", 968, 472, 57],
["return", 968, 472, 57],
["jump", "if_end_1395", 472, 57],
"_nop_ur_60",
"if_else_1394",
"if_end_1395",
["access", 969, 1, 473, 17],
@@ -9952,7 +9952,7 @@
["invoke", 981, 979, 473, 34],
["true", 983, 473, 56],
["return", 983, 473, 56],
["jump", "if_end_1403", 473, 56],
"_nop_ur_61",
"if_else_1402",
"if_end_1403",
["access", 984, "&", 474, 15],
@@ -9966,7 +9966,7 @@
["invoke", 988, 986, 474, 7],
["true", 990, 474, 31],
["return", 990, 474, 31],
["jump", "if_end_1363", 474, 31],
"_nop_ur_62",
"if_else_1362",
"if_end_1363",
["get", 991, 25, 1, 476, 14],
@@ -10115,7 +10115,7 @@
["invoke", 1016, 1014, 478, 36],
["true", 1018, 478, 58],
["return", 1018, 478, 58],
["jump", "if_end_1427", 478, 58],
"_nop_ur_63",
"if_else_1426",
"if_end_1427",
["access", 1019, 2, 479, 19],
@@ -10177,7 +10177,7 @@
["invoke", 1032, 1030, 479, 34],
["true", 1034, 479, 60],
["return", 1034, 479, 60],
["jump", "if_end_1435", 479, 60],
"_nop_ur_64",
"if_else_1434",
"if_end_1435",
["access", 1035, "||", 480, 17],
@@ -10191,7 +10191,7 @@
["invoke", 1039, 1037, 480, 9],
["true", 1041, 480, 34],
["return", 1041, 480, 34],
["jump", "if_end_1419", 480, 34],
"_nop_ur_65",
"if_else_1418",
"if_end_1419",
["access", 1042, 1, 482, 17],
@@ -10253,7 +10253,7 @@
["invoke", 1055, 1053, 482, 32],
["true", 1057, 482, 57],
["return", 1057, 482, 57],
["jump", "if_end_1443", 482, 57],
"_nop_ur_66",
"if_else_1442",
"if_end_1443",
["access", 1058, 1, 483, 17],
@@ -10313,7 +10313,7 @@
["invoke", 1070, 1068, 483, 34],
["true", 1072, 483, 56],
["return", 1072, 483, 56],
["jump", "if_end_1451", 483, 56],
"_nop_ur_67",
"if_else_1450",
"if_end_1451",
["access", 1073, "|", 484, 15],
@@ -10327,7 +10327,7 @@
["invoke", 1077, 1075, 484, 7],
["true", 1079, 484, 31],
["return", 1079, 484, 31],
["jump", "if_end_1411", 484, 31],
"_nop_ur_68",
"if_else_1410",
"if_end_1411",
["get", 1080, 23, 1, 486, 14],
@@ -10430,7 +10430,7 @@
["invoke", 1097, 1095, 487, 32],
["true", 1099, 487, 57],
["return", 1099, 487, 57],
["jump", "if_end_1467", 487, 57],
"_nop_ur_69",
"if_else_1466",
"if_end_1467",
["access", 1100, 1, 488, 17],
@@ -10490,7 +10490,7 @@
["invoke", 1112, 1110, 488, 34],
["true", 1114, 488, 56],
["return", 1114, 488, 56],
["jump", "if_end_1475", 488, 56],
"_nop_ur_70",
"if_else_1474",
"if_end_1475",
["access", 1115, "^", 489, 15],
@@ -10504,7 +10504,7 @@
["invoke", 1119, 1117, 489, 7],
["true", 1121, 489, 31],
["return", 1121, 489, 31],
["jump", "if_end_1459", 489, 31],
"_nop_ur_71",
"if_else_1458",
"if_end_1459",
["get", 1122, 74, 1, 491, 14],
@@ -10656,7 +10656,7 @@
["invoke", 1148, 1146, 492, 61],
["true", 1150, 492, 83],
["return", 1150, 492, 83],
["jump", "if_end_1491", 492, 83],
"_nop_ur_72",
"if_else_1490",
"if_end_1491",
["access", 1151, "[", 493, 15],
@@ -10670,7 +10670,7 @@
["invoke", 1155, 1153, 493, 7],
["true", 1157, 493, 31],
["return", 1157, 493, 31],
["jump", "if_end_1483", 493, 31],
"_nop_ur_73",
"if_else_1482",
"if_end_1483",
["get", 1158, 7, 1, 495, 14],
@@ -10771,7 +10771,7 @@
["invoke", 1174, 1172, 496, 34],
["true", 1176, 496, 56],
["return", 1176, 496, 56],
["jump", "if_end_1514", 496, 56],
"_nop_ur_74",
"if_else_1513",
"if_end_1514",
["access", 1177, "~", 497, 15],
@@ -10785,7 +10785,7 @@
["invoke", 1181, 1179, 497, 7],
["true", 1183, 497, 31],
["return", 1183, 497, 31],
["jump", "if_end_1506", 497, 31],
"_nop_ur_75",
"if_else_1505",
"if_end_1506",
[
@@ -10814,8 +10814,8 @@
["invoke", 1191, 1189, 499, 5],
["true", 1193, 500, 12],
["return", 1193, 500, 12],
["null", 1194, 500, 12],
["return", 1194, 500, 12]
"_nop_ur_76",
"_nop_ur_77"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -11062,8 +11062,8 @@
["store_field", 142, 34, "tokens", 511, 39],
["store_field", 142, 44, "cp", 511, 51],
["return", 142, 511, 51],
["null", 143, 511, 51],
["return", 143, 511, 51]
"_nop_ur_1",
"_nop_ur_2"
],
"name": "<anonymous>",
"filename": "tokenize.cm",
@@ -11078,8 +11078,8 @@
["function", 2, 20, 1, 16],
["move", 1, 2, 1, 16],
["return", 1, 514, 8],
["null", 3, 514, 8],
["return", 3, 514, 8]
"_nop_ur_1",
"_nop_ur_2"
]
},
"filename": "tokenize.cm",

View File

@@ -113,6 +113,7 @@ var slot_positions = {
// Invoke
invoke: [0, 1],
tail_invoke: [0, 1],
goinvoke: [0],
frame: [0, 1],
setarg: [0, 2]
@@ -141,7 +142,8 @@ var writes_dest = {
in: true,
load_index: true, load_dynamic: true, load_field: true,
pop: true, get: true,
invoke: true
invoke: true,
tail_invoke: true
}
// Opcodes where invoke writes to position 1 (result slot), not position 0